Skip to content

Commit 9947a00

Browse files
authored
Merge pull request #884 from ErikJiang/add_renew_certs_pb
Add renew certs playbook
2 parents 1e1fd28 + bf2462e commit 9947a00

File tree

2 files changed

+265
-1
lines changed

2 files changed

+265
-1
lines changed

pkg/util/entrypoint/entrypoint.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const (
2929
UpdateHostsPB = "update-hosts.yml"
3030
RemovePkgsPB = "remove-pkgs.yml"
3131
PreCheckPB = "precheck.yml"
32+
RenewCertsPB = "renew-certs.yml"
3233
)
3334

3435
//go:embed entrypoint.sh.template
@@ -55,7 +56,7 @@ func NewActions() *Actions {
5556
actions.Playbooks.List = []string{
5657
ResetPB, ScalePB, ClusterPB, RemoveNodePB, UpgradeClusterPB,
5758
PingPB, RepoPB, FirewallPB, KubeconfigPB, ClusterInfoPB, UpdateHostsPB,
58-
RemovePkgsPB, PreCheckPB,
59+
RemovePkgsPB, PreCheckPB, RenewCertsPB,
5960
}
6061
actions.Playbooks.Dict = map[string]void{}
6162
for _, pbItem := range actions.Playbooks.List {

playbooks/renew-certs.yml

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
---
2+
- name: Renew Cluster Certificates
3+
hosts: k8s_cluster
4+
gather_facts: true
5+
become: true
6+
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
7+
vars:
8+
valid_days: 3650
9+
k8s_path: /etc/kubernetes
10+
pki_path: "{{ k8s_path }}/pki"
11+
k8s_backup_path: "{{ k8s_path }}-backup-{{ ansible_date_time.iso8601_basic_short }}"
12+
tasks:
13+
- name: Create k8s backup path
14+
file:
15+
path: "{{ k8s_backup_path }}"
16+
state: directory
17+
mode: '0755'
18+
19+
# use synchronize need install sshpass
20+
- name: Backup current kubeconfig
21+
ansible.posix.synchronize:
22+
src: "{{ k8s_path }}/{{ item }}"
23+
dest: "{{ k8s_backup_path }}"
24+
loop:
25+
- admin.conf
26+
- kubelet.conf
27+
- scheduler.conf
28+
- controller-manager.conf
29+
delegate_to: "{{ inventory_hostname }}"
30+
31+
- name: Backup current certificates
32+
ansible.posix.synchronize:
33+
src: "{{ pki_path }}/"
34+
dest: "{{ k8s_backup_path }}/pki/"
35+
delegate_to: "{{ inventory_hostname }}"
36+
37+
- name: Pre-check expiration date of certificate
38+
command: kubeadm certs check-expiration
39+
register: expiration_info
40+
- debug: var=expiration_info.stdout_lines
41+
42+
- name: Generate k8s certificates
43+
vars:
44+
# https://kubernetes.io/docs/setup/best-practices/certificates/#all-certificates
45+
_certs_opt_mapping:
46+
- name: admin.conf
47+
kind: [clientAuth]
48+
target: "{{ pki_path }}/admin.conf"
49+
parent_ca: ca
50+
- name: controller-manager.conf
51+
kind: [clientAuth]
52+
target: "{{ pki_path }}/controller-manager.conf"
53+
parent_ca: ca
54+
- name: scheduler.conf
55+
kind: [clientAuth]
56+
target: "{{ pki_path }}/scheduler.conf"
57+
parent_ca: ca
58+
- name: apiserver
59+
kind: [serverAuth]
60+
target: "{{ pki_path }}/apiserver"
61+
parent_ca: ca
62+
- name: apiserver-kubelet-client
63+
kind: [clientAuth]
64+
target: "{{ pki_path }}/apiserver-kubelet-client"
65+
parent_ca: ca
66+
- name: front-proxy-client
67+
kind: [clientAuth]
68+
target: "{{ pki_path }}/front-proxy-client"
69+
parent_ca: front-proxy-ca
70+
- name: apiserver-etcd-client
71+
kind: [clientAuth]
72+
target: "{{ pki_path }}/apiserver-etcd-client"
73+
parent_ca: etcd/ca
74+
- name: etcd/healthcheck-client
75+
kind: [clientAuth]
76+
target: "{{ pki_path }}/etcd/healthcheck-client"
77+
parent_ca: etcd/ca
78+
- name: etcd/peer
79+
kind: [serverAuth, clientAuth]
80+
target: "{{ pki_path }}/etcd/peer"
81+
parent_ca: etcd/ca
82+
- name: etcd/server
83+
kind: [serverAuth, clientAuth]
84+
target: "{{ pki_path }}/etcd/server"
85+
parent_ca: etcd/ca
86+
87+
block:
88+
- name: Create certs_opt_mapping fact
89+
block:
90+
- name: Set default certs_opt_mapping fact value
91+
set_fact:
92+
certs_opt_mapping: "{{ _certs_opt_mapping }}"
93+
certs_renewal_list: "{{ _certs_opt_mapping | map(attribute='name') }}"
94+
95+
- name: Ensure necessary directories exist
96+
file:
97+
path: "{{ item }}"
98+
state: directory
99+
owner: root
100+
group: root
101+
mode: u=rw
102+
loop:
103+
- "{{ pki_path }}/csr"
104+
- "{{ pki_path }}/ext"
105+
- "{{ pki_path }}/ext/etcd"
106+
107+
- name: Generate new CSR by kubeadm
108+
command: |-
109+
kubeadm certs generate-csr \
110+
--cert-dir=csr \
111+
--kubeconfig-dir=csr \
112+
--config=/etc/kubernetes/kubeadm-config.yaml
113+
args:
114+
chdir: "{{ pki_path }}"
115+
116+
- name: Register SAN extension for all CSR files
117+
shell: |-
118+
openssl req -text -noout \
119+
-reqopt no_subject,no_header,no_version,no_serial,no_signame,no_validity,no_issuer,no_pubkey,no_sigdump,no_aux \
120+
-in csr/{{ item.name }}.csr \
121+
| sed '1,3d;s/ Address//g;s/^[[:blank:]]*//;s/[[:blank:]]*$//'
122+
args:
123+
chdir: "{{ pki_path }}"
124+
register: csr_info
125+
loop: "{{ certs_opt_mapping }}"
126+
loop_control:
127+
label: "{{ item.name }}"
128+
129+
- name: Generate extension files
130+
vars:
131+
cert_v3_ext: |-
132+
keyUsage = critical, digitalSignature, keyEncipherment
133+
extendedKeyUsage = {{ item.0.kind | join(',') }}
134+
{% if item.1.stdout %}
135+
subjectAltName = {{ item.1.stdout }}
136+
{% endif %}
137+
copy:
138+
content: "{{ cert_v3_ext }}"
139+
dest: "{{ pki_path }}/ext/{{ item.0.name }}.ext"
140+
mode: u=rw,g=r,o=
141+
loop: "{{ certs_opt_mapping|zip(csr_info.results)|list }}"
142+
loop_control:
143+
label: "{{ item.0.name }}"
144+
145+
- name: Create new signed certificates
146+
command: |-
147+
openssl x509 -req -days {{ valid_days }} \
148+
-in csr/{{ item.name }}.csr \
149+
-extfile ext/{{ item.name }}.ext \
150+
-CA {{ item.parent_ca }}.crt \
151+
-CAkey {{ item.parent_ca }}.key \
152+
-CAcreateserial \
153+
-out {{ item.target }}.crt
154+
args:
155+
chdir: "{{ pki_path }}"
156+
loop: "{{ certs_opt_mapping }}"
157+
loop_control:
158+
label: "{{ item.name }}"
159+
160+
- name: Copy keys to certificates location and ensure that permissions are strict
161+
vars:
162+
_conf_files: "{{ certs_opt_mapping | selectattr('name', 'search', '.conf') }}"
163+
copy:
164+
src: "{{ pki_path }}/csr/{{ item.name }}.key"
165+
remote_src: true
166+
dest: "{{ item.target }}.key"
167+
owner: root
168+
group: root
169+
mode: u=rw
170+
loop: "{{ certs_opt_mapping | difference(_conf_files) }}"
171+
loop_control:
172+
label: "{{ item.name }}"
173+
174+
- name: Update conf files with embedded certs
175+
vars:
176+
_kubeconf_cn_mapping:
177+
admin.conf: kubernetes-admin
178+
scheduler.conf: system:kube-scheduler
179+
controller-manager.conf: system:kube-controller-manager
180+
block:
181+
- name: Slurp kubeconfig files
182+
slurp:
183+
src: "{{ pki_path }}/csr/{{ item }}"
184+
register: kubeconfig_files_content
185+
loop: "{{ _kubeconf_cn_mapping.keys() | intersect(certs_renewal_list) }}"
186+
187+
- name: Create kubeconfig key files
188+
vars:
189+
_content: "{{ config_file.content | b64decode | from_yaml }}"
190+
copy:
191+
content: "{{ _content.users.0.user['client-key-data'] | b64decode }}"
192+
dest: "{{ pki_path }}/{{ config_file.item }}.key"
193+
owner: root
194+
group: root
195+
mode: u=rw
196+
loop: "{{ kubeconfig_files_content.results }}"
197+
loop_control:
198+
loop_var: config_file
199+
label: "{{ config_file.item }}"
200+
201+
- name: Update conf files with embedded certs
202+
environment:
203+
KUBECONFIG: "/etc/kubernetes/{{ item.key }}"
204+
command: |-
205+
kubectl config set-credentials {{ item.value }} \
206+
--client-key {{ item.key }}.key \
207+
--client-certificate {{ item.key }}.crt --embed-certs
208+
args:
209+
chdir: "{{ pki_path }}"
210+
loop: "{{ _kubeconf_cn_mapping | dict2items | selectattr('key', 'in', certs_renewal_list) }}"
211+
212+
- name: Updating kubeconfig in root path
213+
copy:
214+
src: "{{ k8s_path }}/admin.conf"
215+
remote_src: true
216+
dest: /root/.kube/config
217+
owner: root
218+
group: root
219+
mode: u=rw
220+
221+
- name: Remove conf certificates and temporary directories
222+
file:
223+
path: "{{ pki_path }}/{{ item }}"
224+
state: absent
225+
loop:
226+
- admin.conf.crt
227+
- admin.conf.key
228+
- scheduler.conf.crt
229+
- scheduler.conf.key
230+
- controller-manager.conf.crt
231+
- controller-manager.conf.key
232+
- csr
233+
- ext
234+
235+
rescue:
236+
- name: Restore certificates
237+
ansible.posix.synchronize:
238+
src: "{{ k8s_backup_path }}/"
239+
dest: "{{ pki_path | regex_replace('\\/$', '') }}"
240+
delegate_to: "{{ inventory_hostname }}"
241+
242+
- name: Fail certificates generation
243+
fail:
244+
msg: Certificates generation failed, restored an initial state
245+
246+
- name: Restart kubelet systemd services
247+
block:
248+
- name: Restart services
249+
systemd:
250+
name: kubelet
251+
state: restarted
252+
253+
- name: Wait until cluster is available
254+
command: kubectl cluster-info
255+
retries: 60
256+
delay: 1
257+
register: result
258+
until: result is succeeded and "running" in result.stdout
259+
260+
- name: Run check-expiration for control-plane
261+
command: kubeadm certs check-expiration
262+
register: expiration_info
263+
- debug: var=expiration_info.stdout_lines

0 commit comments

Comments
 (0)