1Password CLIでDocker Composeのシークレットを守る方法 — op run・Connect・Environments使い分け【2026年版】
docker-compose.ymlにDB接続情報やAPIキーを平文で書きたくない人向け。1Password CLIのop run/op inject、Connect server、新機能Environmentsの使い分けと、個人プランの制約・Apple Siliconでの落とし穴まで実践的に整理した。
※ 本記事には1Passwordのアフィリエイトリンクが含まれています。記事内リンクから申し込みがあった場合、筆者に紹介報酬が発生します。内容は独自調査に基づいており、報酬によって評価が変わることはありません。 #PR
エンジニアのゆとです。
OrbStack + Docker Compose + Claude Codeの実践ワークフローを書いたとき、あえて触れなかった話がある。DBやRedisをdocker-composeで増やしていくと、必ず次にぶつかる問題——POSTGRES_PASSWORDやSTRIPE_SECRET_KEYをどこに書くか、だ。
docker-compose.ymlに直書きすればコミット事故のリスクがあるし、.envファイルに逃がしても結局は平文のテキストファイルがディスク上に転がる。Gitの管理外に置いたところで、バックアップやスクリーンショット、docker compose configの出力経由で漏れる経路は消えない。
1Password CLIでこの問題を解決する方法は以前書いたが、あれは単一プロセスにop runで環境変数を注入する話だった。docker-composeは複数サービスが絡む分、話がもう一段ややこしくなる。この記事では、docker-compose環境で1Passwordのシークレットを扱う4つの方法——op run、op inject、Connect Server、そして2026年に追加された新機能Environments——を実際のコマンドベースで整理する。
まず訂正しておきたい誤解 — op runはコンテナの中で動かすものではない
docker-composeと1Passwordを組み合わせようとして最初につまずくのが、この誤解だ。
「コンテナの中でopコマンドを叩いてシークレットを取得する」という設計を考えてしまいがちだが、これは筋が悪い。理由は2つある。
1つ目は認証の問題。1Password CLIのサインインはデスクトップアプリとの統合やTouch ID、あるいはService Accountトークンが前提になっていて、コンテナの中に持ち込むには結局それらの認証情報自体をコンテナに焼き込む必要が出てくる。シークレットを守るために置いた仕組みが、別のシークレット(1Password自体の認証情報)をコンテナイメージに埋め込む結果になっては本末転倒だ。
2つ目はそもそも設計思想の話で、op runは「指定したシークレットをロードし、プロセスの実行時間の間だけ環境変数として利用可能にしたサブプロセスでコマンドを実行する」ためのコマンドだ。つまり主役はホスト側のプロセスであって、コンテナの中身ではない。
正しいメンタルモデルはこうなる。
[ホスト] op run が Vault からシークレットを解決
↓ 環境変数として渡す
[ホスト] docker compose up がその環境変数を読む
↓ environment: セクションで${VAR}展開
[コンテナ] 解決済みの値だけが渡る(op自体はコンテナに一切入らない)
コンテナの中に1Password CLIをインストールする必要はない。むしろインストールしない方が安全、というのがこの記事全体を通じての前提になる。
個人プランでもすぐ使える方法 — op run —env-file
一番手軽で、個人プランでもそのまま使えるのがこの方法だ。
まず、シークレットの「参照」だけを書いたファイルを用意する。値そのものは書かない。
# secrets.env(このファイルはコミットしても実害がない——中身は参照だけ)
DATABASE_URL="op://Development/postgres/connection_string"
STRIPE_SECRET_KEY="op://Development/stripe/secret_key"
REDIS_PASSWORD="op://Development/redis/password"
op://Vault名/アイテム名/フィールド名という形式のURIで、1Password内の保管場所を指すだけのプレースホルダーだ。この状態でリポジトリにコミットしても、Vaultへのアクセス権がなければ何の値も引き出せない。
これをop run経由で解決しながらdocker compose upを実行する。
op run --env-file="./secrets.env" -- docker compose up -d
docker-compose.yml側は、ホストの環境変数を${VAR}で展開する標準的な書き方のままでいい。
services:
api:
image: my-api:latest
environment:
- DATABASE_URL=${DATABASE_URL}
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
worker:
image: my-worker:latest
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD}
op runがホスト側プロセスの環境変数としてDATABASE_URL等を展開してくれるので、Docker Composeの変数展開の仕組みに乗るだけで済む。特別な連携コードは要らない。

op injectを使う場合の注意点
op runの代わりにop injectでテンプレートから解決済みの.envファイルを生成する方法も、1Passwordコミュニティではよく紹介されている。
op inject -i secrets.env.tpl -o .env.resolved
docker compose --env-file .env.resolved up -d
ただしこの方法は「解決済みの平文シークレットを含むファイルをディスクに書き出す」という一手間が増える。書き出したファイルの削除を忘れる、パーミッションを絞り忘れる(デフォルトは0600だが上書き設定に注意)といった事故の余地が生まれるので、単一のdocker-compose起動が目的ならop run --env-fileで完結させた方がシンプルで安全だ。op injectが向いているのは、他のツールが「ファイルとしての.envしか受け付けない」制約がある場合に限る。
見落としがちな罠 — docker compose configで平文が見える
op runで渡した値は「プロセスの実行時間の間だけ」環境変数として存在する設計だが、これはあくまでホスト側のシェルプロセスの話だ。コンテナ側に渡った時点で、その値はDockerの通常の環境変数と何も変わらない。
つまり、コンテナが起動した後に次のコマンドを打てば、解決済みの値は普通に見える。
docker compose config # 展開後の設定を平文で表示
docker inspect my-api-container | grep -A 20 '"Env"'
これは1Passwordの欠陥ではなく、Dockerの環境変数がそもそもそういう仕組みだからだ。op runが守ってくれるのは「シークレットがリポジトリやディスク上のファイルに常駐しない」という部分までで、「起動中のコンテナの環境変数を誰かが覗く」リスクまでは守ってくれない。
同じホストに複数人がSSHでログインする共有VPS環境や、docker inspectの実行権限が広く配られている環境では、この前提を理解した上で権限設計をする必要がある。多人数が触るVPS上での1Password CLI運用はこちらの記事でも別の角度(認証まわり)から書いた。
機密性の高い値をどうしても「起動中のコンテナからも見えないようにしたい」場合は、environment:ではなく、Docker Composeのsecrets:機能でファイルとしてマウントし、アプリ側にファイルパスから読ませる設計に切り替えるのが筋がいい。op injectで一時ファイルに解決してマウントし、コンテナ終了後に消す運用と組み合わせる形になる。
チーム・本番向け — 1Password Connect ServerをDocker Composeでデプロイする
個人開発の範囲を超えて、複数のアプリ・サービスが動的にシークレットを取りに行く構成になると、op runを都度叩く方式は窮屈になってくる。ここで出てくるのがConnect Serverだ。
先に制約を書いておく。Connect ServerはSecrets Automationワークフローの一部で、1Password BusinessまたはTeamsプラン限定の機能だ。個人・Familyプランでは利用できない。この制約はService Accountsが個人プランで使えない話と同根で、1Passwordの開発者向け自動化機能はほぼ全て「チーム管理」を前提にした課金構造になっている。
Business/Teamsプランがある前提で、デプロイの流れは次のようになる。
- 1Password管理コンソールまたはCLIでSecrets Automationワークフローを作成すると、
1password-credentials.jsonが生成される - このファイルをConnect Serverの起動時にマウントする
- トークンを発行してREST API呼び出しに使う
op connect token create my-api-token --server my-connect-server --vault Development
docker-compose.ymlは公式が配布している構成に沿う形で、2つのイメージを組み合わせる。
services:
connect-api:
image: 1password/connect-api:latest
ports:
- "8080:8080"
volumes:
- ./1password-credentials.json:/home/opuser/.op/1password-credentials.json
- data:/home/opuser/.op/data
connect-sync:
image: 1password/connect-sync:latest
volumes:
- ./1password-credentials.json:/home/opuser/.op/1password-credentials.json
- data:/home/opuser/.op/data
volumes:
data:
起動するとlocalhost:8080にREST APIが立ち上がり、発行したトークンをOP_CONNECT_TOKENとして各アプリコンテナに渡せば、アプリ側からVaultの値をAPI経由で取りに行けるようになる。op runのようにホストで事前解決する方式と違い、アプリが起動中に動的に取りに行けるのが強みで、シークレットのローテーション頻度が高いチーム運用に向く。
記事が見つかりません:
2026年の新機能 — Environmentsをop run —environmentで使う
ここが競合記事があまり触れていない部分になる。2026年2月9日、1Password CLIにop environment readと、op run --environmentフラグが追加された。これは2025年10月に導入された「1Password Environments」という新しい仕組み——プロジェクト単位で環境変数一式をVaultとは別の専用スペースにまとめて管理する機能——をCLI・自動化ワークフローから直接読めるようにするアップデートだ。
使い方自体はop run --env-fileとほぼ同じ感覚で叩ける。
op run --environment blgexucrwfr2dtsxe2q4uu7dp4 -- docker compose up -d
Environment ID一つで、プロジェクトに紐づく環境変数一式をまとめて解決してくれる。個別のop://参照をsecrets.envに書き並べる手間が省け、ステージング用・本番用のEnvironmentを分けて--environmentの指定を切り替えるだけで環境ごとの構成を差し替えられる。
ただし公式ドキュメントには実務上ハマりやすい注意点が明記されている。
Apple Silicon Macでは起動時間が長くなる。ローカル開発でdocker composeを毎回起動するたびにop run --environmentを経由すると、起動のたびに数秒単位の待ち時間が乗ることになる。公式もこの点を認識していて、ローカル開発では代わりに「ローカルマウントの.envファイル」経由でEnvironmentsの値を使う方式を推奨している。つまり、docker-composeをホットリロードしながら頻繁に立ち上げ直すローカル開発ではop run --environmentを毎回叩くよりも、.envファイルへのインポートを一度済ませてから通常のdocker-compose運用に戻す方が実用的、ということになる。
もう一点、管理コンソールでのEnvironments設定自体にOwner・Administrator権限が必要な旨も明記されており、事実上Connect Serverと同様にチーム/Business運用を前提にした機能という位置づけだ。個人プランで検証しようとすると、この管理コンソール側の壁に先にぶつかる可能性が高い。
ベータ機能なので、本番の docker-compose 運用にいきなり組み込むよりは、まずステージング環境や検証用プロジェクトで挙動を確認してから採用を判断するのが無難だ。
結局どれを選べばいいか
用途別に整理するとこうなる。
- 個人開発・フリーランスでローカルのdocker-composeを動かすだけ →
op run --env-file一択。個人プランでそのまま使え、追加のインフラも要らない - 複数サービスが動的にシークレットを取りに行くチーム構成、シークレットのローテーションが頻繁 → Connect Server(Business/Teams必須)
- CI/CDのビルドパイプラインでdocker imageをビルドする際にシークレットが要る → Service Accountトークンを
OP_SERVICE_ACCOUNT_TOKENとして渡す構成。この話は1Password + GitHub Actions + Claude Codeの記事で別途書いた - プロジェクト単位で環境変数一式をまとめて管理したい、最新機能を試したい → Environments。ただしローカル開発でのApple Silicon起動遅延と管理コンソール権限の制約は事前に把握しておく
自分は今のところ個人開発のdocker-compose環境ではop run --env-fileだけで困っていない。Environmentsは面白い機能だが、ローカルで毎回叩くには少し重く、現状は本番寄りの構成向けだと感じている。
関連記事



