diff --git a/defaults/main.yml b/defaults/main.yml index 91083f6..926c000 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -6,6 +6,12 @@ yq: version: v4.31.2 binary: yq_linux_amd64 # -------------------------------------- +# -- kubectl version +# -------------------------------------- +kubectl: + version: v1.26.6 + arch: amd64 +# -------------------------------------- # -- Path to k8s admin config # -------------------------------------- k8s_config_path: /etc/kubernetes/admin.conf @@ -44,7 +50,16 @@ role_type: ClusterRole # -- https://kubernetes.io/docs/reference/access-authn-authz/rbac/ # -------------------------------------- role: cluster-admin - +# -------------------------------------- +# users: +# - username: "admin" +# cluster: "microk8s-cluster" +# certificate_expires_in: 500 +# binding_type: ClusterRoleBinding +# role_type: ClusterRole +# role: cluster-admin +# -------------------------------------- +users: [] # -------------------------------------- # -- Use with microk8s # -------------------------------------- diff --git a/handlers/main.yml b/handlers/main.yml index d8af5f1..3986a93 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -2,4 +2,4 @@ - name: remove certificates file: state: absent - path: "{{ working_dir }}" \ No newline at end of file + path: "{{ cert_dir }}" \ No newline at end of file diff --git a/tasks/create-user.yaml b/tasks/create-user.yaml new file mode 100644 index 0000000..5a2ba0e --- /dev/null +++ b/tasks/create-user.yaml @@ -0,0 +1,99 @@ +--- +- name: Prepare cert directory + block: + - name: Set workdir as fact + set_fact: + cert_dir: "{{ working_dir }}/.certs/{{ username }}" + + - name: Create a directory if it does not exist + ansible.builtin.file: + path: "{{ cert_dir }}" + state: directory + mode: "0775" +- block: + - name: Generate openssl certificate + tags: openssl + block: + - name: Generate an OpenSSL private key + community.crypto.openssl_privatekey: + path: "{{ cert_dir }}/{{ username }}.key" + size: 2048 + + - name: Generate an OpenSSL Certificate Signing Request + community.crypto.openssl_csr: + path: "{{ cert_dir }}/{{ username }}.csr" + privatekey_path: "{{ cert_dir }}/{{ username }}.key" + common_name: "{{ username }}" + + - name: Generate an OpenSSL certificate signed with your own CA certificate + become: true + community.crypto.x509_certificate: + path: "{{ cert_dir }}/{{ username }}.crt" + csr_path: "{{ cert_dir }}/{{ username }}.csr" + ownca_path: "{{ k8s_cert_path }}/{{ k8s_cert_crt_file }}" + ownca_privatekey_path: "{{ k8s_cert_path }}/{{ k8s_cert_key_file }}" + provider: ownca + entrust_not_after: "+{{ certificate_expires_in }}d" + + - 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 "{{ cert_dir }}/{{ username }}.crt" | base64 -w 0 + register: user_cert_data_output + + - name: Get user key data + shell: cat "{{ cert_dir }}/{{ username }}.key" | base64 -w 0 + register: user_key_data_output + + - name: Set variables for template + set_fact: + kubernetes_server: "{{ kubernetes_server | default(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="{{ cert_dir }}/{{ username }}.crt" \ + --client-key="{{ cert_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 }}/{{ username }}.config" + force: false + tags: config + + - name: Bind user to role + block: + - name: Generate role binding yaml + template: + src: role-binding.j2 + dest: "{{ cert_dir }}/{{ username }}.yaml" + + - name: Apply role binding manifest + environment: + KUBECONFIG: "{{ k8s_config_path }}" + shell: kubectl apply -f "{{ cert_dir }}/{{ username }}.yaml" + tags: add_user diff --git a/tasks/main.yml b/tasks/main.yml index 8e9c0d8..e41f0e9 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -7,18 +7,6 @@ # -- 4. Remove certificates (Optional) # -------------------------------------- --- -- name: Prepare working directory - block: - - name: Set workdir as fact - set_fact: - working_dir: "{{ working_dir }}/.certs/{{ username }}" - - - name: Create a directory if it does not exist - ansible.builtin.file: - path: "{{ working_dir }}" - state: directory - mode: "0775" - - name: Ensure required packages are installed tags: packages block: @@ -26,13 +14,13 @@ # -- Prepare kubectl repo # ------------------------- - name: Add an apt signing key for Kubernetes - become: yes + become: true apt_key: url: https://packages.cloud.google.com/apt/doc/apt-key.gpg state: present - name: Adding apt repository for Kubernetes - become: yes + become: true apt_repository: repo: deb https://apt.kubernetes.io/ kubernetes-xenial main state: present @@ -42,110 +30,55 @@ # -- Install yq # -------------------------------------- - name: Ensure yq is installed - become: yes + become: true get_url: url: "https://github.com/mikefarah/yq/releases/download/{{ yq.version }}/{{ yq.binary }}" dest: /usr/bin/yq mode: "0777" - - name: Ensure kubectl and openssl are installed - become: yes + - block: + - name: Download kubectl release + uri: + url: https://dl.k8s.io/release/{{ kubectl.version }}/bin/linux/{{ kubectl.arch }}/kubectl + dest: /tmp + + - name: Download the kubectl checksum file + uri: + url: https://dl.k8s.io/{{ kubectl.version }}/bin/linux/{{ kubectl.arch }}/kubectl.sha256 + dest: /tmp + + - name: Validate the kubectl binary against the checksum file + shell: echo "$(cat /tmp/kubectl.sha256) /tmp/kubectl" | sha256sum --check + register: result + + - name: Assert that the kubectl binary is OK + vars: + expected: "/tmp/kubectl: OK" + assert: + that: + - result.stdout == expected + fail_msg: "{{ result.stdout }}" + success_msg: "{{ result.stdout }}" + + - name: Ensure openssl is installed + become: true package: - name: "{{ packages }}" + name: "openssl" state: present - vars: - packages: - - kubectl - - openssl -- name: Generate openssl certificate - tags: openssl - block: - - name: Generate an OpenSSL private key - community.crypto.openssl_privatekey: - path: "{{ working_dir }}/{{ username }}.key" - size: 2048 + - name: Create a directory if it does not exist + ansible.builtin.file: + path: "{{ working_dir }}" + state: directory + mode: "0775" - - 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: "{{ k8s_cert_path }}/{{ k8s_cert_crt_file }}" - ownca_privatekey_path: "{{ k8s_cert_path }}/{{ k8s_cert_key_file }}" - provider: ownca - entrust_not_after: "+{{ certificate_expires_in }}d" - -- 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 - -- 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 - environment: - KUBECONFIG: "{{ k8s_config_path }}" - shell: kubectl apply -f "{{ working_dir }}/{{ username }}.yaml" - tags: add_user +- name: Create kubernetes user + loop: "{{ users }}" + include_tasks: create-user.yaml + vars: + certificate_expires_in: "{{ item.certificate_expires_in | default('500') }}" + username: "{{ item.username }}" + cluster: "{{ item.cluster }}" + binding_type: "{{ item.binding_type | default('ClusterRoleBinding') }}" + role_type: "{{ item.role_type | default('ClusterRole') }}" + role: "{{ item.role | default('cluster-admin') }}" \ No newline at end of file diff --git a/templates/config.j2 b/templates/config.j2 index f9b98d8..d8e09e0 100644 --- a/templates/config.j2 +++ b/templates/config.j2 @@ -8,8 +8,8 @@ contexts: - context: cluster: {{ cluster }} user: {{ username }} - name: {{ username }}@{{ cluster }} -current-context: {{ username }}@{{ cluster }} + name: {{ cluster }} +current-context: {{ cluster }} kind: Config preferences: {} users: