1 關于K8S Secret
我們通常將應用程序使用的密碼、API密鑰保存在K8S Secret中,然后應用去引用。對于這些敏感信息,安全性是至關重要的,而傳統的存儲方式可能會導致密鑰在存儲、傳輸或使用過程中受到威脅,例如在git中明文存儲密碼或在配置文件中以明文形式存放密碼。
2 SealedSecrets
為了解決Secret的安全問題,SealedSecrets通過使用公鑰加密技術來提高密鑰的安全性。它使用了非對稱加密算法,將明文的secret加密為SealedSecrets,只有具有相應私鑰的受信任的控制器才能解密和使用密鑰。在這種情況下,即使是創建密鑰的人也無法從加密的secret中恢復原始secret。
3 部署SealedSecrets
直接通過helm安裝,
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm search repo sealed-secrets/sealed-secrets
NAME CHART VERSION APP VERSION DESCRIPTION
sealed-secrets/sealed-secrets 2.15.3 0.26.2 Helm chart for the sealed-secrets controller.
這里有個坑,需要注意下,因為默認helm安裝的controller名字是sealed-secrets,但是客戶端工具kubeseal默認是用的服務名稱是sealed-secrets-controller,因此安裝時要通過–set-string設置下名字,否則使用kubeseal時會有下列報錯,
error: cannot get sealed secret service: services "sealed-secrets-controller" not found.
Please, use the flag --controller-name and --controller-namespace to set up the name and namespace of the sealed secrets controller
安裝當前最新版本2.15.3
helm install sealed-secrets --set-string fullnameOverride=sealed-secrets-controller sealed-secrets/sealed-secrets --version 2.15.3
NAME: sealed-secrets
LAST DEPLOYED: ...
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:...
sealed-secrets默認會安裝到kube-system namespace,
kubectl get po -n kube-system | grep sealed-secrets
sealed-secrets-6bdbdfcf6-kgt7x 1/1 Running 0 2m22s
部署后,控制器會在當前namespace中搜索帶有 sealedsecrets.bitnami.com/sealed-secrets-key標簽的secret。如果找不到,控制器會在其namespace中創建新的secret,并將密鑰對的公鑰部分打印到輸出日志中,
kubectl logs -f sealed-secrets-controller-f994b58c6-f46pt -n kube-system
level=INFO msg="Starting sealed-secrets controller" version=v0.26.2
level=INFO msg="Searching for existing private keys"
level=INFO msg="New key written" namespace=kube-system name=sealed-secrets-keyml59m
level=INFO msg="Certificate generated" certificate=....
控制器使用的密鑰對就被保存在sealed-secrets-keyml59m,這個secret需要嚴格安全保存,它是這個集群加密的原始密鑰,所有secret都依賴這個來加密。
4 加密secret
SealedSecrets提供了一個客戶端工具kubeseal來加密secret,所以首先要先安裝這個工具,
KUBESEAL_VERSION='' # Set this to, for example, KUBESEAL_VERSION='0.23.0'
wget "https://github.com/bitnami-labs/sealed-secrets/releases/download/v${KUBESEAL_VERSION:?}/kubeseal-${KUBESEAL_VERSION:?}-linux-amd64.tar.gz"
tar -xvzf kubeseal-${KUBESEAL_VERSION:?}-linux-amd64.tar.gz kubeseal
sudo install -m 755 kubeseal /usr/local/bin/kubeseal
然后就可以開始加密我們的secret了,
假設我們有以下secret,
$ cat mysecret.yaml
apiVersion: v1
kind: Secret
metadata:name: mysecretnamespace: kube-system
data:foo: YmFy # <- base64 encoded "bar"
我們直接使用kubeseal對其加密,并輸出到mysecret_sealed.yaml
$ kubeseal < mysecret.yaml > mysecret_sealed.yaml
$ cat mysecret_sealed.yaml
{"kind": "SealedSecret",..."spec": {..."encryptedData": {"foo": "AgCKwrBaLJxNPLfClItshQrWEoD0ntykNbOGKcA/F/a8Cj3lZ7aFLiNJ+pqp8AZcHpsBeUpSZwQv4OtHaXnSgJO+L4q4yLFYVKL9oDBHKvZyWjZfEeDPASUn1dSz6FBs88S/HhvfPxJY98MBNPAQwVAnnfIrscZ/vhYm7qYaj55mwJNWd0X9JjJ6EcLpKpib/qa6jFhBivmwbZ275ykU60v4nAvN8I3pEAZxD4TYk+Fni4wBj6y9EZyG6rkO9jNG+Ff0Xs3RVyEoCf9kt+t2ylusPJ+tHJNrGZ2qxXL3UCQEGwKPMV4ZNHvVRgiJT2C/l5x1L6BHWHIV/oio0BNNBT7CrvlG2EDEBbQz6J12ZjPquWHLUbLIXx4kKBbTxhYVRs4YS9F2RHwWu6ItU/M19iRLHqpJe5jXWzme4Oo2GCYqyQc4BB/Z9w2TxJKqLr7CidT+nfeKMLWMng8Qf+Curtnz4CPwp75Xj4Kj6obgICkNJn6PKL7F6JSszHVfAWVhjHsODUEdWG3cV9Mne/7BdoOfHoNvHIY3Bjbms0Fzl9VndAeFwpymJRaEHHkZALk0uWBfTcaw7HyL4EDMEapJ8Rd4v++gMuOaMSEjN1vQwygMxmLqsrx55Rm2vXcsd0flj239TQ2BC3GYvzKpJBqV7sf65Zuzmpd9iVYeLO7soCnRImwJ6KQOh4fG6K3KGPf6uNmvwW4="}}
}
這種方式要求你當前已經連接到k8s apiserver,如果要使用離線方式加密,需要提前先把公鑰下載到本地,
kubeseal --fetch-cert > public-key-cert.pem
然后加密時指定密鑰文件即可,
kubeseal --cert=public-key-cert.pem < secret.yaml > sealed-secret.yaml
5 部署加密后的secret
我們可以直接apply加密后的mysecret_sealed.yaml
$ k apply -f mysecret_sealed.yaml
sealedsecret.bitnami.com/mysecret created
在controller日志里就能看到secret被成功解密,
level=INFO msg=Updating key=kube-system/mysecret
level=INFO msg="Event(v1.ObjectReference{Kind:\"SealedSecret\", Namespace:\"kube-system\", Name:\"mysecret\", UID:\"c77070a1-167b-4897-bed5-336c857a6f1e\", APIVersion:\"bitnami.com/v1alpha1\", ResourceVersion:\"1326784263\", FieldPath:\"\"}): type: 'Normal' reason: 'Unsealed' SealedSecret unsealed successfully"
6 解密secret
如果實在需要解密加密過的secret,可以使用kubeseal --recovery-unseal來操作,但是前提是你本地保存了控制器使用的公私鑰密鑰對。
如果你有權限,可以通過以下命令下載密鑰對,
kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml > sealed-secrets-key.yaml
然后再解密
kubeseal --recovery-unseal --recovery-private-key sealed-secrets-key.yaml < mysealedsecret.yaml > mysecret.yaml
7 其他
-
加密secret時需要先對數據進行base64加密,這里有個隱藏的坑,我習慣直接是用命令行加密,比如加密123456
$ echo "123456" | base64 MTIzNDU2Cg==
但是這里會有個問題,加密后的密碼其實是包含了一個換行符,因此再經過sealedsecret加密的話,如果應用程序直接使用這個值去校驗就會報錯,你就會很郁悶,明明密碼正確為啥加密后就不行。
對此,echo時需要加個-n參數即可,
$ echo -n "123456" | base64 MTIzNDU2
-
部署加密后的secret前,可以用kubeseal校驗下,
cat mysecret_sealed.yaml | kubeseal --validate
如果出錯會有以下報錯,
error: unable to decrypt sealed secret
-
SealedSecrets控制器使用的密鑰對默認每30天renew一次,舊的密鑰無法解密新的加密secret,所以不要隨便刪除舊的secret
參考文檔:
4. https://github.com/bitnami-labs/sealed-secrets