多段ssh (途中のホストで名前解決)


構成

Host Port User HostName IP target の名前解決
local - - - - 不可
jump1 10022 user1 jump1.domain1.example.com -
jump2 20022 user2 jump2.domain2.example.com - 不可
target 30022 user3 target.domain3.example.com 192.168.3.3 -

目標

local から jump1、jump2 を経由し、target に ssh 接続。
ただし、target の名前解決は jump1 で実行。

普通にやるとこうなる:

user0@local$ ssh -p 10022 [email protected]
user1@jump1$ ssh -p 20022 [email protected]
user2@jump2$ ssh -p 30022 [email protected] # jump2 は target を名前解決できない
user3@target$

config を書いてこうしたい:

user0@local$ ssh target
user3@target$

準備

jump1 で resolve を実行すると target の名前解決ができるものとする。

user1@jump1$ resolve target.domain3.example.com
192.168.3.3

解決策

local の ~/.ssh/config:

Host jump1
    Port 10022
    User user1
    # local が名前解決
    HostName jump1.domain1.example.com

Host jump2
    Port 20022
    User user2
    # jump1 が名前解決
    HostName jump2.domain2.example.com
    ProxyCommand ssh -W %h:%p jump1

Host target
    Port 30022
    User user3
    # local から jump1 に ssh アクセスし、resolve を実行し、target を名前解決
    ProxyCommand ssh -W $(ssh jump1 resolve target.domain3.example.com </dev/null):%p jump2

一般化

nameserver で target を名前解決し、local から jump 経由で target にアクセス。

目標:

local$ ssh target
target$

localの ~/.ssh/config:

Host jump
    ...
Host target
    ProxyCommand ssh -W $(ssh nameserver resolve target </dev/null):%p jump

local から nameserver に必ずしも直接アクセスできる必要は無い。
nameserver へは ProxyCommand を使い、複数の jump サーバー経由でアクセスしても良い。

注意

ProxyCommand に </dev/null が無いと以下のようにエラーとなり、ssh 接続できない。

user0@local$ ssh target
Bad packet length 1231976033.
ssh_dispatch_run_fatal: Connection to UNKNOWN port 65535: message authentication code incorrect

また、ProxyCommand を利用しない多段 ssh で名前解決を実行しても、同様のエラーが発生する場合がある:

ProxyCommand ssh -W $(ssh jump1 ssh nameserver resolve </dev/null):%p jump2

これは </dev/null を ssh の引数に工夫して入れ込めば恐らく解決できる。
しかし、ssh が3段や4段となるとクオートが大変だったり色々面倒くさいので検証していない。