本文发布于Cylon的收藏册,转载请著名原文链接~


tls 证书在 k8s 集群上大量使用的话,当到期时会存在批量替换的难度,比如说每个名称空间,多个业务的使用,在这篇博文中,将尝试批量替换整个集群的证书(前提,在没有使用 vault, cert-manager这类组件的集群之上)。

基本操作

步骤1:首先不知道有多少个名称空间使用了这个证书,所以需要遍历所有的名称空间,这里使用 kubectl 的 json path 实现

$ kubectl get ns -o jsonpath='{range $.items[*]}{.metadata.name}{"\n"}{end}'

步骤2:拿到名称空间的名字后,就需要循环这个名称空间下所有的 secret

for ns in `kubectl get ns -o jsonpath='{range $.items[*]}{.metadata.name}{"\n"}{end}'`
do
	kubectl get secret -n $ns -o jsonpath='{range $.items[*]}{.metadata.name}{"\n"}{end}'
done

步骤3:找到与这个匹配的证书进行替换

把步骤3拆解为下面几个步骤:

  • 拿去到符合要求的secret的名字
  • 匹配名称是否为修改的secret
  • 做替换操作

由于步骤2使用的是 jsonpath 拿到的 secret name,由于 kubectl 并不支持高级jsonpath语法,官方推荐使用jq,那么使用jq获取名字

kubectl get secret -n $ns -o json|jq -r .items[].metadata.name

使用 awk 做字符串匹配,匹配是否包含对应的字符串关键词

awk '$1 ~ /xxxx/ { print }'

最后使用 kubectl replace 替换现有的 secret

kubectl create secret tls $secertName -n $ns --cert=xxx.crt --key=xxx.key --dry-run -o yaml| kubectl replace -f -

三个步骤整个为一个命令,如下所示:

for ns in `kubectl get ns -o jsonpath='{range $.items[*]}{.metadata.name}{"\n"}{end}'`
do
	for secertName in `kubectl get secret -n $ns -o json|jq -r .items[].metadata.name|awk '$1 ~ /xxxx/ { print }';
	do
		kubectl create secret tls $secertName -n $ns --cert=xxx.crt --key=xxx.key --dry-run -o yaml| kubectl replace -f -
	done
done

注意:

  • ingress 使用的证书会立即更新
  • 如果是作为 secret 挂在到 Pod 中需要重启,这是因为 kubelet volume 机制导致的。

高级用法

查询证书内容,并根据域名进行替换

查看证书域名的命令

ns=xxx
secret_name=xxx
keywords=xxx
_command=xxxx
openssl x509 -in <(
    ${_command} get secret -n $ns $secret_name -ojson | \
    jq --arg secret_key $(
        ${_command} get secret -n ${ns} ${secret_name} -ojson | \
        jq -r '.data | keys[]' | \
        awk -v keywords=${keywords} '$0 ~ keywords { print }'
    ) -r '.data | .[$secret_key]' | base64 -d
) -text -noout | \
grep -i "subject: "

步骤拆解

# 替换的名称空间
ns=kube-system
# 替换的secret_name
secret_name=test
# 替换key的关键词,通常secret作为tls存在时,为xxx.crt
keywords=crt
# kubectl命令
_command=kubectl --kubeconfig=kubeconfig

# shell语法,将一个命令的输出作为openssl的输入
openssl x509 -in <(
    ${_command} get secret -n $ns $secret_name -ojson | \
    # jq --arg secret_key 是 jq语法,将 $() 命名为secret_key作为变量传入到下个命令使用
    jq --arg secret_key $(
        ${_command} get secret -n ${ns} ${secret_name} -ojson | \
        jq -r '.data | keys[]' | \
        # awk -v keywords=${keywords} 是awk语法,将keyworkd作为变量传递到awk内部
        # '$0 ~ keywords { print }' 打印出符合条件的行
        awk -v keywords=${keywords} '$0 ~ keywords { print }'
    ) -r '.data | .[$secret_key]' | base64 -d
) -text -noout | \
grep -i "subject: "

更新前没出意外需要备份下对应资源,批量备份集群内指定域名的 secret 命令

```bash
# 指定域名的secret
keywords=xxx
_command=xxxx
for ns in `${_command} get ns -o jsonpath='{range $.items[*]}{.metadata.name}{"\n"}{"end"}'`
do
    for secret_name in `${_command} get secret -n $ns -o json|jq -r '.items[] | select( .type == "kubernetes.io/tls") | .metadata.name'`
    do  
        openssl x509 -in <(
            ${_command} get secret -n ${ns} ${secret_name} -ojson | \
            jq --arg secret_key $(
                    ${_command} get secret -n ${ns} ${secret_name} -ojson | 
                    jq -r '.data | keys[]' | \
                    awk '$0 ~ /crt/ { print }'
                ) -r '.data|.[$secret_key]'|base64 -d
        ) -text -noout | \
        grep -i "subject: "| \
        awk -v ns=${ns} -v secret_name=${secret_name} -v cmd=${_command} -v kw=${keywords} \
            '$0 ~ kw { system(
                cmd" get secret -n "ns" "secret_name" -oyaml > primetive/"ns"."secret_name".yaml"
            )}'
    done
done

批量替换命令,查询 tls 签发域名,并进行替换

keywords=xxx
_command=xxxx
for ns in `${_command} get ns -o jsonpath='range $.items[*]}{.metadata.name}{"\n"}{"end"}'
do
    for secret_name in `${_command} get secret -n $ns -o json|jq -r '.items[] | select( .type == "kubernetes.io/tls") | .metadta.name'`
    do  
        openssl x509 -n <(
            ${_command} get secret -n ${ns} ${secret_name} -ojson | \
            jq --arg secret_key $(${_command} get secret -n ${ns} ${secret_name} -ojson | \
            jq -r '.data | .keys[]' | \
            awk '$0 ~ /crt/ { print }' -r '.data|.[$secret_key]'|base64 -d
        ) -text -noout | \
        grep -i "subject: "| \
        awk -v ns=${ns} -v secret_name=${secret_name} -v commond=${_command}\
            '$0 ~ ${keywords} { system(
                command" create secret tls -n "ns" "secret_name" --cert=ca.crt --key=key.key --dry-run -oyaml|command" replace -f -"
            )}'
    done
done

本文发布于Cylon的收藏册,转载请著名原文链接~

链接:https://www.oomkill.com/2024/02/kubernetes-update-secert/

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」 许可协议进行许可。