一. 需求
需要在每个namespace中都创建相同的secret,比如登录harbor的用户认证,cicd中要使用的baseimage等等
二. 解决方案-externalsecret
官网: https://external-secrets.io/latest/

它有几个概念:
·secretStore
SecretStore 将身份验证/访问的关注点与工作负载所需的实际 Secret 和配置分开。ExternalSecret 指定要获取的内容,SecretStore 指定如何访问。Namespace 级别。
·ExternalSecret
ExternalSecret 声明要获取的数据。它引用了一个知道如何访问该数据的 SecretStore。控制器使用该 ExternalSecret 作为创建 Secret 的蓝本。Namespace 级别。
·ClusterSecretStore
ClusterSecretStore 是一个全局的、集群范围的 SecretStore,可以从所有命名空间中引用。可以将它作为Secret Provider 的中央网关。

·ClusterExternalSecret
ClusterExternalSecret 是一个集群范围的资源,可用于将 ExternalSecret 推送到特定的命名空间。 使用 namespaceSelector 可以选择命名空间,并且任何匹配的命名空间都将具有在其中创建的 externalSecretSpec 中指定的 ExternalSecret。
三. 原理

1.ESO(ExternalSecretOperator) 使用 spec.secretStoreRef 来查找合适的 SecretStore。如果不存在或 spec.controller 字段不匹配,将丢弃不再处理。
2.ESO 使用 SecretStore.spec 的指定凭据实例化外部 API 客户端。
3.ESO 根据 ExternalSecret 的要求获取机密值,如果有必要,将对机密信息解码。
4.ESO 根据 ExternalSecret.target.template 提供的模板创建 Kind=Secret。可以使用来自外部 API 的机密值对 Secret.data 进行模板化。
5.ESO 确保机密值与外部 API 保持同步。
四. 部署
helm部署:
$ helm repo add external-secrets https://charts.external-secrets.io
$ helm install external-secrets \
external-secrets/external-secrets \
-n external-secrets \
--create-namespace \
--set installCRDs=true
五. 使用
5.1 从vault中获取敏感信息
1.安装 vault
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault hashicorp/vault --set "server.dev.enabled=true"
2.准备数据
# kubectl exec -it vault-0 -- /bin/sh
$ vault kv put secret/foo my-value=s3cr3t
3.创建 SecretStore,引用 Vault
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
spec:
provider:
vault:
# vault kv put secret/foo my-value=s3cr3t
server: "http://vault.default.svc.cluster.local:8200"
path: "secret"
version: "v2"
auth:
# points to a secret that contains a vault token
# https://www.vaultproject.io/docs/auth/token
tokenSecretRef:
name: "vault-token"
key: "token"
---
apiVersion: v1
kind: Secret
metadata:
name: vault-token
data:
token: cm9vdA== # "root"
4.创建 ExternalSecret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: vault-example
spec:
refreshInterval: 15s
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: example-of-vault-sync
data:
- secretKey: foobar
remoteRef:
key: secret/foo
property: my-value
5.验证同步结果
kubectl get secret example-of-vault-sync -ojsonpath='{.data.foobar}'|base64 -d
s3cr3t
5.2 多个namespace共享secret
1.创建两个namespace
$ kubectl create ns easyops-pipeline-ai
$ kubectl create ns easyops-pipeline-devops
2.创建ClusterSecretStore
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: images-cluster-secret-store
spec:
provider:
fake:
data:
- key: images
valueMap:
openjdk-1.8: 'xx.xx.xx.xx/public/openjdk:1.8'
openjdk-11: 'xx.xx.xx.xx/public/openjdk:11.0.20'
python-3.8-gcc: 'xx.xx.xx.xx/public/python:3.8'
3.创建clusterexternal实例,里面指定需要共享数据的namespace即可
apiVersion: external-secrets.io/v1beta1
kind: ClusterExternalSecret
metadata:
name: images-cluster-external-secret
spec:
externalSecretSpec:
dataFrom:
- extract:
conversionStrategy: Default
decodingStrategy: None
key: images
metadataPolicy: None
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: images-cluster-secret-store
target:
creationPolicy: Orphan
deletionPolicy: Retain
name: images
namespaces:
- easyops-pipeline-ai
- easyops-pipeline-devops
4.测试
[root@k8s-master1 baseimage]# kubectl get secrets -n easyops-pipeline-ai
NAME TYPE DATA AGE
default-token-kxqc8 kubernetes.io/service-account-token 3 4d5h
easyops-gitlab-secret kubernetes.io/basic-auth 2 3d
easyops-harbor-secret kubernetes.io/dockerconfigjson 1 3d6h
gitlab-webhook-token Opaque 1 3d
images Opaque 38 41s
tekton-build-sa-token-pnvxc kubernetes.io/service-account-token 3 3d
[root@k8s-master1 baseimage]# kubectl get secrets -n easyops-pipeline-devops
NAME TYPE DATA AGE
default-token-dqlmx kubernetes.io/service-account-token 3 31d
easy-opslocal-secret kubernetes.io/tls 2 31d
easyopshub kubernetes.io/dockerconfigjson 1 31d
images Opaque 38 48s
可以看到两个 namespace 都注入了images这个 secret。如果后期有其他 namespace 需要这个 secret,直接在ClusterExternalSecret资源中添加 namespace 即可。

