用 External Secrets Operator 消灭多账户 Kubernetes 的秘密蔓延

2026-06-09 16 预计阅读时间: 1 分钟
来源: cncf.io AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:6 分钟

Kubernetes 的基础设施 provisioning 已经高度自动化——ArgoCD、Terraform、Crossplane 把集群和命名空间像流水线一样产出。但秘密管理却常常卡在手动复制和 YAML 粘贴的阶段。当组织把开发、预发布、生产拆到不同集群、命名空间甚至云账户之后,秘密的"蔓延"问题就彻底失控了:同一个数据库密码被复制到十几个 namespace,轮换时漏掉一个就等于没轮换。

原生 Secret 的天花板

Kubernetes 原生 Secret 只是一个 base64 编码的键值对,没有轮换机制,没有审计日志,也没有跨集群同步能力。单集群里勉强够用,一旦跨账户、跨集群部署,你面对的是:

  • 每个集群独立存储一份相同的秘密,轮换时需要逐个更新
  • 没有统一的权限边界——谁能读、谁能写散落在各集群的 RBAC 里
  • GitOps 仓库里出现 base64 编码的"秘密",安全团队直接报警

External Secrets Operator 的核心思路

External Secrets Operator(ESO)的逻辑很简单:Kubernetes 不应该是秘密的源头,它只是秘密的消费者。真正的源头是 AWS Secrets Manager、HashiCorp Vault、GCP Secret Manager 这些专业服务。ESO 定期从外部源拉取秘密,写入本地 Secret 对象,让应用像往常一样挂载使用。

关键组件:

  • SecretStore:定义外部秘密源的连接方式和认证信息(每个 namespace 或集群一份)
  • ExternalSecret:声明"我要从外部源取哪个秘密,映射到本地 Secret 的哪个 key"
  • ClusterSecretStore:集群级别的 SecretStore,跨 namespace 共用

实战:多账户场景下的 ESO 配置

下面是一个典型的多账户 AWS 场景:生产账户的 Secrets Manager 存着真实凭据,开发集群通过 ESO 跨账户拉取(或拉取开发版本的凭据)。

1. 安装 ESO

helm repo add external-secrets https://charts.external-secrets.io
helm repo update
helm install external-secrets \\n  external-secrets/external-secrets \\n  -n external-secrets-system \\n  --create-namespace

2. 配置跨账户 SecretStore

假设生产集群在 AWS 账户 A,需要读取账户 B 的 Secrets Manager,或者反过来——开发集群需要读取生产账户的只读凭据。关键是 IAM 跨账户角色信任:

apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  name: aws-prod-secretstore
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-east-1
      role: arn:aws:iam::PROD_ACCOUNT_ID:role/cross-account-eso-role
      auth:
        jwt:
          serviceAccountRef:
            name: eso-sa
            namespace: external-secrets-system

对应的 IAM 角色需要信任开发集群的 OIDC provider:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::DEV_ACCOUNT_ID:role/eso-dev-cluster-role"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

3. 声明 ExternalSecret

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: my-app
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-prod-secretstore
    kind: ClusterSecretStore
  target:
    name: db-credentials-secret
    creationPolicy: Owner
  data:
    - secretKey: username
      remoteRef:
        key: prod/db/credentials
        property: username
    - secretKey: password
      remoteRef:
        key: prod/db/credentials
        property: password

应用 Pod 的 Deployment 完全不用改——它仍然挂载 db-credentials-secret 这个原生 Secret。ESO 在背后定期刷新,密码轮换后最多 1 小时自动同步到集群。

4. 多集群同步策略

如果你有 ArgoCD 或 Flux 管理多集群,ExternalSecret 和 SecretStore 可以作为 GitOps 仓库的一部分统一分发:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: external-secrets-config
  namespace: argocd
spec:
  source:
    repoURL: https://github.com/your-org/k8s-secrets-config
    path: external-secrets
  destination:
    server: https://kubernetes.default.svc
    namespace: external-secrets-system
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

每个集群的 SecretStore 用不同的 role ARN 指向对应账户,ExternalSecret 声明保持一致——同一个 Git 仓库,不同集群自动拿到正确账户的秘密。

落地前的取舍清单

决策点 建议
外部秘密源选什么 AWS 环境优先 Secrets Manager;混合云或多云选 Vault
refreshInterval 多长 生产环境 15m–1h;开发环境可以 5m 方便调试
用 ClusterSecretStore 还是 namespace 级别 跨 namespace 共用选 Cluster;严格隔离选 namespace 级别
删除 ExternalSecret 后本地 Secret 会不会残留 creationPolicy: Owner 时 ESO 会自动清理;Orphan 则保留
和 GitOps 冲突吗 不冲突——SecretStore 和 ExternalSecret 是 CRD,可以 GitOps 管理;同步出的原生 Secret 不要放进 Git

ESO 不是银弹。它解决的是"秘密从哪来、怎么同步"的问题,但不解决"谁有权访问外部源"的 IAM 治理。跨账户角色信任链需要和云安全团队一起设计。另外,如果你的 Vault 或 Secrets Manager 本身就配置混乱,ESO 只会把混乱更快地搬运到 Kubernetes 里——先治理源头,再接入 ESO。


相关推荐