notes/articles/2. Add Kubernetes roles/Add Kubernetes Roles.md
Allen Languor 71f4cd0462 articles
2021-06-04 06:03:46 +03:00

208 lines
6.8 KiB
Markdown

# Add Kubernetes users with Ansible
Hi! In the [previous article](https://gist.github.com/allanger/84db2647578316f8e721f7219052788f), I've told how to deploy k8s cluster with ansible. Now I'm going to tell, how to add users to your cluster to be able to control your k8s remotely.
My Github: https://github.com/allanger/kubernetes-rbac-ansible-role
Let's imagine you've deployed a bare-metal cluster and you ssh to the master node every time you wanna do something with it. It's not cool, right? So you need to add a user to your cluster.
You can do it manually but, I think, after the first time you perform it, you'd like to do it automatically. That's why I've created this Ansible role.
Clone the repo and go to /vars/main.yaml file.
If you know what you wanna do, set all variables yourself, but if you're not sure, you should update only the `username` var.
In this case, we're adding a cluster-admin user, because I guess if you're able to run this role against your master node, you're a cluster admin.
```
---
# --------------------------------------
# -- K8s username
# --------------------------------------
username: "admin"
# --------------------------------------
# -- How many days certificate
# -- will be valid
# --------------------------------------
certificate_expires_in: 500
# --------------------------------------
# -- K8s cluster name
# --------------------------------------
cluster: "kubernetes"
# --------------------------------------
# -- RoleBinding parameters
# --------------------------------------
# -- Binding type:
# ---- ClusterRoleBinding
# ---- RoleBinding
# --------------------------------------
binding_type: ClusterRoleBinding
# --------------------------------------
# -- Role type
# -- ClusterRole
# -- Role
# --------------------------------------
role_type: ClusterRole
# --------------------------------------
# -- Cluster role name
# -- https://kubernetes.io/docs/reference/access-authn-authz/rbac/
# --------------------------------------
role: cluster-admin
```
When you're done, let's go to `/tasks/main.yaml`.
In the first block, we are creating a working directory. In this directory, Ansible will store certificates and configs. (It will be removed after the play, so it's a temporary dir)
```
- name: Prepare working directory
block:
- name: Set workdir as fact
set_fact:
working_dir: "{{ ansible_env.HOME }}/.certs/{{ username }}"
- name: Create a directory if it does not exist
ansible.builtin.file:
path: "{{ working_dir }}"
state: directory
mode: "0775"
```
In the second block, we're installing packages that will be used while running the role.
```
- name: Ensure required packages are installed
block:
# --------------------------------------
# -- yq is a lightweight and portable
# -- command-line YAML processor
# --------------------------------------
- name: Ensure yq is installed
become: yes
get_url:
url: "https://github.com/mikefarah/yq/releases/download/{{ yq.version }}/{{ yq.binary }}"
dest: /usr/bin/yq
mode: "0777"
- name: Ensure openssl is installed
package:
name: openssl
state: present
tags: packages
```
Then we will generate a certificate:
```
- name: Generate openssl certificate
block:
- name: Generate an OpenSSL private key
community.crypto.openssl_privatekey:
path: "{{ working_dir }}/{{ username }}.key"
size: 2048
- name: Generate an OpenSSL Certificate Signing Request
community.crypto.openssl_csr:
path: "{{ working_dir }}/{{ username }}.csr"
privatekey_path: "{{ working_dir }}/{{ username }}.key"
common_name: "{{ username }}"
- name: Generate an OpenSSL certificate signed with your own CA certificate
become: yes
community.crypto.x509_certificate:
path: "{{ working_dir }}/{{ username }}.crt"
csr_path: "{{ working_dir }}/{{ username }}.csr"
ownca_path: /etc/kubernetes/pki/ca.crt
ownca_privatekey_path: /etc/kubernetes/pki/ca.key
provider: ownca
entrust_not_after: "+{{ certificate_expires_in }}d"
tags: openssl
```
When the certificate is ready we need to add a user to our cluster
```
- name: Add user to cluster
block:
# --------------------------------------
# -- Get k8s server from admin.conf
# --------------------------------------
- name: Get k8s server
shell: yq e '.clusters[0] | select(.name == "{{ cluster }}").cluster.server' "{{ k8s_config_path }}"
register: kubernetes_server_output
# --------------------------------------
# -- Get k8s certificate authority data
# -- from admin-conf
# --------------------------------------
- name: Get k8s certificate authority data
shell: yq e '.clusters[0] | select(.name == "{{ cluster }}").cluster.certificate-authority-data' "{{ k8s_config_path }}"
register: kubernetes_cad_output
- name: Get user cert data
shell: cat "{{ working_dir }}/{{ username }}.crt" | base64 -w 0
register: user_cert_data_output
- name: Get user key data
shell: cat "{{ working_dir }}/{{ username }}.key" | base64 -w 0
register: user_key_data_output
- name: Set variables for template
set_fact:
kubernetes_server: "{{ kubernetes_server_output.stdout }}"
kubernetes_cad: "{{ kubernetes_cad_output.stdout }}"
user_cert_data: " {{ user_cert_data_output.stdout }}"
user_key_data: " {{ user_key_data_output.stdout }}"
- name: Create k8s user
ansible.builtin.shell: |
kubectl config set-credentials "{{ username }}"\
--client-certificate="{{ working_dir }}/{{ username }}.crt" \
--client-key="{{ working_dir }}/{{ username }}.key"
notify: remove certificates
- name: Set user context
ansible.builtin.shell: |
kubectl config set-context "{{ username }}@{{ cluster }}" \
--cluster={{ cluster }} --user="{{ username }}"
- name: Create config file from template
template:
src: config.j2
dest: "{{ working_dir }}/config"
- name: Storing config on the local machine
ansible.builtin.fetch:
src: "{{ working_dir }}/config"
dest: ./
flat: yes
tags: config
```
As you can see, in the step "Create k8s user" I'm notifying the handler that's gonna remove certs and configs after the run. If you wanna save them, just comment the string `notify: remove certificates`
Now we've left with the last block:
```
- name: Bind user to role
block:
- name: Generate role binding yaml
template:
src: role-binding.j2
dest: "{{ working_dir }}/{{ username }}.yaml"
- name: Apply role binding manifest
shell: kubectl apply -f "{{ working_dir }}/{{ username }}.yaml"
tags: add_user
```
It's gonna gerenate k8s manifest for adding a RoleBinding or ClusterRoleBinding nad apply it.
To run the playbook, simply do:
```
$ ansible-playbook ./kubernetes-create-user.yaml -i ${PATH_TO_INVENTORY}
# -- then copy config file
$ cp config ~/.kube/config
# chown $USER ~/.kube/config
# -- to check that everything is great
# -- run the following and ensure
# -- you get all resources from you cluster
$ kubectl get all --all-namespaces
```
This role doesn't support adding user groups, so I would be happy if anybody will contribute. Or I will do it myself one day.