KubernetesにBitwarden Secrets Managerを導入してみる
自宅サーバーでk8sを構築しているのですが、Secretの管理に頭を悩ませていました。
kubectlで管理するのは面倒くさいし、自宅サーバーなのでロストする可能性もあります。
これを改善しようと調べてみると、いくつかの選択肢がありました。
-
PortainerやLensでSecretのGUI管理
→ 自宅k8sで、オペレーションミスでSecretを失う可能性もあるため却下 -
Sealed Secretsやsopsといった暗号化済みのテキストを書き込み、使用時に復号する方式
→ 暗号化されているとはいえGit履歴に残るのが嫌 -
Bitwarden Secrets Manager(BSM)とExternal Secrets Operator(ESO)で管理
→ 普段からBitwardenを使用していたことと、外部のサービスに預けられるのでデータを失う確率が自分で管理するより低いだろう
パッとこの3つが上がったのですが、3を選択しました。
調べてもBSMの情報はあまりなかったので記事にしてみることにしました。
ちなみに Bitwarden Passowrd Manager と Bitwarden Secrets Manager は全くの別物なので注意してください。
Password Managerの方は1Passowrdみたいなよくあるパスワードマネージャーで、Secrets ManagerはAWS Secrets Mangerのようなシステム環境向けのシークレット管理サービスです。
導入
External Secrets Operator (ESO) のインストール
まずはHelmでExternal Secrets Operatorをインストールします。
BSMを使用する場合、Bitwarden SDK Serverも一緒にインストールする必要があります。
# Helmリポジトリの追加
helm repo add external-secrets https://charts.external-secrets.io
# External Secrets OperatorとBitwarden SDK Serverをインストール
helm install external-secrets \
external-secrets/external-secrets \
-n external-secrets \
--create-namespace \
--set bitwarden-sdk-server.enabled=true
Bitwarden SDK ServerはHTTPSで動作するので、cert-managerで証明書を生成する必要があります。
cert-managerがまだインストールされていない場合は、先にインストールしてください。
Bitwarden Secrets Managerの準備
BSMにアクセスするためには、Machine Accountが必要です。
BitwardenのWebコンソールからMachine Accountを作成し、アクセストークンを取得してください。
取得したトークンをKubernetes Secretとして保存します。
kubectl create secret generic bitwarden-access-token \
-n default \
--from-literal=token='YOUR_ACCESS_TOKEN_HERE'
SecretStore の設定
SecretStoreを作成して、ESOがBSMに接続できるようにします。
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
name: bitwarden-secretsmanager
spec:
provider:
bitwardensecretsmanager:
apiURL: https://api.bitwarden.com
identityURL: https://identity.bitwarden.com
auth:
secretRef:
credentials:
key: token
name: bitwarden-access-token
bitwardenServerSDKURL: https://bitwarden-sdk-server.external-secrets.svc.cluster.local:9998
# cert-managerで生成した証明書のCA Bundleを設定
caBundle: "<BASE64_ENCODED_CA_CERTIFICATE>"
# BSMのOrganization ID
organizationID: "your-organization-id"
# BSMのProject ID
projectID: "your-project-id"
ExternalSecret の設定
SecretStoreの準備ができたら、ExternalSecretを作成してBSMからシークレットを取得します。
UUIDで取得する場合
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: my-external-secret
spec:
refreshInterval: 1h
secretStoreRef:
name: bitwarden-secretsmanager
kind: SecretStore
target:
name: my-k8s-secret
creationPolicy: Owner
data:
- secretKey: my-secret-key
remoteRef:
key: "339062b8-a5a1-4303-bf1d-b1920146a622" # BSMのシークレットUUID
名前で取得する場合
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: my-external-secret
spec:
refreshInterval: 1h
secretStoreRef:
name: bitwarden-secretsmanager
kind: SecretStore
target:
name: my-k8s-secret
creationPolicy: Owner
data:
- secretKey: my-secret-key
remoteRef:
key: "secret-name" # BSMで設定したシークレット名
動作確認
ExternalSecretが正しく同期されているか確認します。
kubectl get externalsecret my-external-secret
# 出力例
# NAME STORE REFRESH INTERVAL STATUS READY
# my-external-secret bitwarden-secretsmanager 1h SecretSynced True
StatusがSecretSyncedになっていれば成功です。
作成されたSecretの内容も確認できます。
kubectl get secret my-k8s-secret -o jsonpath='{.data.my-secret-key}' | base64 -d
Discussion