SSH через Jump Host с динамическим номером порта

SSH через Jump Host с динамическим номером порта

У меня есть 3 хоста:

  1. Мой компьютер.
  2. Jump Host (он же бастион) со статическим IP-адресом.
  3. Сервер с динамическим IP-адресом; за маршрутизатором/брандмауэром NAT, без открытых входящих портов.

В настоящее время сервер подключается к Jump Host и устанавливает SSH-туннель через -R "0:localhost:22", поэтому порт динамически выделяется Jump Host (до сих пор это было очень надежно).

С некоторымимагия сокета, у меня есть динамически выделенный номер порта, записанный в файле на Jump Host.

С помощью этого я могу подключиться к хосту Jump по SSH и запуститьssh -p $(cat /path/to/port-file) localhost

Но можно ли пропустить этот дополнительный шаг?


Это было бы полезно для Ansible, где мне inventory.ymlнужно обновить номер порта:

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_config» на Jump Host, используя ssh -F /path/to/ssh_config, со следующим содержимым:

Host tunnel.server
  HostName localhost
  Port 34625

Но я не думаю, что смогу использовать это с ProxyCommand.


Я также подозреваю, что StrictHostKeyChecking=noего, возможно, придется ввести в какой-то момент, когда изменится номер порта.

решение1

Второе частичное решение, вдохновленное @anx...

Создать файл сокета

ssh -R '/path/to/socket-file:localhost:22' tunnel@jh

Затем, чтобы использовать этот сокет (из Jump Host), я могу использовать socat:

ssh -o "ProxyCommand socat - UNIX-CLIENT:/path/to/socket-file" localhost

Использование socatкажется ненужным шагом, хотя я уверен, что должен быть способ заставить команду sshиспользовать файл сокета напрямую, но я пока не могу его найти.

Я также не нашел, как использовать этот файл сокета с моего компьютера (так как ProxyCommand запускается на локальном хосте, а не на JumpHost).

Я также должен отметить; поскольку tunnelучетная запись (на Jump Host) очень ограничена (она нужна только для установки этих туннельных соединений), мне нужно настроить StreamLocalBindMask=0111так, чтобы моя учетная запись на Jump Host могла использовать этот файл сокета. Аналогично, старый файл сокета должен быть удален, если устанавливается новое соединение, через StreamLocalBindUnlink=yes.

Оба эти параметра необходимо задать на хосте Jump в «/etc/ssh/sshd_config»:

Match User tunnel
  StreamLocalBindMask 0111
  StreamLocalBindUnlink yes

К сожалению, Matchправила игнорируются в "/etc/ssh/sshd_config.d/tunnel.conf" до OpenSSH 8.4, выпущенного 27 сентября 2020 г. (отчет об ошибке), и в настоящее время это недоступно в Ubuntu 20.04.1 LTS.

решение2

Временное решение, не идеальное...

Добавьте на мой компьютер почасовое задание cron, оно соберет номер(а) порта с хоста Jump и создаст новый ~/.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чтобы быть уверенным, что получаю номер обратно. Если мой Jump Host будет скомпрометирован, я не хочу, чтобы файл порта содержал дополнительную (вредоносную) конфигурацию SSH.

Связанный контент