SSH キーを自分で管理したい場合は、Cloudflare Tunnel を使って、サーバーから Cloudflare のグローバルネットワークへ、アウトバウンドのみのセキュアな接続を作成できます。サーバー(またはプライベートネットワーク内の別ホスト)で cloudflared デーモンを動かします。SSH サーバーが信頼する SSH キーを持つユーザーは、デバイスに Cloudflare One Client をインストールし、Zero Trust 組織へ登録すればサーバーへアクセスできます。ユーザーはサーバーのプライベートホスト名へ直接 SSH できます(例: ssh.internal.local)。サーバーへのアクセスは、アプリケーションレベルの Access ポリシーではなく、ネットワークレベルの Gateway ポリシーで制御します。
- Cloudflare Zero Trust 組織
- ユーザーデバイスに Cloudflare One Client がインストールされていること
- デバイスが Zero Trust 組織に 登録 されていること
この例では、Google Cloud Platform(GCP)の仮想マシン(VM)上に SSH サーバーを立てます。SSH 接続に対応する任意のマシンでも構いません。すでに SSH サーバーがある場合は、ステップ 2 へ進んでください。
VM インスタンスを作る前に、SSH キーペアを作成します。
-
ターミナルを開き、次のコマンドを入力します。
ssh-keygen -t rsa -f ~/.ssh/gcp_ssh -C <username in GCP> -
求められたらパスフレーズを入力します。2 回入力します。
次の 2 つのファイルが生成されます。秘密鍵を含む
gcp_sshと、公開鍵を含むgcp_ssh.pubです。 -
コマンドラインで次を入力します。
cat ~/.ssh/gcp_ssh.pub -
出力をコピーします。GCP で VM インスタンスを作成するときに使います。
SSH キーペアができたので、VM インスタンスを作成できます。
- Google Cloud Console ↗ で 新しいプロジェクトを作成 ↗ します。
- Compute Engine > VM instances を開きます。
- Create instance を選びます。
- VM インスタンスに名前を付けます。例:
ssh-server。 - Advanced options > Security > Manage Access までスクロールします。
- Add manually generated SSH keys で Add item を選び、作成した公開鍵を貼り付けます。
- Create を選びます。
- VM インスタンスが起動したら、SSH の横のドロップダウンを開き、Open in browser window を選びます。
このセクションでは、SSH サーバー用の新しい Cloudflare Tunnel を作成します。cloudflared ホストから到達できるプライベートネットワーク上のすべてのサービスで、同じトンネルを再利用できます。
-
Cloudflare ダッシュボードにログインし、Networking > Tunnels を開きます。
Tunnels を開く ↗ -
Create a tunnel を選択します。
-
トンネルの名前を入力します。このトンネル経由で接続するリソースの種類がわかる名前(例:
enterprise-VPC-01)を推奨します。 -
Create Tunnel を選択します。
-
オペレーティングシステムを選び、インストールコマンドをコピーして、オリジンサーバーのターミナルで実行します。
-
トンネルの接続を待ちます。接続が確立したら Continue を選択します。
ホスト名ルートを使うと、静的な IP ルートを管理せずに ssh.internal.local へ直接 SSH できます。クラウドプロバイダーがプロビジョニングする動的インフラなど、SSH サーバーの IP が不明または一時的な場合に特に有効です。
ホスト名ルーティングの仕組み
Cloudflare Tunnel にホスト名ルートを作成すると、次のように動作します。
- ユーザーがプライベートホスト名へ SSH します(例:
ssh user@ssh.internal.local)。 - Gateway がそのホスト名を 初期解決 IP に解決します。
- トラフィックは WARP トンネル経由で Cloudflare へ向かいます。
- Gateway のネットワークポリシーが接続を評価します。
cloudflaredが接続を SSH サーバーのプライベート IP へプロキシします。
プライベート DNS リゾルバーを設定していない場合、または IP アドレスへ SSH したい場合は、ステップ 4 へ進んでください。
トンネルにホスト名ルートを追加するには:
-
Networking > Tunnels を開き、対象のトンネルを選びます。
-
Routes タブで Add route を選び、Private hostname を選びます。
-
SSH サーバーのホスト名を入力します(例:
ssh.internal.local)。ホスト名の形式制限
- 文字数制限: 255 文字未満である必要があります。
- 使えるワイルドカード: ワイルドカード(
*)は 1 つだけ使え、DNS ラベル全体を表す必要があります。 例:*.internal.local - 使えないワイルドカード: 次のワイルドカード形式はサポートされていません。
*-dev.internal.localやdev-*.internal.localのような部分ワイルドカード。foo*bar.internal.localやfoo.*.internal.localのように、途中に入るワイルドカード。*.*.internal.localのように、ホスト名に複数のワイルドカードがある場合。
- ワイルドカードのトリム: 先頭のワイルドカード(
*)は取り除かれ、暗黙のドット(.)があると見なされます。たとえば、*.internal.localはinternal.localとして保存されますが、ワイルドカード階層のすべてのサブドメインに一致します(foo.internal.localは対象、foo.bar.internal.localは対象外)。 - ドットのトリム: 先頭と末尾のドット(
.)は使えますが、保存時に取り除かれます。
-
Save を選びます。
Gateway がプライベートホスト名のリクエストを受け取ったら、そのホスト名を SSH サーバーのプライベート IP アドレスへ解決する必要があります。
デフォルトでは、cloudflared はホストマシンに設定されたプライベート DNS リゾルバーを使います(Linux では /etc/resolv.conf など)。cloudflared を動かしているマシンが、ローカルのシステムリゾルバーで ssh.internal.local をプライベート IP に解決できる場合、追加の設定は不要です。ステップ 3.3 へ進んでください。
ローカル DNS 解決を確認する
cloudflared が ssh.internal.local を解決できるか確認するには、cloudflared ホストで次のコマンドを実行します。
nslookup ssh.internal.localServer: 127.0.2.2
Address: 127.0.2.2#53
Non-authoritative answer:
Name: ssh.internal.local
Address: 10.2.0.3出力にはサーバーのプライベート IP アドレス(GCP VM の Internal IP)が含まれている必要があります。ホスト名の解決に失敗した場合:
- プライベート DNS リゾルバーに、
ssh.internal.localをサーバーのプライベート IP へ向けるレコードがあることを確認します。 - GCP では、
internal.localがプライベート DNS リゾルバーで解決されるよう、Cloud DNS にプライベートゾーンを追加 ↗ する必要がある場合があります。
cloudflared に、ホストのデフォルトリゾルバーとは異なる特定の内部 DNS サーバーを使わせる場合は、その DNS サーバーを IP/CIDR ルート で Cloudflare に明示的に接続する必要があります。あわせて、Gateway のリゾルバーポリシー を設定し、クエリをこのプライベート DNS サーバーへルーティングします。
-
DNS サーバーの IP/CIDR ルートを作成する手順です。
-
Networking > Routes を開きます。
Routes を開く ↗ -
Add CIDR route を選びます。
-
内部 DNS リゾルバーのプライベート IP アドレスを入力します。
-
この DNS サーバーがあるネットワークに接続している Cloudflare Tunnel を選びます。
-
Create を選びます。
-
-
リゾルバーポリシーを作成する手順です。
- Traffic policies > Resolver policies を開きます。
- Create a policy を選びます。
- プライベートホスト名に一致する式を作成します。
セレクター 演算子 値 Host in ssh.internal.local - Configure custom DNS resolvers で、内部 DNS サーバーのプライベート IP アドレスを入力します。
- ドロップダウンメニューから
- Privateのルーティングオプションと、前の手順で選んだトンネルに割り当てた 仮想ネットワーク を選びます。 - Create policy を選びます。
プライベートホスト名に接続するには、Cloudflare One Client が次のトラフィックを Cloudflare へ転送するよう設定します。
- 初期解決 IP:
- IPv4:
172.64.128.0/20 - IPv6:
2606:4700:0cf1:4000::/64
これがデフォルトの範囲です。既存ネットワークと衝突する場合は、IPv4 向けに カスタムの初期解決 IP 範囲を設定 できます。
- IPv4:
- プライベートホスト名の DNS クエリ
WARP の デバイスプロファイル で、初期解決 IP が WARP トンネル経由でルーティングされるよう Split Tunnels を設定します。設定内容は Split Tunnels のモード によって異なります。
- Exclude mode: Split Tunnels のリストから
100.64.0.0/10を削除します。Cloudflare One サービスで明示的に使っていない IP 範囲を戻す ことを推奨します。これにより、CGNAT アドレス空間を使う既存のプライベートネットワーク設定との衝突リスクを下げられます。 - Include mode: 次の IP アドレスを Split Tunnel のエントリとして追加します。
- IPv4:
172.64.128.0/20 - IPv6:
2606:4700:0cf1:4000::/64
これがデフォルトの範囲です。既存ネットワークと衝突する場合は、IPv4 向けに カスタムの初期解決 IP 範囲を設定 できます。
- IPv4:
Local Domain Fallback で、プライベートホスト名のトップレベルドメインを削除します。これにより、WARP はその DNS クエリを解決のため Cloudflare Gateway へ送ります。
たとえば SSH ホスト名が ssh.internal.local の場合、Local Domain Fallback から internal.local を削除します。
ホスト名 ではなく IP アドレスで SSH サーバーに接続するには、サーバーのプライベート IP アドレスを含む CIDR ルートを追加 します。
デフォルトでは、WARP は RFC 1918 空間 ↗ 向けのトラフィックを除外します。これはプライベートネットワークでよく使われ、インターネットから到達できない IP アドレスです。Cloudflare One Client が private network へトラフィックを送るには、Split Tunnels を設定し、private network の IP/CIDR が Cloudflare One Client 経由でルーティングされるようにします。
-
まず、Split Tunnels のモード が Exclude と Include のどちらになっているかを確認します。
-
モードに応じて Split Tunnel のルートを編集します。
Exclude モードを使っている場合:
a. private network の IP/CIDR 範囲を含む ルートを削除 します。たとえば、ネットワークが AWS のデフォルト範囲
172.31.0.0/16を使っている場合は、172.16.0.0/12を削除します。b. private network が明示的に使っていない IP/CIDR 範囲を再追加 します。上記の AWS の例では、
172.16.0.0/13、172.24.0.0/14、172.28.0.0/15、172.30.0.0/16を新たに追加します。こうすると、172.31.0.0/16向けのトラフィックだけが Cloudflare One Client 経由になります。再追加する IP アドレスは、次の計算機で求められます。
計算機の使い方
- Base CIDR に、Split Tunnels から削除した RFC 1918 範囲を入力します。
- Subtracted CIDRs に、private network が使う IP/CIDR 範囲を入力します。
- 計算機の結果を Split Tunnel の Exclude モードのリストに戻します。
Cloudflare One Client に含めるプライベート IP 範囲を狭めると、ユーザーの ローカルリソースへのアクセス を壊すリスクを下げられます。
Include モードを使っている場合:
- 必要な Zero Trust ドメイン または IP アドレス を Split Tunnel の include リストに追加します。
- private network の IP/CIDR 範囲を含める ルートを追加 します。
デフォルトでは、組織に登録されたすべてのデバイスがサーバーへ SSH できます。特定のユーザーだけを許可またはブロックするには、Gateway ネットワークポリシーを作成します。ユーザー ID、デバイスポスチャ、所在地などの条件でポリシーを作れます。
- Traffic policies > Traffic settings を開きます。
- Proxy and inspection で、Allow Secure Web Gateway to proxy traffic をオンにします。
- TCP を選択します。
- UDP を選択します(内部 DNS リゾルバーへのトラフィックをプロキシするために必要です)。
- (推奨)
pingやtracerouteなどの診断ツールのトラフィックをプロキシするには、ICMP を選択します。cloudflared経由で ICMP トラフィックを許可するには、システムの更新 も必要な場合があります。
-
cloudflare_api_token↗ に次の権限を追加します。Zero Trust Write
-
cloudflare_zero_trust_device_settings↗ リソースを使い、TCP または UDP のプロキシ(あるいは両方)をオンにします。resource "cloudflare_zero_trust_device_settings "global_warp_settings" { account_id = var.cloudflare_account_id gateway_proxy_enabled = true gateway_udp_proxy_enabled = true }
これで Cloudflare は、登録済みデバイスからのトラフィックをプロキシします。split tunnel の設定 で除外したトラフィックは対象外です。Gateway がトラフィックを転送する仕組みの詳細は、Gateway プロキシ を参照してください。
次の例は 2 つのポリシーで構成します。1 つ目は特定のユーザーが SSH サーバーへ到達できるようにし、2 つ目はその他すべてのトラフィックをブロックします。
-
Traffic policies > Firewall policies > Network を開きます。
-
Create a policy を選びます。
-
ポリシーに名前を付けます(例:
Allow SSH to internal server)。 -
SSH ホスト名と許可するユーザーに一致する式を作成します。
Selector Operator Value SNI in ssh.internal.localUser Email in admin@example.com,devops@example.com -
Action で Allow を選びます。
-
Create policy を選びます。
Cloudflare One Client のユーザーがプライベートネットワーク全体にアクセスできないようにするには、プライベート IP 空間向けの キャッチオール Gateway Block ポリシー を作成することを推奨します。そのうえで、特定のアプリケーションや IP へのアクセスを許可する、優先度の高い Allow ポリシー(Access または Gateway)を重ねます。
保護を重ねるには、DNS 解決を制御する Gateway DNS ポリシーを作成します。
-
Traffic policies > Firewall Policies > DNS を開きます。
-
Create a policy を選びます。
-
ポリシーに名前を付けます(例:
Allow SSH hostname resolution)。 -
次の式を作成します。
Selector Operator Value Host in ssh.internal.localUser Email in admin@example.com,devops@example.com -
Action で Allow を選びます。
-
Create policy を選びます。
トンネルルートとユーザーデバイスの設定が終わると、ユーザーはそのマシンへ SSH できます。SSH サーバーが SSH キーを要求する場合は、SSH コマンドにそのキーを含めます。
ssh -i ~/.ssh/gcp_ssh <username>@ssh.internal.localCloudflare One Client は Zero Trust 組織に接続している必要があります。作成した Gateway ネットワークポリシーに一致するユーザーは接続できます。
接続できない場合は、次を確認します。
-
DNS 解決を確認する - デバイスから、プライベートホスト名を解決できることを確認します。
nslookup ssh.internal.localServer: 127.0.2.2 Address: 127.0.2.2#53 Non-authoritative answer: Name: ssh.internal.local Address: 172.64.128.48クエリは WARP の DNS プロキシ で解決され、Gateway の 初期解決 IP を返す必要があります。解決に失敗する、または別の IP が返る場合は、Local Domain Fallback の設定と Gateway の resolver ポリシー を確認します。
-
Gateway ログを確認する - Gateway ネットワークログ を確認し、ポリシーによって接続がブロックされていないかを見ます。
-
トンネルの状態を確認する - トンネルの状態 を確認し、トンネルが正常で接続されていることを確かめます。
-
初期解決 IP への接続をテストする - プライベートホスト名で SSH サーバーに接続すると、デバイスは 初期解決 IP へ接続します。
ssh -v <username>@ssh.internal.local... Authenticated to ssh.internal.local ([172.64.128.48]:22) using "publickey". ...アカウントの 初期解決 IP レンジ 内の IP への接続を示す行を探します。リクエストが失敗する場合は、初期解決 IP が WARP トンネル経由でルーティング されていることを確認します。トンネルログ で、リクエストがサーバーのプライベート IP へルーティングされていることも確認できます。