
私たちcoiaiはモックアップの作成業務がメインで今までの開発は1-2名程度でした。しかし、6名以上で開発を進めていく案件が増えてきたため、開発環境を見直す必要に迫られました。
今まで環境変数は .env ファイルで管理していました。しかしこれからは、平文として秘密情報が確認できない状態にすること、チームで環境変数の共有の際にセキュアな共有方法を確保することを目的とし、環境整備を行いました。
.env の平文で持つのをやめ、bws run を使うと、秘密は実行の瞬間だけローカル開発の秘密情報は .env + .gitignore が定番だが、いくつか弱点がある。
.env をチャットやUSBで渡すことになりがち。cat .env や printenv を実行する。Bitwarden 自身がこの点をブログで指摘している1 と 2 を解決するのがシークレット管理サービスで、Bitwarden Secrets Manager は
その中でも安価(Password Manager とは別契約)かつ CLI が単体バイナリで導入が軽い。
注意点としてPassword Manager(個人のパスワード保管)とは別プロダクトです!Password Manager は弊社でも利用していますが、今回Secret Manager を追加で契約した形になります。
概念は3つだけです。
| 概念 | 役割 |
|---|---|
| プロジェクト | シークレットの入れ物。今回は 1 リポジトリ = 1 プロジェクト |
| シークレット | KEY / VALUE / メモ の3つ組。.env の 1 行 = 1 シークレット にする |
| マシンアカウント | 人間ではなくプログラム用のアカウント。プロジェクト単位で読み取り/読み書き権限を付与し、アクセストークンを発行する |
Secrets Manager プロジェクト「MyProject」
├─ GOOGLE_CLIENT_ID = xxxx.apps.googleusercontent.com
├─ GOOGLE_CLIENT_SECRET = GOCSPX-xxxx
├─ POSTGRES_PASSWORD = xxxx
└─ ...
▲ 読み書き: 管理者用マシンアカウント(自分)
▲ 読み取りのみ: メンバー用マシンアカウント(チーム配布)
MyProject)を作成0.xxxxxxxx... 形式)bws は Rust 製の単体バイナリ。winget には無いので
GitHub リリースからbws-x86_64-pc-windows-msvc-<version>.zip を取得し、%LOCALAPPDATA%\Programs\bws あたりに展開して PATH に追加する。
$dir = "$env:LOCALAPPDATA\Programs\bws"
New-Item -ItemType Directory -Force $dir | Out-Null
Invoke-WebRequest "https://github.com/bitwarden/sdk-sm/releases/download/bws-v2.1.0/bws-x86_64-pc-windows-msvc-2.1.0.zip" -OutFile "$env:TEMP\bws.zip"
Expand-Archive "$env:TEMP\bws.zip" $dir -Force
# PATH への追加(ユーザー環境変数)
[Environment]::SetEnvironmentVariable("Path",
[Environment]::GetEnvironmentVariable("Path","User") + ";$dir", "User")
トークンはファイルに書かず、ユーザー環境変数として保存する。
setx BWS_ACCESS_TOKEN "0.xxxxxxxx-xxxx-...."
EU サーバー契約の場合はサーバー URL の設定も必要:bws config server-base https://vault.bitwarden.eu
bws secret create KEY VALUE <プロジェクトID> を繰り返せばよい。
手元の .env から一括登録するならこんなワンライナーでも足りる
(本プロジェクトでは push/pull/diff できる補助スクリプトにした):
$pid_ = (bws project list | ConvertFrom-Json)[0].id
Get-Content .env | Where-Object { $_ -match "^\s*[^#].*=" } | ForEach-Object {
$k, $v = $_ -split "=", 2
bws secret create $k.Trim() $v.Trim() $pid_
}
登録が終わったら .env は削除する。ここがこの移行のゴール。
秘密が必要なコマンドに bws run -- を前置するだけ。プロジェクト内の全シークレットが
KEY 名の環境変数としてそのプロセス(とその子プロセス)にだけ注入される。
bws run -- py scripts/drive_sync.py # Google API を使うスクリプト
bws run -- docker compose up -d db # compose の ${VAR} 展開にも効く
値の確認・変更は Web Vault の GUI か CLI で:
bws secret list <プロジェクトID> # 一覧(値も表示されるので注意)
bws secret edit --value "新しい値" <シークレットID>
bws run は「環境変数を注入する」だけなので、アプリ側が環境変数を読めれば動く。
.env」の順に.env でも動く、という逃げ道が残る${POSTGRES_USER:-default} 形式の変数展開は、.env ファイルがbws run -- docker compose up でsetx した環境変数が見えないsetx は「これから新しく開くシェル」にしか効かない。設定後に同じウィンドウで
実行して「未設定です」と言われたら、ターミナルを開き直すか、現在のシェルに手で読み込む:
$env:BWS_ACCESS_TOKEN = [Environment]::GetEnvironmentVariable("BWS_ACCESS_TOKEN","User")
404 Not Foundbws secret create が [404 Not Found] Resource not found. で失敗する場合、
シークレットやプロジェクトが無いのではなく、マシンアカウントに書き込み権限が無い
のが原因のことが多い。Bitwarden は権限不足を(リソースの存在を隠すため)404 で返す。bws project list が通るのに create が 404 なら、まず権限を疑う。
bws run の引用符問題(Windows)bws run は受け取ったコマンドをシェル経由で再実行するため、bws run -- py -c "import os; ..." のような複雑な引用符は途中で剥がれて壊れる。
ワンライナーではなくスクリプトファイルにしてから bws run -- py script.py とするのが確実。
この構成で無くなるのは「秘密のディスク上の平文コピー」と「配布の属人化」。
一方で残るものもある:
BWS_ACCESS_TOKEN 自体はユーザー環境変数(レジストリ)に平文で残る。token_drive.json 等)のように、bws run は実行のたびに API へ取りに行くためオフラインでは動かない。.env を生成して、済んだら消す運用にする公式のベストプラクティスとしては、さらに
「マシンアカウントは用途(人・エージェント・CI)ごとに分ける」
「短命な用途のトークンには有効期限を付ける」が挙げられている。
.env の役割は「シークレット管理サービス + 実行時注入」で置き換えられるbws run -- を前置するだけで、setx 1回だけbws run の仕様・認証方法この記事をシェア
coiai
この記事もおすすめ
株式会社coiaiは、「想像できることを美しく実現」を掲げ、XR・Web・アプリ・システム開発およびDX支援を行う会社です。 創業2022年、東京都練馬区に本社を置き、要件のヒアリングからPoC(概念実証)、本番運用まで一貫して伴走します。 まずはお気軽にご相談ください。
主なご相談内容
詳しい会社情報は会社概要ページでご覧いただけます。