FAQ
Q1. op runをコンテナの中にインストールして使ってはダメですか?
動かないわけではないが推奨しない。コンテナ内で認証するには1Passwordの認証情報自体をコンテナに持ち込む必要があり、シークレットを守るための仕組みが別のシークレット漏洩経路を作ってしまう。op runはホスト側で解決し、結果だけをコンテナに渡す設計が前提になっている。
Q2. op run —env-fileで渡したシークレットは、コンテナが起動した後も安全ですか?
「ディスクにファイルとして残らない」という意味では安全だが、起動中のコンテナの環境変数自体はdocker inspectやdocker compose configで普通に見える。これはDockerの環境変数機構そのものの仕様であり、1Passwordの制約ではない。より厳密に隠したい値はenvironment:ではなくsecrets:機能でファイルマウントする設計に切り替える。
Q3. Connect ServerとEnvironments、Service Accountsの違いがよくわかりません。
ざっくり言うと、Connect Serverは「アプリが動的にAPI経由でシークレットを取りに行く」ための自社ホスト型REST API、Service Accountsは「CLI/自動化がヘッドレスで認証する」ための認証方式、Environmentsは「プロジェクト単位で環境変数一式をまとめて管理する」新しい保管の仕組み。3つとも個人・Familyプランでは使えず、Business/Teams以上を前提にしている点は共通する。
Q4. 個人プランのまま、Environmentsだけ試すことはできますか?
管理コンソールでの設定にOwner・Administrator権限が必要と公式ドキュメントに明記されており、個人プランでの検証は難しい可能性が高い。試すならBusiness/Teamsのトライアル環境で挙動を確認するのが確実だ。