動的ポート番号を使用したジャンプホスト経由の SSH

動的ポート番号を使用したジャンプホスト経由の SSH

ホストは3つあります:

  1. ぼくのコンピュータ。
  2. 静的 IP を持つジャンプ ホスト (別名 bastion)。
  3. 動的 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

残念ながら、Match2020年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 構成が含まれることは望ましくありません。

関連情報