承認済みのプロキシはジャンプホスト上で loopback だけで待ち受けているため、そのマシンの外からは何も到達できません。VPN や新しいプロキシは不要で、必要なのはそのマシンの一つのポートを自分の一つのポートへ運ぶことです。ローカル転送はまさにそれを行い、コマンド一つとアプリケーションの設定一つで済みます。混乱はたいてい、どの loopback アドレスがどのマシンのものかを取り違えることから生じます。

固定のプロキシが既にあるかを判断する

この手法は、すでに動作しているサービスを転送します。リモートホストに SSH デーモンしかなくプロキシがなければ、どれだけ転送してもプロキシは作られず、接続はリモート側から拒否されます。プロキシがバインドされていること、そのポート、そして 127.0.0.1 で待ち受けているのか特定のインターフェースアドレスで待ち受けているのかを確認してください。転送が狙うべきはそのアドレスだからです。

これを先に確認すれば、何にも接続されたことのないトンネルをデバッグせずに済みます。

転送を組み立ててコマンドを読む

必要な形は、ノート PC 上の loopback ポートをバインドし、サーバー側からプロキシのアドレスへ、サーバーが見る形で接続します。

ssh -NT -o ControlPath=none -o ExitOnForwardFailure=yes \
  -L 127.0.0.1:13128:127.0.0.1:3128 [email protected]

-N はリモートコマンドを抑止し、-T は termios の割り当てを抑止します。必要なのはシェルではなくトンネルだからです。最初の loopback アドレスはノート PC が待ち受ける場所で、二つ目は SSH サーバー側で解決されます。したがってそこでの 127.0.0.1 は、そのマシン上のプロキシを意味します。ExitOnForwardFailure は、ローカルポートがすでに使われている場合に何も転送しないセッションを始めるのではなく、コマンドをはっきりと失敗させます。宛先アドレスはサーバーが解決する形で書いてください。ノート PC だけで解決できる名前は相手側で失敗します。

このいずれかが機能する前に、サーバー自身のポリシーが適用されます。AllowTcpForwarding が許可している必要があり、PermitOpen はセッションが到達できる宛先とポートを制限できます。そのためクライアントが受け入れる転送でも、サーバーが拒否することがあります。拒否はクライアント側で転送エラーまたはチャネルエラーとして現れます。そのメッセージを読むほうが、コマンドを編集するより速いです。

一つのアプリケーションを転送に向ける

http://127.0.0.1:13128 の HTTP プロキシを使うようアプリケーションを設定してください。リモートのプロキシが要求する場合は資格情報も設定します。HTTPS の宛先ではアプリケーション自身の証明書検証を残してください。プロキシのトンネルはそれを置き換えません。これは一つのサービスの固定転送なので、アプリケーションにはプロキシの存在を伝える必要があり、自動検出に任せるべきではありません。

恒久的な設定をする前の簡単な確認として、curl -x http://127.0.0.1:13128 -I https://example.com を実行します。これはプロキシが対応すべき HTTP CONNECT メソッドを試します。

権限は元の場所に残す

リモートのプロキシは依然として許可する宛先とメソッドを決めており、SSH ログインがすべてのアカウントに黙って汎用の Web リレーを与えるべきではありません。ノート PC 側で 127.0.0.1 にバインドすれば、ポートをローカルネットワークに公開せずに済みますが、同じマシン上の他のプロセスからポートが隠れるわけではありません。そのバインドをワイルドカードアドレスに置き換えてプロキシを共有するのは、管理されないオープンリレーが生まれる経路です。

SSH の伝送はサーバーまでの区間を保護します。その先ではプロキシが独自に接続を開くため、宛先への平文 HTTP リクエストは、最初の区間が暗号化されていてもサーバーの先では平文のままです。

両端を検証してから片付ける

ローカルトンネルの設定とリモートサービスの成功は別の結果であり、コマンドの終了ステータスは前者しか教えてくれません。ss -ltn でリスナーが存在することを確認し、次に許可されるアプリケーションのリクエストと、プロキシが拒否すべきリクエストを行います。どちらも期待どおりなら経路は本物です。トンネルが上がっていてすべてのリクエストが失敗するなら、プロキシが拒否しているか宛先に到達できていません。

終わったら、トンネルを所有する SSH プロセスを停止し、アプリケーションからプロキシ設定を削除し、タスクより長生きするリスナーを残さずにローカルポートが消えたことを確認してください。

関連記事