Featured image of post BitwardenSecretsManagerを使ってみる

BitwardenSecretsManagerを使ってみる

BitwardenSecretsManagerの導入検討と、最低限使用可能なところまでの検討メモ。Infisical Cloudも候補に挙がったけれど現状パスワードマネージャをBitwardenで使っているので管理を共通化出来るということでBitwardenを先に試すことにした。

概要

最近APIのシークレットを.envとかに入れるのが嫌なので何かしらマネージャー管理にようと考えて候補を検討して、結局パスワードマネージャー同様にBitwardenにして進めてみた。
比較はInfisical。 管理上の問題とかでBitwardenを選択。
そのままセットアップしていたところマシンアカウントのアクセストークンを環境変数に直接保存する運用が公式運用となっていたので、ちょっと微妙だなとファイル保存して実行時だけ使用する環境で構築した。
可能であれば暗号保存したほうが良いと思うが、結局それも同じ問題を抱えそうなのでいったんこの方式で使ってみる。

検討した製品・サービス

比較検討

シークレットマネージャーはパスワードマネージャー同様にそれなりに普及してきているので候補は色々ある。
BitwardenSecretsManager(以下BitwardenSM)と比較したのはInfisical。
こちらのほうが大分高機能で色々出来る感じなのとOSS版とクラウド版があって、クラウド版はFreeでも個人なら普通に使えるレベルだった。

調査はChatGPTで調べて公式ドキュメントを参照していった感じ。
ChatGPTまとめで比較としてはこんな感じになった。

条件Bitwarden SM FreeInfisical Self-hostInfisical Cloud Free
料金無料OSS部分は無料無料
Secret数無制限100個超なら問題なし100個超なら問題なし
Project数3無制限無制限
人間ユーザー最大2Identity枠に含むIdentity枠に含む
Machine Identity3 Machine AccountsFreeでは人間含め計5 Identityが基準人間含め計5 Identity
1人利用時のMachine枠3おおむね44
複数VMから同一Secret取得○○○
2FA○○○
FIDO2/WebAuthn 2FA○明示なし明示なし
パスキーによるログイン○(Beta)現行Free仕様では確認できず現行Free仕様では確認できず
Entra ID SSO× EnterpriseのみFreeでは×× Pro以上
Audit Log×Freeでは××
Secret VersioningBitwarden方式Freeでは×Freeでは×
運用管理不要自分で必要不要
障害・バックアップ責任Bitwarden自分Infisical
データを自宅内に限定×◎×

当初はセルフホストも考えたけど、結局Cloud版とあまり変わらない制限だったので、Infisicalのセルフホスト版は早めに除外してクラウドのBitwardenSMとInfisical Cloudで比較した。
一番大きな違いとしてBitwardenSMはProject数に制限があること、BitwardenSMはWebログインにパスキーが使えること。
BitwardenSMのPlans表にはTwo-step loginのところにそういった記載は無いけれどBitwardenPasswordManager側とWebログインのアカウントが共通なのでパスキーもベータ扱いだけど使える。

こちらももう少し細かくまとめた。

項目Bitwarden Secrets Manager FreeInfisical Cloud Free
月額$0$0
人間ユーザー最大2Machine含め合計5 identities
Machine用ID3 Machine Accounts5 identitiesの内数
1人利用時のMachine枠3実質4
Secret数無制限数による上限は料金表に記載なし
Project数3無制限
Environment独立した同等概念なし3 / Project
Secret FolderProject中心○
Secret Reference基本的なSecret管理○
Secret Override―○
CLI○ bws○
API/SDKによる取得○○
コンテナへの環境変数注入○○
Machineごとの権限設定○○
Secret Sync限定的なIntegrations10 Syncs
2FA○○
Entra ID SSO××
SAML SSO×(Enterprise)×(Pro)
FIDO2/WebAuthnBitwardenアカウントで○Freeの主要機能として記載なし
Passkeyログイン○現状は主要Free機能として記載なし
Audit Log××
Secret Versioning専用履歴機能としてFreeにはなし×
自動Secret Rotation××
Point-in-time Recovery××
IP Allowlist××
Freeの主な制約3 Projects / 3 Machines5 identities

Project数は自宅の利用ならそんなに必要ないかな?ということで、いったんBitwardenに集約することにした。
駄目なら移行しちゃえばいいし。 AIエージェントが賢くなりすぎて移行がやりやすくなって色々試せるのが最近のいいところ。

