Claude Codeに1Passwordのシークレットを渡す2つの方法 ── 生体認証とサービスアカウントの使い分け

Claude Code × 1Password ── 指紋認証をするノートPCと、Devと書かれた金庫にAPIキーが収められているイラスト
目次

承認待ちで止まった

Claude Code に作業を任せて席を離れたら、進んでいませんでした。1Password の承認ダイアログが出たまま、待っていたのです。

私は 1Password CLI(op)でシークレットを管理しています。生体認証でアプリと連携する構成は、人間が使うぶんには快適でした。ところが Claude Code に op を実行させると、私の環境ではそのたびに承認を求められました。

この記事は、その経験から開発専用の Vault「Dev」とサービスアカウントに切り替えた判断の記録です。設定手順の網羅ではなく、何を守って何を諦めたかを書きます。

Claude Code 時代の .env の問題

私がまず意識していたのは、.env を Git に入れないことでした。読むのは自分と、権限を絞った CI だけだったので、それで足りていました。

Claude Code はプロジェクトのファイルを読みます。.gitignore に入れていても、エージェントが cat .env すればその時点でコンテキストに乗ります。ツールへの入力や出力に含まれれば、MCP サーバーやサブエージェントにも渡ります。

守る相手が「Git」から「自分が動かしているエージェント」に変わった。これが前提です。

1Password CLI の基本

op では、値の代わりに op://Vault名/アイテム名/フィールド名 という参照を書き、実行時に本物の値へ置き換えます。

# .env には参照だけ書く(このファイルは平文のキーを含まない)
WP_APP_PASSWORD=op://Dev/kwrkb-wp-mcp/credential

# 実行時に注入
op run --env-file=.env -- node server.js

op run 自体は平文の .env を生成せず、起動するプロセスへ環境変数として渡します。標準出力・標準エラーに出た値は既定でマスクされます。ただし、起動先のプロセス自身は値を普通に使えますし、起動先が値をファイルやログへ書き出すことまでは防ぎません。

つまり op run は、実行プロセスからシークレットを隠す仕組みではありません。 隠れるのは「ファイルとしての平文」だけです。

私が使い分けた2つの認証方法

op が 1Password にアクセスするには認証が必要です。ここでは私が使った2つを扱います。

生体認証(デスクトップアプリ連携) サービスアカウント
認証 指紋・Windows Hello で承認 トークンで自動
取得できる範囲 自分のアカウント全体 指定した Vault のみ
無人実行 承認する人が必要 可
誰がゲートか 人間の承認 Vault と接続先の権限

生体認証パターン:人間の承認が挟まる

デスクトップアプリ連携を有効にすると、op がアカウントへアクセスするときにアプリ側で承認を求められます。承認するまで処理は進みません。

私の環境では、Mac でも Windows でも、Claude Code から op を実行するたびに承認を求められました。ただし、これはすべての環境で毎回承認が必要という意味ではありません。公式の仕様では、承認は1アカウント単位でターミナルセッション内に保持され、10分間操作がないと切れます。macOS・Linux では同じターミナルのサブシェルにも承認が及び、Windows ではサブシェルで別の承認が必要とされています。承認の引き継ぎ方は OS や実行方法で異なります。

なお WSL では、この構成をそもそも使っていません。1Password のアプリは Windows 側で動いているため、生体認証で連携するには Windows 側の op.exe を呼ぶ形になります。実際に試したところ、op.exe run -- node server.js のように書くと、起動されるのは WSL の node ではなく Windows 側の node でした。WSL に入れたツールチェーンで動かしたいのに、実行環境が Windows にすり替わってしまいます。これでは使いものにならないので、WSL には Linux 版の op を入れ、最初からサービスアカウントで動かしています。

注意したいのは、承認されるのはアカウントへのアクセスであって、個々の操作内容を毎回確認する仕組みではないことです。それでも、短い対話的な作業なら人間の承認を挟む構成で十分でした。

サービスアカウントパターン:無人実行のための選択

