ホストは3つあります:
- ぼくのコンピュータ。
- 静的 IP を持つジャンプ ホスト (別名 bastion)。
- 動的 IP を持つサーバー。NAT ルーター/ファイアウォールの背後にあり、受信ポートは開いていません。
現在、サーバーはジャンプ ホストに接続し、 を介して SSH トンネルを確立する-R "0:localhost:22"
ため、ポートはジャンプ ホストによって動的に割り当てられます (これまでのところ、これは非常に信頼性が高いです)。
一部でソケットマジック動的に割り当てられたポート番号をジャンプ ホスト上のファイルに記録します。
これで、ジャンプホストにSSHで接続して実行できます。ssh -p $(cat /path/to/port-file) localhost
しかし、この余分なステップをスキップすることは可能でしょうか?
inventory.yml
これは、ポート番号を更新する必要があるAnsible に役立ちます。
server:
# /usr/bin/ssh jh cat /path/to/port-file
ansible_port: "34625"
ansible_host: "localhost"
ansible_ssh_common_args: "-o ProxyCommand='ssh -q -W %h:%p jh' -o StrictHostKeyChecking=no"
以下を使用できる可能性がありますProxyCommand
:
~/.ssh/config
私のコンピュータのファイルでは、コマンド置換を(ある程度)使用できます。
Host server
ProxyCommand ssh -q -W localhost:$(echo "34625") jh
echo -n
これは、置換がローカル コンピューター上で行われるような場合に( がなくても) 機能します。
SSH を使用して最初にポート番号を取得するのは非効率的であるにもかかわらず、これは機能しません。
Host server
ProxyCommand ssh -q -W localhost:$(ssh jh cat /path/to/port-file) jh
その結果は次のようになります:
Bad packet length 1349676916.
ssh_dispatch_run_fatal: Connection to UNKNOWN port 65535: message authentication code incorrect
そして奇妙なことに、サーバー (チェーンの最後) は認証ログにこれを記録します:
sshd[5558]: Bad protocol version identification '' from ::1 port 36048
これは、ポート番号が返されていることを意味します。ただし、この時点でなぜそれが壊れるのかはわかりません。
そして、ssh -vvv
それが私のホストキーを識別していることを示しています~/.ssh/known_hosts
。
ssh -F /path/to/ssh_config
また、 を使用して、次の内容のカスタム「ssh_config」ファイルを Jump Host 上に作成しようとしました。
Host tunnel.server
HostName localhost
Port 34625
しかし、これを で使用することはできないと思いますProxyCommand
。
またStrictHostKeyChecking=no
、ポート番号が変更される時点で導入する必要があるのではないかと考えています。
答え1
@anx に触発された 2 番目の部分的な解決策...
ソケットファイルを作成する
ssh -R '/path/to/socket-file:localhost:22' tunnel@jh
次に、このソケット (ジャンプ ホストから) を使用するには、次を使用しますsocat
。
ssh -o "ProxyCommand socat - UNIX-CLIENT:/path/to/socket-file" localhost
の使用はsocat
不要な手順のように思えますが、ソケットファイルを直接使用するコマンドを取得する方法があるはずですssh
が、まだ見つけることができません。
また、このソケット ファイルを自分のコンピューターから使用する方法も見つかりませんでした (ProxyCommand は JumpHost ではなく localhost で実行されるため)。
tunnel
また、アカウント (ジャンプ ホスト上) は非常に制限されているため(トンネル接続を確立するためだけに存在します)、StreamLocalBindMask=0111
ジャンプ ホスト上のアカウントがこのソケット ファイルを使用できるように設定する必要があります。同様に、 を介して新しい接続が確立された場合は、古いソケット ファイルを削除する必要がありますStreamLocalBindUnlink=yes
。
これらのオプションは両方とも、ジャンプ ホストの "/etc/ssh/sshd_config" で設定する必要があります。
Match User tunnel
StreamLocalBindMask 0111
StreamLocalBindUnlink yes
残念ながら、Match
2020年9月27日にリリースされたOpenSSH 8.4より前のバージョンでは、「/etc/ssh/sshd_config.d/tunnel.conf」のルールは無視されます(バグレポート) であり、これは現在 Ubuntu 20.04.1 LTS では利用できません。
答え2
一時的な解決策であり、理想的ではありません...
コンピューターに 1 時間ごとの cron ジョブを追加すると、ジャンプ ホストからポート番号が収集され、新しい~/.ssh/config_tunnels
ファイルが作成されます。
#!/bin/bash
set -u;
config_path="${HOME}/.ssh/config_tunnels";
port=$(/bin/ssh jh /bin/cat /path/to/port-file 2> /dev/null | /bin/sed 's/[^0-9]//g');
if [[ "${port}" -lt 1024 ]]; then
exit; # Probably a blank/zero value (e.g. connection issue).
fi
{
echo "";
echo "Host server";
echo " ProxyCommand ssh -q -W localhost:${port} jh";
echo "";
} > "${config_path}";
chown user:group "${config_path}";
chmod 600 "${config_path}";
メイン~/.ssh/config
ファイルは を使用できますInclude ~/.ssh/config_tunnels
。
注: 番号が返されることを確認するために使用していますsed
。ジャンプ ホストが侵害された場合、ポート ファイルに余分な (悪意のある) SSH 構成が含まれることは望ましくありません。