InfisicalのOSSセルフホストとCloudFreeの比較

OSSセルフホストもMITライセンス部分が一部ということで機能制限されているようなので、これもChatGPTで条件まとめ。

機能OSSセルフホスト
Web管理画面○
Secret保存・取得○
CLI / API / SDK○
Machine Identity○
Universal Auth○
複数Project○
Secret Folder○
Secret Reference / Import / Override○
Docker / Kubernetes / Terraform等連携○
Infisical Agent○
2FA○
SAML SSO / Entra ID SSO×
OIDC SSO×(ライセンス対象)
LDAP×
SCIM×
高度なRBAC / Access Control×
Secret Versioning×
Point-in-Time Recovery×
Audit Log×
Secret Rotation×
Dynamic Secrets×
Custom Roles×
Temporary Access×
Approval Workflow×
External KMS / HSM×
SIEMへのAudit Log転送×

Bitwarden Secrets Managerセットアップ

公式のスタートアップ説明はこちらSecrets Manager Quick Start

Bitwarden Secrets Managerの有効化

Bitwarden Password Managerを利用しているなら、Webログイン後画面の左下にSecrets Managerへの切替メニューがあるのでそこを選択して、組織名とPlanを設定して有効化。
有効化するとWebログイン後、Password ManagerとSecrets Managerの切替メニューが左側のサイドメニュー下側に現れるようになるのでそこで、そこで切り替える。

Bitwardenメニュー

ユーザーのロール設定

Admin Consoleでメンバーを選択し、シークレットマネージャー利用ユーザーのメンバーロールを編集して一番下にある「このユーザーはシークレットマネージャーにアクセスできます」のチェックをONにしておく。
自分の場合は一人で管理者だけなので最初からチェックついていました。

Projectの作成

最初にProjectを作成する。
FreePlanでは3Projectまでなのでどうしようか迷ったけど

  • applications
  • infrastructure
  • other あたりにしておく。
    BitwardenSMのFreePlanでは分類がやりにくい問題はあるので、分類するほどシークレットが多い場合はInfisical Cloudのほうが良さそう。

マシンアカウントの作成

シークレットのアクセスを自動化するためにマシンアカウントを作成する。
これも3アカウントに限定されるので、必要があれば機能別に分けるようにするつもりだけどいったんは1アカウントで様子見する。
作成したマシンアカウントに先ほど作成したProjectを割り当て。
とりあえず読み取り専用で登録。

Secrets Manager CLI(bws)のインストール

公式のドキュメントはこちらSecrets Manager CLI
テストでインストールしたマシンの条件はこちら

1
2
3
4
Distributor ID:	Ubuntu
Description:	Ubuntu 24.04.5 LTS
Release:	24.04
Codename:	noble

Linuxなので

1
sudo curl https://bws.bitwarden.com/install | sh

としたら

1
unzip is required to install bws.

と指摘されたので先に入れておく。正常にインストールしたらバージョン確認

1
2
$ bws --version
bws 2.1.0

アクセス

マシンアカウントのアクセストークンを使用してアクセスする。
マシンアカウントでアクセストークンを作成し、環境変数に設定するのが公式の設定。

1
export BWS_ACCESS_TOKEN=<アクセストークン>

しかしアクセストークンを環境変数に与えるのはなんか嫌だ。
ということで、bwsグループを作ってこのグループに参加しているユーザのみトークンファイルを読めるようにしておいて、コマンド実行時にそこから実行時に環境変数に値を入れるようにする。
環境には残さないようにしたラッパー経由でbwsコマンドにアクセスするようにする。

1
2
3
4
5
6
7
sudo groupadd --system bws
sudo mkdir /etc/bws
sudo vi /etc/bws/access-token
sudo chown root:bws /etc/bws/access-token
sudo chmod 640 /etc/bws/access-token

sudo usermod -aG bws $USER

その後、ラッパー用のスクリプトをユーザーローカルに作成する

 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
mkdir -p ~/bin

cat > ~/bin/bws <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

# 万一呼び出し元でxtraceが有効でも、Secretを出力させない
set +x

readonly REAL_BWS="/usr/local/bin/bws"
readonly TOKEN_FILE="/etc/bws/access-token"

if [[ ! -x "$REAL_BWS" ]]; then
    printf 'bws wrapper: executable not found: %s\n' "$REAL_BWS" >&2
    exit 127
