├── .gitignore
├── LICENSE
├── README.md
├── other-zh_CN.md
├── other.md
└── update-kubeadm-cert.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .vscode
3 | /tmp
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 yuyicai
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # update-kube-cert
2 |
3 | A tool to update and extend Kubernetes certificate expiration dates in kubeadm-initiated clusters.
4 |
5 | ## Overview
6 |
7 | This script helps you manage Kubernetes certificates by:
8 |
9 | - Extending certificate validity to 10 years for existing Kubernetes clusters. (includes both cluster with certificate expiration issues and normal cluster)
10 | - Generating long-lived CA certificates (100 years) before initializing new clusters
11 |
12 | ## Usage
13 |
14 | ### Get the Script
15 |
16 | ```bash
17 | git clone https://github.com/yuyicai/update-kube-cert.git
18 | cd update-kube-cert
19 | ```
20 |
21 | ### For Existing Clusters
22 |
23 | Renew certificates to 10 years:
24 | Run on all control plane nodes (master0, master1, master2...)
25 |
26 | ```bash
27 | bash update-kubeadm-cert.sh --cri containerd
28 | ```
29 |
30 |
31 |
32 | Terminal Output
33 |
34 | ```bash
35 | root@master0:~/update-kube-cert# bash update-kubeadm-cert.sh --cri containerd
36 | [2025-04-01T00:09:48.47+0800] [INFO] checking if all certificate files are existed...
37 | [2025-04-01T00:09:48.47+0800] [INFO] backup /etc/kubernetes to /etc/kubernetes.old-2025-04-01_00-09-48
38 | [2025-04-01T00:09:48.48+0800] [INFO] checking certificate expiration before update...
39 | |-----------------------------------|----------------------------|
40 | | CERTIFICATE | EXPIRES |
41 | | ca.crt | Mar 29 16:09:05 2035 GMT |
42 | | apiserver.crt | Mar 31 16:09:05 2026 GMT |
43 | | apiserver-kubelet-client.crt | Mar 31 16:09:05 2026 GMT |
44 | | front-proxy-ca.crt | Mar 29 16:09:05 2035 GMT |
45 | | front-proxy-client.crt | Mar 31 16:09:05 2026 GMT |
46 | |-----------------------------------|----------------------------|
47 | | controller-manager.conf | Mar 31 16:09:05 2026 GMT |
48 | | scheduler.conf | Mar 31 16:09:05 2026 GMT |
49 | | admin.conf | Mar 31 16:09:05 2026 GMT |
50 | | super-admin.conf | Mar 31 16:09:05 2026 GMT |
51 | |-----------------------------------|----------------------------|
52 | | etcd/ca.crt | Mar 29 16:09:05 2035 GMT |
53 | | etcd/server.crt | Mar 31 16:09:05 2026 GMT |
54 | | etcd/peer.crt | Mar 31 16:09:05 2026 GMT |
55 | | etcd/healthcheck-client.crt | Mar 31 16:09:05 2026 GMT |
56 | | apiserver-etcd-client.crt | Mar 31 16:09:05 2026 GMT |
57 | |-----------------------------------|----------------------------|
58 | [2025-04-01T00:09:48.52+0800] [INFO] updating certificates with 3650 days expiration...
59 | [2025-04-01T00:09:48.53+0800] [INFO] updated /etc/kubernetes/pki/etcd/server.crt
60 | [2025-04-01T00:09:48.55+0800] [INFO] updated /etc/kubernetes/pki/etcd/peer.crt
61 | [2025-04-01T00:09:48.56+0800] [INFO] updated /etc/kubernetes/pki/etcd/healthcheck-client.crt
62 | [2025-04-01T00:09:48.57+0800] [INFO] updated /etc/kubernetes/pki/apiserver-etcd-client.crt
63 | [2025-04-01T00:09:48.59+0800] [INFO] restarted etcd
64 | [2025-04-01T00:09:48.61+0800] [INFO] updated /etc/kubernetes/pki/apiserver.crt
65 | [2025-04-01T00:09:48.62+0800] [INFO] updated /etc/kubernetes/pki/apiserver-kubelet-client.crt
66 | [2025-04-01T00:09:48.63+0800] [INFO] updated /etc/kubernetes/controller-manager.conf
67 | [2025-04-01T00:09:48.65+0800] [INFO] updated /etc/kubernetes/scheduler.conf
68 | [2025-04-01T00:09:48.66+0800] [INFO] updated /etc/kubernetes/admin.conf
69 | [2025-04-01T00:09:48.68+0800] [INFO] updated /etc/kubernetes/super-admin.conf
70 | [2025-04-01T00:09:48.69+0800] [INFO] updated /etc/kubernetes/pki/front-proxy-client.crt
71 | [2025-04-01T00:09:48.71+0800] [INFO] restarted control-plane pod: apiserver
72 | [2025-04-01T00:09:48.73+0800] [INFO] restarted control-plane pod: controller-manager
73 | [2025-04-01T00:09:48.76+0800] [INFO] restarted control-plane pod: scheduler
74 | [2025-04-01T00:09:48.83+0800] [INFO] restarted kubelet
75 | [2025-04-01T00:09:48.83+0800] [INFO] checking certificate expiration after update...
76 | |-----------------------------------|----------------------------|
77 | | CERTIFICATE | EXPIRES |
78 | | ca.crt | Mar 29 16:09:05 2035 GMT |
79 | | apiserver.crt | Mar 29 16:09:48 2035 GMT |
80 | | apiserver-kubelet-client.crt | Mar 29 16:09:48 2035 GMT |
81 | | front-proxy-ca.crt | Mar 29 16:09:05 2035 GMT |
82 | | front-proxy-client.crt | Mar 29 16:09:48 2035 GMT |
83 | |-----------------------------------|----------------------------|
84 | | controller-manager.conf | Mar 29 16:09:48 2035 GMT |
85 | | scheduler.conf | Mar 29 16:09:48 2035 GMT |
86 | | admin.conf | Mar 29 16:09:48 2035 GMT |
87 | | super-admin.conf | Mar 29 16:09:48 2035 GMT |
88 | |-----------------------------------|----------------------------|
89 | | etcd/ca.crt | Mar 29 16:09:05 2035 GMT |
90 | | etcd/server.crt | Mar 29 16:09:48 2035 GMT |
91 | | etcd/peer.crt | Mar 29 16:09:48 2035 GMT |
92 | | etcd/healthcheck-client.crt | Mar 29 16:09:48 2035 GMT |
93 | | apiserver-etcd-client.crt | Mar 29 16:09:48 2035 GMT |
94 | |-----------------------------------|----------------------------|
95 | [2025-04-01T00:09:48.89+0800] [INFO] DONE!!!enjoy it
96 |
97 | please copy admin.conf to /root/.kube/config manually.
98 | # back old config
99 | cp /root/.kube/config /root/.kube/config_backup
100 | # copy new admin.conf to /root/.kube/config for kubectl manually
101 | cp -i /opt/kube/tmp/kubernetes/admin.conf /root/.kube/config
102 |
103 |
104 | root@master0:~/update-kube-cert# kubectl get po -A
105 | NAMESPACE NAME READY STATUS RESTARTS AGE
106 | kube-system coredns-668d6bf9bc-7kwkk 0/1 Pending 0 37m
107 | kube-system coredns-668d6bf9bc-b68dx 0/1 Pending 0 37m
108 | kube-system etcd-master0 1/1 Running 4 (4m21s ago) 37m
109 | kube-system kube-apiserver-master0 1/1 Running 2 (60s ago) 37m
110 | kube-system kube-controller-manager-master0 1/1 Running 4 (49s ago) 37m
111 | kube-system kube-proxy-5mf68 1/1 Running 0 37m
112 | kube-system kube-scheduler-master0 1/1 Running 3 (48s ago) 37m
113 | root@master0:~/update-kube-cert#
114 | root@master0:~/update-kube-cert# crictl --runtime-endpoint unix:///run/containerd/containerd.sock pods
115 | POD ID CREATED STATE NAME NAMESPACE ATTEMPT RUNTIME
116 | 59935ee07550b About a minute ago Ready kube-apiserver-master0 kube-system 2 (default)
117 | 37b73945aee1f About a minute ago NotReady kube-apiserver-master0 kube-system 1 (default)
118 | 5f05c3a5abfac 4 minutes ago Ready etcd-master0 kube-system 4 (default)
119 | 40c2c1480cbc8 5 minutes ago Ready kube-controller-manager-master0 kube-system 1 (default)
120 | 781806f0cc91d 6 minutes ago NotReady etcd-master0 kube-system 3 (default)
121 | 75b68162b9476 37 minutes ago Ready kube-proxy-5mf68 kube-system 0 (default)
122 | dc3da94fda7f9 37 minutes ago Ready kube-scheduler-master0 kube-system 0 (default)
123 | ```
124 |
125 |
126 |
127 | ### For New Clusters
128 |
129 | Generate 100 year CA certificates before running `kubeadm init`
130 | Just generate CA on the first control plane node (master0, which will run `kubeadm init`)
131 |
132 | ```bash
133 | # master0
134 | # 1. Generate 100 years CA certificates
135 | bash update-kubeadm-cert.sh --action gen-ca
136 |
137 | # 2. Initialize your cluster with kubeadm
138 | # kubeadm will use the existing CA certificates generated by the script
139 | kubeadm init --upload-certs [options]
140 |
141 | # 3. Update all certificates to 100 years use extended expiration
142 | bash update-kubeadm-cert.sh --cri containerd --days 36500
143 |
144 | # 4. Join master1, master2 to the cluster and just run 'bash update-kubeadm-cert.sh --cri containerd --days 36500' on them
145 | ```
146 |
147 |
148 |
149 | Key Kubeadm init Output
150 | kubeadm uses the existing CA certificates generated by the script
151 |
152 | ```bash
153 | ...
154 | [certs] Using existing ca certificate authority
155 | ...
156 | [certs] Using existing front-proxy-ca certificate authority
157 | ...
158 | [certs] Using existing etcd/ca certificate authority
159 | ...
160 | ```
161 |
162 |
163 |
164 |
165 |
166 |
167 | Full terminal Output
168 |
169 | ```bash
170 | root@master0:~/update-kube-cert# bash update-kubeadm-cert.sh --action gen-ca
171 | [2025-04-01T00:14:35.89+0800] [INFO] generating CA with 36500 days expiration...
172 | [2025-04-01T00:14:35.90+0800] [INFO] generating k8s CA...
173 | [2025-04-01T00:14:36.06+0800] [INFO] generated /etc/kubernetes/pki/ca.crt
174 | [2025-04-01T00:14:36.06+0800] [INFO] generating front-proxy CA...
175 | [2025-04-01T00:14:36.11+0800] [INFO] generated /etc/kubernetes/pki/front-proxy-ca.crt
176 | [2025-04-01T00:14:36.11+0800] [INFO] generating etcd CA...
177 | [2025-04-01T00:14:36.14+0800] [INFO] generated /etc/kubernetes/pki/etcd/ca.crt
178 | |-----------------------------------|----------------------------|
179 | | CERTIFICATE | EXPIRES |
180 | | ca.crt | Mar 7 16:14:36 2125 GMT |
181 | | apiserver.crt | |
182 | | apiserver-kubelet-client.crt | |
183 | | front-proxy-ca.crt | Mar 7 16:14:36 2125 GMT |
184 | | front-proxy-client.crt | |
185 | |-----------------------------------|----------------------------|
186 | | controller-manager.conf | |
187 | | scheduler.conf | |
188 | | admin.conf | |
189 | |-----------------------------------|----------------------------|
190 | | etcd/ca.crt | Mar 7 16:14:36 2125 GMT |
191 | | etcd/server.crt | |
192 | | etcd/peer.crt | |
193 | | etcd/healthcheck-client.crt | |
194 | | apiserver-etcd-client.crt | |
195 | |-----------------------------------|----------------------------|
196 | [2025-04-01T00:14:36.18+0800] [INFO] DONE!!! generated CA for new cluster.
197 | # create new cluster after generating CA, you can use the following command:
198 | kubeadm init [options]
199 | # after running kubeadm init, update certificates for 100 yeas
200 | bash update-kubeadm-cert.sh --cri containerd --days 36500
201 | root@master0:~/update-kube-cert#
202 | root@master0:~/update-kube-cert#
203 | root@master0:~/update-kube-cert# kubeadm init
204 | [init] Using Kubernetes version: v1.32.3
205 | [preflight] Running pre-flight checks
206 | [WARNING SystemVerification]: cgroups v1 support is in maintenance mode, please migrate to cgroups v2
207 | [preflight] Pulling images required for setting up a Kubernetes cluster
208 | [preflight] This might take a minute or two, depending on the speed of your internet connection
209 | [preflight] You can also perform this action beforehand using 'kubeadm config images pull'
210 | W0401 00:15:10.683957 13914 checks.go:846] detected that the sandbox image "" of the container runtime is inconsistent with that used by kubeadm.It is recommended to use "registry.k8s.io/pause:3.10" as the CRI sandbox image.
211 | [certs] Using certificateDir folder "/etc/kubernetes/pki"
212 | [certs] Using existing ca certificate authority
213 | [certs] Generating "apiserver" certificate and key
214 | [certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local master0] and IPs [10.96.0.1 10.0.0.186]
215 | [certs] Generating "apiserver-kubelet-client" certificate and key
216 | [certs] Using existing front-proxy-ca certificate authority
217 | [certs] Generating "front-proxy-client" certificate and key
218 | [certs] Using existing etcd/ca certificate authority
219 | [certs] Generating "etcd/server" certificate and key
220 | [certs] etcd/server serving cert is signed for DNS names [localhost master0] and IPs [10.0.0.186 127.0.0.1 ::1]
221 | [certs] Generating "etcd/peer" certificate and key
222 | [certs] etcd/peer serving cert is signed for DNS names [localhost master0] and IPs [10.0.0.186 127.0.0.1 ::1]
223 | [certs] Generating "etcd/healthcheck-client" certificate and key
224 | [certs] Generating "apiserver-etcd-client" certificate and key
225 | [certs] Generating "sa" key and public key
226 | [kubeconfig] Using kubeconfig folder "/etc/kubernetes"
227 | [kubeconfig] Writing "admin.conf" kubeconfig file
228 | [kubeconfig] Writing "super-admin.conf" kubeconfig file
229 | [kubeconfig] Writing "kubelet.conf" kubeconfig file
230 | [kubeconfig] Writing "controller-manager.conf" kubeconfig file
231 | [kubeconfig] Writing "scheduler.conf" kubeconfig file
232 | [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
233 | [control-plane] Using manifest folder "/etc/kubernetes/manifests"
234 | [control-plane] Creating static Pod manifest for "kube-apiserver"
235 | [control-plane] Creating static Pod manifest for "kube-controller-manager"
236 | [control-plane] Creating static Pod manifest for "kube-scheduler"
237 | [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
238 | [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
239 | [kubelet-start] Starting the kubelet
240 | [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests"
241 | [kubelet-check] Waiting for a healthy kubelet at http://127.0.0.1:10248/healthz. This can take up to 4m0s
242 | [kubelet-check] The kubelet is healthy after 501.312263ms
243 | [api-check] Waiting for a healthy API server. This can take up to 4m0s
244 | [api-check] The API server is healthy after 3.501053598s
245 | [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
246 | [kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster
247 | [upload-certs] Skipping phase. Please see --upload-certs
248 | [mark-control-plane] Marking the node master0 as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
249 | [mark-control-plane] Marking the node master0 as control-plane by adding the taints [node-role.kubernetes.io/control-plane:NoSchedule]
250 | [bootstrap-token] Using token: pwjq3f.6vdgdbfy8mk3gq0s
251 | [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
252 | [bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to get nodes
253 | [bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
254 | [bootstrap-token] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
255 | [bootstrap-token] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
256 | [bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
257 | [kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
258 | [addons] Applied essential addon: CoreDNS
259 | [addons] Applied essential addon: kube-proxy
260 |
261 | Your Kubernetes control-plane has initialized successfully!
262 |
263 | To start using your cluster, you need to run the following as a regular user:
264 |
265 | mkdir -p $HOME/.kube
266 | sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
267 | sudo chown $(id -u):$(id -g) $HOME/.kube/config
268 |
269 | Alternatively, if you are the root user, you can run:
270 |
271 | export KUBECONFIG=/etc/kubernetes/admin.conf
272 |
273 | You should now deploy a pod network to the cluster.
274 | Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
275 | https://kubernetes.io/docs/concepts/cluster-administration/addons/
276 |
277 | Then you can join any number of worker nodes by running the following on each as root:
278 |
279 | kubeadm join 10.0.0.186:6443 --token pwjq3f.6vdgdbfy8mk3gq0s \
280 | --discovery-token-ca-cert-hash sha256:6cef6024c7b0a25a2b81c31907248a2dc124eada0fd7abd565bbe60d6ad775a1
281 | root@master0:~/update-kube-cert#
282 | root@master0:~/update-kube-cert#
283 | root@master0:~/update-kube-cert# bash update-kubeadm-cert.sh --cri containerd --days 36500
284 | [2025-04-01T00:16:12.09+0800] [INFO] checking if all certificate files are existed...
285 | [2025-04-01T00:16:12.09+0800] [INFO] backup /etc/kubernetes to /etc/kubernetes.old-2025-04-01_00-16-12
286 | [2025-04-01T00:16:12.09+0800] [INFO] checking certificate expiration before update...
287 | |-----------------------------------|----------------------------|
288 | | CERTIFICATE | EXPIRES |
289 | | ca.crt | Mar 7 16:14:36 2125 GMT |
290 | | apiserver.crt | Mar 31 16:15:10 2026 GMT |
291 | | apiserver-kubelet-client.crt | Mar 31 16:15:10 2026 GMT |
292 | | front-proxy-ca.crt | Mar 7 16:14:36 2125 GMT |
293 | | front-proxy-client.crt | Mar 31 16:15:10 2026 GMT |
294 | |-----------------------------------|----------------------------|
295 | | controller-manager.conf | Mar 31 16:15:10 2026 GMT |
296 | | scheduler.conf | Mar 31 16:15:10 2026 GMT |
297 | | admin.conf | Mar 31 16:15:10 2026 GMT |
298 | | super-admin.conf | Mar 31 16:15:10 2026 GMT |
299 | |-----------------------------------|----------------------------|
300 | | etcd/ca.crt | Mar 7 16:14:36 2125 GMT |
301 | | etcd/server.crt | Mar 31 16:15:10 2026 GMT |
302 | | etcd/peer.crt | Mar 31 16:15:10 2026 GMT |
303 | | etcd/healthcheck-client.crt | Mar 31 16:15:10 2026 GMT |
304 | | apiserver-etcd-client.crt | Mar 31 16:15:10 2026 GMT |
305 | |-----------------------------------|----------------------------|
306 | [2025-04-01T00:16:12.14+0800] [INFO] updating certificates with 36500 days expiration...
307 | [2025-04-01T00:16:12.15+0800] [INFO] updated /etc/kubernetes/pki/etcd/server.crt
308 | [2025-04-01T00:16:12.16+0800] [INFO] updated /etc/kubernetes/pki/etcd/peer.crt
309 | [2025-04-01T00:16:12.17+0800] [INFO] updated /etc/kubernetes/pki/etcd/healthcheck-client.crt
310 | [2025-04-01T00:16:12.18+0800] [INFO] updated /etc/kubernetes/pki/apiserver-etcd-client.crt
311 | [2025-04-01T00:16:12.21+0800] [INFO] restarted etcd
312 | [2025-04-01T00:16:12.22+0800] [INFO] updated /etc/kubernetes/pki/apiserver.crt
313 | [2025-04-01T00:16:12.23+0800] [INFO] updated /etc/kubernetes/pki/apiserver-kubelet-client.crt
314 | [2025-04-01T00:16:12.25+0800] [INFO] updated /etc/kubernetes/controller-manager.conf
315 | [2025-04-01T00:16:12.26+0800] [INFO] updated /etc/kubernetes/scheduler.conf
316 | [2025-04-01T00:16:12.28+0800] [INFO] updated /etc/kubernetes/admin.conf
317 | [2025-04-01T00:16:12.29+0800] [INFO] updated /etc/kubernetes/super-admin.conf
318 | [2025-04-01T00:16:12.30+0800] [INFO] updated /etc/kubernetes/pki/front-proxy-client.crt
319 | [2025-04-01T00:16:12.33+0800] [INFO] restarted control-plane pod: apiserver
320 | [2025-04-01T00:16:12.35+0800] [INFO] restarted control-plane pod: controller-manager
321 | [2025-04-01T00:16:12.37+0800] [INFO] restarted control-plane pod: scheduler
322 | [2025-04-01T00:16:12.42+0800] [INFO] restarted kubelet
323 | [2025-04-01T00:16:12.42+0800] [INFO] checking certificate expiration after update...
324 | |-----------------------------------|----------------------------|
325 | | CERTIFICATE | EXPIRES |
326 | | ca.crt | Mar 7 16:14:36 2125 GMT |
327 | | apiserver.crt | Mar 7 16:16:12 2125 GMT |
328 | | apiserver-kubelet-client.crt | Mar 7 16:16:12 2125 GMT |
329 | | front-proxy-ca.crt | Mar 7 16:14:36 2125 GMT |
330 | | front-proxy-client.crt | Mar 7 16:16:12 2125 GMT |
331 | |-----------------------------------|----------------------------|
332 | | controller-manager.conf | Mar 7 16:16:12 2125 GMT |
333 | | scheduler.conf | Mar 7 16:16:12 2125 GMT |
334 | | admin.conf | Mar 7 16:16:12 2125 GMT |
335 | | super-admin.conf | Mar 7 16:16:12 2125 GMT |
336 | |-----------------------------------|----------------------------|
337 | | etcd/ca.crt | Mar 7 16:14:36 2125 GMT |
338 | | etcd/server.crt | Mar 7 16:16:12 2125 GMT |
339 | | etcd/peer.crt | Mar 7 16:16:12 2125 GMT |
340 | | etcd/healthcheck-client.crt | Mar 7 16:16:12 2125 GMT |
341 | | apiserver-etcd-client.crt | Mar 7 16:16:12 2125 GMT |
342 | |-----------------------------------|----------------------------|
343 | [2025-04-01T00:16:12.48+0800] [INFO] DONE!!!enjoy it
344 |
345 | please copy admin.conf to /root/.kube/config manually.
346 | # back old config
347 | cp /root/.kube/config /root/.kube/config_backup
348 | # copy new admin.conf to /root/.kube/config for kubectl manually
349 | cp -i /opt/kube/tmp/kubernetes/admin.conf /root/.kube/config
350 | root@master0:/etc/kubernetes#
351 | root@master0:/etc/kubernetes# cp /opt/kube/tmp/kubernetes/admin.conf /root/.kube/config
352 | root@master0:/etc/kubernetes#
353 | root@master0:/etc/kubernetes# kubeadm certs check-expiration
354 | [check-expiration] Reading configuration from the "kubeadm-config" ConfigMap in namespace "kube-system"...
355 | [check-expiration] Use 'kubeadm init phase upload-config --config your-config.yaml' to re-upload it.
356 |
357 | CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED
358 | admin.conf Mar 07, 2125 16:16 UTC 99y ca no
359 | apiserver Mar 07, 2125 16:16 UTC 99y ca no
360 | apiserver-etcd-client Mar 07, 2125 16:16 UTC 99y etcd-ca no
361 | apiserver-kubelet-client Mar 07, 2125 16:16 UTC 99y ca no
362 | controller-manager.conf Mar 07, 2125 16:16 UTC 99y ca no
363 | etcd-healthcheck-client Mar 07, 2125 16:16 UTC 99y etcd-ca no
364 | etcd-peer Mar 07, 2125 16:16 UTC 99y etcd-ca no
365 | etcd-server Mar 07, 2125 16:16 UTC 99y etcd-ca no
366 | front-proxy-client Mar 07, 2125 16:16 UTC 99y front-proxy-ca no
367 | scheduler.conf Mar 07, 2125 16:16 UTC 99y ca no
368 | super-admin.conf Mar 07, 2125 16:16 UTC 99y ca no
369 |
370 | CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
371 | ca Mar 07, 2125 16:14 UTC 99y no
372 | etcd-ca Mar 07, 2125 16:14 UTC 99y no
373 | front-proxy-ca Mar 07, 2125 16:14 UTC 99y no
374 | ```
375 |
376 |
377 |
378 | ## After Running
379 | Copy the admin configuration to your kubectl config directory
380 |
381 | ```bash
382 | # Backup existing config
383 | cp $HOME/.kube/config $HOME/.kube/config_backup
384 |
385 | # Copy new config
386 | cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
387 | ```
388 |
389 | ## Options
390 | ``` bash
391 | -c, --cri (default: containerd)
392 | Set the cri type, in order to restart control-plane and etcd service by different command, 'docker' or 'crictl'.
393 | -a, --action (default: update)
394 | update: Update certificates 10 years for existing clusters
395 | check: Only check the expiration of the certificates without updating them.
396 | gen-ca: Generate 100 years CA before kubeadm init cluster. (only used for new clusters, not for existing clusters)
397 | --days Set the number of days for certificate expiration. (default: 3650)
398 | -h, --help Show this help message and exit.
399 | ```
400 |
401 | ## Certificate Files Updated
402 | certificates files:
403 | ```
404 | /etc/kubernetes/pki/apiserver.crt
405 | /etc/kubernetes/pki/apiserver-kubelet-client.crt
406 | /etc/kubernetes/pki/front-proxy-client.crt
407 | /etc/kubernetes/pki/apiserver-etcd-client.crt
408 | /etc/kubernetes/pki/etcd/server.crt
409 | /etc/kubernetes/pki/etcd/peer.crt
410 | /etc/kubernetes/pki/etcd/healthcheck-client.crt
411 | ```
412 | kubeconfig files:
413 | ```
414 | /etc/kubernetes/admin.conf
415 | /etc/kubernetes/controller-manager.conf
416 | /etc/kubernetes/scheduler.conf
417 | /etc/kubernetes/super-admin.conf (after Kubernetes v1.29.0, this script will check automatically)
418 | /etc/kubernetes/kubelet.conf (before Kubernetes v1.17.0, this script will check automatically)
419 | ```
420 |
421 | ## FAQ
422 |
423 | - **Can I generate CA for 100 years on an existing cluster by this script?**
424 | No, this script only updates the certificates on existing clusters, not including CA.
425 |
426 | - **How can I Change CA for an existing cluster?**
427 | See: https://kubernetes.io/docs/tasks/tls/manual-rotation-of-ca-certificates/
428 |
429 | - **If I have a multi-master cluster, do I need to run this on all master?**
430 | Yes, you should run this script on all control plane nodes, by not on worker nodes.
431 |
432 | - **How to force restart control-plane pods manually?**
433 | If any control plane components couldn't be automatically restarted, you should manually restart them.
434 |
435 | ```bash
436 | # Make sure kubelet is running
437 | systemctl restart kubelet
438 |
439 | # Move manifests to trigger kubelet to recreate the pods
440 | mv /etc/kubernetes/manifests /etc/kubernetes/manifests_backup
441 |
442 | # Wait for kubelet to remove the old pods
443 | sleep 120
444 |
445 | # Restore manifests, kubelet will recreate the pods
446 | mv /etc/kubernetes/manifests_backup /etc/kubernetes/manifests
447 |
448 | # Check the status of control-plane pods
449 | kubectl get pods -n kube-system -o wide
450 | ```
451 |
452 | - **What happens if the script fails?**
453 | The script performs backup of critical files before making changes. If it fails, you can find backups in `/etc/kubernetes.old-$(date +%Y-%m-%d_%H-%M-%S)`.
454 |
455 | - **Can I run this on worker nodes?**
456 | No, this script should only be run on control plane nodes.
457 |
458 | - **Will this cause downtime?**
459 | There might be a brief disruption while control plane components restart with new certificates.
460 | But on multi-master clusters, the disruption should be minimal.
461 |
462 | - **How can I skip etcd certificate update?**
463 | You can use the env `KUBE_SKIP_ETCD_CERTS` to skip etcd certificate update.
464 | ```bash
465 | # just update kubernetes master certificates, not etcd
466 | export KUBE_SKIP_ETCD_CERTS=true
467 | bash update-kubeadm-cert.sh --cri containerd
468 | ```
469 |
470 |
471 | ## License
472 | MIT License
473 |
--------------------------------------------------------------------------------
/other-zh_CN.md:
--------------------------------------------------------------------------------
1 | # 使用脚本处理后证书是延续 10 年吗?
2 |
3 | 准确来说并不是
4 |
5 | kubeadm 签发的 CA 默认有效期是 10 年 (从 init 集群那一刻开始算),当 CA 到期后,整套证书体系都失效了
6 |
7 | 也就是说,10 年有效期是从 init 集群那一刻开始算的,不是从执行脚本更新证书那一刻开始算
8 |
9 | # kubeadm 证书相关命令发展
10 |
11 | - `v1.8` 版开始提供了证书生成命令 `kubeadm alpha phase certs `
12 | - `v1.13` 版开始证书生成命令改为 `kubeadm init phase certs `
13 | - `v1.15` 版增加了证书更新命令 `kubeadm alpha certs renew `(这个命令与上面两个区别是:上面两个是生成证书,这个是更新证书),`v1.15` 版之后可使用 `kubeadm alpha certs renew ` 来更新证书
14 |
15 | # kubeadm 命令更新证书手动处理
16 |
17 | 使用该脚本更新证书,不涉及下面这个 bug,无需手动处理
18 |
19 | bug 见 https://github.com/kubernetes/kubeadm/issues/1753 ,这个 bug 在 `1.17` 版修复
20 |
21 | 针对小于 `1.17版本` ,使用 `kubeadm alpha certs renew ` 来更新证书
22 |
23 | `kubeadm alpha certs renew` 并不会更新 kubelet 证书(kubelet.conf 文件里面写的客户端证书),因为 kubelet 证书是默认开启自动轮回更新的,但是在执行 `kubeadm init` 的 master 节点的 kubelet.conf 文件里面的证书是以 base64 编码写死的 (类似 controller-manager.conf 里面的证书)
24 |
25 | 在用 `kubeadm` 命令更新 master 证书时需要手动将 kubelet.conf 文件的 `client-certificate-data` 和 `client-key-data` 改为:
26 |
27 | ```yaml
28 | client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem
29 | client-key: /var/lib/kubelet/pki/kubelet-client-current.pem
30 | ```
31 |
--------------------------------------------------------------------------------
/other.md:
--------------------------------------------------------------------------------
1 | # Is the certificate valid for 10 years after executing the script?
2 |
3 | No, technically.
4 |
5 | The default CA that issued by kubeadm is valid for 10 years (from the moment you init the cluster). And the whole certificate system will expire when the CA expires.
6 |
7 | In other words, the 10-year validity period starts from the moment the cluster is initiated, instead of from the moment the script is executed to renew the certificate.
8 |
9 | # The history of kubeadm certificate related commands
10 |
11 | - Since `v1.8`, it provides the certificate generation command `kubeadm alpha phase certs `.
12 | - The command changed to `kubeadm init phase certs ` in `v1.13`
13 | - The certificate renewal command `kubeadm alpha certs renew ` comes since `v1.15`. (the difference between this command and the above two is: The above two are to generate certificates. But this one is to renew certificates) So after `v1.15`, you can simply use `kubeadm alpha certs renew ` to renew certificates. name>` to renew the certificate
14 |
15 | # handle kubeadm command bug manually
16 |
17 | If use this script to update the certificate, this bug won't appear. And there is no need to handle it.
18 |
19 | See https://github.com/kubernetes/kubeadm/issues/1753 for the detail of the bug, which was fixed in `1.17` version.
20 |
21 | For versions less than `1.17`, use `kubeadm alpha certs renew ` to renew the certificate.
22 |
23 | `kubeadm alpha certs renew` does not renew the kubelet certificate (the client certificate written in the kubelet.conf file) because the kubelet certificate is automatically renewed by default. But in the kubelet.conf file of the master node where `kubeadm init` is executed, the certificate is hard coded in base64 encoding format. (like the controller-manager.conf certificate)
24 |
25 | When updating the master certificate with the `kubeadm` command, you need to manually change the `client-certificate-data` and `client-key-data` in the kubelet.conf file to the following contents:
26 |
27 | ```yaml
28 | client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem
29 | client-key: /var/lib/kubelet/pki/kubelet-client-current.pem
30 | ```
31 |
--------------------------------------------------------------------------------
/update-kubeadm-cert.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # MIT License
4 | #
5 | # The full license can be found at:
6 | # https://github.com/yuyicai/update-kube-cert/blob/master/LICENSE
7 |
8 | # more information about the kubernetes certificates can be found at:
9 | # https://kubernetes.io/docs/setup/best-practices/certificates/
10 |
11 | # renew certificates to 10 years for existing cluster
12 | # bash update-kubeadm-cert.sh --cri containerd
13 | # generate 100 years CA before kubeadm init cluster (only used for new clusters)
14 | # bash update-kubeadm-cert.sh --action gen-ca
15 | # check the expiration of the certificates without updating them
16 | # bash update-kubeadm-cert.sh --action check
17 |
18 | # GitHub: https://github.com/yuyicai/update-kube-cert
19 |
20 | # version of the script
21 | VERSION="v2.1.0"
22 |
23 | set -o errexit
24 | set -o pipefail
25 | # set -o xtrace
26 |
27 | # loglevel: debug, info
28 | LOG_LEVEL=${LOG_LEVEL:-"info"}
29 |
30 | # set cri: docker, containerd
31 | # cri is used to determine the command used to restart the control-plane pod
32 | # when cri is docker, use `docker restart` to restart the control-plane pod
33 | # when cri is containerd, use `crictl stopp` to restart the control-plane pod (kill the pod, and kubelet will recreate the pod)
34 | KUBE_CRI=${KUBE_CRI:-"containerd"}
35 |
36 | # set default certificate expiration days
37 | KUBE_CERT_DAYS=${KUBE_CERT_DAYS:-3650}
38 |
39 | # set default CA expiration days
40 | KUBE_CA_DAYS=${KUBE_CA_DAYS:-36500}
41 |
42 | # skip update etcd certs
43 | KUBE_SKIP_ETCD_CERTS=${KUBE_SKIP_ETCD_CERTS:-"false"}
44 |
45 | # ----------------------------- Certificates Path Begin -----------------------------
46 | # set default kubernetes path
47 | KUBE_PATH=${KUBE_PATH:-"/etc/kubernetes"}
48 | KUBE_PKI_PATH=${KUBE_PATH}/pki
49 |
50 | # master certificates path
51 | # api-server
52 | KUBE_CERT_CA=${KUBE_PKI_PATH}/ca
53 | KUBE_CERT_APISERVER=${KUBE_PKI_PATH}/apiserver
54 | KUBE_CERT_APISERVER_KUBELET_CLIENT=${KUBE_PKI_PATH}/apiserver-kubelet-client
55 | # kubeconfig
56 | KUBE_CONF_CONTROLLER_MANAGER=${KUBE_PATH}/controller-manager
57 | KUBE_CONF_SCHEDULER=${KUBE_PATH}/scheduler
58 | KUBE_CONF_ADMIN=${KUBE_PATH}/admin
59 | # super-admin.conf, add on v1.29.0
60 | # https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.29.md#no-really-you-must-read-this-before-you-upgrade
61 | KUBE_CONF_SUPER_ADMIN=${KUBE_PATH}/super-admin
62 | KUBE_CONF_KUBELET=${KUBE_PATH}/kubelet
63 | # front-proxy
64 | KUBE_FRONT_PROXY_CA=${KUBE_PKI_PATH}/front-proxy-ca
65 | KUBE_FRONT_PROXY_CLIENT=${KUBE_PKI_PATH}/front-proxy-client
66 |
67 | # etcd certificates path
68 | KUBE_ETCD_CERT_CA=${KUBE_PKI_PATH}/etcd/ca
69 | KUBE_ETCD_CERT_SERVER=${KUBE_PKI_PATH}/etcd/server
70 | KUBE_ETCD_CERT_PEER=${KUBE_PKI_PATH}/etcd/peer
71 | KUBE_ETCD_CERT_HEALTHCHECK_CLIENT=${KUBE_PKI_PATH}/etcd/healthcheck-client
72 | KUBE_ETCD_CERT_APISERVER_ETCD_CLIENT=${KUBE_PKI_PATH}/apiserver-etcd-client
73 |
74 | KUBE_ETCD_CERT_LIST=("${KUBE_ETCD_CERT_CA}" "${KUBE_ETCD_CERT_SERVER}" "${KUBE_ETCD_CERT_PEER}" "${KUBE_ETCD_CERT_HEALTHCHECK_CLIENT}" "${KUBE_ETCD_CERT_APISERVER_ETCD_CLIENT}")
75 |
76 | KUBE_MASTER_CERT_LIST=("${KUBE_CERT_CA}" "${KUBE_CERT_APISERVER}" "${KUBE_CERT_APISERVER_KUBELET_CLIENT}" "${KUBE_FRONT_PROXY_CA}" "${KUBE_FRONT_PROXY_CLIENT}")
77 |
78 | KUBE_MASTER_CONF_LIST=("${KUBE_CONF_CONTROLLER_MANAGER}" "${KUBE_CONF_SCHEDULER}" "${KUBE_CONF_ADMIN}")
79 | # if super-admin.conf is existed, add it to the list
80 | if [[ -f "${KUBE_CONF_SUPER_ADMIN}.conf" ]]; then
81 | KUBE_MASTER_CONF_LIST+=("${KUBE_CONF_SUPER_ADMIN}")
82 | fi
83 | # add kubelet.conf to the list if needed
84 | # kubelet.conf does not need to update for K8s v1.17+
85 | # https://github.com/kubernetes/kubeadm/issues/1753
86 |
87 | # if the kubelet.conf contains kubelet-client-current.pem, it does not need to update
88 | IS_KUBELET_NEED_RESTART="false"
89 | if [[ -f "${KUBE_CONF_KUBELET}.conf" ]]; then
90 | grep -q kubelet-client-current.pem "${KUBE_CONF_KUBELET}.conf" 2>/dev/null || KUBE_MASTER_CONF_LIST+=("${KUBE_CONF_KUBELET}") && IS_KUBELET_NEED_RESTART="true"
91 | fi
92 |
93 | # ----------------------------- Certificates Path End -----------------------------
94 |
95 | # Determines if the kubelet, apiserver, controller-manager, scheduler, etcd should be restarted after update certificates
96 | # Set to false if you want to restart manually
97 | KUBE_RESTART_SERVICES=true
98 |
99 | # is need restart control-plane manually
100 | IS_NEED_RESTART_CONTROL_PLANE_MANUALLY=false
101 |
102 | # set output color
103 | COLOR_NC='\033[0m'
104 | COLOR_RED='\033[31m'
105 | COLOR_GREEN='\033[32m'
106 | COLOR_YELLOW='\033[33m'
107 | COLOR_BLUE='\033[34m'
108 | COLOR_PURPLE='\033[35m'
109 |
110 | # loglevel color
111 | LOG_INFO_COLOR="${COLOR_GREEN}"
112 | LOG_WARNING_COLOR="${COLOR_YELLOW}"
113 | LOG_ERROR_COLOR="${COLOR_RED}"
114 | LOG_DEBUG_COLOR="${COLOR_PURPLE}"
115 |
116 | log_err() {
117 | printf "[$(date +'%Y-%m-%dT%H:%M:%S.%2N%z')] ${LOG_ERROR_COLOR}[ERROR]${COLOR_NC} %b\n" "$@"
118 | }
119 |
120 | log_info() {
121 | printf "[$(date +'%Y-%m-%dT%H:%M:%S.%2N%z')] ${LOG_INFO_COLOR}[INFO]${COLOR_NC} %b\n" "$@"
122 | }
123 |
124 | log_warning() {
125 | printf "[$(date +'%Y-%m-%dT%H:%M:%S.%2N%z')] ${LOG_WARNING_COLOR}[WARNING]${COLOR_NC} %b\n" "$@"
126 | }
127 |
128 | log_debug() {
129 | if [[ "${LOG_LEVEL}" == "debug" ]]; then
130 | printf "[$(date +'%Y-%m-%dT%H:%M:%S.%2N%z')] ${LOG_DEBUG_COLOR}[DEBUG]${COLOR_NC} %b\n" "$@"
131 | fi
132 | }
133 |
134 | # get x509v3 subject alternative name from the old certificate
135 | # like: DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:some.domain.com, IP:x.x.x.x
136 | cert_get_subject_alt_name() {
137 | local cert_file_path=${1}.crt
138 | local alt_name
139 | alt_name=$(openssl x509 -text -noout -in "${cert_file_path}" | grep -A1 'Alternative' | tail -n1 | sed 's/[[:space:]]*Address//g' | sed 's/^[[:space:]]*//')
140 | printf "%s\n" "${alt_name}"
141 |
142 | }
143 |
144 | # get subject from the old certificate
145 | # like: /CN=kube-apiserver
146 | cert_get_subj() {
147 | local cert_file_path=${1}.crt
148 | local subj
149 | subj=$(openssl x509 -text -noout -in "${cert_file_path}" | grep "Subject:" | sed 's/Subject:/\//g;s/\,/\//;s/[[:space:]]//g')
150 | printf "%s\n" "${subj}"
151 | }
152 |
153 | # generate certificate whit client, server or peer
154 | # Args:
155 | # $1 (the path of certificate, without suffix.
156 | # example: /etc/kubernetes/pki/apiserver)
157 | # $2 (the type of certificate, must be one of 'client', 'server', 'peer')
158 | # $3 (the subject of certificate)
159 | # $4 (the validity of certificate) (days)
160 | # $5 (the path of ca, without suffix.
161 | # example: /etc/kubernetes/pki/ca)
162 | # $6 (the x509v3 subject alternative name of certificate.
163 | # This option is required when the type of certificate is 'server' or 'peer'.
164 | # example: "DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:some.domain.com, IP:10.96.0.1, IP:10.0.0.185")
165 | cert_gen_cert() {
166 | local cert_file_path=${1}.crt
167 | local key_file_path=${1}.key
168 | local csr_file_path=${1}.csr
169 | local cert_type=${2}
170 | local subj=${3}
171 | local cert_days=${4}
172 | local ca_cert_file_path=${5}.crt
173 | local ca_key_file_path=${5}.key
174 | local alt_name=${6}
175 | local cert_name=${cert_file_path##*/}
176 | local common_csr_conf='distinguished_name = dn\n[dn]\n[v3_ext]\nkeyUsage = critical, digitalSignature, keyEncipherment\nbasicConstraints = critical, CA:FALSE\n'
177 | # check x509v3 subject alternative name when the type of certificate is 'server' or 'peer'
178 | if [[ "${cert_type}" == "server" || "${cert_type}" == "peer" ]]; then
179 | if [[ -z "${alt_name}" ]]; then
180 | log_err "x509v3 subject alternative name is required when the type of certificate is 'server' or 'peer'"
181 | exit 1
182 | fi
183 | log_debug "[${cert_name}] x509v3 subject alternative name: ${alt_name}"
184 | fi
185 | log_debug "[${cert_name}] subject: ${subj}"
186 |
187 | # set the extended key usage for the certificate with different types
188 | case "${cert_type}" in
189 | client)
190 | csr_conf=$(printf "%bextendedKeyUsage = clientAuth\n" "${common_csr_conf}")
191 | ;;
192 | server)
193 | csr_conf=$(printf "%bextendedKeyUsage = serverAuth\nsubjectAltName = %b\n" "${common_csr_conf}" "${alt_name}")
194 | ;;
195 | peer)
196 | csr_conf=$(printf "%bextendedKeyUsage = serverAuth, clientAuth\nsubjectAltName = %b\n" "${common_csr_conf}" "${alt_name}")
197 | ;;
198 | *)
199 | log_err "unknown, unsupported certs type: ${COLOR_YELLOW}${cert_type}${COLOR_NC}, supported type: client, server, peer"
200 | exit 1
201 | ;;
202 | esac
203 |
204 | # gen csr
205 | log_debug "[${cert_name}] generate csr"
206 | if ! openssl req -new -key "${key_file_path}" -subj "${subj}" -reqexts v3_ext \
207 | -config <(printf "%b" "${csr_conf}") \
208 | -out "${csr_file_path}" >/dev/null 2>&1; then
209 | log_err "Failed to generate CSR: ${csr_file_path}"
210 | exit 1
211 | fi
212 | # gen cert
213 | log_debug "[${cert_name}] generate cert"
214 | if ! openssl x509 -in "${csr_file_path}" -req \
215 | -CA "${ca_cert_file_path}" -CAkey "${ca_key_file_path}" -CAcreateserial -extensions v3_ext \
216 | -extfile <(printf "%b" "${csr_conf}") \
217 | -days "${cert_days}" -out "${cert_file_path}" >/dev/null 2>&1; then
218 | log_err "Failed to generate certificate: ${cert_file_path}"
219 | exit 1
220 | fi
221 | log_debug "[${cert_name}] remove csr"
222 | # remove csr
223 | rm -f "${csr_file_path}"
224 | }
225 |
226 | cert_update_kubeconf() {
227 | local cert_path_without_suffix=${1}
228 | local kubeconf_file_path=${cert_path_without_suffix}.conf
229 | local cert_file_path=${cert_path_without_suffix}.crt
230 | local key_file_path=${cert_path_without_suffix}.key
231 | local subj
232 | local cert_base64
233 |
234 | # get the key file from the old kubeconf
235 | grep "client-key-data" "${kubeconf_file_path}" | awk '{print$2}' | base64 -d >"${key_file_path}"
236 | # get the old certificate file from the old kubeconf
237 | grep "client-certificate-data" "${kubeconf_file_path}" | awk '{print$2}' | base64 -d >"${cert_file_path}"
238 | # get subject from the old certificate
239 | subj=$(cert_get_subj "${cert_path_without_suffix}")
240 | # generate new certificate
241 | cert_gen_cert "${cert_path_without_suffix}" "client" "${subj}" "${KUBE_CERT_DAYS}" "${KUBE_CERT_CA}"
242 | # convert the new certificate to base64 code
243 | cert_base64=$(base64 -w 0 "${cert_file_path}")
244 |
245 | # set new certificate base64 code to kubeconf
246 | sed -i 's/client-certificate-data:.*/client-certificate-data: '"${cert_base64}"'/g' "${kubeconf_file_path}"
247 |
248 | # remove certificate, key file after set kubeconf
249 | rm -f "${cert_file_path}"
250 | rm -f "${key_file_path}"
251 | }
252 |
253 | cert_update_etcd_cert() {
254 | local subj
255 | local subject_alt_name
256 | local cert
257 |
258 | # generate new etcd server, peer certificate (extendedKeyUsage = serverAuth, clientAuth)
259 | # /etc/kubernetes/pki/etcd/server.crt
260 | # /etc/kubernetes/pki/etcd/peer.crt
261 | for cert in ${KUBE_ETCD_CERT_SERVER} ${KUBE_ETCD_CERT_PEER}; do
262 | log_debug "updating ${cert}.crt"
263 | subj=$(cert_get_subj "${cert}")
264 | subject_alt_name=$(cert_get_subject_alt_name "${cert}")
265 | cert_gen_cert "${cert}" "peer" "${subj}" "${KUBE_CERT_DAYS}" "${KUBE_ETCD_CERT_CA}" "${subject_alt_name}"
266 | log_info "updated ${COLOR_BLUE}${cert}.crt${COLOR_NC}"
267 | done
268 |
269 | # generate new etcd healthcheck-client, apiserver-etcd-client certificate (extendedKeyUsage = clientAuth)
270 | # /etc/kubernetes/pki/etcd/healthcheck-client.crt
271 | # /etc/kubernetes/pki/apiserver-etcd-client.crt
272 | for cert in ${KUBE_ETCD_CERT_HEALTHCHECK_CLIENT} ${KUBE_ETCD_CERT_APISERVER_ETCD_CLIENT}; do
273 | log_debug "updating ${cert}.crt"
274 | subj=$(cert_get_subj "${cert}")
275 | cert_gen_cert "${cert}" "client" "${subj}" "${KUBE_CERT_DAYS}" "${KUBE_ETCD_CERT_CA}"
276 | log_info "updated ${COLOR_BLUE}${cert}.crt${COLOR_NC}"
277 | done
278 |
279 | # restart etcd pod if needed
280 | # This will restart etcd if KUBE_RESTART_SERVICES is set to true
281 | restart_etcd
282 | }
283 |
284 | restart_etcd() {
285 | # restart etcd if needed
286 | if [[ "${KUBE_RESTART_SERVICES}" == "true" ]]; then
287 | log_debug "restarting etcd"
288 | set +e
289 | case ${KUBE_CRI} in
290 | "docker")
291 | docker ps 2>/dev/null | grep 'k8s_etcd' | awk '{print$1}' | xargs -r -I '{}' docker restart {} >/dev/null 2>&1
292 | ;;
293 | "containerd")
294 | crictl --runtime-endpoint unix:///run/containerd/containerd.sock pods | grep 'etcd-' | awk '{print$1}' | xargs -r -I '{}' crictl --runtime-endpoint unix:///run/containerd/containerd.sock stopp {} >/dev/null 2>&1
295 | ;;
296 | esac
297 | is_etcd_restarted=$?
298 | set -e
299 | if [[ "${is_etcd_restarted}" != "0" ]]; then
300 | IS_NEED_RESTART_CONTROL_PLANE_MANUALLY=true
301 | log_warning "failed to restart etcd, please restart etcd manually"
302 | else
303 | log_info "restarted etcd"
304 | fi
305 | else
306 | IS_NEED_RESTART_CONTROL_PLANE_MANUALLY=true
307 | log_info "please restart etcd manually, KUBE_RESTART_SERVICES is set to false"
308 | fi
309 | }
310 |
311 | cert_update_master_cert() {
312 | local subj
313 | local subject_alt_name
314 | local conf
315 |
316 | # generate new apiserver server certificate (extendedKeyUsage = serverAuth)
317 | # /etc/kubernetes/pki/apiserver.crt
318 | subj=$(cert_get_subj "${KUBE_CERT_APISERVER}")
319 | log_debug "updating ${KUBE_CERT_APISERVER}.crt"
320 | subject_alt_name=$(cert_get_subject_alt_name "${KUBE_CERT_APISERVER}")
321 | cert_gen_cert "${KUBE_CERT_APISERVER}" "server" "${subj}" "${KUBE_CERT_DAYS}" "${KUBE_CERT_CA}" "${subject_alt_name}"
322 | log_info "updated ${COLOR_BLUE}${KUBE_CERT_APISERVER}.crt${COLOR_NC}"
323 |
324 | # generate new apiserver-kubelet-client certificate (extendedKeyUsage = clientAuth)
325 | # /etc/kubernetes/pki/apiserver-kubelet-client.crt
326 | log_debug "updating ${KUBE_CERT_APISERVER_KUBELET_CLIENT}.crt"
327 | subj=$(cert_get_subj "${KUBE_CERT_APISERVER_KUBELET_CLIENT}")
328 | cert_gen_cert "${KUBE_CERT_APISERVER_KUBELET_CLIENT}" "client" "${subj}" "${KUBE_CERT_DAYS}" "${KUBE_CERT_CA}"
329 | log_info "updated ${COLOR_BLUE}${KUBE_CERT_APISERVER_KUBELET_CLIENT}.crt${COLOR_NC}"
330 |
331 | # generate new kubeconf for controller-manager,scheduler and kubelet (extendedKeyUsage = clientAuth)
332 | # /etc/kubernetes/controller-manager.conf,scheduler.conf,admin.conf,kubelet.conf,super-admin.conf
333 | # Note: kubelet.conf does not need to update for K8s v1.17+ unless it contains kubelet-client-current.pem,
334 | # it will be skipped in the KUBE_MASTER_CONF_LIST if it does not contain the kubelet-client-current.pem
335 | # Note: super-admin.conf was added in v1.29.0, it will be included in the KUBE_MASTER_CONF_LIST if it exists
336 | for conf in "${KUBE_MASTER_CONF_LIST[@]}"; do
337 | # update kubeconf
338 | log_debug "updating ${conf}.conf"
339 | cert_update_kubeconf "${conf}"
340 | log_info "updated ${COLOR_BLUE}${conf}.conf${COLOR_NC}"
341 | done
342 |
343 | # generate new front-proxy-client certificate (extendedKeyUsage = clientAuth)
344 | # /etc/kubernetes/pki/front-proxy-client
345 | log_debug "updating ${KUBE_FRONT_PROXY_CLIENT}.crt"
346 | subj=$(cert_get_subj "${KUBE_FRONT_PROXY_CLIENT}")
347 | cert_gen_cert "${KUBE_FRONT_PROXY_CLIENT}" "client" "${subj}" "${KUBE_CERT_DAYS}" "${KUBE_FRONT_PROXY_CA}"
348 | log_info "updated ${COLOR_BLUE}${KUBE_FRONT_PROXY_CLIENT}.crt${COLOR_NC}"
349 |
350 | # restart apiserver, controller-manager, scheduler and kubelet if needed
351 | restart_control_plane
352 | }
353 |
354 | restart_control_plane() {
355 | # restart control-plane pods if needed
356 | if [[ "${KUBE_RESTART_SERVICES}" == "true" ]]; then
357 | for item in "apiserver" "controller-manager" "scheduler"; do
358 | log_debug "restarting control-plane pod: ${item}"
359 | set +e
360 | case ${KUBE_CRI} in
361 | "docker")
362 | docker ps 2>/dev/null | awk "k8s_kube-${item}" | awk '{print$1}' | xargs -r -I '{}' docker restart {} >/dev/null 2>&1
363 | ;;
364 | "containerd")
365 | crictl --runtime-endpoint unix:///run/containerd/containerd.sock pods | grep "kube-${item}-" | awk '{print $1}' | xargs -r -I '{}' crictl --runtime-endpoint unix:///run/containerd/containerd.sock stopp {} >/dev/null 2>&1
366 | ;;
367 | esac
368 | is_control_plane_restarted=$?
369 | set -e
370 | if [[ "${is_control_plane_restarted}" != "0" ]]; then
371 | IS_NEED_RESTART_CONTROL_PLANE_MANUALLY=true
372 | log_warning "failed to restart ${item}, please restart ${item} manually"
373 | else
374 | log_info "restarted control-plane pod: ${item}"
375 | fi
376 | done
377 |
378 | if [[ "${IS_KUBELET_NEED_RESTART}" == "true" ]]; then
379 | set +e
380 | systemctl restart kubelet
381 | is_kubelet_restarted=$?
382 | set -e
383 | if [[ "${is_kubelet_restarted}" != "0" ]]; then
384 | log_warning "failed to restart kubelet, please restart kubelet manually
385 | systemctl restart kubelet"
386 | else
387 | log_info "restarted kubelet"
388 | fi
389 | fi
390 | else
391 | IS_NEED_RESTART_CONTROL_PLANE_MANUALLY=true
392 | log_info "please restart control-plane pods manually, KUBE_RESTART_SERVICES is set to false"
393 | fi
394 | }
395 |
396 | # get certificate expires date
397 | cert_get_cert_expires_date() {
398 | local cert_file_path=${1}.crt
399 | local cert_expires
400 |
401 | cert_expires=$(openssl x509 -text -noout -in "${cert_file_path}" 2>/dev/null | awk -F ": " '/Not After/{print$2}')
402 | printf "%s\n" "${cert_expires}"
403 | }
404 |
405 | # get kubeconfig expires date
406 | cert_get_kubeconfig_expires_date() {
407 | local config_file_path=${1}.conf
408 | local cert_content
409 | local cert_expires
410 |
411 | cert_content=$(grep "client-certificate-data" "${config_file_path}" 2>/dev/null | awk '{print$2}' | base64 -d)
412 | cert_expires=$(openssl x509 -text -noout -in <(printf "%s" "${cert_content}") 2>/dev/null | awk -F ": " '/Not After/{print$2}')
413 | printf "%s\n" "${cert_expires}"
414 | }
415 |
416 | # check etcd certificates expires information
417 | cert_check_etcd_certs_expires() {
418 | local cert
419 | local name
420 |
421 | for cert in "${KUBE_ETCD_CERT_LIST[@]}"; do
422 | name=${cert##*/}
423 | [[ "${name}" == "apiserver-etcd-client" ]] || name="etcd/${name}"
424 | printf "| %-33s | %-27s|\n" "${name}.crt" "$(cert_get_cert_expires_date "${cert}")"
425 | done
426 | }
427 |
428 | split_line() {
429 | printf "|%b|%b|\n" "-----------------------------------" "----------------------------"
430 | }
431 |
432 | # check master certificates expires information
433 | cert_check_master_certs_expires() {
434 | local cert
435 | local conf
436 | local name
437 |
438 | for cert in "${KUBE_MASTER_CERT_LIST[@]}"; do
439 | name=${cert##*/}
440 | printf "| %-33s | %-27s|\n" "${name}.crt" "$(cert_get_cert_expires_date "${cert}")"
441 | done
442 |
443 | split_line
444 |
445 | for conf in "${KUBE_MASTER_CONF_LIST[@]}"; do
446 | name=${conf##*/}
447 | printf "| %-33s | %-27s|\n" "${name}.conf" "$(cert_get_kubeconfig_expires_date "${conf}")"
448 | done
449 | }
450 |
451 | # check all certificates expires
452 | cert_check_expires() {
453 | local cert
454 | local conf
455 | local name
456 |
457 | split_line
458 | printf "| %-33s | %-27s|\n" "CERTIFICATE" "EXPIRES"
459 |
460 | for cert in "${KUBE_MASTER_CERT_LIST[@]}"; do
461 | name=${cert##*/}
462 | printf "| %-33s | %-27s|\n" "${name}.crt" "$(cert_get_cert_expires_date "${cert}")"
463 | done
464 |
465 | split_line
466 |
467 | for conf in "${KUBE_MASTER_CONF_LIST[@]}"; do
468 | name=${conf##*/}
469 | printf "| %-33s | %-27s|\n" "${name}.conf" "$(cert_get_kubeconfig_expires_date "${conf}")"
470 | done
471 |
472 | split_line
473 |
474 | for cert in "${KUBE_ETCD_CERT_LIST[@]}"; do
475 | name=${cert##*/}
476 | [[ "${name}" == "apiserver-etcd-client" ]] || name="etcd/${name}"
477 | printf "| %-33s | %-27s|\n" "${name}.crt" "$(cert_get_cert_expires_date "${cert}")"
478 | done
479 |
480 | split_line
481 | }
482 |
483 | # backup kubernetes files, copy $KUBE_PATH to $KUBE_PATH.old-$(date +%Y-%m-%d_%H-%M-%S)
484 | cert_backup_kube_file() {
485 | local file=${KUBE_PATH}
486 | local time_date
487 | time_date=$(date +'%Y-%m-%d_%H-%M-%S')
488 | log_info "backup ${file} to ${file}.old-${time_date}"
489 | cp -rp "${file}" "${file}.old-${time_date}"
490 | }
491 |
492 | check_file() {
493 | local file=${1}
494 | if [[ ! -f ${file} ]]; then
495 | log_err "file not found: ${file}"
496 | exit 1
497 | elif [[ ! -r ${file} || ! -w ${file} ]]; then
498 | log_err "insufficient permissions for ${file}"
499 | exit 1
500 | fi
501 | log_info "found file: ${file}"
502 | }
503 |
504 | # make sure the etcd certificates are existed
505 | cert_check_etcd_files_existed() {
506 | local cert
507 | local conf
508 |
509 | # Check all certificate files
510 | for cert in "${KUBE_ETCD_CERT_LIST[@]}"; do
511 | check_file "${cert}.crt"
512 | check_file "${cert}.key"
513 | done
514 |
515 | # Check all kubeconfig files
516 | for conf in "${KUBE_MASTER_CONF_LIST[@]}"; do
517 | check_file "${conf}.conf"
518 | done
519 | }
520 |
521 | # make sure the master certificates are existed
522 | cert_check_master_files_existed() {
523 | local cert
524 | local conf
525 |
526 | # Check all certificate files
527 | for cert in "${KUBE_MASTER_CERT_LIST[@]}"; do
528 | check_file "${cert}.crt"
529 | check_file "${cert}.key"
530 | done
531 |
532 | # Check all kubeconfig files
533 | for conf in "${KUBE_MASTER_CONF_LIST[@]}"; do
534 | check_file "${conf}.conf"
535 | done
536 | }
537 |
538 | cert_gen_ca() {
539 | # make sure the directory exists
540 | if [[ ! -d "${KUBE_PKI_PATH}" ]]; then
541 | mkdir -p "${KUBE_PKI_PATH}"
542 | log_debug "created directory: ${KUBE_PKI_PATH}"
543 | fi
544 | # etcd
545 | if [[ ! -d "${KUBE_PKI_PATH}/etcd" ]]; then
546 | mkdir -p "${KUBE_PKI_PATH}/etcd"
547 | log_debug "created directory: ${KUBE_PKI_PATH}/etcd"
548 | fi
549 |
550 | local ca_list=("${KUBE_PKI_PATH}/ca" "${KUBE_PKI_PATH}/front-proxy-ca" "${KUBE_PKI_PATH}/etcd/ca")
551 | # Check if CA keys already exist
552 | for ca in "${ca_list[@]}"; do
553 | if [[ -f "${ca}.key" ]]; then
554 | log_err "${ca}.key already exists, make sure you want to regenerate the CA. please backup the existing ca certs, keys and remove them before regenerating the CA."
555 | exit 1
556 | fi
557 | if [[ -f "${ca}.crt" ]]; then
558 | log_err "${ca}.crt already exists, make sure you want to regenerate the CA. please backup the existing ca certs, keys and remove them before regenerating the CA."
559 | exit 1
560 | fi
561 | done
562 |
563 | csr_conf='distinguished_name = dn\n[dn]\n[ v3_ca_ext ]\nkeyUsage = critical, digitalSignature, keyEncipherment, keyCertSign\nbasicConstraints = critical, CA:true\n'
564 |
565 | # generate ca.crt
566 | log_info "generating k8s CA..."
567 | openssl genrsa -out "${KUBE_PKI_PATH}"/ca.key 2048 >/dev/null 2>&1
568 | log_debug "generated ${KUBE_PKI_PATH}/ca.key"
569 | openssl req -x509 -new -nodes -key "${KUBE_PKI_PATH}"/ca.key \
570 | -subj "/CN=kubernetes" \
571 | -config <(printf "%bsubjectAltName = DNS:kubernetes" "${csr_conf}") \
572 | -extensions v3_ca_ext \
573 | -days "${KUBE_CA_DAYS}" \
574 | -out "${KUBE_PKI_PATH}"/ca.crt >/dev/null 2>&1
575 | log_info "generated ${COLOR_BLUE}${KUBE_PKI_PATH}/ca.crt${COLOR_NC}"
576 |
577 | # generate front-proxy-ca.crt
578 | log_info "generating front-proxy CA..."
579 | openssl genrsa -out "${KUBE_PKI_PATH}"/front-proxy-ca.key 2048 >/dev/null 2>&1
580 | log_debug "generated ${KUBE_PKI_PATH}/front-proxy-ca.key"
581 | openssl req -x509 -new -nodes -key "${KUBE_PKI_PATH}"/front-proxy-ca.key \
582 | -subj "/CN=front-proxy-ca" \
583 | -config <(printf "%bsubjectAltName = DNS:front-proxy-ca" "${csr_conf}") \
584 | -extensions v3_ca_ext \
585 | -days "${KUBE_CA_DAYS}" \
586 | -out "${KUBE_PKI_PATH}"/front-proxy-ca.crt >/dev/null 2>&1
587 | log_info "generated ${COLOR_BLUE}${KUBE_PKI_PATH}/front-proxy-ca.crt${COLOR_NC}"
588 |
589 | # generate etcd/ca.crt
590 | log_info "generating etcd CA..."
591 | openssl genrsa -out "${KUBE_PKI_PATH}"/etcd/ca.key 2048 >/dev/null 2>&1
592 | log_debug "generated ${KUBE_PKI_PATH}/etcd/ca.key"
593 | openssl req -x509 -new -nodes -key "${KUBE_PKI_PATH}"/etcd/ca.key \
594 | -subj "/CN=etcd-ca" \
595 | -config <(printf "%bsubjectAltName = DNS:etcd-ca" "${csr_conf}") \
596 | -extensions v3_ca_ext \
597 | -days "${KUBE_CA_DAYS}" \
598 | -out "${KUBE_PKI_PATH}"/etcd/ca.crt >/dev/null 2>&1
599 | log_info "generated ${COLOR_BLUE}${KUBE_PKI_PATH}/etcd/ca.crt${COLOR_NC}"
600 | }
601 |
602 | help() {
603 | printf "%b\n" "
604 | Usage: bash update-kubeadm-cert.sh [OPTIONS]
605 | Version: ${VERSION}
606 | Example:
607 | # renew certificates to 10 years for existing cluster
608 | bash update-kubeadm-cert.sh --cri containerd
609 | # generate 100 years CA before kubeadm init cluster (only used for new clusters)
610 | bash update-kubeadm-cert.sh --action gen-ca
611 | # check the expiration of the certificates without updating them
612 | bash update-kubeadm-cert.sh --action check
613 | Options:
614 | -c, --cri (default: containerd)
615 | Set the cri type, in order to restart control-plane and etcd service by different command, 'docker' or 'crictl'.
616 | -a, --action (default: update)
617 | update: Update certificates 10 years for existing clusters
618 | check: Only check the expiration of the certificates without updating them.
619 | gen-ca: Generate 100 years CA before kubeadm init cluster. (only used for new clusters, not for existing clusters)
620 | --days Set the number of days for certificate expiration. (default: 3650)
621 | -h, --help Show this help message and exit.
622 |
623 | more info: https://github.com/yuyicai/update-kube-cert
624 | "
625 | }
626 |
627 | main() {
628 | local action="update" # default action
629 |
630 | # read the options
631 | ARGS=$(getopt -n update-kubeadm-cert.sh -a -o a:c:h --long action:,cri:,days:,help -- "$@")
632 | eval set -- "$ARGS"
633 | # extract options and their arguments into variables.
634 | while true; do
635 | case "$1" in
636 | -h | --help)
637 | help
638 | exit 0
639 | ;;
640 | -a | --action)
641 | # Set the action (update, check, gen-ca)
642 | case "$2" in
643 | "update" | "check" | "gen-ca")
644 | action=$2
645 | shift 2
646 | ;;
647 | *)
648 | echo 'Unsupported action '"$2"'. Valid options are "update", "check", "gen-ca".'
649 | exit 1
650 | ;;
651 | esac
652 | ;;
653 | -c | --cri)
654 | # Set the container runtime interface (KUBE_CRI) to use.
655 | case "$2" in
656 | "docker" | "containerd")
657 | KUBE_CRI=$2
658 | shift 2
659 | ;;
660 | *)
661 | echo 'Unsupported cri '"$2"'. Valid options are "docker", "containerd".'
662 | exit 1
663 | ;;
664 | esac
665 | ;;
666 | --days)
667 | # This option is deprecated, use KUBE_CERT_DAYS and KUBE_CA_DAYS instead
668 | # Set the number of days for certificate expiration
669 | if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then
670 | KUBE_CERT_DAYS=$2
671 | shift 2
672 | else
673 | echo "Invalid value for --days. It should be a positive integer."
674 | exit 1
675 | fi
676 | ;;
677 | --)
678 | shift
679 | break
680 | ;;
681 | *)
682 | echo "Invalid arguments '$1'"
683 | help
684 | exit 1
685 | ;;
686 | esac
687 | done
688 |
689 | # Only check the expiration of the certificates without updating them
690 | if [[ "${action}" == "check" ]]; then
691 | log_info "checking certificate expiration only..."
692 | cert_check_expires
693 | log_info "${COLOR_GREEN}DONE!!!${COLOR_NC}"
694 | exit 0
695 | fi
696 |
697 | # Generate 100 years CA before kubeadm init cluster (only used for new clusters)
698 | if [[ "${action}" == "gen-ca" ]]; then
699 | log_info "generating CA with ${KUBE_CA_DAYS} days expiration..."
700 | cert_gen_ca
701 | cert_check_expires
702 | log_info "${COLOR_GREEN}DONE!!!${COLOR_NC} generated CA for new cluster.
703 | # create new cluster after generating CA, you can use the following command:
704 | kubeadm init [options]
705 | # after running kubeadm init, update certificates for 100 yeas
706 | bash update-kubeadm-cert.sh --cri containerd --days 36500
707 | "
708 | exit 0
709 | fi
710 |
711 | # make sure the certificates are existed
712 | log_info "checking if all certificate files are existed..."
713 | if [[ "${KUBE_SKIP_ETCD_CERTS}" != "true" ]]; then
714 | cert_check_etcd_files_existed
715 | else
716 | log_info "skipping etcd certificates check"
717 | fi
718 | cert_check_master_files_existed
719 | log_info "all certificate files are existed"
720 |
721 | # backup kubernetes files
722 | cert_backup_kube_file
723 | # check expires before updating the certificates
724 | log_info "checking certificate expiration before update..."
725 | cert_check_expires
726 |
727 | # update certificates 10 years for existing clusters
728 | log_info "updating certificates with ${KUBE_CERT_DAYS} days expiration..."
729 |
730 | # etcd
731 | if [[ "${KUBE_SKIP_ETCD_CERTS}" != "true" ]]; then
732 | # update etcd certificates
733 | cert_update_etcd_cert
734 | else
735 | log_info "skipping etcd certificates update"
736 | fi
737 |
738 | # master
739 | # update master certificates and kubeconf
740 | cert_update_master_cert
741 |
742 | # check expires after updating the certificates
743 | log_info "checking certificate expiration after update..."
744 | cert_check_expires
745 |
746 | log_info "${COLOR_GREEN}DONE!!!${COLOR_NC}enjoy it"
747 |
748 | # printf cofy admin.conf manually info
749 | printf "\n%b\n\n\n" "please copy admin.conf to ${HOME}/.kube/config manually.
750 | # back old config
751 | cp $HOME/.kube/config $HOME/.kube/config_backup
752 | # copy new admin.conf to ${HOME}/.kube/config for kubectl manually
753 | ${LOG_WARNING_COLOR}cp -i ${KUBE_PATH}/admin.conf ${HOME}/.kube/config${COLOR_NC}"
754 |
755 | if [[ "${IS_NEED_RESTART_CONTROL_PLANE_MANUALLY}" == "true" ]]; then
756 | log_warning "please restart control-plane pods manually"
757 | printf "\n%b\n" "${LOG_WARNING_COLOR}you can use the following command to restart control-plane pods:${COLOR_NC}
758 | # make sure kubelet is running
759 | systemctl restart kubelet
760 | # move manifests to trigger kubelet to recreate the pods
761 | mv /etc/kubernetes/manifests /etc/kubernetes/manifests_backup
762 | # wait for 2 minutes, let kubelet remove the old pods
763 | sleep 120
764 | # restore manifests, kubelet will recreate the pods
765 | mv /etc/kubernetes/manifests_backup /etc/kubernetes/manifests
766 | # check the status of control-plane pods
767 | kubectl get pods -n kube-system -o wide"
768 | fi
769 | }
770 |
771 | # call the main function with all command-line arguments
772 | main "$@"
773 |
--------------------------------------------------------------------------------