当从文件生成的密钥需要更新时,我该如何在Kubernetes上进行更新?

181

我使用了一个方法创建了一个秘密

kubectl create secret generic production-tls \
  --from-file=./tls.key \
  --from-file=./tls.crt

如果我想更新这些值,我该怎么做?

9个回答

395
这应该可以工作:
kubectl create secret generic production-tls \
--save-config \
--dry-run=client \
--from-file=./tls.key --from-file=./tls.crt \
-o yaml | \
kubectl apply -f -

14
在最新版本的k8s中,为了避免CLI警告,您需要在kubectl create secret命令中提供--save-config参数。 - David House
6
最近(2019年9月)可用于TLS密钥的语法如下:kubectl create secret tls my-domain-tls --namespace=default --key=./tls.key --cert=./tls.crt --dry-run -o yaml | kubectl apply -f - 证书是明文的。 - ldg
5
需要在kubectl 1.18或更高版本中使用--dry-run=client - RichVel
这将创建一个名为"kubectl.kubernetes.io/last-applied-configuration"的配置,其中不包含加密值。 - SergkeiM
2
@Froxz,一个 Secret 中的值并没有被加密; 它们只是简单地使用了 base64 编码。使用这个命令并不会改变安全性。 - Janos Lenart

121

您可以删除并立即重新创建该机密:

kubectl delete secret production-tls \
--ignore-not-found

kubectl create secret generic production-tls \
--from-file=./tls.key \
--from-file=./tls.crt

我把这些命令放在一个脚本中。 --ignore-not-found 参数可以防止在第一次运行时收到警告。


6
在删除密钥时,Pod会发生什么? - Bruno Medeiros
7
无论是通过环境变量获取秘钥还是作为卷挂载,正在运行的pod都不会受到影响。如果在没有秘钥的时间启动了一个pod,它将遇到错误;因此,Janos的答案是首选方案。 - P.J.Meisch
2
是的,我明白了,使用apply更有意义,谢谢! - Bruno Medeiros
2
取决于您要将秘密添加到哪个命名空间,如果不是“_default_”,那么您当然必须添加命名空间参数。 - P.J.Meisch
1
该解决方案并不等同于 OP 请求的更新。删除该密钥意味着失去该密钥中的所有元数据以及任何其他字段。 - Denilson
显示剩余2条评论

15

另外,您还可以使用 jq=|= 运算符来动态更新密码。

TLS_KEY=$(base64 < "./tls.key" | tr -d '\n')
TLS_CRT=$(base64 < "./tls.crt" | tr -d '\n')
kubectl get secrets production-tls -o json \
        | jq '.data["tls.key"] |= "$TLS_KEY"' \
        | jq '.data["tls.crt"] |= "$TLS_CRT"' \
        | kubectl apply -f -

虽然这种方法可能不像kubectl create secret generic --dry-run那样优雅或简单,但从技术上讲,该方法确实是更新值而非删除/重新创建。你还需要可用的jqbase64(或openssl enc -base64)命令,tr是一个常见的Linux实用程序,用于修剪尾随的换行符。

有关jq更新运算符|=的更多详细信息,请参见此处


1
你能否在base64命令中添加-w0以禁用行换行?https://linux.die.net/man/1/base64 - patricknelson
@chunk_split不行。我正在使用macOS,base64命令的BSD版本没有该选项。 - Devy
1
从概念上讲,将值分配给变量会增加它们在日志文件中泄漏的机会,当某人使用 set -x 打开调试时。在更实际的层面上,由于 jq 参数位于单引号之间,因此 shell 变量不会被扩展。因此,最终的秘密将具有文字字符 $TLS_KEY 和 $TLS_CRT,而不是它们的实际值。 您需要执行类似以下的操作:jq --arg TLS_KEY $TLS_KEY '.data["tls.key"] |= "$TLS_KEY"' - Denilson

14

由于我无法回复Devy上面的答案,我很喜欢它,因为它将保留所有权,而删除和重新创建可能会丢失记录中的任何额外信息。我为那些可能不会立即理解其变量未插值的新手添加了此内容。

TLS_KEY=$(base64 < "./tls.key" | tr -d '\n')
TLS_CRT=$(base64 < "./tls.crt" | tr -d '\n')
kubectl get secrets production-tls -o json \
        | jq ".data[\"tls.key\"] |= \"$TLS_KEY\"" \
        | jq ".data[\"tls.crt\"] |= \"$TLS_CRT\"" \
        | kubectl apply -f -

这让我尝试使用kubectl的'patch'方法,它似乎也可以工作。

kubectl \
        patch \
        secret \
        production-tls \
        -p "{\"data\":{\"tls.key\":\"${TLS_KEY}\",\"tls.crt\":\"${TLS_CRT}\"}}"

感谢Devy给出最符合我需求的答案。


2
请使用 base64 -w 0 替代 tr -d - Jeremy Morren
1
如果你使用"stringData"而不是"data",你就不需要对值进行base64编码。 - neu242

4

虽然来晚了,但这里是我的意见。

潜在地,我们可以同时使用patchedit选项。

  • With edit :

    kubectl edit secrets/<SECRET_NAME> -n <NAME_SPACE>
    
    • NOT the recommended way of editing the secrets.
    • You should have enough permission to do the above edit.
    • The value should be base64 encode by yourself and then the encoded value should be placed while editing.
  • With patch :


3

对于更具体的情况,您可能需要指定需要更新证书的名称空间并删除旧证书。

删除证书

kubectl delete secret -n `namespace`

为特定的命名空间创建新证书。
kubectl create secret {your-cert-name} --key /etc/certs/{name}.com.key --cert /etc/certs/{name}.com.crt -n {namespace}

一个例子:oc delete secret secret-name -n "openshift-config" - Eduardo Lucio

2
你可以使用补丁密钥:
kubectl patch secret my-secret  --patch="{\"data\": { \"tls.key\": \"$(base64 -w0 ./tls.key)\",\"tls.crt\": \"$(base64 -w0 ./tls.crt)\"  }}" 

1
太棒了!谢谢 @Maoz Zadok。对于MacOS需要稍作调整,base64命令需要一个-i输入参数,并且没有-w换行参数。意思是:kubectl patch secret tls-secret --patch="{\"data\": { \"tls.key\": \"$(base64 -i ./key.pem)\",\"tls.crt\": \"$(base64 -i ./cert.crt)\" }}" - undefined

2

为了进一步解释这些答案,我发现在删除时添加“--ignore-not-found”有助于我们的CICD,因为如果密钥不存在,它不会出错,而是会继续创建:

kubectl delete secret production-tls --ignore-not-found
kubectl create secret generic production-tls --from-file=./tls.key --from-file=./tls.crt.

1
我找到了一种最好的方法:
kubectl create secret generic production-tls --from-file=./tls.key  --from-file=./tls.crt --dry-run=client -o yaml | kubectl apply -f -

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接