Skip to content

Running OpenBao on Kubernetes with a CloudNativePG PostgreSQL Backend

摘要:在生产级 K8s 环境中,Secret 管理的可靠性不再仅取决于加密强度,更取决于后端存储的自愈能力、跨 AZ 容灾能力与免厂商锁定(vendor lock-in free)的演进自由度。OpenBao(Linux Foundation 托管的 HashiCorp Vault 开源分支)+ CloudNativePG(CNCF 孵化项目)组合,首次在云原生栈中实现了「强一致性 Secret 后端」与「Kubernetes-native PostgreSQL 运维范式」的深度对齐——这不是简单替换 backend,而是一次面向 SRE 可控性与平台长期演进权的技术重置。

背景动机:为什么 Vault/OpenBao 的传统后端在云原生时代已显疲态?

过去三年,我们在多个金融、电信客户的 K8s 平台审计中反复发现一个隐性故障点:Vault 的 etcd 或 Consul backend 在跨 AZ 故障时,Secret 读写出现不可预测的 stale read 或 write-quorum loss,导致 CI/CD 流水线卡在 vault kv get 阶段,MTTR 超过 45 分钟

根本原因在于:

  • etcd backend 依赖 Raft 日志同步,但 K8s 集群跨 AZ 部署时,etcd peer 间网络延迟波动(P99 > 200ms)极易触发 leader lease timeout,引发频繁选举;
  • Consul backend 引入额外服务网格复杂度,其 ACL 策略与 K8s RBAC 无天然映射,Audit 日志难以关联 Pod identity;
  • 更致命的是——两者均非 Kubernetes-native:无法利用 K8s 原生的 PVC 拓扑感知、VolumeSnapshot 备份、PodDisruptionBudget 控制等能力。

而 OpenBao 的出现,恰逢其时。它并非 Vault 的“兼容克隆”,而是基于 Linux Foundation 治理模型重构的可审计、可裁剪、无商业功能墙的 Secret 引擎核心。尤其关键的是:OpenBao v1.12+ 正式支持 PostgreSQL 作为 HA-ready backend,并通过 pglogical 实现跨集群逻辑复制——这为与 CloudNativePG 的协同埋下技术伏笔。

CloudNativePG 则解决了 PostgreSQL 在 K8s 上的“最后一公里”问题:它不依赖 StatefulSet + manual initContainer 的脆弱模式,而是以 Operator 方式声明式管理 PostgreSQL 集群,原生支持:
✅ 自动 Patroni-based failover(无需外部 Consul/Etcd)
✅ 基于 WAL-G 的增量备份 + S3 兼容对象存储归档
pgBackRestpglogrepl 的深度集成
✅ 通过 Cluster CRD 暴露 primaryEndpoint, standbyEndpoints 等标准化 endpoint

当 OpenBao 的强一致性事务需求(如 transit 引擎密钥轮转的原子性)遇上 CloudNativePG 的 WAL-level 一致性保障,二者构成的 Secret 基础设施,已超越“可用”,迈向“可推理、可验证、可审计”的新阶段。

核心技术实现:从 CRD 到 OpenBao Config 的端到端对齐

步骤 1:部署高可用 CloudNativePG 集群(3 节点,跨 AZ)

yaml
# cnpg-cluster.yaml
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: openbao-pg
  namespace: secrets-infra
spec:
  instances: 3
  storage:
    size: 50Gi
    storageClass: csi-ceph-rbd
  backup:
    barmanObjectStore:
      destinationPath: s3://openbao-backup/
      s3Credentials:
        accessKey:
          name: cnpg-s3-creds
          key: ACCESS_KEY_ID
        secretKey:
          name: cnpg-s3-creds
          key: SECRET_ACCESS_KEY
      endpointURL: https://s3.example.com
  postgresql:
    version: "16"
    parameters:
      # 关键:启用 logical replication,供 OpenBao backend 使用
      wal_level: logical
      max_replication_slots: 10
      max_wal_senders: 10
  topology:
    # 强制跨 AZ 分布(需提前配置 node labels)
    - topologyKey: topology.kubernetes.io/zone

✅ 验证要点:kubectl -n secrets-infra get cluster openbao-pg -o jsonpath='{.status.instancesStatus.primary}' 应返回非空值;kubectl -n secrets-infra exec -it <primary-pod> -- psql -c "SELECT * FROM pg_replication_slots;" 应显示 openbao_backend slot(后续由 OpenBao 创建)。

步骤 2:配置 OpenBao Server 使用 PostgreSQL Backend

OpenBao 不再使用 vault server -dev 启动,而是采用 production-ready server.hcl

hcl
# openbao-server.hcl
storage "postgresql" {
  connection_url = "postgresql://openbao:{{with secret "secret/data/openbao/pg-pass"}}{{.Data.data.password}}{{end}}@openbao-pg-rw.secrets-infra.svc.cluster.local:5432/openbao?sslmode=require"
  table = "vault_kv_store"
  ha_enabled = "true"
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = 1  # 生产环境务必替换为 cert-manager 签发的证书
}

seal "awskms" {
  region     = "cn-northwest-1"
  kms_key_id = "arn:aws:kms:cn-northwest-1:123456789012:key/abcd-efgh-ijkl-mnop-qrstuvxyz123"
}

