macOS で SSH した Claude Code が未ログインになる|keychain 解錠の解決策
最近、自宅の mac mini で長時間動かしたいジョブをいくつか走らせるようになり、ノート PC から SSH で操作する機会が増えました。ところがリモート側で Claude Code を起動すると、毎回 /login を要求されます。前夜に mac mini の Terminal でログインして使い終わったばかりなのに、です。SSH 経由で tmux attach して元の session に戻った場合にも、同じ未ログイン状態に出会うことがあります(純粋な SSH より頻度は低いものの、確実に起きます)。最初は Claude Code のバグかと思ったのですが、何度か検証した結果、security unlock-keychain を 1 回打てば直ることがわかりました。これは Claude Code の問題ではなく、macOS の login keychain の挙動特性で、Keychain にトークンや認証情報を保存するすべてのツールで起こり得ます。
結論:1 行で解決
mac に SSH した後、下記コマンドを実行します。ログインパスワードを聞かれるので入力すれば解錠完了、その後 Claude Code を起動し直せば /login を要求されずにそのまま使えます。
# 現在のユーザーの login keychain を解錠
security unlock-keychain ~/Library/Keychains/login.keychain-db
# パスは省略可能。デフォルトが login keychain
security unlock-keychain
現在の状態を確認したい場合は、security show-keychain-info でアイドル自動ロック秒数を、security list-keychains で現在マウントされている keychain を確認できます。
なぜ SSH すると起きるのか
macOS の login keychain は暗号化ファイルで、各種アプリが書き込んだパスワード・トークン・証明書が格納されています。暗号化鍵はユーザーのログインパスワードなので、内容を読み書きするには事前に「解錠」が必要です。解錠が起きるタイミングは通常、Mac の前で画面ログインしたとき。loginwindow が同じパスワードで login keychain を自動的に解錠してくれます。その後、ログアウトせず、自動ロックも発動しなければ、同じユーザーが起動したあらゆるプロセスが Keychain Services API 経由で内部のデータを読めます。
問題は SSH が loginwindow を経由しない ことです。sshd は PAM でアカウントとパスワード(または公開鍵)を検証した後、そのまま shell を開きます。途中で keychain を解錠する処理は一切走りません。そのため SSH session のユーザー身元は正しいものの、Claude Code が keychain からログイントークンを読もうとしても keychain がロックされていて読めない、という状態になります。表面的な症状が「再ログインを要求される」というわけです。
tmux が 時々 影響を受ける理由:tmux server は常駐プロセスで、通常は最初に GUI Terminal で起動したものです。そのときには keychain がすでに解錠されていたため、別の場所から attach し直した session も解錠状態を引き継げます。ただし途中で keychain がロックされた場合 — show-keychain-info の秒数を超えてアイドルした、手動でロックした、設定によってはスリープ時にロックされた、tmux server 自体が再起動された、といったケース — 再 attach 時には純粋な SSH と同じくトークンが読めなくなります。
なぜ security unlock-keychain が効くのか
security は macOS 内蔵の Keychain Services 操作 CLI で、unlock-keychain は指定した keychain(デフォルトは login keychain)をパスワードで解錠します。解錠は プロセス間共有の状態 で、現在の shell だけに有効ではなく、「現在のユーザー」のその後のすべてのプロセスに対して有効になります。SSH session で解錠してから起動した Claude Code がトークンを読めるのは、このためです。
関連コマンドをいくつか:
# keychain の自動ロック設定(秒数、スリープ時ロックの有無)を確認
security show-keychain-info ~/Library/Keychains/login.keychain-db
# アイドル自動ロックを 2 時間に、スリープ時はロックしないように
security set-keychain-settings -t 7200 ~/Library/Keychains/login.keychain-db
# 反対に手動でロックする
security lock-keychain ~/Library/Keychains/login.keychain-db
# -p でパスワードを直接渡す(shell history に残るので非推奨)
security unlock-keychain -p 'your-password' ~/Library/Keychains/login.keychain-db
-p に平文パスワードを渡すのは危険です。shell history にもプロセスリストにも残るので、対話入力か、権限保護されたファイルから読み込んで stdin で渡すスクリプトでラップするのが無難です。
Claude Code だけではない
login keychain にトークン・パスワード・認証情報を保存するツールは、SSH や keychain がロックされた tmux session で同じ症状を出す可能性があります。下表に踏みやすいツールをまとめておきます。同じ問題を Google 検索で探している人がたどり着けるようにという意図もあります。
| ツール / シーン | ロック時の症状 | 備考 |
|---|---|---|
| Claude Code | 起動時に /login 表示、または agent の API 呼び出しが直接 401 | トークンは login keychain に格納 |
| GitHub CLI(gh) | gh auth status が not logged in、gh auth token が取れない | --secure-storage 利用時または macOS デフォルト |
| git + osxkeychain helper | HTTPS push/pull のたびにパスワードを聞かれる | git config --global credential.helper osxkeychain |
Docker Desktop / docker login | docker pull でプライベートイメージが 401 unauthorized | credentials store が osxkeychain 経由 |
| AWS CLI / aws-vault | profile の credentials が見つからない、MFA トークンが読めない | aws-vault は keychain をデフォルト backend に |
| npm / yarn / pnpm | npm publish が 401、registry auth token が読めない | keytar 経由の Electron ツール全般で同様 |
| 1Password CLI(op) | session 失効、生体認証で解錠不可 | biometric unlock は GUI の補助が必要 |
| Xcode codesign / notarytool | 署名や公証時に開発者証明書が見つからない、errSecInternalComponent | CI が SSH ビルドする場面で頻発 |
| fastlane match | 証明書のインポート失敗、繰り返しパスワードを要求される | 公式ドキュメントは CI で先に unlock-keychain を推奨 |
| VS Code / Cursor Remote-SSH | GitHub・Copilot・同期ログイン状態が消える | リモート側の Electron が keychain を読めない |
| その他 Electron CLI(keytar) | 多種多様なトークン失効 | pnpm、Slack CLI、Firebase CLI など |
長期的な対策
便利な alias を作る
タイプ量を減らしたいだけなら ~/.zshrc に追加して、必要なときに手動で解錠するだけで十分です:
alias unlock='security unlock-keychain ~/Library/Keychains/login.keychain-db'
自動ロック時間を伸ばす
mac mini が個人専用の社内ネットワーク機器なら、アイドルロック時間を伸ばすか、スリープ時ロックをオフにすることで発生頻度を下げられます。セキュリティとのトレードオフなので、共用環境では避けてください。
# -t 秒数:何秒アイドルしたらロックするか。-l なしでスリープ時ロックなし
security set-keychain-settings -t 28800 ~/Library/Keychains/login.keychain-db
Mac を GUI ログイン状態に保つ
Mac をサーバー的に使う場合、「システム設定 → ユーザ」で自動ログインをオンにしておくと、loginwindow が起動時に login keychain を解錠してくれて、その後のすべての SSH session が解錠状態を共有できます。画面ロックと keychain ロックはデフォルトでは別物ですが、アイドル秒数とスリープ設定は相互に影響するので、上の set-keychain-settings と組み合わせるとより安定します。
SSH 時に自動解錠する(要注意)
~/.zprofile 内で expect や権限保護されたファイルから読み込んで自動解錠することもできます。ただしこれはログインパスワードをディスクに置くのと等価で、リスクは keychain がもともと守ろうとしていたものと同じです。実用上は、強くコントロールされた個人専用機でない限り推奨できません。実際に使った折衷案は、別マシン上の 1Password にパスワードを保存し、SSH 時に op read で取り出して security unlock-keychain に pipe する方法。パスワードはメモリ上を一瞬通るだけになります。
まとめ
ひとことで:login keychain は GUI ログインでしか自動解錠されず、SSH では解錠されない。macOS Keychain にトークンや認証情報を保存するツールはすべて、SSH や一部の tmux session で「未ログイン/認証情報失効」として現れる可能性があります。遭遇したらまず security unlock-keychain、そして自動ロック時間の調整や自動ログインなどを組み合わせて発生頻度を下げます。tmux session の仕組みについてさらに知りたい場合は、以前書いた tmux ターミナル多重化チュートリアル(繁體中文)も参考にどうぞ。