Claude Media
sshHostAllowlistでClaude Code DesktopのSSH接続先を制限する

sshHostAllowlistでClaude Code DesktopのSSH接続先を制限する

sshHostAllowlistはClaude Code DesktopのSSHセッションを許可ホストだけに絞るmanaged設定です。書き方とパターンの一致規則、CLIには効かない適用範囲をまとめます。

sshHostAllowlistは何を止めて何を止めないか

sshHostAllowlistは、Claude Code DesktopのSSHセッションが接続できるホストを、管理者が許可したパターンだけに絞るmanaged設定です。許可パターンを配ると、ユーザーは解決後のホスト名がパターンに一致するホストにしか接続できません。空配列を配った端末では、SSHセッション機能そのものが止まります。

DesktopのSSHセッションでは、接続先のマシン上でClaudeがファイルを編集し、コマンドを実行します。接続先を管理対象のサーバーに限りたいときに使うのがこの設定です。

一方で、止まる範囲は広くありません。「CLIにも効くはず」「Bashツールのsshも止まるはず」という前提で配ると、制限が空振りします。適用範囲から先に押さえます。

SSH接続そのものの追加方法や認証まわりはClaude Code SSH接続ガイドにあります。ここでは、管理者が配るこの設定に絞ります。

効く範囲は狭い — Desktopアプリの接続先選択だけ

適用範囲

sshHostAllowlistが届く場所と届かない場所

  • 届く: Desktopアプリ

    Desktopアプリが開くSSHセッションの接続先です。手元の端末のmanaged settingsから読まれます。

  • 届かない: CLIとIDE拡張

    ターミナルのclaudeコマンドとIDE拡張は、このキーを読みません。

  • 届かない: Bashツールのssh

    セッション内でBashツールが実行するsshコマンドは制限の対象外です。

ターミナル中心のチームがこの設定を配っても、CLI側の接続は何も変わりません。Claude Codeのセッション内でssh some-hostを実行すれば、許可リストの外にも届きます。

この設定が制御するのは、Desktopアプリがどのホストへ接続するかです。ネットワークの出口(egress)は制御しません。強い境界が必要なら、組織のネットワーク制御やゼロトラストの仕組みを併用する前提で設計します。

設定手順 — managed settingsに配列を書く

手順

許可リストを配る手順

  1. 1

    許可するホスト名を洗い出す

    接続を許すホストを、ホスト名ベースでまとめます。サブドメイン単位で許すならワイルドカード、1台だけなら完全一致で書きます。

  2. 2

    managed settingsに書く

    ユーザー設定やプロジェクト設定に書いても読まれません。sshHostAllowlistはmanaged settings専用のキーです。

  3. 3

    手元の端末で動作を見る

    配布後は、Desktopの環境ドロップダウンからSSH接続を選び、許可したホストに入れて、許可外のホストが拒否されることを確かめます。

書き方は次のとおりです。

{
  "sshHostAllowlist": ["*.devboxes.example.com", "bastion.example.com"]
}

この例が許すのは、devboxes.example.comとその配下のサブドメインすべて、それにbastion.example.comの1台です。キーを置かなければ既定は未設定で、どのホストにも接続できます。つまり、設定を配り忘れた端末は、制限なしの状態のままです。

配列を空にすると意味が変わります。"sshHostAllowlist": []は「許可ホストなし」ではなく、SSHセッションを丸ごと無効にする指定です。段階的に絞る途中で仮の空配列を置くと、SSH経由で開発している人の作業が止まります。

パターンの一致規則 — 判定されるのは解決後のHostName

パターンの型は3つで、大文字小文字は区別されません。

  • *: 任意のホストに一致する(制限なしと同じ効果)
  • *.example.com: example.com自体と、配下のすべてのサブドメインに一致する
  • それ以外: ホスト名との完全一致

次の表は、["*.devboxes.example.com", "bastion.example.com"]に対する判定を、型の規則どおりに当てはめた例です。

