У меня есть 3 хоста:
- Мой компьютер.
- Jump Host (он же бастион) со статическим IP-адресом.
- Сервер с динамическим 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.