1Password の CLI で環境変数を管理する
はじめに
現代のアプリケーションは外部サービスのAPIキーなど様々なクレデンシャルを持つことが多いです。
これらを開発者間で安全に共有するには sops、 doppler、 git-crypt などのツールが使えます。
また、開発時はこれらのクレデンシャルを direnv などを使って環境変数に設定することも多いのではないでしょうか。
しかし、これらはどれも追加のツールをインストールする必要があります。
もし1Passwordを使っているチームに属しているなら1Passwordでクレデンシャルを管理して、それを環境変数にセットできると新たなツールを導入する必要がなくて楽です。
この記事ではそれを実現する手順を紹介します。
CLIの設定
まず1PasswordのCLIをインストールします。これで op
コマンドが使えるようになります。
brew install --cask 1password/tap/1password-cli
op signin
コマンドでサインインをすると、セッションを export
するコマンドが出力されるのでそれを eval
します。
これが成功すると1Passwordの認証が済んだ状態になって、各アイテムにアクセスできます。
eval $(op signin)
変数の設定
foo-vault
という保管庫に foo-item
というタイトルのセキュアノートを作る際は以下のコマンドを実行します。
op item create --vault foo-vault --title foo-item --category 'Secure Note'
例として環境変数を2つ追加します。
ここでは foo-section
というセクションに値を追加することにします。セクションは省略可能ですが、省略した場合は自動でランダムな名前が付きます。
op item edit --vault foo-vault foo-item foo-section.FOO=bar
op item edit --vault foo-vault foo-item foo-section.FIZZ=buzz
ここでは op item edit
コマンドを使用しましたが、もちろんGUI上から設定しても良いです。
1Password上では以下の画像のように表示されます。FIZZ
だけ Reveal
しています。
変数の参照
例えば foo-vault
という保管庫に foo-item
という名前のアイテムがある場合は op item get --format json --vault foo-vault foo-item
というコマンドで以下のような JSON を取得できます。
{
"id": "XXXXXXXXXXXXXXXX",
"title": "foo-item",
"version": 4,
"vault": {
"id": "XXXXXXXXXXXXXXXX",
"name": "foo-vault"
},
"category": "SECURE_NOTE",
"last_edited_by": "XXXXXXXXXXXXXXXX",
"created_at": "2023-01-05T23:03:45Z",
"updated_at": "2023-01-05T23:05:14Z",
"sections": [
{
"id": "XXXXXXXXXXXXXXXX",
"label": "foo-section"
}
],
"fields": [
{
"id": "notesPlain",
"type": "STRING",
"purpose": "NOTES",
"label": "notesPlain",
"reference": "op://foo-vault/foo-item/notesPlain"
},
{
"id": "XXXXXXXXXXXXXXXX",
"section": {
"id": "XXXXXXXXXXXXXXXX",
"label": "foo-section"
},
"type": "CONCEALED",
"label": "FOO",
"value": "bar",
"reference": "op://foo-vault/foo-item/foo-section/FOO"
},
{
"id": "XXXXXXXXXXXXXXXX",
"section": {
"id": "XXXXXXXXXXXXXXXX",
"label": "foo-section"
},
"type": "CONCEALED",
"label": "FIZZ",
"value": "buzz",
"reference": "op://foo-vault/foo-item/foo-section/FIZZ"
}
]
}
jq
コマンドでいい感じにクエリしたりフォーマットすることによって .env
ファイルを作ったり、 GitHub Actions にこの設定を同期したりするすることが可能です。
.env
ファイルを作る例:
op item get --format json --vault foo-vault foo-item | jq -r '.fields[] | select(.value) | (.label) + "=" + (.value)' > .env
GitHub Actions にこの設定を同期する例:
eval $(op item get --format json --vault foo-vault foo-item | jq -r '.fields[] | select(.value) | "gh secret set " + (.label) + " -b \"" + (.value) + "\""')
secret reference
op
コマンドでは secret reference と呼ばれる以下のような構文が使えます。
先程の op item get
コマンドの出力に含まれる reference
というフィールドがそれです。
op://vault-name/item-name/section-name]field-name
この secret reference を op read
コマンドに渡すことによって、値を1つだけ取り出すことができます。
$ op read op://foo-vault/foo-item/foo-section/FOO
bar
.env ファイルを生成するアプローチ
op read
コマンドを活用すると色々なことができますが、ファイルの一部分に 1Password 上の値を埋め込みたいだけであれば op inject
コマンドを使うと便利です。
op read
コマンドと同様に secret reference が使用できます。
$ cat .gitignore
.env
$ cat .env.template
HOGE=op://lambdasawa-sandbox/op-cli/default/HOGE
$ op inject -i .env.template -o .env
$ cat .env
HOGE=hogehogehoge
op inject
コマンドは .env
のフォーマットに限らず、 YAML や JSON などのファイルに対しても使用できます。
環境変数設定済みのシェルを立ち上げるアプローチ
op inject
コマンドでファイルに値を埋め込むことができるので、 op run
コマンドと direnv
などの仕組みを使って 1Password の値を環境変数に埋め込むことができます。
しかし op run
コマンドを使うと direnv
などに依存せずに環境変数を設定することができます。
$ cat .env.template
FOO=op://foo-vault/foo-item/foo-section/FOO
# このシェルでは環境変数が未設定なので何も出力されない
$ echo $FOO
# このコマンドで環境変数が設定された状態で bash が起動する
$ op run --env-file=.env.template --no-masking bash
# 環境変数が取れることが確認できる
$ echo $FOO
bar
$ exit
exit
# exit したら未設定の状態の戻るので何も出力されない
$ echo $FOO
Discussion