如何用Sealed Secrets对Kubernetes的秘密进行加密?

538 阅读6分钟

正如我们所知,Kubernetes中的Secrets用于存储敏感数据,如密码、密钥、证书和令牌。秘密是以base64编码的,当它们被Pod连接和读取时,会自动解密。

Kubernetes集群中的秘密是以base64编码的,但不是加密的!

这些数据是 "唯一 "编码的,所以如果一个用户可以访问你的秘密,他可以简单地执行一个base64 decode 命令来查看你的敏感数据(kubectl get secret my-secret -o jsonpath="{.data.password}" | base64 --decode)。

由于秘密没有被加密,将它们提交到你的Git仓库可能是不安全的。

Sealed Secrets是一个解决方案,可以将你的Kubernetes Secret加密成一个SealedSecret ,这样就可以安全地存储--即使是提交到公共仓库。SealedSecret只能由运行在目标集群中的控制器解密,其他任何人都不能解密。

它是如何工作的?

封闭秘密的基本原则是使用公钥密码学。公共证书被用于密封秘密。控制器拥有的私钥用于解密密封的秘密。

加密过程中默认使用名称空间。因此,不同名称空间上的两个相同的秘密将有一组不同的加密数据在其中。

默认情况下,秘密名称也在加密过程中被使用。这一设计决定不允许对密封的秘密资源进行重命名。这提高了安全性,因为RBAC(基于角色的访问控制)可以通过名称强制限制秘密的访问,而Sealed Secrets通过禁止秘密被重新命名来遵循它。

有3种类型的作用域可供使用。

  • 严格范围要求名称空间和秘密名称都是加密过程的一部分。
  • namespace-wide作用域只要求秘密名称作为加密过程的一部分。
  • cluster-wide不需要这两者。

设置密封的秘密组件

Kubeseal

kubeseal 是一个用于密封/加密k8s秘密的CLI客户端。

wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.18.0/kubeseal-0.18.0-linux-amd64.tar.gz
tar -xvf kubeseal-0.18.0-linux-amd64.tar.gz
sudo mv kubeseal /usr/local/bin/kubeseal

封闭的秘密控制器

目前的部署过程可以在目标集群上手动完成helm install命令或kubectl。

通过helm图表进行安装

helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm dependency update sealed-secrets
helm install sealed-secrets sealed-secrets/sealed-secrets \
  --namespace kube-system \
  --version 2.2.0 

通过Kubectl安装

wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.18.1/controller.yaml

kubectl apply -f controller.yaml

你可以通过执行以下命令确保相关Pod按照预期运行。

kubectl get pods -n kube-system | grep sealed-secrets-controller

封闭秘密Create Secret

下面给出了Kubernetes Secret的代码。将代码保存在文件名secrets.yaml中。

apiVersion: v1
kind: Secret
metadata:
  creationTimestamp: null
  name: my-secret
  namespace: test-ns
data:
  password: cG9zdGdyZXM=  # <- base64 encoded postgres
  username: YWRtaW5AcG9zdGdyZXM= # <- base64 encoded admin@postgres

这里的用户名和密码是base64编码的。请记住,你不打算执行这个文件。你将使用Kubeseal为这个秘密生成加密数据,并在Kubernetes集群上执行密封秘密。

你可以使用kubeseal检索生成的公钥证书,并将其存储在你的本地磁盘上。

kubeseal --fetch-cert > public-key-cert.pem

kubeseal使用它在运行时从Kubernetes集群中运行的控制器中获取的公钥对秘密进行加密。如果用户不能直接访问集群,那么集群管理员可以从控制器的日志中获取公钥,并让用户可以访问它。

然后使用kubeseal使用公钥文件创建一个SealedSecret CRD,如下所示。

kubeseal --format=yaml --cert=public-key-cert.pem < secret.yaml > sealed-secret.yaml

生成的Secret与Base64编码的用户名密码密钥的值如下。

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  creationTimestamp: null
  name: my-secret
  namespace: test-ns
