Визуальный гайд по туннелям SSH (с лабами)

TL;DR: Шпаргалка по пробросу портов по SSH целиком на одном листе.
SSH - еще один пример древних технологий, которые активно используются до сих пор. Можно даже сказать, что подхватить пару трюков SSH будет полезнее, чем изучить десяток инструментов Cloud Native, которые рискуют устареть в следующем квартале.
Одна из моих любых частей этой технологии - это туннели SSH. Одними только стандартными инструментами, а иногда - одной только командой, можно добиться следующего:
- Получить доступ к внутреннему VPC через доступный извне инстанс EC2.
- Открыть хосту локальный порт виртуальной машины, используемой для разработки.
- Пробросить доступ из интернета к любому серверу в вашей домашней/приватной сети.
И даже больше 😍
Но не смотря на то, что я использую туннели SSH ежедневно, у меня постоянно возникаются трудности с подбором правильной команды. Мне нужен локальный или удаленный туннель? Какие использовать флаги? Писать локальный_порт:удаленный_порт или наоборот? Так что я решил наконец собрать все кусочки информации в кучу, и из этого получилась серия лабораторных работ и визуальная шпаргалка 🙈

Проброс локального порта (Local Port Forwarding)
Начну с туннеля, который я использую чаще всего. Часто на удаленной машине есть какой-то сервис, который слушает по порту на localhost или на приватном интерфейсе. Я могу подключиться к этой машине только по SSH, а мне очень нужно получить доступ к порту этого сервиса. Например, это удобно в таких сценариях:
- Получение доступа к БД (MySQL, PostgreSQL, Redis и т.п.) с помощью моднявой UI-утилиты на вашем ноуте.
- Открытие в браузере веб-сервиса, который доступен только в частной сети.
- Получение доступа к порту контейнера без публикации его в публичный интерфейс хоста.
Все юзкейсы выше могут быть решены одной командой:
ssh -L [local_addr:]local_port:remote_addr:remote_port [user@]sshd_addr
Флаг -L
означает, что мы запускаем проброс локального порта. Что это значит:
- На вашей машине клиент SSH начнет слушать по порту
local_port
(скорее всего, наlocalhost
, но это неточно, см. настройку GatewayPorts). - Любой трафик на этот порт будет перенаправлен на
remote_addr:remote_port
на той машине, к которой вы подключили по SSH.
Вот как это выглядит на диаграмме:

ssh -f -N -L
, чтобы запустить сессию проброса порта в фоновом режиме.Проброс локального порта с хостом-бастионом (Local Port Forwarding with a Bastion Host)
Это может показаться неочевидным, но команда ssh -L
позволяет пробросить локальный порт на удаленный порт любого хоста, не только SSH-сервера. Обратите внимание, что remote_addr
и sshd_addr
могут быть одинаковыми, а могут быть разными:
ssh -L [local_addr:]local_port:remote_addr:remote_port [user@]sshd_addr
Не знаю, насколько легитимно здесь употребление термина "хост-бастион", но так я сам себе представляю этот сценарий:

Я часто используют этот трюк, чтобы получить доступ к сервисам, которые доступны с бастиона, но не с моего ноутбука (например, при использовании инстанса EC2 с публичным и приватным интерфейсами, чтобы подключаться к кластеру OpenSearch, запущенному на VPC).
Проброс удаленного порта (Remote Port Forwarding)
Другой популярный (но обратный) сценарий работы - это когда вы хотите открыть свой локальный сервис внешнему миру. Конечно, для этого вам понадобится входной шлюз с доступом извне, но не страшитесь! Любой сервер с демоном SSH доступный из интернета может быть использован как такой шлюз:
ssh -R [remote_addr:]remote_port:local_addr:local_port [user@]gateway_addr
Команда выше выглядит ничуть не сложнее, чем ее аналог ssh -L
. Но есть подковырка...
По-умолчанию туннель выше позволит использовать в качестве удаленного адреса только localhost шлюза. Другими словами, ваш локальным порт будет доступен только изнутри самого сервера-шлюза, и, скорее всего, это не то, что вам нужно. Например, я обычно использую публичный адрес шлюза в качестве удаленного адреса, чтобы открывать свои локальные сервисы в интернет. Чтобы это работало, вам надо задать на сервере SSH настройку GatewayPorts yes
.
Вот для чего пригодится проброс удаленного порта:
- Открытие доступа к сервису в процессе разработки с вашего ноутбука в интернет для демонстрации.
- Хмм... Приходят на ум еще несколько эзотерических примеров, но не думаю, что они будут интересны здесь. Любопытно, для чего другие люди используют проброс удаленного порта!
Вот как это выглядит на диаграмме:

ssh -f -N -R
, чтобы запустить сессию проброса порта в фоновом режиме.Проброс удаленного порта в домашнюю/частную сеть (Remote Port Forwarding from a Home/Private Network)
Как и у проброса локального порта, у проброса удаленного порта тоже есть свой режим хоста-бастиона. Но в этот раз роль бастиона играет машина с клиентом SSH (т.е. ваш рабочий ноутбук). Этот режим, в особенности, позволяет открыть внешнему миру доступ к какому-то порту в вашей домашней (или частной) сети, к которому ваш ноутбук имеет доступ, через хост шлюза:
ssh -R [remote_addr:]remote_port:local_addr:local_port [user@]gateway_addr
Выглядит практически идентично простому пробросу удаленного порта, но пара local_addr:local_port
становится адресом устройства в домашней сети. Как это можно представить в виде диаграммы:

Так как я обычно использую свой ноутбук как тонкий клиент, в то время как разработка проходит на домашнем сервере, я полагаюсь на проброс удаленного порта, если мне нужно открыть свой локальный сервис в интернет, а единственная машина-шлюз, которая имеет к нему доступ - это мой ноутбук.
Кратко
После выполнения всех лабораторных и зарисовок, я отметил:
- Слово "локальный" (
local
) может означать как машину с клиентом SSH, так и машину в частной сети, доступную с нее. - Слово "удаленный" (
remote
) может означать как машину с сервером SSH (sshd), так и машину в частной сети, доступную с нее. - Проброс локального порта (local port forwarding,
ssh -L
) означает, что клиент ssh начинает слушать по новому порту. - Проброс удаленного порта (remote port forwarding,
ssh -R
) означает, что сервер ssh начинает слушать по еще одному порту. - Можно запомнить мненомики
ssh -L local:remote
иssh -R remote:local
, причем левая сторона всегда открывает новый порт.
Вместо заключения
Надеюсь материалы выше помогли вам стать мастером туннелей SSH 🧙 Если вам интересна тема компьютерных сетей, но вам кажется, что большинство материалов о них написаны бородатыми сетевиками и недоступны простым разработчикам, вот еще несколько статьей, которые могут оказаться вам полезны:
- Computer Networking Introduction: Ethernet and IP
- Illustrated introduction to Linux iptables
- Bridge vs. Switch: What I Learned From a Data Center Tour
- Container Networking Is Simple (not really)
Приятного чтения!
Ресурсы
- SSH Tunneling Explained от гуру сетей из Teleport.
- SSH Tunneling: Examples, Command, Server Config от SSH Academy.
Материал подготовлен с ❤️ редакцией Кухни IT.