Last active
May 21, 2024 18:43
-
-
Save langburd/d7ff3a5f622e2c9f5cf52607de32fcc1 to your computer and use it in GitHub Desktop.
An Ansible playbook for manually updating certificates used by some K8S components installed with Kubespray. Valid for K8S version <1.16.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
- name: Generate new kubelet certificates | |
hosts: k8s-cluster | |
gather_facts: true | |
serial: 1 | |
vars: | |
valid_point_1: 10d | |
valid_point_2: 20d | |
tasks: | |
- name: Disable docker repository | |
yum_repository: | |
name: docker-engine | |
description: Docker-Engine Repository | |
baseurl: https://yum.dockerproject.org/repo/main/centos/7 | |
enabled: no | |
gpgcheck: yes | |
keepcache: "0" | |
gpgkey: https://yum.dockerproject.org/gpg | |
file: docker | |
state: absent | |
when: ansible_distribution in ["CentOS","RedHat"] | |
- name: Check if the certificate pem file exists | |
stat: | |
path: /var/lib/kubelet/pki/kubelet-client-current.pem | |
register: kubelet_pem | |
- name: Insure the Python cryptography library is installed | |
pip: | |
name: cryptography | |
when: kubelet_pem.stat.exists | |
- name: Check validity of existing pem file | |
openssl_certificate_info: | |
path: /var/lib/kubelet/pki/kubelet-client-current.pem | |
valid_at: | |
point_1: "+{{ valid_point_1 }}" | |
point_2: "+{{ valid_point_2 }}" | |
register: cert_info | |
when: kubelet_pem.stat.exists | |
- debug: | |
msg: "Certificate is not valid before: {{ cert_info.not_before }}" | |
when: kubelet_pem.stat.exists | |
- debug: | |
msg: "Certificate is not valid after: {{ cert_info.not_after }}" | |
when: kubelet_pem.stat.exists | |
- debug: | |
msg: "Certificate is expired: {{ cert_info.expired }}" | |
when: kubelet_pem.stat.exists | |
- debug: | |
msg: "Cert is valid in {{ valid_point_1 }}: {{ cert_info.valid_at.point_1 }}" | |
when: kubelet_pem.stat.exists | |
- debug: | |
msg: "Cert is valid in {{ valid_point_2 }}: {{ cert_info.valid_at.point_2 }}" | |
when: kubelet_pem.stat.exists | |
- name: Check kubelet.conf for hardcoded certificate and key | |
lineinfile: | |
path: /etc/kubernetes/kubelet.conf | |
regexp: "^.*client-certificate.*$" | |
line: " client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem" | |
state: present | |
check_mode: yes | |
register: cert_is_hardcoded | |
no_log: true | |
- name: Replace hardcoded client certificate in kubelet.conf with path to client certificate file | |
replace: | |
path: /etc/kubernetes/kubelet.conf | |
regexp: "client-certificate-data.*" | |
replace: "client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem" | |
backup: yes | |
when: cert_is_hardcoded.changed | |
register: kubelet_conf | |
no_log: true | |
- name: Replace hardcoded client key in kubelet.conf with path to client key file | |
replace: | |
path: /etc/kubernetes/kubelet.conf | |
regexp: "client-key-data.*" | |
replace: "client-key: /var/lib/kubelet/pki/kubelet-client-current.pem" | |
backup: yes | |
when: cert_is_hardcoded.changed | |
register: kubelet_conf | |
no_log: true | |
# Block of regenerating certificates | |
- name: Generate new kubelet certificates | |
block: | |
- name: Check that the ca.key exists | |
stat: | |
path: /etc/kubernetes/ssl/ca.key | |
register: ca_key_on_node | |
- name: Slurp ca.key from first master node | |
slurp: | |
src: /etc/kubernetes/ssl/ca.key | |
register: ca_key | |
delegate_to: "{{ groups['kube-master'] | first }}" | |
when: not ca_key_on_node.stat.exists or 'kube-node' in group_names | |
no_log: true | |
- name: Copy ca.key to the node | |
lineinfile: | |
path: /etc/kubernetes/ssl/ca.key | |
create: yes | |
line: "{{ ca_key['content'] | b64decode }}" | |
when: ca_key is defined and ca_key | length > 0 and (not ca_key_on_node.stat.exists or 'kube-node' in group_names) | |
no_log: true | |
- name: Generate new kubelet configuration for the node | |
shell: | |
args: | |
cmd: /usr/local/bin/kubeadm alpha kubeconfig user --org system:nodes --client-name system:node:$(hostname) | |
register: new_kubelet_configuration | |
no_log: true | |
- name: Get client_certificate from generated kubelet configuration | |
set_fact: | |
client_certificate: "{{ new_kubelet_configuration.stdout_lines[17] | regex_replace('client-certificate-data: (.*$)', '\\1') | b64decode }}" | |
when: new_kubelet_configuration.stdout_lines is defined | |
- name: Get client_key from generated kubelet configuration | |
set_fact: | |
client_key: "{{ new_kubelet_configuration.stdout_lines[18] | regex_replace('client-key-data: (.*$)', '\\1') | b64decode }}" | |
when: new_kubelet_configuration.stdout_lines is defined | |
no_log: true | |
- name: Set desired pem file path | |
set_fact: | |
pem_file_path: /var/lib/kubelet/pki/kubelet-client-{{ ansible_date_time.date }}-{{ ansible_date_time.hour }}-{{ ansible_date_time.minute }}-{{ ansible_date_time.second }}.pem | |
- name: Create pem file | |
lineinfile: | |
path: "{{ pem_file_path }}" | |
create: yes | |
line: "{{ client_certificate }}{{ client_key }}" | |
when: pem_file_path is defined and client_certificate is defined and client_key is defined | |
no_log: true | |
- name: Link created pem file to 'kubelet-client-current.pem' | |
file: | |
src: "{{ pem_file_path }}" | |
dest: /var/lib/kubelet/pki/kubelet-client-current.pem | |
state: link | |
force: yes | |
register: kubelet_client_current_pem | |
when: pem_file_path is defined | |
- name: Find old PEM files | |
find: | |
paths: | |
- /var/lib/kubelet/pki/ | |
file_type: file | |
contains: "-----BEGIN CERTIFICATE-----" | |
patterns: | |
- "kubelet-client-*.pem" | |
excludes: | |
- "{{ kubelet_client_current_pem.src | basename }}" | |
register: found_old_pems | |
when: kubelet_client_current_pem.src is defined | |
- name: Delete old PEM files | |
file: | |
path: "{{ item.path }}" | |
state: absent | |
with_items: "{{ found_old_pems.files }}" | |
when: kubelet_client_current_pem.src is defined and found_old_pems.files is defined | |
always: | |
- name: Delete ca.key from the worker nodes | |
file: | |
path: /etc/kubernetes/ssl/ca.key | |
state: absent | |
when: not ca_key_on_node.stat.exists | |
no_log: true | |
# Conditions for the block | |
when: not kubelet_pem.stat.exists or cert_is_hardcoded.changed or cert_info.expired or not cert_info.valid_at.point_1 or not cert_info.valid_at.point_2 | |
- name: Restart Kubelet service | |
service: | |
name: kubelet | |
state: restarted | |
when: kubelet_conf.changed or kubelet_client_current_pem.changed | |
# Usage: | |
# ansible-playbook -vv -i inventory/CLUSTER_INVENTORY/hosts.cfg includes/cert_kubelet_renew.yml | |
# ansible-playbook -vv -i inventory/CLUSTER_INVENTORY/hosts.cfg includes/cert_kubelet_renew.yml --limit NODE_NAME |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment