1PasswordのCLIを使って、環境変数の安全な管理ができるようになった。さらに、1Passwordの値を直接読み取って、docker composeも実行できるようにした。
TL;DR
- 1Passwordに現在の環境変数をインポートする
- 手動でもできるが、opコマンド(1PasswordのCLI)を使うと楽
- .env.localから1Passwordの値を書き換える
OP_ROOT_ENV_PATH="hoge-vault/local/root-env"
MYSQL_ROOT_PASSWORD="op://${OP_ROOT_ENV_PATH}/MYSQL_ROOT_PASSWORD"
MYSQL_DATABASE="op://${OP_ROOT_ENV_PATH}/MYSQL_DATABASE"
- .envから1Passwordの値を読み込める形でdocker composeを実行する
cp .env.local .env && \
op run --env-file="./.env" -- docker compose up -d && docker compose ps
はじめに
ローカル環境変数の値を.env.localにベタ書きしていたが、git管理されてしまうため、セキュリティ上の問題がある。以前勤務していた会社では、
- 社内wikiの記述や特定の管理者のみが管理
- 必要になればslackのDMでのやりとり
- サーバーで直接環境変数を設定する
とかなり手間をかけて環境変数を扱っていた。セキュリティや事故防止を考えれば苦肉の策だったかもしれないが、当時の自分にもいい代替案は提示できなかった。
その後転職先で1Passwordを知った。家族との諸々のアカウント共有にも便利で家庭内でも導入した。いろいろ試しているうちに、開発にも利用できることがわかったため、さっそく導入してみた。
移行前の状況
環境変数
.env.localにベタ書きで保持されている
# MySQL 環境変数
MYSQL_ROOT_PASSWORD=hogeroot
MYSQL_DATABASE=hogedb
MYSQL_DATABASE_TEST=test_hoge
MYSQL_USER=hogedb
MYSQL_PASSWORD=hogepassword
コンテナ起動コマンド
.env.localを.envにコピーして、コンテナを起動
cp .env.local .env && docker compose up -d && docker compose ps
1Passwordの開発者設定
下記の記事を参考にした。
1Password>設定>開発者で
1Password CLIと連携
にチェックを入れる
現行の.envの内容を1Passwordにインポートする
vault、セクション、環境の構成を決める
私は下記の構成にした。
- vault: hoge-vault
- アイテムタイプ: セキュアノート
- アイテム名: local(環境)
- セクション: root-env
他の記事を見ると、環境変数ごとにアイテムを作成し、セクションと環境を割り当てる方法もあるようだ。
vault、アイテムを作成する
現行の.envから、opコマンドを作成する
.env.localから各環境変数ごとのopコマンドを作成するために、雛形用ファイルを作成する。
cp .env.local .env_to_op_command
VSCodeの置換機能を使って、各環境変数ごとのopコマンドを作成する。下記の置換方法は一例だ。作成したコマンドや.envの内容によって、置換方法は異なる。
検索:
^(.+)$
置換:
op item edit --vault hoge-vault local root-env.$1
op item edit --vault hoge-vault local root-env.MYSQL_ROOT_PASSWORD=hogeroot
op item edit --vault hoge-vault local root-env.MYSQL_DATABASE=hogedb
op item edit --vault hoge-vault local root-env.MYSQL_DATABASE_TEST=test_hoge
op item edit --vault hoge-vault local root-env.MYSQL_USER=hogedb
op item edit --vault hoge-vault local root-env.MYSQL_PASSWORD=hogepassword
作成したコマンドをターミナルにコピペして実行すると、1Passwordに.env.localの内容がインポートされる。
インポートが確認できたら、.env_to_op_commandは削除する。
現行の.env.localが1Passwordの値を読み取れるようにする
1Passwordの秘密参照を.env.localに書き換える
1PasswordのセクションまでのパスをOP_ROOT_ENV_PATHとして設定する。まずVSCodeの置換機能を使って、既存の.env.localの値を書き換える。
検索:
^(.+?)=(.+)$
置換:
$1="op://${OP_ROOT_ENV_PATH}/$1"
# MySQL 環境変数
MYSQL_ROOT_PASSWORD="op://${OP_ROOT_ENV_PATH}/MYSQL_ROOT_PASSWORD"
MYSQL_DATABASE="op://${OP_ROOT_ENV_PATH}/MYSQL_DATABASE"
MYSQL_DATABASE_TEST="op://${OP_ROOT_ENV_PATH}/MYSQL_DATABASE_TEST"
MYSQL_USER="op://${OP_ROOT_ENV_PATH}/MYSQL_USER"
MYSQL_PASSWORD="op://${OP_ROOT_ENV_PATH}/MYSQL_PASSWORD"
1Passwordの秘密参照を取得
1PasswordのGUIで、各変数の値を右クリックし、秘密参照をコピーを選択して、秘密参照を取得する。"op://hoge-vault/local/root-env/MYSQL_ROOT_PASSWORD"のような形式だ。
.env.localに上記1Password秘密参照のセクション部分までを変数として設定する。
# 1Passwordのパス
OP_ROOT_ENV_PATH="hoge-vault/local/root-env"
# MySQL 環境変数
MYSQL_ROOT_PASSWORD="op://${OP_ROOT_ENV_PATH}/MYSQL_ROOT_PASSWORD"
MYSQL_DATABASE="op://${OP_ROOT_ENV_PATH}/MYSQL_DATABASE"
MYSQL_DATABASE_TEST="op://${OP_ROOT_ENV_PATH}/MYSQL_DATABASE_TEST"
MYSQL_USER="op://${OP_ROOT_ENV_PATH}/MYSQL_USER"
MYSQL_PASSWORD="op://${OP_ROOT_ENV_PATH}/MYSQL_PASSWORD"
補足
ここでOP_ROOT_ENV_PATHは文字列として扱いたいので、op://をつけない。
もし、
OP_ROOT_ENV_PATH="op://hoge-vault/local/root-env"
とop://をつけると、1Passwordの読み込みが始まってしまう。
公式ドキュメント
によれば、秘密参照のルールは
op://<vault-name>/<item-name>/[section-name/]<field-name>
となっているが、上記例ではセクション名のroot-envで終わっている。
そのためエラーが出てしまうので、op://をつけないようにする。
1Password CLI起点のdocker composeコマンドを作成
既存のコマンドは
cp .env.local .env && docker compose up -d && docker compose ps
となっているが、このまま実行すると、.envで1Passwordの値を読み取れない。そのため、1Passwordの値を読み取れるように、docker composeコマンドを修正する。
op runオプションの追加
を参考に下記のオプションを利用する
-
--env-file="./.env"- 環境変数を読み取るファイルを相対パスで指定する
-
--- 1Passwordの環境変数をロードして実行したいコマンドを指定する
上記を使い、元のコマンドを下記のように修正する。
- 1Passwordの環境変数をロードして実行したいコマンドを指定する
cp .env.local .env && \
op run --env-file="./.env" -- docker compose up -d && docker compose ps
これで、1Passwordに格納されている値を利用して、コンテナ実行を行うことが可能となった。
今後やってみたいこと
1Passowrd Service Accountの導入
公式ドキュメントを読んでいると、
We recommend using 1Password Service Accounts to follow the principle of least privilege. Service accounts support restricting 1Password CLI to specific vaults, so that processes in your authorized terminal session can only access items required for a given purpose.
最小限の権限の原則に従うために、1Passwordサービスアカウントを使用することをお勧めします。サービスアカウントは、1Password CLIを特定のVaultに制限することをサポートします。したがって、承認されたターミナルセッション内のプロセスは、特定の目的に必要なアイテムにのみアクセスできます。
とあった。個人開発のローカル環境作成だと大げさかもしれないが、web公開する場合は導入してみたい。
またこれを利用すれば、理屈上実際の値を意識、一切利用しない開発が可能になるかもしれない
.env.localの環境変数をまとめる
# MySQL 環境変数
MYSQL_ROOT_PASSWORD="op://${OP_ROOT_ENV_PATH}/MYSQL_ROOT_PASSWORD"
MYSQL_DATABASE="op://${OP_ROOT_ENV_PATH}/MYSQL_DATABASE"
MYSQL_DATABASE_TEST="op://${OP_ROOT_ENV_PATH}/MYSQL_DATABASE_TEST"
MYSQL_USER="op://${OP_ROOT_ENV_PATH}/MYSQL_USER"
MYSQL_PASSWORD="op://${OP_ROOT_ENV_PATH}/MYSQL_PASSWORD"
の書き方であれば、これらの値は環境を意識する必要がないので.env.localからは切り離し、
環境を切り替える仕組みは
# 1Passwordのパス
OP_ROOT_ENV_PATH="hoge-vault/local/root-env"
だけに集約できないかなと考えている
