Перейти к содержимому

ProxyJump и bastion-хосты через ~/.ssh/config

Иногда сервер живет в приватной сети, без публичного IP. Единственная точка входа — bastion host с белым адресом. Руками набирать ssh -J user@bastion user@private каждый раз — лишняя боль. Разберу, как настроить всё через ~/.ssh/config, чтобы ходить в приватные сети в одно касание.

Зачем нужен bastion host

Bastion (jump host, jump box) — промежуточный сервер с публичным доступом, через который проксируются соединения к инфраструктуре без внешних адресов. Типичная схема:

Лaptop → Bastion (публичный IP) → Private server (10.0.1.5)

Bastion не обязан быть «защищенным как Форт-Нокс» — он просто открытый узел. Весь access control держится на ключах и, при необходимости, на security groups / firewall.

Примечание

Bastion-хост не терминальная точка — он только проксирует трафик. На нем не нужно поднимать VPN или дополнительные сервисы.

ProxyJump — современный синтаксис

-J (ProxyJump) появился в OpenSSH 7.3. Параметр принимает хост в формате [user@]host[:port] и поднимает SOCKS5-прокси через указанный узел.

Базовый вызов:

ssh -J user@bastion.example.com user@10.0.1.5

Аутентификация на обоих хостах по ключам. Если пользователь совпадает, указывать его не обязательно:

ssh -J bastion.example.com 10.0.1.5

С портом, отличным от 22:

ssh -J bastion.example.com:2222 10.0.1.5

Через конфиг то же самое описывается компактно:

Host private-server
    HostName 10.0.1.5
    ProxyJump bastion.example.com

После этого ssh private-server подключается через bastion автоматически.

ProxyCommand — классический подход

ProxyJump — обертка над ProxyCommand. Если нужно больше контроля или работа с более старым OpenSSH, используй ProxyCommand напрямую.

ssh -o ProxyCommand="ssh -W %h:%p bastion.example.com" 10.0.1.5

-W пробрасывает stdin/stdout на целевой хост. В конфиге:

Host private-server
    HostName 10.0.1.5
    ProxyCommand ssh -W %h:%p bastion.example.com

Разница с ProxyJump минимальна, но ProxyCommand позволяет подставить переменные, условия и цепочки команд.

Несколько хопов подряд

Цепочка из двух bastion-хостов:

ssh -J bastion1.example.com,bastion2.example.com 10.0.1.5

В конфиге:

Host private-server
    HostName 10.0.1.5
    ProxyJump bastion1.example.com,bastion2.example.com

OpenSSH соединяет хосты последовательно: laptop → bastion1 → bastion2 → private-server. Проверь, что ключи есть на каждом узле.

Для сложных сценариев ProxyCommand с nc (netcat) дает больше гибкости:

Host dmz-server
    HostName 192.168.1.10
    ProxyCommand ssh -W %h:%p bastion.example.com

Host private-server
    HostName 10.0.1.5
    ProxyCommand ssh -W %h:%p dmz-server

Цепочка работает, но каждый хоп добавляет задержку. Для интерактивной работы больше двух хопов — признак проблемы в архитектуре сети.

Полный пример конфига

# Bastion host (публичный вход)
Host bastion
    HostName bastion.example.com
    User admin
    Port 22
    IdentityFile ~/.ssh/id_ed25519
    ForwardAgent yes
    ServerAliveInterval 60
    ServerAliveCountMax 3

# Приватный сервер через bastion
Host private-web
    HostName 10.0.1.5
    User appuser
    ProxyJump bastion
    IdentityFile ~/.ssh/id_ed25519
    ServerAliveInterval 60
    ServerAliveCountMax 3

# Приватная база данных
Host private-db
    HostName 10.0.2.10
    User dbadmin
    ProxyJump bastion
    IdentityFile ~/.ssh/id_ed25519
    LocalForward 5433 127.0.0.1:5432
Подсказка

ForwardAgent yes на bastion позволяет агенту пробросить ключи дальше. Не включать, если не доверяешь bastion-машине.

LocalForward в примере пробрасывает порт PostgreSQL с приватного сервера на локальный localhost:5433. Удобно для подключения IDE или psql.

Проверить, что конфиг читается без ошибок:

ssh -G private-web | grep -E '^(hostname|proxyjump)'

Если видишь правильные значения — конфиг подхватился.

Типичные ошибки и решения

Connection timeout при ProxyJump

Проверь, что bastion доступен напрямую:

ssh bastion.example.com echo ok

Если не проходит — проблема в сети, не в конфиге.

Permission denied (publickey) на bastion

Убедись, что ключ добавлен в ssh-agent:

ssh-add ~/.ssh/id_ed25519
ssh-add -l

Если агент пустой — добавь ключ и проверь ssh -vT bastion.

Работает в одну сторону, не работает в другую

ProxyJump туннелирует TCP. ICMP (ping) не пройдет. Проверяй соединение через nc -zv host port или ssh -v.

Agent refused operation при пробросе агента

Проверь переменную SSH_AUTH_SOCK:

echo $SSH_AUTH_SOCK

Если пусто — запусти агент:

eval "$(ssh-agent -s)"
ssh-add

Медленное подключение через цепочку

Проверь MTU. Иногда MTU в VPN/LAN меньше, чем нужно для TCP-over-TCP. Добавь в конфиг:

Host *
    IPQoS lowdelay throughput

Для совсем медленных каналов попробуй сжатие:

Host *
    Compression yes

ProxyJump покрывает 90% случаев. Если нужна визуализация или UI-менеджер — смотри в сторону sssh-config или Terminator, но для консольной работы ~/.ssh/config с ProxyJump достаточно.