spec:
  encryptedData:
    password: AgCEP9MHaeVGelL3jSbnfUF47m+eR0Vv4ufzPyPXBvEjYcJluI0peLgilSqWUMnDLjp00UJq186nRYufEf7Bi1Jxm39t3nDbW13+wTSbblVzb9A2iKJI2VbxgTG/IDodNFxFWdKefZdZgVct2hTsuwlivIxpdxDZtcND4h+Cx8YFQMUpT5oO26oqISzRTh5Ewa6ehWtv6krfeFmbMQCF70eg0yioe6Op0YaQKloiFVInc1JK5KTR5iQYCeKb2R0ovKVa/lipbqjHCYSRhLR/3q5wz/ZuWz7g7ng6G9Q7o1pVv3udQYUvp2B6XvK1Nezc85wbhGgmuz5kcZUa36uF+eKMes6UdPcD7q58ndaj/0KWozdTAuk1OblV7mrUaK8Q45GIf+JqaBfzVt52INMT07P4MId/KB31sZDeE+OwEXhCDVTBAlxSRM0U9NjxDDb+mwUzxHNZHL1sY8M1YCoX+rr6n1+yW1HG42VHLCRzeBa2V31OFuQTNjoNxDEfUq+CSTRNDCmt8UvercSkgyM3mBa6JpHdkySllpqyEJDYKM1YvVRrjVvg1qGTF5dOCx6x3ROXnZtA3NBIafTu0+pHovVo+X7nUkl7hyupd0KKzBG+afgNpYQOxeuei5A+o++o92G5lexxk2v4bQt6ANYBxMlvT0LdBUW9e/L2y+TuNAHL23Xa/aTq1lagNBi9JTowX0lx0br2CqDbKg==
    username: AgArwZm3qh83Fpzles1r/PjTDKQ2/SZ482IKC84T72/kI4M29aG2VT4SCXcqbmtVDYuVUN0wTbsFYsnwY1DSRrL4oup2xRg6N34IxHjj0ZtF1q0YtBKIM/DPcF2bBVAYc9/vOI0L3+VVSF9r93XYEMUWX6hY9eHa8VUHBM/Y65Sj3Il7Pmx/qoEcZ+e9UJhqWEJPotz6W5OMh/Al/QPJZknwUulM4coZ3C0J4TmrBVexPturcRCimDEQnd9UitotnGDoNAp2O28ovhXoImNsJBhNK5LykesRxEfIp4UJOb3I0CpLdoz9khEcb2r31j+KTtxifLez7Rg3Pg7BGpR3EKC3INZWrR8S/aUm5u/dP12ELgW3nq4WbafRitrZcHhLFZkHma/Er8miFbuTXvpFcXE1g+BnG2vIs4kHSl2QcP32HPGKHJJt0KEd1dUJrXXTjS9eXHJ2KsA5DZk4TcFA5dPAG76ZdKo0GCIQwvNeT0Ao4ntqmeOiijAQgmhXdCtD2WVavXi54h0f8F2ue6b0mBFCgTGKZyypjbXznzB/MPAZxgIu+UWQzV1CczwKlitPy638s/9iSan2/u2rhKu2SP0JFMZ6pPnfO51nMpDHtCDGFc1unjsjM4ZpnNXtaQJJmXo7Hw0L4dW2/N3uxCfxNtmYuBxE1t4GCefSUCTIleDgmAbB00nKkja+ml9bidcxawlIgHnoq/XNCqy2R3PkEw==
  template:
    data: null
    metadata:
      creationTimestamp: null
      name: my-secret
      namespace: test-ns

注意,原始Secret中的密钥--即用户名密码--在SealedSecret中没有被加密,只有它们的值被加密。如果有必要,你可以在SealedSecret的YAML文件中改变这些密钥的名称,并且仍然能够将其成功部署到集群中。然而,你不能改变 SealedSecret 的名称命名空间。这样做将使SealedSecret失效,因为原始Secret的名称和命名空间在加密过程中被用作输入参数。

与该秘密有关的YAML清单不再需要,可以被删除。SealedSecret是唯一将被部署到集群中的资源,如下所示。

kubectl apply -f sealed-secret.yaml 

一旦SealedSecret CRD在集群中被创建,控制器就会意识到它,并使用私钥解封底层Secret,并将其部署到同一命名空间。这可以通过查看控制器的日志看到。

管理封印密钥

如果没有控制器管理的私钥,就没有办法解密SealedSecret中的加密数据。运行下面的命令,以便从集群中检索出私钥。

kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml > master.yaml

现在,让我们首先删除控制器的安装,它创建的包含私钥的Secret,名为my-secret的SealedSecret资源以及从它那里解封的Secret。

kubectl delete secret mysecret
kubectl delete SealedSecret mysecret
kubectl delete secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key
kubectl delete -f controller.yaml

现在,使用master.yaml文件将包含私钥的Secret放回集群中,并在EKS上重新部署SealedSecret CRD、控制器和RBAC工件。

kubectl apply -f master.yaml 
kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key
kubectl apply -f controller.yaml

查看新启动的控制器豆荚的日志。注意,在你的集群中,控制器豆荚的名字将是不同的。从日志中你可以看到,控制器能够在kube-system命名空间中找到现有的Secretsealed-secrets-keyb2fkv,因此没有创建新的密钥对。

kubectl logs -f sealed-secrets-controller-59ddc747c4-djsbc -n kube-system

现在,让我们重新部署SealedSecret,并验证控制器是否能够成功解封它。

kubectl create -f sealed-secret.yaml 
kubectl logs -f sealed-secrets-controller-59ddc747c4-djsbc -n kube-system

结论

将你的敏感数据存储在Kubernetes Secret对象中是一种常见的做法,但别忘了,Secret只是被编码,而不是被加密。因此,如果你想把它们存储在Git仓库中,你就需要找到一个安全的解决方案。密封的Secret可以帮助你看到,它可以成为一个解决方案,你可以在你身边尝试。