[GitOps] - 如何管理Secrets

在GitOps中管理Secrets一直是一个麻烦的事情,因为GitOps需要用Git仓库来管理一切部署文件,而Secrets又不是能公开的东西,所以我们需要找一些方法来管理。

常用方法

由于GitOps一般是采取Kubernetes来进行部署的,所以本质就是需要把Secrets放进Kubernetes的Secrets里面,一般有一下几种方式

  • 本地执行部署
    • 本地保存Secrets的manifest文件,Git库里不保存
    • 本地保存.env文件,利用插件或者脚本生成Secrets的manifest文件
  • 加密
    • Git库里保存加密的Secrets文件,使用key来解密文件
  • CD部署
    • 利用环境变量,在CD里注入Secrets
  • 云服务商
    • 利用类似HashiCorp’s Vault的服务,动态获取

以上方法都有些优点和缺点

  • 本地执行部署
    • 优点:简单方便
    • 缺点:需要人工管理Secrets
  • 加密
    • 优点:不用到处传Secrets文件,全文件Git库管理
    • 缺点:配置麻烦,需要管理key,加密文件公开
  • CD
    • 优点:不用到处传Secrets文件
    • 缺点:只能通过CD进行部署,操作
  • 云服务商
    • 优点:Secrets中心化管理,获取灵活
    • 缺点:还是要管理身份认证的Secrets,可能要交钱

本质就是,要么加密放在Git库里,要么从云动态获取

工具

现在一般有以下的工具来管理(Secret Management)

  • Bitnami Sealed Secrets
  • GoDaddy Kubernetes External Secrets
  • External Secrets Operator
  • Hashicorp Vault
  • Banzai Cloud Bank-Vaults
  • Helm Secrets
  • Kustomize secret generator plugins
  • aws-secret-operator
  • KSOPS
  • argocd-vault-plugin

例子

我现在遇到的场景是,我们使用ArgoCD进行部署,同时使用kustomize进行manifest文件的管理,如果使用ArgoCD的话,因为ArgoCD是一直监视着manifest文件的库的,而如果manifest文件的库里面没有Secrets文件的话,那么ArgoCD自然就会执行失败,所以需要采取下面的方式

  • 加密放库里
  • 云服务商动态获取

对于pull方式的secrets管理,不能限定获取secrets的使用场景,比如只能在CD执行,且需要能够动态获取到secrets。

本次采取加密的方式进行管理,使用sops来加密文件(.env),sops可以使用多种方式来加密文件,例如

  • AWS KMS
  • PGP key
  • GCP KMS
  • Azure Key Vault
  • Hashicorp Vault

假设我们采取AWS KMS,且我们ArgoCD也部署在AWS上的话,我们就不需要处理ArgoCD访问KMS的验证。然后对于加密的文件,由于我们采取的是kustomize管理manifest文件,所以使用kustomize-sopssecretgenerator来生成Secret的yaml文件。

通过这样的方式,我们既可以本地执行(如果有KMS权限的话),也可以在CD里执行,同样也可以在ArgoCD里执行。只要能获取到KMS

具体实现

安装

kustomize-sopssecretgenerator需要安装路径安装,kustomize对插件路径有要求,具体可以自己查看官方文档

文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.
├── application
│ ├── base
│ │ ├── kustiomization.yaml
│ │ ├── kustiomization.yaml
│ │ └── install.yaml
│ └── overlay
│ ├── prod
│ │ ├── .env
│ │ ├── generator.yaml
│ │ ├── sopsSecretsGenerator.yaml
│ │ ├── awsServiceAccount.yaml
│ │ └── kustiomization.yaml
│ └── test
│ │ ├── .env
│ │ ├── sopsSecretsGenerator.yaml
│ │ ├── awsServiceAccount.yaml
│ ├── generator.yaml
│ └── kustiomization.yaml
└── .sops.yaml

步骤

首先需要准备我们的Secrets文件

  • application/overlay/prod/.env
1
FOO=BOO

创建KMS

记录下KMS的arn,下面写为<aws-kms-arn>,注意自己设置权限。

设置AWS CLI

设置默认profile或者自己自定义名字,用来访问KMS

加密文件

其实就是使用sops来加密文件,sops需要key才能加密文件,由于我们采取了KMS,有2种方式来指定key,一种是:通过终端,另外一种是:使用.sops.yaml文件

  • 终端