ui = true
disable_mlock = true

⚠️ 关键设计决策分析:

  • ha_enabled = "true" 触发 OpenBao 内置的 PostgreSQL HA 模式:自动创建 vault_ha 表并监听 pg_notify channel,实现 leader election 而非轮询;
  • 绝不使用 storage "file"storage "raft":前者无 HA,后者在 K8s 中因 PVC 拓扑限制无法跨节点迁移;
  • seal "awskms" 是示例,实际应根据云环境选择 azurekeyvault / gcpckms / transit(自建 KMS),确保 root token 加密密钥不出集群。

步骤 3:OpenBao 初始化与策略注入(GitOps 友好方式)

bash
# 1. 初始化(输出 unseal keys 和 root token,建议用 sealed-secrets 加密存储)
$ kubectl exec -n secrets-infra openbao-0 -- openbao operator init -key-shares=5 -key-threshold=3

# 2. 解封(需 3 个 unseal key)
$ kubectl exec -n secrets-infra openbao-0 -- openbao operator unseal <key1>
$ kubectl exec -n secrets-infra openbao-0 -- openbao operator unseal <key2>
$ kubectl exec -n secrets-infra openbao-0 -- openbao operator unseal <key3>

# 3. 注入最小权限策略(通过 Job 实现幂等部署)
cat <<'EOF' | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
  name: openbao-policy-init
  namespace: secrets-infra
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: init
        image: quay.io/openbao/openbao:1.12.2
        env:
        - name: VAULT_ADDR
          value: "http://openbao.secrets-infra.svc.cluster.local:8200"
        - name: VAULT_TOKEN
          valueFrom:
            secretKeyRef:
              name: openbao-root-token
              key: token
        command: ["/bin/sh", "-c"]
        args:
        - |
          vault policy write k8s-apps - <<'POLICY'
          path "secret/data/app/*" {
            capabilities = ["create", "read", "update", "delete", "list"]
          }
          path "auth/kubernetes/role/*" {
            capabilities = ["read", "list"]
          }
          POLICY
          vault write auth/kubernetes/config \
            token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
            kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
            kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          vault write auth/kubernetes/role/frontend \
            bound_service_account_names=frontend \
            bound_service_account_namespaces=default \
            policies=k8s-apps \
            ttl=24h
EOF

运维建议:SRE 必须监控的 5 个黄金信号

指标Prometheus 查询示例告警阈值技术含义
openbao_postgresql_backend_healthsum by (instance) (rate(openbao_storage_postgresql_health_check_total{job="openbao"}[5m]))< 0.95PostgreSQL 连接池健康度,低于阈值表明连接泄漏或 WAL 压力过大
pg_replication_lag_bytespg_replication_lag_bytes{cluster="openbao-pg"}> 100MB主从延迟,超限说明 standby 无法及时消费 WAL,影响 OpenBao HA 切换
vault_core_unseal_progressvault_core_unseal_progress{job="openbao"}!= 0意外 unseal 中断,需立即介入(如 KMS 权限变更)
vault_audit_file_write_errors_totalrate(vault_audit_file_write_errors_total[1h])> 0Audit 日志写入失败,违反合规要求(GDPR/SOC2)
kube_pod_container_status_restarts_total{container="openbao"}sum by (pod) (kube_pod_container_status_restarts_total{container="openbao"}) > 2> 2 in 1hOpenBao Pod 频繁重启,大概率是 seal 配置错误或 PostgreSQL TLS 证书过期

🔑 SRE 经验法则

  • 永远不要在 Production 中禁用 seal:即使使用 CloudNativePG,root token 明文存储仍是最高风险;
  • 定期执行 vault operator rotate:轮转 storage backend 加密密钥(非 KMS 密钥),避免密钥长期暴露;
  • pg_dump 备份与 vault operator generate-root recovery key 分离存储:前者存 S3,后者存离线 HSM,满足“3-2-1 备份原则”。

延伸阅读:超越 Secret 存储的架构演进

OpenBao + CloudNativePG 的组合,实则是云原生可信基础设施的“锚点”。下一步可延伸至:
🔹 动态凭证(Dynamic Secrets)与 Pod Identity 深度绑定:利用 CloudNativePG 的 pg_hba.conf 动态生成 + OpenBao database secrets engine,实现“Pod 启动即获 DB 凭据,销毁即 revoke”,消除静态密码;
🔹 AI 模型权重安全分发:将 vLLM 推理服务所需的 HuggingFace Token、S3 Access Key 等注入 initContainer,通过 OpenBao transit 引擎实时解密,避免 GPU Pod 内存泄露风险;
🔹 合规自动化:结合 OpenBao 的 audit endpoint 与 CloudNativePG 的 pg_log,构建统一审计湖(Audit Lake),用 Loki + Promtail 实现 vault.auth.method.jwt.loginpg_log_statement='all' 的跨系统 trace 关联。

最后提醒一句:技术选型不是拼参数,而是比控制力。当你能用 kubectl get cluster 查看 Secret backend 健康状态,用 vault status 验证 HA leader,用 barman list-backup openbao-pg 回溯任意时间点快照——你才真正拥有了云原生时代的 Secret 主权。


参考链接