208 lines
6.8 KiB
Markdown
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. |