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

Визуальный гайд по туннелям SSH (с лабами)
👋
Хочешь поучаствовать в жизни сайта? Мы ищем авторов!
Это полный перевод статьи и всех диаграмм Ивана Величко: A Visual Guide to SSH Tunnels (with labs).
Оглавление

TL;DR: Шпаргалка по пробросу портов по SSH целиком на одном листе.

SSH - еще один пример древних технологий, которые активно используются до сих пор. Можно даже сказать, что подхватить пару трюков SSH будет полезнее, чем изучить десяток инструментов Cloud Native, которые рискуют устареть в следующем квартале.

Одна из моих любых частей этой технологии - это туннели SSH. Одними только стандартными инструментами, а иногда - одной только командой, можно добиться следующего:

  • Получить доступ к внутреннему VPC через доступный извне инстанс EC2.
  • Открыть хосту локальный порт виртуальной машины, используемой для разработки.
  • Пробросить доступ из интернета к любому серверу в вашей домашней/приватной сети.

И даже больше 😍

Но не смотря на то, что я использую туннели SSH ежедневно, у меня постоянно возникаются трудности с подбором правильной команды. Мне нужен локальный или удаленный туннель? Какие использовать флаги? Писать локальный_порт:удаленный_порт или наоборот? Так что я решил наконец собрать все кусочки информации в кучу, и из этого получилась серия лабораторных работ и визуальная шпаргалка 🙈

Полная версия (1.9 Мб)

Проброс локального порта (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, чтобы запустить сессию проброса порта в фоновом режиме.

Лабораторная 1.

Проброс локального порта с хостом-бастионом (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).

Лабораторная 2.

Проброс удаленного порта (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, чтобы запустить сессию проброса порта в фоновом режиме.

Лабораторная 3.

Проброс удаленного порта в домашнюю/частную сеть (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 становится адресом устройства в домашней сети. Как это можно представить в виде диаграммы:

Так как я обычно использую свой ноутбук как тонкий клиент, в то время как разработка проходит на домашнем сервере, я полагаюсь на проброс удаленного порта, если мне нужно открыть свой локальный сервис в интернет, а единственная машина-шлюз, которая имеет к нему доступ - это мой ноутбук.

Лабораторная 4.

Кратко

После выполнения всех лабораторных и зарисовок, я отметил:

  • Слово "локальный" (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 🧙 Если вам интересна тема компьютерных сетей, но вам кажется, что большинство материалов о них написаны бородатыми сетевиками и недоступны простым разработчикам, вот еще несколько статьей, которые могут оказаться вам полезны:

Приятного чтения!

Ресурсы

Материал подготовлен с ❤️ редакцией Кухни IT.

Олег Ямников

Олег Ямников

Главный кухонный корреспондент.