問題は、人間が PC の前にいない状況です。私の場合、2つあります。

  • kurabebako のネタ探しを定期実行する:タスクスケジューラで動かすので、承認する人がいません
  • 外出先から自分の PC に繋ぎ、WordPress MCP で記事を操作する:操作しているのは自分ですが、指紋を当てる手は PC の前にありません

後者は見落としがちです。リモートでエージェントを動かすということは、自分が操作していても、実行先としては無人だということです。

承認する人がいない以上、生体認証は成立しません。私の無人実行ではサービスアカウントを選びました。トークンを環境変数 OP_SERVICE_ACCOUNT_TOKEN に入れておけば、op は承認なしで動きます。

# サービスアカウントで動いていることを確認
op whoami

Vault「Dev」で取得できる範囲を絞る

承認というゲートを外す代わりに、サービスアカウントに見せる範囲を Vault で絞ります。

  1. 開発専用の Vault「Dev」を作る
  2. サービスアカウントを発行するとき、Dev だけにアクセス権を与える。取得が目的なら読み取りのみを基本にする
  3. Dev に入れるのは、Claude Code に実際に使わせるキーだけ

サービスアカウントからは、権限のない Vault は見えません。Dev に入れるものを絞ることで、トークンが漏れた場合に取得されるシークレットを限定できます。銀行やメインのパスワードは Dev に入れないので、トークンごと漏れても届きません。

ただし、取得した先で何ができるかは別の話です。Dev 内の WordPress 用認証情報が記事の削除まで許すなら、その操作による被害は Vault では防げません。取得範囲は Vault で、取得したキーでできることは接続先の権限で、それぞれ絞る必要があります。

トークンの置き場所(Mac・Windows・WSL)

サービスアカウントトークンは、OS ごとに置き場所を変えています。

  • Mac:キーチェーン
  • Windows:資格情報マネージャー
  • WSL:~/.zsh_secret に書いて .zshrc から読み込む

WSL では利便性を優先し、平文ファイルに保存しています。資格情報マネージャーは Windows 側にあり、WSL から呼ぶには一手間かかります。毎日使うものとしては不便が勝ちました。chmod 600 とリポジトリからの除外はしていますが、同じユーザーで動くプロセスからは読めます。

ここで分けて考えたいことがあります。私の構成では、Claude Code が実行するシェルからもトークンを利用できます。つまりエージェントからトークンを秘匿する設計にはなっていません。 別プロセスや別ユーザーで分離する余地はありますが、私はそこまでしていません。

一方で、保存方法の違いは別の場面で残ります。バックアップ、ファイルの持ち出し、誤って共有したとき、平文ファイルはそのまま流出します。WSL の妥協はエージェントに対する防御とは無関係ですが、保存時の保護には妥協が残っています。だからこそ、トークンのアクセス範囲を絞って運用しています。

秘匿に頼らず、範囲で決める

ここまでをまとめると、今回の構成の考え方はこうなります。

  1. 私の構成では、トークンをエージェントから秘匿していない
  2. 防御線は Vault の範囲と接続先の権限
  3. だから Dev には「本当に使うもの」しか入れず、各キーの権限も絞る

Dev に入れる前に、キーごとに「漏れたら何が起きるか」を一度考えておくと判断しやすくなります。

  • 利用上限や支出上限を API 側で設定できるか
  • 失効・再発行がすぐできるか
  • 本番環境や決済に届くキーではないか

失効しても、それまでに行われた操作や取得されたデータは元に戻りません。この基準で見て迷うキーは、Claude Code に渡す設計そのものを見直すべきだと思います。

まとめ

今回の構成では、トークンの秘匿に頼らず、Vault と接続先の権限を絞ることで被害を限定しています。生体認証は人間の承認が挟まるぶん安心ですが、定期実行やリモート操作のように承認する人がいない場面では成立しないため、私はサービスアカウントを選びました。

ただし、保存時の保護は別の問題です。WSL の平文保存には妥協が残っており、ここは利便性との折り合いとして意識的に受け入れています。

参考

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次