fi

if [[ ! -r "$TOKEN_FILE" ]]; then
    printf 'bws wrapper: token file is not readable: %s\n' "$TOKEN_FILE" >&2
    exit 126
fi

BWS_ACCESS_TOKEN="$(<"$TOKEN_FILE")"

if [[ -z "$BWS_ACCESS_TOKEN" ]]; then
    printf 'bws wrapper: token file is empty: %s\n' "$TOKEN_FILE" >&2
    exit 1
fi

export BWS_ACCESS_TOKEN

exec "$REAL_BWS" "$@"
EOF

chmod 700 ~/bin/bws

再ログイン後、おそらく自動で優先的なパスとして選択してくれるので以下で確認。

1
type -a bws

/home/user/bin/bwsが最優先になっていればOK

docker-compose起動用のスクリプトの作成

当初の目的のメインがdocker composeの.envファイルに秘密情報を書かないようにする、なのでdocker composeで利用できるようにする。
普段行っているように

1
docker compose up -d

とすると、bws runと組み合わせられない。
しかし組み合わせる場合オプションにProjectIDをつけることになるとすると毎回UUIDを引っ張ってくる必要があって面倒くさいので、起動用のスクリプトを作成する。

以下のような感じで作成した。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/usr/bin/env bash
set -euo pipefail

readonly PROJECT_ID="プロジェクトID"

exec bws run --project-id "$PROJECT_ID" --  '
    : "${SERVICE_TOKEN:?SERVICE_TOKEN is not set}"

    export TOKEN="$SERVICE_TOKEN"
    unset SERVICE_TOKEN

    exec docker compose up -d
'

これを実行できるように権限を与えて

1
2
chmod 755 compose-up
./compose-up

で実行させるようにした。
終了はこれまで通りdocker compose down。
課題として、compose.yamlで配列として環境変数を渡している場合、終了時に環境変数がないとワーニングが出て嫌なので

  • compose.yamlの環境変数の渡し方はリストにして直接指定する
  • BitwardenSMに登録している環境変数名とコンテナに渡す環境変数が違う場合はcompose-upのexportのところで変換してやる という形で対応した。

systemd-credsによるAccessToken暗号化

先程までの方法だと、マシンアカウントのAccessTokenが残るじゃないかと思って色々考えていたけど、systemdと連係をするのであればsystemd-credsが使用できる。

1
2
3
4
5
6
7
8
sudo install -d -m 700 /etc/credstore.encrypted

systemd-ask-password -n "BWS Access Token:" |
sudo systemd-creds encrypt \
    --with-key=host+tpm2 \
    --name=bws-access-token \
    - \
    /etc/credstore.encrypted/bws-access-token

これを実行するとトークンの入力を聞かれるので入力すると/etc/credstore.encrypted/bws-access-tokenに暗号化した状態でトークンを保存してくれる。
そして鍵情報はTPMを利用しているので、Proxmox使っている場合はvTPMを割り当てている必要がある。今回作った。

確認方法

1
sudo systemd-creds decrypt /etc/credstore.encrypted/bws-access-token -

ただし、こちらはroot権限が必要になるのでユーザ権限で起動するようなroot-less運用している場合は

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
mkdir -p ~/.config/credstore.encrypted
chmod 700 ~/.config/credstore.encrypted

systemd-ask-password -n "BWS Access Token:" |
systemd-creds encrypt \
    --user \
    --with-key=host+tpm2 \
    --name=bws-access-token \
    - \
    ~/.config/credstore.encrypted/bws-access-token

としてCredentialファイルを作成する。
そしてこれを使ってSystemdのUnitファイルを修正して実行したとこNG。
調べてみたらsystemd 257のバグらしくユーザーサービスとしてLoadCredentialEncryptedとかが使えないようで258で修正予定とのこと。

As of systemd 257, the ImportCredential, LoadCredential, LoadCredentialEncrypted, SetCredential and SetCredentialEncrypted settings do not work in user services. This should be fixed by [1] in systemd 258.

引用元

じゃあsystemサービスとしてUnit移行させてそこからユーザーサービスとして起動させるか?と思ったけど、将来Quadletに移行しようとした場合はsystemサービスのUnitからユーザーサービスとして起動できないみたいなので、移行してさらに移行みたいなことをしないといけなさそうなのが面倒。
ということで一旦Podman管理のサービスは後回しにすることに。