解決後のホスト名一致するパターン結果
box1.devboxes.example.com一致するパターン*.devboxes.example.com結果許可
devboxes.example.com一致するパターン*.devboxes.example.com結果許可(ワイルドカードは親ドメイン自身も含む)
Bastion.Example.com一致するパターンbastion.example.com結果許可(大文字小文字は無視)
other.example.com一致するパターンなし結果拒否

見落としやすいのは、判定の対象です。SSH Hostの欄には、user@hostnameの形か、~/.ssh/configで定義したHost名を入れられます。ポートの欄は、空ならSSH configの値か22番が使われます。判定にはその入力文字列そのものでなく、~/.ssh/configをssh -Gで解決した後のHostNameと、許可パターンを突き合わせます。HostのエイリアスやProxyCommand・ProxyJumpを使う構成も、最終的に解決されるHostNameが一致すれば許可されます。

実際の解決結果は、手元でssh -Gを実行すると確認できます。次はOpenSSH 10.2p1(macOS同梱)で、先頭の設定をそのまま別ファイルに書いて実行した出力です(接続は発生しません)。

Host devbox1
  HostName box1.devboxes.example.com
  ProxyJump bastion.example.com
ssh -F ./ssh_config -G devbox1 | grep -i -E "^(hostname|proxyjump|port) "
hostname box1.devboxes.example.com
port 22
proxyjump bastion.example.com

devbox1というエイリアスで接続しても、判定にはその解決結果のhostnameが使われます。したがって*.devboxes.example.comに一致して許可されます。逆に、エイリアス名のdevbox1を許可リストに書いても、解決後のホスト名と一致しないので効きません。許可パターンを決める前に、ユーザーが使う接続名でssh -Gを回し、hostnameの行を集めておくと書き漏れを防げます。

接続先の判定は手元、接続後の統制はリモート

SSHセッションでは、managed settingsを読む場所が段階で変わります。

読み込み元

どの端末のmanaged settingsが効くか

手元の端末

接続先を選ぶとき

Desktopアプリが動いている端末のmanaged settingsを読みます。sshConfigs・sshHostAllowlist・disableDesktopLocalSessionsは、いずれもここから読まれます。

リモートホスト

接続したあと

セッションは、リモートホスト上のmanaged settingsファイルを読みます。Claude Codeとしての統制は、こちらに置いたものが効きます。

接続後のセッションは、リモートに置いたmanaged settingsの権限ルールや、availableModelsのようなモデル制限に従います。モデル制限は、Desktopのセッションでもターミナルと同じように適用されます。

つまり、リモートの開発VMに厳しいポリシーを配っても、そのVMへ誰が接続できるかは変わりません。接続先の制限は手元の端末に、セッション内の統制はリモートに、と配る場所を分けます。

Desktopのセッションには、SSH以外にも種類があり、managed settingsの届き先がそれぞれ違います。

  • この端末のローカルセッション: 端末に置いたmanaged settingsファイルが適用されます。管理コンソールから配信した設定も、Anthropic APIを使うセッションで対象のログインやキーを使っていれば届きます
  • クラウドセッション: サーバー側で管理される設定(server-managed settings)を受け取ります。端末に置いたファイルは届きません。Anthropic管理のVMで動くためです
  • SSHセッション: リモートホストのmanaged settingsファイルを読みます

SSH接続先の制限を端末のファイルに書き、リモートのファイルには別の統制を書く、という二重の配布になる点が、他の種類との違いです。

接続先の側にも前提があります。リモートマシンはLinuxかmacOSで、初回の接続時にDesktopがClaude Codeをリモートへ自動でインストールします。個人用のスキルも、手元ではなくリモートのホームディレクトリにある~/.claude/skills/から読まれます。許可ホストを決めるときは、接続先のこの条件も合わせて見ます。

接続後のSSHセッションでも、権限モード・コネクタ・プラグイン・MCPサーバーが使えます。ただしclaude.aiのコネクタは、Desktopが利用者ごとにClaude Codeへ直接渡します。そのため、リモートのmanaged-mcp.jsonなどMCPの設定ではこれらを止められません。コネクタを統制したいときは、組織側のコネクタのツール制御を使います。「接続後の統制はリモート」という原則の例外です。

