Глеб Гончаров

Системный администратор в ФанБоксе. Автоматизирую и сопровождаю инфраструктуру для проектов мобильных операторов.

Создание и поддержание SSH-туннеля

Иногда в работе над проектами приходится прибегать к уловкам для организации сетевых доступов. В тех случаях, когда согласован SSH с поддержкой перенаправления портов, альтернативным способом организации доступа становится SSH-туннель.

Рассмотрим пример создания такого туннеля с поддержанием работы с помощью systemd. Представим, что есть два сервера: сервер A (alice.example.com) с IP-адресом 10.0.0.1 и B (bob.example.com) с IP-адресом 10.0.0.2. Задача: пробросить порт 3128/tcp с сервера B на сервер A для доступа к HTTP-прокси.

Настройка

Перед началом убедитесь, что Port Forwarding разрешён на сервере: включите опцию AllowTcpForwarding. Подробнее об использовании перенаправлении TCP-портов в справке sshd_config(5).

Далее заводим непривилегированного пользователя autossh на обоих серверах. Этот пользователь будет подключаться к серверу B, а там, в свою очередь, аутентифицироваться и перенаправлять порт.

sudo useradd -m -d /home/autossh/ -s /bin/bash autossh

Генерируем пару закрытого и открытого ключей (RSA 4096 бит) на сервере A. В 2019 году 4096 бит достаточно для обеспечения должного уровня безопасности, не опасаясь подбора ключа. Вероятно, если вы читаете эту заметку в будущем, увеличьте размер ключа до 8192 бит или выше. Парольную фразу указывать не нужно.

su - autossh
mkdir -p /home/autossh/.ssh/ident
ssh-keygen -t rsa -b 4096 -f /home/autossh/.ssh/ident/ident@bob.example.com

Копируем текст публичного ключа в файл /home/autossh/.ssh/authorized_keys вручную или с помощью ssh-copy-id(1) на сервер B. Это позволит пользователю autossh аутентифицироваться по нему при подключении.

# Using ssh-copy-id
ssh-copy-id -i /home/autossh/.ssh/ident/ident@bob.example.com.pub autossh@bob.example.com

# Manually
cat ~/.ssh/ident/ident@bob.example.com.pub | ssh autossh@bob.example.com 'cat >> ~/.ssh/authorized_keys'

Проверяем подключение к серверу B. Продолжаем, если всё в порядке.

ssh -i /home/autossh/.ssh/ident/ident@bob.example.com autossh@bob.example.com

Конфигурируем SSH-клиент на сервере A.

# vim /home/autossh/.ssh/config
Host bob-example-com-proxy
    HostName            bob.example.com
    User                autossh
    Port                22
    IdentityFile        ~/.ssh/ident/ident@bob.example.com
    RemoteForward       10.0.0.1:3128 10.0.0.2:3128
    ServerAliveInterval 30
    ServerAliveCountMax 3

Создаём systemd-юнит. Обратите внимание на символ @ в названии: после него может быть указан параметр для юнита. Конфигурация шаблонизируется спецификаторами, описанными в документации к systemd.unit.

# sudo vim /usr/lib/systemd/system/autossh@.service
[Unit]
Description=Persistent SSH tunnel (%i)
After=network.target

[Service]
User=autossh
ExecStart=/usr/bin/ssh -NT -o ExitOnForwardFailure=yes %i
RestartSec=5
Restart=always

[Install]
WantedBy=multi-user.target

Применяем изменения.

sudo systemctl daemon-reload

Запускаем юнит и добавляем в автозапуск. Имя параметра соответствует названию профиля SSH-клиента в $HOME/.ssh/config.

sudo systemctl start autossh@b-example-com-proxy.service
sudo systemctl enable autossh@b-example-com-proxy.service

Готово. Проверяем перенаправление портов на сервере A.

cat < /dev/null > /dev/tcp/10.0.0.1/3128 && echo OK || echo NOK

Отладить подключение можно либо из-под пользователя autossh, либо добавив -vvv в systemd-юнит. Приведённое выше работает и для LocalForward для перенаправления порта с удалённого сервера на локальный. Легко комбинировать с и другими возможностями SSH, когда в цепочке несколько узлов.