我一直用自建的 Vaultwarden 管理密码。最近突然意识到,K3s 集群里的密码都直接写在 Git 仓库里,既不安全也不优雅。于是决定把这些密码迁移到 Bitwarden,并实现自动同步到集群。
整个过程其实很顺利,这里记录一下操作流程,方便大家参考。
为什么要做这件事
虽然我用 ArgoCD 自动发布服务,但密码等敏感信息都直接写在 Git 仓库里。这样做不仅不安全,而且维护起来很麻烦。

我希望能有一个自动同步 Secrets 的控制器,把密码从 Bitwarden 自动同步到 K8s 集群,提高安全性和管理效率。正好在 ArgoCD 文档 里看到官方推荐用独立的 Secrets 管理系统,比如 external-secrets。
架构设计
方案很简单:在集群里部署 Bitwarden 的转发服务和 external-secrets 控制器,Secrets 会自动创建到对应的 namespace。
详细流程可以参考:argocd bitwarden

实现步骤
我是用 ArgoCD 做 IaC 管理的,下面用 Application 的方式举例说明。
安装 external-secrets
用 Helm 安装 external-secrets,并开启 ClusterSecretStore 的 CRD 支持。
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
| apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: external-secrets namespace: argocd spec: project: default source: repoURL: 'https://external-secrets.github.io/external-secrets/' chart: external-secrets targetRevision: 0.19.2 helm: parameters: - name: bitwarden-sdk-server.enabled value: "false" - name: "crds.createClusterSecretStore" value: "true" destination: server: 'https://kubernetes.default.svc' namespace: external-secrets syncPolicy: automated: selfHeal: true prune: true syncOptions: - CreateNamespace=true - ServerSideApply=true
|
部署 Bitwarden 服务
部署 Bitwarden CLI 服务,确保能正常获取密码。可以在容器里执行 bw list items
验证。

1 2 3 4 5 6 7 8 9 10 11 12
| kubectl apply -f - <<EOF apiVersion: v1 kind: Secret metadata: name: bitwarden-cli namespace: external-secrets type: Opaque data: BW_HOST: $(echo -n "https://xxxxx" | base64 | tr -d '\n') BW_USERNAME: $(echo -n "" | base64 | tr -d '\n') BW_PASSWORD: $(echo -n "" | base64 | tr -d '\n') EOF
|
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
|
--- apiVersion: apps/v1 kind: Deployment metadata: name: bitwarden-cli spec: template: spec: containers: - name: bitwarden-cli image: ghcr.io/charlesthomas/bitwarden-cli:2025.6.1 --- apiVersion: v1 kind: Service metadata: name: bitwarden-cli spec: --- kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: external-secret-2-bw-cli spec:
|
配置 external-secrets 的密码获取方式
告诉 external-secrets 如何从 Bitwarden 获取密码。
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 42 43 44 45
| --- apiVersion: external-secrets.io/v1 kind: ClusterSecretStore metadata: name: bitwarden-login spec: provider: webhook: url: "http://bitwarden-cli:8087/object/item/{{ .remoteRef.key }}" headers: Content-Type: application/json result: jsonPath: "$.data.login.{{ .remoteRef.property }}" --- apiVersion: external-secrets.io/v1 kind: ClusterSecretStore metadata: name: bitwarden-fields spec: provider: webhook: url: "http://bitwarden-cli:8087/object/item/{{ .remoteRef.key }}" result: jsonPath: "$.data.fields[?@.name==\"{{ .remoteRef.property }}\"].value" --- apiVersion: external-secrets.io/v1 kind: ClusterSecretStore metadata: name: bitwarden-notes spec: provider: webhook: url: "http://bitwarden-cli:8087/object/item/{{ .remoteRef.key }}" result: jsonPath: "$.data.notes" --- apiVersion: external-secrets.io/v1 kind: ClusterSecretStore metadata: name: bitwarden-attachments spec: provider: webhook: url: "http://bitwarden-cli:8087/object/attachment/{{ .remoteRef.property }}?itemid={{ .remoteRef.key }}" result: {}
|
自动同步密码到集群
假如你已经在 Bitwarden 里保存了密码,只需创建 ExternalSecret,控制器会自动同步到 K8s 集群。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: xx spec: refreshInterval: 1h secretStoreRef: name: bitwarden-secretsmanager kind: SecretStore data: - secretKey: AAA sourceRef: storeRef: name: bitwarden-notes kind: ClusterSecretStore remoteRef: key: AAA
|
最终会自动生成 K8s Secret,数据已经同步到集群,可以直接挂载和使用。
1 2 3 4 5 6 7 8 9 10 11 12
| apiVersion: v1 type: Opaque kind: Secret metadata: name: xx namespace: default ownerReferences: - apiVersion: external-secrets.io/v1 kind: ExternalSecret name: xx data: AAA: QkJCQ0NDRERE
|
总结与建议
以前用 AWS SSM 管理密码,但因为成本没用起来。现在用 Bitwarden 管理 K8s 密码,既安全又方便。如果线上环境对安全性要求高,建议还是用专业的密码管理工具。
几点补充说明:
- Bitwarden 是我自建的密码管理工具,已经做了自动备份和容灾,所以用它管理集群密码比较放心。
- Bitwarden 支持权限控制。如果用它管理 K8s 密钥,建议单独建一个 organization 存储,并用专门的用户读取。这样即使集群被攻破,也能保证其他密码安全。