sshConfigsと組み合わせる — 候補を配り、到達先を絞る

接続先の候補を最初から配りたいときは、sshConfigsを使います。ユーザーの環境ドロップダウンに接続が自動で並びます。id・name・sshHostが必須で、sshPortとsshIdentityFileは任意です。

{
  "sshConfigs": [
    {
      "id": "shared-dev-vm",
      "name": "Shared Dev VM",
      "sshHost": "user@dev.example.com",
      "sshPort": 22,
      "sshIdentityFile": "~/.ssh/id_ed25519"
    }
  ]
}

managed settingsで配った接続は、ユーザーが選べるだけで、編集も削除もできません。ただしsshConfigsは、ユーザー自身が~/.claude/settings.jsonに書ける設定でもあります。アプリのダイアログから追加した接続は、そこに保存される仕組みです。つまり、sshConfigsだけでは接続先を制限できません。制限の役目はsshHostAllowlistが担います。

3つの設定キーの役割は次のとおりです。

設定キー書ける場所役割
sshConfigs書ける場所managed / ユーザー(自分のsettings.json)役割環境ドロップダウンに接続先候補を追加する
sshHostAllowlist書ける場所managedのみ役割接続できるホストのパターンを制限する(空配列でSSH自体を無効化)
disableDesktopLocalSessions書ける場所managedのみ役割端末上のローカルセッションを止め、SSHやクラウドだけを残す

disableDesktopLocalSessionsは、値がJSONの真偽値trueのときだけ有効です。文字列の"true"や1は無視され、警告がログに残ります。Claude Desktop v1.37937.0以降が必要で、ターミナルのCLIはこのキーを読みません。

有効にした端末では、環境ドロップダウンのLocalが灰色になって選べなくなり、SSH接続が設定されていれば、新規セッションは最初のSSH接続を既定にします。既存のローカルセッションは一覧に残りますが、続きの操作はできません。同じ端末へのSSH接続も拒否されます。

灰色のLocalには、組織が無効にした旨のツールチップが付きます。Windowsでは、WSLの項目も同じように灰色になります。WSLの可否は別のポリシーで決まります。既存のローカルセッションを続けようとすると、この端末ではローカルセッションを使えないという趣旨のメッセージが出ます。

ローカルを止めると、開発者はSSHかクラウドで作業することになります。そのときの到達先を絞る部品がsshHostAllowlistで、配布側はsshConfigsで最初の接続を用意しておく組み合わせです。拒否された端末に出る画面の違いや配布の要件は、disableWslSessionsでClaude Code DesktopのWSLを組織展開するでも扱っています。

配布前の確認とつまずき

配る前に、次の3点を見ます。

  • ワイルドカードが広すぎないか: *.example.comと書くと、example.com自体と配下のサブドメインがすべて対象です。他部門が管理するサブドメインまで入ります
  • sshConfigsの接続先が許可パターンに入っているか: 配ったsshHostが解決後に許可パターンへ一致しなければ、その接続には入れない想定になります。候補を配る側と許可する側は、同じ表で管理すると食い違いません
  • SSH経由で開発している人への周知: 空配列は影響が大きく、既存の作業フローを止めます

つまずきやすい点は、次の3つです。

  • ユーザー設定に書いた: ~/.claude/settings.jsonや.claude/settings.jsonに書いても無視されます。managed settingsにだけ書きます
  • エイリアス名を書いた: 判定は解決後のHostNameです。短いエイリアスではなく、実際のホスト名を書きます
  • リモート側に配った: 接続先の許可判定は、手元の端末のmanaged settingsを見ます。リモートのVMに配っても、そこへの接続は止まりません

まとめ

許可リストは、Desktopアプリの接続先を絞る入口の制御で、CLI・IDE拡張・Bashツールのsshには届きません。判定はssh -Gで解決した後のHostNameで行われるので、パターンを決める前に実際の解決結果を集めておくと、書き漏れが減ります。

この記事を共有:XはてブLinkedIn