我一直用自建的 Vaultwarden 管理密码。最近突然意识到,K3s 集群里的密码都直接写在 Git 仓库里,既不安全也不优雅。于是决定把这些密码迁移到 Bitwarden,并实现自动同步到集群。

整个过程其实很顺利,这里记录一下操作流程,方便大家参考。

为什么要做这件事

虽然我用 ArgoCD 自动发布服务,但密码等敏感信息都直接写在 Git 仓库里。这样做不仅不安全,而且维护起来很麻烦。

1755960391002.png

我希望能有一个自动同步 Secrets 的控制器,把密码从 Bitwarden 自动同步到 K8s 集群,提高安全性和管理效率。正好在 ArgoCD 文档 里看到官方推荐用独立的 Secrets 管理系统,比如 external-secrets

架构设计

方案很简单:在集群里部署 Bitwarden 的转发服务和 external-secrets 控制器,Secrets 会自动创建到对应的 namespace。

详细流程可以参考:argocd bitwarden

1755962102555.png

实现步骤

我是用 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 验证。

1755963071234.png

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
# 参考文档:
# https://bitwarden.corvo.fun/#/vault?organizationId=unassigned&search=ext&itemId=502e2c9a-fefc-4d6d-93a9-0f66d7d4191a
# https://external-secrets.io/latest/examples/bitwarden/#deploy-bitwarden-credentials

---
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 集群。

1755962739832.png

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 密码,既安全又方便。如果线上环境对安全性要求高,建议还是用专业的密码管理工具。

几点补充说明:

  1. Bitwarden 是我自建的密码管理工具,已经做了自动备份和容灾,所以用它管理集群密码比较放心。
  2. Bitwarden 支持权限控制。如果用它管理 K8s 密钥,建议单独建一个 organization 存储,并用专门的用户读取。这样即使集群被攻破,也能保证其他密码安全。