今天是2025年8月15日,大噩耗啊:
external-secrets / external-secrets
⭐ 5416 | 🔀 1032 | Go 97.6%
External Secrets Operator 项目暂停发布
由于维护团队规模过小,External Secrets Operator 决定暂停所有官方版本发布,直到重建足够的维护团队。
Key Takeaways
- 项目暂停所有官方版本发布,包括新功能、补丁和容器镜像。
- 将继续审核和合并社区的 PR,但不会提供 GitHub Discussions、Slack 或问题评论的支持。
- 需要至少五名长期维护者来确保项目的可持续发展。
- 鼓励依赖该项目的公司或团队积极参与贡献。
- 贡献者可通过填写表单或查看治理文档加入项目。
居然暂停发布了,那就抓紧时间把Vault跟它的集成记录下来:
一、首先必须在集群里安装Vault,然后安装external -secrets,都用helm装即可
1helm repo add hashicorp https://helm.releases.hashicorp.com
2helm repo update
3helm install vault hashicorp/vault --set "server.dev.enabled=true" --set "injector.enabled=true" --namespace default
4
5
6helm repo add external-secrets https://charts.external-secrets.io
7helm repo update
8helm install external-secrets external-secrets/external-secrets --namespace external-secrets --create-namespace --set installCRDs=true
二、k8s授权,k8的授权体系就是 sa -> role -> rolebinding
那kubernetes会把pod中sa的Token注入到文件:/var/run/secrets/kubernetes.io/serviceaccount/token
那调用k8s api中的token reviewer是可以对Token令牌进行验证的,我们先建立一系列k82资源
1---
2apiVersion: v1
3kind: ServiceAccount
4metadata:
5 name: external-secrets-sa
6 namespace: external-secrets
7
8---
9apiVersion: rbac.authorization.k8s.io/v1
10kind: ClusterRole
11metadata:
12 name: external-secrets-clusterrole
13rules:
14 - apiGroups: [""]
15 resources: ["secrets"]
16 verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
17 - apiGroups: ["authorization.k8s.io"]
18 resources: ["selfsubjectrulesreviews"]
19 verbs: ["create"]
20
21---
22apiVersion: rbac.authorization.k8s.io/v1
23kind: ClusterRoleBinding
24metadata:
25 name: external-secrets-clusterrolebinding
26subjects:
27 - kind: ServiceAccount
28 name: external-secrets-sa
29 namespace: external-secrets
30roleRef:
31 kind: ClusterRole
32 name: external-secrets-clusterrole
33 apiGroup: rbac.authorization.k8s.io
如上,我们建立了一个sa,然后有api group的权限,同时授予了整个集群级别的权限
三、登录vault,配置vault使用k8s的认证方式进行身份认证
那 enable kubernetes 其实设置了 vault 可以使用kubernetes的认证方式来进行vault-role角色的身份认证
1# 进入容器
2kubectl exec -it vault-0 -- /bin/sh
3
4# 登录,要输入的token可以从日志里看到
5vault login root
6
7# 开启kubernetes认证方式
8vault auth enable kubernetes
9
10# 每个pod里面都有sa,k8s会将这个sa的token注入到文件/var/run/secrets/kubernetes.io/serviceaccount/token
11# 那就用这个sa的token,调用k8s token_reviewer进行身份认证
12# 认证通过vault就会颁发一个对应vault-role的vault-token令牌出来
13# 用vault-token就可以去vault里读取到vault-secret的内容了
14vault write auth/kubernetes/config \
15 token_reviewer_jwt=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
16 kubernetes_host="https://kubernetes.default.svc:443" \
17 kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
18
19# 拿token的另一种方法:
20# kubectl get secret $(kubectl get serviceaccount external-secrets-sa -o jsonpath="{.secrets[0].name}") -o jsonpath="{.data.token}" | base64 --decode
21
22
23# vault的认证体系跟AWS一样
24# 先建policy,后建role
25# 所以先建一个读secret的策略
26vault policy write external-secrets-policy - <<EOF
27path "secret/data/*" {
28 capabilities = ["read", "list"]
29}
30EOF
31
32# 然后建立一个vault的role,将这个vault-role绑定到k8s的sa账号上
33# 那k8s token review认证通过就可以获得相应vault-role的权限
34vault write auth/kubernetes/role/external-secrets-operator \
35 bound_service_account_names=external-secrets-sa \
36 bound_service_account_namespaces=external-secrets \
37 policies=external-secrets-policy \
38 ttl=24h
39
40# 放数据进去vault
41vault kv put secret/my-app MY_SECRET_NAME="Fuck Dingdang"
42vault kv get secret/my-app
四、external-secret同步的设定
external-secret相当于中间人,他有很多自定义的资源,来自动进行vault-secret和k8s-secret之间的同步
ClusterSecretStore指定了vault server、vault-role、k8s sa的关系
1---
2apiVersion: external-secrets.io/v1
3kind: ClusterSecretStore
4metadata:
5 name: vault-cluster-secretstore
6spec:
7 provider:
8 vault:
9 server: "http://vault.default.svc.cluster.local:8200" # 请根据你的vault服务地址调整
10 path: "secret" # KV引擎挂载路径,与你vault kv put命令中路径对应
11 version: "v2" # KV版本为v2
12 auth:
13 kubernetes:
14 mountPath: "kubernetes" # 你启用的k8s auth路径
15 role: "external-secrets-operator" # 你在vault中创建的role名称
16 serviceAccountRef:
17 name: external-secrets-sa # 你为ESO创建的ServiceAccount名称
18 namespace: external-secrets # ServiceAccount所在命名空间
ExternalSecret 指定了利用vault-role获得了vault-secret,放置到最终要用到的k8s-secret中
注意有刷新,每小时会刷新一次的
1---
2apiVersion: external-secrets.io/v1
3kind: ExternalSecret
4metadata:
5 name: demo-external-secret
6 namespace: default
7spec:
8 refreshInterval: 1h
9 secretStoreRef:
10 name: vault-cluster-secretstore
11 kind: ClusterSecretStore
12 target:
13 name: demo-secret
14 creationPolicy: Owner
15 data:
16 - secretKey: MY_SECRET_NAME
17 remoteRef:
18 key: my-app
19 property: MY_SECRET_NAME # Vault中具体的键名
通过以上两个资源,那vault里存放的secret就被同步到k8s的secret中了
五、实际部署一个应用看看
那我们随便起个deployment
1---
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5 name: demo-deployment
6 namespace: default # 使用目标命名空间,可以修改为你的实际命名空间
7 labels:
8 app: demo
9spec:
10 replicas: 1 # 副本数量,可以根据需要调整
11 selector:
12 matchLabels:
13 app: my-app
14 template:
15 metadata:
16 labels:
17 app: my-app
18 spec:
19 containers:
20 - name: demo-container
21 image: nginx:latest
22 imagePullPolicy: IfNotPresent # 如果本地已经存在镜像则不拉取
23 ports:
24 - containerPort: 8080 # 容器暴露的端口
25 env:
26 - name: MY_SECRET_NAME
27 valueFrom:
28 secretKeyRef:
29 name: demo-secret # 引用的 Secret 名称
30 key: MY_SECRET_NAME # Secret 中的键名
31
32---
33apiVersion: v1
34kind: Secret
35metadata:
36 name: demo-secret
37 namespace: default # 使用目标命名空间,可以修改为你的实际命名空间
38type: Opaque
39data:
40 MY_SECRET_NAME: AABBCC
实在太复杂痛苦了,最终的环境变量应该如下:
1MY_SECRET_NAME="Fuck Dingdang"
但这没有结束呢。
六、安装配置reloader自动轮换
如果secret被改了,如AK的Secret自动轮换了,那pod也必须跟着自动重启以加载新的变量
1# 安装reloader
2kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml
在deploy中container的部分新增annotations
:
1metadata:
2 annotations:
3 reloader.stakater.com/auto: "true"
如下:
1---
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5 name: demo-deployment
6 namespace: default
7 annotations:
8 reloader.stakater.com/auto: "true"
9 labels:
10 app: demo
11spec:
12 replicas: 1 # 副本数量,可以根据需要调整
13 selector:
14 matchLabels:
15 app: my-app
16 template:
17 metadata:
18 labels:
19 app: my-app
20 spec:
21 containers:
22 - name: demo-container
23 image: nginx:latest
24 imagePullPolicy: IfNotPresent # 如果本地已经存在镜像则不拉取
25 ports:
26 - containerPort: 80
27 env:
28 - name: MY_SECRET_NAME
29 valueFrom:
30 secretKeyRef:
31 name: demo-secret # 引用的 Secret 名称
32 key: MY_SECRET_NAME # Secret 中的键名
这样ENV环境变量改变的时候就可以自动重起pod
七、另一种注入式的做法vault injector
Deployment新增annotations:
1metadata:
2 annotations:
3 vault.hashicorp.com/agent-inject: "true"
4 vault.hashicorp.com/role: "demo-role"
5 vault.hashicorp.com/agent-inject-secret-MY_SECRET_NAME: "secret/data/demo"
6 vault.hashicorp.com/agent-inject-template-MY_SECRET_NAME: |
7 {{- with secret "secret/data/demo" -}}
8 export MY_SECRET_NAME="{{ .Data.data.MY_SECRET_NAME }}"
9 {{- end -}}
完整如下:
1---
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5 name: demo-deployment
6 namespace: default
7 annotations:
8 vault.hashicorp.com/agent-inject: "true"
9 vault.hashicorp.com/role: "demo-role"
10 vault.hashicorp.com/agent-inject-secret-MY_SECRET_NAME: "secret/data/demo"
11 vault.hashicorp.com/agent-inject-template-MY_SECRET_NAME: |
12 {{- with secret "secret/data/demo" -}}
13 export MY_SECRET_NAME="{{ .Data.data.MY_SECRET_NAME }}"
14 {{- end }}
15spec:
16 replicas: 1
17 selector:
18 matchLabels:
19 app: my-app
20 template:
21 metadata:
22 labels:
23 app: my-app
24 annotations:
25 vault.hashicorp.com/agent-inject: "true"
26 vault.hashicorp.com/role: "demo-role"
27 vault.hashicorp.com/agent-inject-secret-MY_SECRET_NAME: "secret/data/demo"
28 vault.hashicorp.com/agent-inject-template-MY_SECRET_NAME: |
29 {{- with secret "secret/data/demo" -}}
30 export MY_SECRET_NAME="{{ .Data.data.MY_SECRET_NAME }}"
31 {{- end }}
32 spec:
33 serviceAccountName: demo-sa
34 containers:
35 - name: demo-container
36 image: nginx:latest
37 imagePullPolicy: IfNotPresent
38 ports:
39 - containerPort: 80
如上也可以做到secret有改动,就自动重启
八、补全一下用k8s Token凭据验证vault角色的过程
1# 先建立一个SA
2apiVersion: v1
3kind: ServiceAccount
4metadata:
5 name: demo-sa
6 namespace: default
7
8# 然后定义一个Deployment,在spec附上这个SA
9---
10apiVersion: apps/v1
11kind: Deployment
12metadata:
13 labels:
14 app: nginx
15 name: nginx
16 namespace: default
17spec:
18 serviceAccountName: demo-sa
19 replicas: 1
20 selector:
21 matchLabels:
22 app: nginx
23 template:
24 metadata:
25 labels:
26 app: nginx
27 spec:
28 containers:
29 - env:
30 - name: VAULT_ADDR
31 value: "http://vault.default.svc.cluster.local:8200" # 替换为 Vault 的服务地址
32 image: nginx:latest
33 imagePullPolicy: IfNotPresent
34 name: nginx
35
36# 登录vault服务(开发模式,登录用户是root)
37vault login root
38
39# 启用 Kubernetes Auth 模式
40vault auth enable kubernetes
41
42# vault 使用 sa Token进行身份识别
43vault write auth/kubernetes/config \
44 token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
45 kubernetes_host="https://kubernetes.default.svc:443" \
46 kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
47
48# 创建一个policy
49vault policy write demo-policy - <<EOF
50path "secret/data/*" {
51 capabilities = ["read", "list"]
52}
53EOF
54
55# 创建一个vault-role,绑定到sa
56vault write auth/kubernetes/role/demo-role \
57 bound_service_account_names=demo-sa \
58 bound_service_account_namespaces=default \
59 policies=demo-policy \
60
61# 存放测试kv数据
62vault kv put secret/demo MY_SECRET_NAME="BBCCDDEE"
63vault kv get secret/demo
64
65# 启动一个deployment
66---
67apiVersion: apps/v1
68kind: Deployment
69metadata:
70 labels:
71 app: nginx
72 name: nginx
73 namespace: default
74spec:
75 serviceAccountName: demo-sa
76 replicas: 1
77 selector:
78 matchLabels:
79 app: nginx
80 template:
81 metadata:
82 labels:
83 app: nginx
84 spec:
85 containers:
86 - env:
87 - name: VAULT_ADDR
88 value: "http://vault.default.svc.cluster.local:8200" # 替换为 Vault 的服务地址
89 image: nginx:latest
90 imagePullPolicy: IfNotPresent
91 name: nginx
92
93# 进入deployment的pod中
94kubectl exec -it nginx -- /bin/sh
95
96# 拿到本地sa的Token
97export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
98
99# 注意pod里有环境变量VAULT_ADDR,如果没有要定义一下
100# 然后用curl拿vault-token
101curl -X POST "${VAULT_ADDR}/v1/auth/kubernetes/login" \
102 -H "Content-Type: application/json" \
103 -d '{
104 "role": "demo-role",
105 "jwt": "'$TOKEN'"
106 }'
107
108# curl 返回字符串中的 client_token 字段
109export VAULT_TOKEN="hvs.CAESaaaBBBcccDDDEEEfffGGG"
110
111# 用vault_token获得kv的数据
112curl -X GET "${VAULT_ADDR}/v1/secret/data/demo" -H "X-Vault-Token: $VAULT_TOKEN"
所以,其实vault有api接口,可以直接调用curl来认证并获取数据,这就极大的扩展了vault的接口范围。
好了,就到这里吧!