作者 |阳明
来源 | k8s技术圈(ID:kube100)
GitOps 的核心理念就是一切皆代码,意味着用户名、密码、证书、token 等敏感信息也要存储到 Git 仓库中,这显然是非常不安全的,不过我们可以通过 Vault、Keycloak、SOPS 等 Secret 管理工具来解决,最简单的方式是使用 SOPS,因为它可以使用 PGP 密钥来加密内容,如果你使用 kustomize 则还可以在集群内使用相同的 PGP 密钥解密 Secret。ArgoCD 虽然没有内置的 Secret 管理,但是却可以与任何 Secret 管理工具集成。
sops 是一款开源的加密文件的编辑器,支持 YAML、JSON、ENV、INI 和 BINARY 格式,同时可以用 AWS KMS、GCP KMS、Azure Key Vault、age 和 PGP 进行加密,官方推荐使用 age 来进行加解密,所以我们这里使用 age。age[1] 是一个简单、现代且安全的加密工具(和 Go 库)。
SOPS 与 AGE
首先需要安装 age 工具,可以直接从 Release 页面[2] 下载对应的安装包:
然后安装 sops,同样直接从 Release 页面[3]下载对应的安装包:
通过下述命令来查看安装是否成功:
我们先创建一个简单的 Secret 来测试下使用 sops 进行加密:
生成的 secret 资源清单文件如下所示:
接下来我们使用 age-keygen 命令生成加密的公钥和私钥,可以用如下命令将私钥保存到一个 key.txt 文件中:
然后我们可以使用上面的私钥来加密生成的 secret.yaml 文件:
加密后生成的 secret.enc.yaml 文件内容如下所示,显示乱码:
同样我们还可以对该加密文件进行解密:
同样对于 sops 来说也是支持和 age 进行集成的,我们可以使用下面的 sops 命令来对 secret.yaml 文件进行加密:
加密后的文件内容如下所示:
可以看到主要字段都被加密了。但是其他字段比如 kind 也被加密了,我们可以通过创建一个 .sops.yaml 文件来指定需要被加密的字段,如下所示:
这样的话则只会对 username 和 password 两个字段进行加密。
ArgoCD 集成 SOPS
现在我们可以使用 sops 来对私密的文件进行加解密了,前面示例中我们在 ArgoCD 中使用的 Helm Chart 方式来同步应用,比如我们会在 values 文件中提供一些比较私密的信息,直接明文提供存储到 Git 仓库上显然是非常不安全的,这个时候我们就可以使用 sops 来对这些 values 文件进行加密,当然在同步应用的时候自然就需要 ArgoCD 能够支持对手 SOPS 进行解密了,这里我们还需要使用到 helm-secrets[4] 这个 Helm 插件。
接下来我们需要让 Argo CD 来支持 SOPS,一般来说主要有两种方法:
- 使用 helm 和 sops 创建自定义的 ArgoCD Docker 镜像,并使用自定义 Docker 镜像,但是 Argo CD 的每个新版本都需要更新该镜像。
- 在 Argo CD 存储库服务器部署中添加一个初始化容器,以获取带有 sops 的 helm 插件,如此处所述,并在 Pod 中使用它。即使更新了 Argo CD 版本,也不需要更新插件,除非插件版本和 Argo CD 版本存在兼容性问题。
为了简单我们这里使用第一种自定义镜像的方式,如下所示的 Dockerfile,它将 sops 和 helm-secrets 集成到 Argo CD 镜像中:
使用上面的 Dockerfile 重新构建镜像(cnych/argocd:v2.4.9)后,重新替换 argocd-repo-server 应用的镜像,其他组件不需要。
由于默认情况下 ArgoCD 只支持 http:// 和 https:// 作为远程 value 协议,所以我们需要将 helm-secrets 协议也添加到 argocd-cm 这个 ConfigMap 中去。
接下来我们还需要配置 Argo CD 存储库服务器,使它可以访问私钥来解密加密的文件。这里使用前面 age-keygen 命令生成的私钥文件 key.txt 创建一个 Kubernetes Secret 对象:
现在我们需要将该 Secret 以 Volume 的形式挂载到 argocd-repo-server 中去:
然后更新 argocd-repo-server 组件,更新完成后我们就可以创建如下所示的 Argo CD 应用来对加密文件进行解密了:
现在我们再次使用前面的 devops-demo 应用示例进行测试。 
devops-demo deploy
我们使用 sops 将要部署的 my-values.yaml 文件进行加密:
加密后的文件内容如下所示:
image:
repository: ENC[AES256_GCM,data:ZDnA7yTAe2B+TbcQYhcs4yufLgXJWHzX7IUnYdOXtsqzfEo=,iv:4yn+RkQoTHNVW8Y5yDzHsY2hhpMo8yw6j/uj9g6AvMA=,tag:IPwFo2AfLT7yBwoKrvCLCg==,type:str]
tag: ENC[AES256_GCM,data:koDRtD5NfWn03JJLAZnYYWLgwsJr/kSKtw8WHJoeSLD8Zco4M0Doqw==,iv:DbxefZ03J7dGRviRq2DQHhRkcBiBY5FgSh1lJwjwzEg=,tag:zc6ZL5ObSymSVH+caxUzpA==,type:str]
pullPolicy: ENC[AES256_GCM,data:dJ+xl6llTN2NcEKL,iv:XhX3RGirpJI0Wc1Q/9ld2xWQYqE+6ZLL6laIXEI1unQ=,tag:dDwEUa7nTq9TOkYI2cE0Pg==,type:str]
ingress:
enabled: ENC[AES256_GCM,data:eZB9GA==,iv:p12fWs14ATWke0IiMz0SpAb2rW+ViYcEpGRbOoNt9Uk=,tag:w371uI/KRESNP30eD9rrTQ==,type:bool]
ingressClassName: ENC[AES256_GCM,data:WviAhbo=,iv:Vqx0R8RVWkGipZkR2HZfyOYyZdkc+1fhFEV7AdpI4t0=,tag:fv2hf94svXOQeqfjqXN4gg==,type:str]
path: ENC[AES256_GCM,data:jg==,iv:cRm/OXlGEbNEHhAAm/JpPx5sP9GRmW1fyEAi+SZhfjY=,tag:QAJmQSQ5qWfjnzrm+MWLbQ==,type:str]
hosts:
- ENC[AES256_GCM,data:tb32cnmE1d2qnzzsmG2NzMVOPxkW,iv:RH57dgs0gIS28mB83YX+SQNFNjwoTfPa28YvZsCAJW4=,tag:J7SJXkZKPyydx8NvvCh22w==,type:str]
resources:
limits:
cpu: ENC[AES256_GCM,data:uys2,iv:UfAl2lP2wLzc0GkLcBs33vl4dQqLiXWmoyyucqovuVM=,tag:yXRpMIS11s0iqVZQpJ/Bdw==,type:str]
memory: ENC[AES256_GCM,data:fBHSfog=,iv:lf6fTZfOPlhQVspm2BAl56ps8Q5W6Qz4tMT7A8Au9tA=,tag:XZqHEWEb2qBjWms/qTsAOQ==,type:str]
requests:
cpu: ENC[AES256_GCM,data:MDYW,iv:/j6A3oVQ4HILXFLVAr8Rjcq2CDdHrtPa70uySxQQeBI=,tag:EyWwWl0hFkTWzHFBXndFeA==,type:str]
memory: ENC[AES256_GCM,data:qiwPiRI=,iv:m/oFxJrcdysf26ry7LEcL6IQRRqi5B8Zsjc/YJOkO7c=,tag:3brvdx+dFUN0VyJ6KO8biQ==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1wvdahagxfgqc53awmmgz52njdk2zm6vkw760tc368gstsypgvusqy7zvtt
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyeHNNTWJhWHZHZERJNnlh
L1FpMkdibERFM2ZtU2FFZ1VhMnYxVG90dUNBCmpTVEk3ODg4aWlhOEY3cDdMSWFW
ZmdoaGtQT3NDU0E0bEZPQlJqNXNuamsKLS0tIHhEcm5memczQTNaVGZzUGNGQmsw
cW1QSDd4dDdwZnI2ZzloM2tGRFJxTW8KMPU93lWiNMMaCfOUANmsv+kfi4R7NAzP
nV2H2EyCTQGsNTeKCS/HkmiSD4/4RLui4Z6TbPf8ALpeGHDH8rVSoA==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2022-08-18T08:18:05Z"
mac: ENC[AES256_GCM,data:Z+KJTZRP6L2QEcSG6S43fvqWsROAwEVnQcVkpN/yU1Kk8x0PUXXZkdyJiykQ+7HRBNWJp1wKF1TAlqnrZyUSXx7zl5fZGbalgK8kRKzzTzdSsB+Cp4Km5uYNqWUh+RFtzRVOYwOU7fOsAxiHLFMjzaqLAE6+WsCY9xjfj67NymA=,iv:Kyckp64XCkmpbeSEiampXp47Qr9ZIJRZUWsLDhHIw/4=,tag:/eH5d5e9anLRoiCxdWPS/w==,type:str]
pgp:
- created_at: "2022-08-18T08:18:05Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA0Eva10jiAHJAQ/9HZJck5xCbIB43fYrmnrMokwQB5HPMMCpl8gw/U4Cz/RD
zs6nlIXhO1U29rQT3s2G9IjfCS0ehfwA6lKGXAuK10jY9HJ7dVthWnKlNsCq35d/
5ZKzKIT2mvK1h6+qYai86FwGyG436nAw198oNvC4d9E46PfBcx7PXP1lRFoOJI7V
St81HwFTWOd88tkPyIfv2XW1bcvWo7Qz8YunNqGriD3SREwgkSlcyIL4neumWAru
YGzTmwEXFjwcTIzel57fI42Qd61wq1p7CKw8njs1pOGucC3uX1b99f1BaeLdQl3C
lJvYrP0SYKJ/JA2kPRkeJHDd39ywI8A/iNOW4nRFxbMoAHdEiwAUg2DOCfMwDgVu
WQiQqTF+7AycdqjpXYjYZ7SI3al6jhcDA2KxvNsPNjT8F5yl3c9MIwMdo/NRoc6G
XNGXqbR+8kChFQiVKCUopbCqHtFaVVV6Ldhk3fB76ht3vgJx9XFR8+KYFLHAezIO
VdzzWqVPv72lO3CkyqHfoL8FwxjNI9KAQkU1T3ETv5YJw7mUWWvdMVee9SVf8Qa1
m3JJGqcRd9kyH/u8tMKsrgfG1/KVeyx1gStlO3ioHlCyjsNBAUZ2QIsFa7gxUmQL
HqgCIqGC/SjFv1+5sHF807sYBBWfARQZRTum/Pg3FHpRiVhNPcvEUPIZjQhT79fS
UQHw1EvK5Wj4Ea3/3jNt9bim+pJrxCoUAKByU8lyjL7vOsogiM7sgp50t54oI/3V
G0hvOZNvWV/V0YLqXoTVEru/rqLUKzHunl9psutAXlUOkA==
=4l27
-----END PGP MESSAGE-----
fp: CCC4D0692165A88405EF1F579CC5737D5CCB9760
unencrypted_suffix: _unencrypted
version: 3.7.3
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
现在我们需要将该文件重新提交到 Git 仓库中去,接着我们要重新创建 Application 应用,对应的资源清单文件如下所示:
其中核心是 valuesFiles 配置的 secrets+age-import:///helm-secrets-private-keys/key.txt?my-values.enc.yaml,表示导入 /helm-secrets-private-keys/key.txt 文件中的私钥来对 my-values.enc.yaml 文件进行解密。
重新创建上面的对象后,同步应用后正常可以同步成功。
参考资料
[1]age: https://github.com/FiloSottile/age/
[2]Age Release 页面: https://github.com/FiloSottile/age/releases
[3]SOPS Release 页面: https://github.com/mozilla/sops/releases/download/v3.7.3/sops-v3.7.3.linux.amd64
[4]helm-secrets: https://github.com/jkroepke/helm-secrets