1
sops --aws-profile <aws-profile> --kms <aws-kms-arn> -e -i application/overlays/prod/.env
  • yaml文件
1
2
3
4
creation_rules:
- path_regex: \.env$
kms: <aws-kms-arn>
aws_profile: <aws-profile>

加密过后,加密文件自身会储存加密使用的信息,解密的时候就不需要指定参数了

1
2
# 解密
sops -d application/overlays/prod/.env

设置kustomize-sopssecretgenerator

  • application/overlay/prod/generator.yaml
1
2
3
4
5
6
7
8
apiVersion: goabout.com/v1beta1
kind: SopsSecretGenerator
metadata:
name: my-secret
# 根据自己需要是否设置 disableNameSuffixHash
disableNameSuffixHash: true
envs:
- .env
  • application/overlay/prod/kustiomization.yaml
1
2
3
4
5
6
7
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

bases:
- ../../base
generators:
- generator.yaml

生成manifest文件

1
kustomize build --enable-alpha-plugins application/overlays/prod

--enable-alpha-plugins用于允许使用插件,注意kustomize的版本,以前的版本可能是--enable_alpha_plugins或者是其他的flag

到这一步,如果只需要本地执行,则已经可以kustomize build --enable-alpha-plugins application/overlays/prod | kubectl apply -f -了,对于ArgoCD,我们还需要设置一些东西

设置ArgoCD

需要对ArgoCD的kustomize设置上flag,通过官方文档 Declarative Setup,我们对argocd-cm.yaml进行配置

对于ArgoCD本身的部署,我们也采用kustomize的文件进行部署。而不是执行指令,这样可以通过ArgoCD来管理自己(Manage Argo CD Using Argo CD)

1
2
3
4
5
6
7
8
9
10
11
---
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
labels:
app.kubernetes.io/name: argocd-cm
app.kubernetes.io/part-of: argocd
data:
# Build options/parameters to use with kustomize build (optional)
kustomize.buildOptions: --enable-alpha-plugins

这样ArgoCD就知道使用插件了

在ArgoCD里安装kustomize-sopssecretgenerator

更详细参见:Using SopsSecretsGenerator with ArgoCD

  • application/overlay/sopsSecretsGenerator.yaml
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
apiVersion: apps/v1
kind: Deployment
metadata:
name: argocd-repo-server
spec:
template:
spec:
volumes:
- name: custom-tools
emptyDir: {}
initContainers:
- name: install-goaboutsops
image: alpine:3.11.3
command: ["/bin/sh", "-c"]
args:
- echo "Installing goabout kustomize sops...";
set -e;
set -x;
wget -O /custom-tools/SopsSecretGenerator https://github.com/goabout/kustomize-sopssecretgenerator/releases/download/v${VERSION}/SopsSecretGenerator_${VERSION}_${PLATFORM}_${ARCH};
chmod -v +x /custom-tools/SopsSecretGenerator;
set +x;
echo "Done.";
volumeMounts:
- mountPath: /custom-tools
name: custom-tools
env:
- name: VERSION
value: 1.4.0
- name: PLATFORM
value: linux
- name: ARCH
value: amd64
containers:
- name: argocd-repo-server
volumeMounts:
- mountPath: /.config/kustomize/plugin/goabout.com/v1beta1/sopssecretgenerator/SopsSecretGenerator
name: custom-tools
subPath: SopsSecretGenerator
env:
- name: XDG_CONFIG_HOME
value: /.config
  • awsServiceAccount.yaml

虽然上面说了EKS可以通过role等来访问kms,不过似乎sops不是很支持(或者没设置对)
因为sops会按照加密的方式来解密,所以这里还是用上iam用户来解密
所以加密时不能使用aws_profile,否则解密也会用aws_profile,需要手动把aws_profile清空

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: apps/v1
kind: Deployment
metadata:
name: argocd-repo-server
spec:
template:
spec:
containers:
- name: argocd-repo-server
env:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: argocd-aws-credentials
key: accesskey
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: argocd-aws-credentials
key: secretkey

然后ArgoCD也可以正常获取KMS了

总结

利用加密放在Git库的方式,只要我们能够获取Key,就能够部署,具备很大的灵活性,同时文件啥的还是集中管理,不会过个一年后忘记CD里面设置的Secret是啥样,然后花1个多小时重新设置一遍。但是加密的文件还是公开的,这或许是不好的地方了,配置也相对其他方法更复杂一些,或许以后还能有更好的方法。

参考