Table of Contents
ssh forwarding
Туннель можно организовать как изнутри сети, к ресурсам к которой хотим получить доступ, на внешний ssh-сервер. Также можно организовать туннель с хоста в Интернете на пограничный ssh-сервер сети, чтобы получить доступ к внутренним ресурсам.
Чаще всего используются следующие сценарии проброса SSH:
- Local TCP forwarding – проброс локального порта на удаленный сервер;
- Remote TCP forwarding – проброс удаленного порта на локальный компьютер;
- Двойной SSH туннель – позволяет соединить между собой через SSH сервер компьютеры без выделенных белых IP адресов или находящиеся за NAT (если не подходит решение с OpenVPN)
Используемые флаги
-f # Запросит ssh перейти в фоновый режим только перед выполнением команды. Это полезно если ssh собирается запросить пароль или парольную фразу, но пользователь хочет сделать это в фоновом режиме -N # Не выполнять удаленную команду. Это полезно если вы хотите только перенаправить порты -R # Указывает заданный порт на удаленной машине который будет перенаправлен к заданной машине и локальному порту.
Local TCP forwarding
ssh -f -N -R 2222:10.10.10.14:22 username@12.34.56.78
Подключаемся к созданному туннелю. На хосте 12.34.56.78 вводим:
ssh -p2222 username@localhost
И попадаем на хост 10.10.10.14. Таким же образом, можно получить доступ к любому другому ресурсу, например:
ssh -f -N -R 2080:10.10.10.14:80 username@12.34.56.78
Введя на хосте 12.34.56.78
w3m -dump http://localhost:2080
Получим дамп web-ресурса на 10.10.10.14.
Remote TCP forwarding
Посмотреть все установленные туннели можно так:
ssh -f -N -L 4080:192.168.0.10:80 nameuser@88.77.66.55
Аналогично, вводим на своём хосте:
w3m -dump http://localhost:4080
И получаем доступ к web-ресурсу узла 192.168.0.10, который находится за хостом 88.77.66.55.
Поддержка туннелей в поднятом состоянии
Посмотреть все установленные туннели можно так:
sudo lsof -i -n | egrep '\<ssh\>' # либо sudo lsof -i -n | egrep '\<sshd\>'
Не секрет, что связь иногда обрывается, туннели при этом будут отваливаться по таймауту. Чтобы не утруждать себя дополнительным монотонным вбиванием команды на поднятие туннеля и мониторингом этого процесса, автоматизируем его:
crontab -e
И создаём расписание примерно следующего вида:
TUNCMD1='ssh -f -N -R 2222:10.11.12.13:22 username@99.88.77.66' TUNCMD2='ssh -f -N -R 2080:10.11.12.14:80 username@99.88.77.66' */5 * * * * pgrep -f "$TUNCMD1" &>/dev/null || $TUNCMD1 */5 * * * * pgrep -f "$TUNCMD2" &>/dev/null || $TUNCMD2
Сохраняемся. И проверяем:
crontab -l
Из практического опыта – cron-задания на перезапуск недостаточно. Разве что соединение абсолютно стабильно. В реальной жизни встречается в 0% случаев. Даже соединённые напрямую кабелем две сетевые карты легко могут потерять n-ное количество пакетов и tcp-соединение упадёт. Клиент и сервер будут пребывать в святой уверенности, что всё в порядке, просто вторая сторона ничего не передаёт.
Нужен keepalive
. Добавлять нужно в /etc/ssh_config
, либо в ~/.ssh/config
. Интервал и счётчик – по вкусу:
TCPKeepAlive no ServerAliveInterval 300 ServerAliveCountMax 3
Также, данные опции можно указать при подключении:
ssh -p 2222 -o "TCPKeepAlive no" -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \ > -R 3306:127.0.0.1:3306 username@99.88.77.66
autossh
Утилита autossh предназначена для мониторинга соединений ssh и их автоматического восстановления в случае разрыва. Входит в репозиторий Ubuntu
sudo apt install autossh
Клиент
Создадим юнит /etc/systemd/system/autossh.service
со следующим содержимым
[Unit] Description=AutoSSH to My Server After=network.target [Service] Environment="AUTOSSH_GATETIME=0" ExecStart=/usr/bin/autossh -N -M 0 -o "ExitOnForwardFailure=yes" -o "ServerAliveInterval=180" -o "ServerAliveCountMax=3" -o "PubkeyAuthentication=yes" -o "PasswordAuthentication=no" -i /root/.ssh/id_rsa -R 2223:localhost:22 tunnel@host_ip Restart=always [Install] WantedBy=multi-user.target
Добавляем в автозагрузку и стартуем
systemctl enable autossh
systemctl start autossh
Заходим на хост
ssh -p2223 localhost
Сервер
Для повышения безопасности туннеля, на сервере создадим пользователя без доступа к shell -s /bin/false
, но имеющий домашнюю директорию -m
useradd -d /home/tunnel -s /bin/false -m tunnel
Передадим ему ssh ключ:
ssh-copy-id -i ~/.ssh/id_rsa.pub tunnel@host_ip