ssh-tunnel

SSH – тоннели

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

Например, вот так будет выглядеть схема обратного туннеля, в котором обращение к порту 80 SSH-клиента выполняется через SSH-сервер с определенного IP-адреса (1.2.3.4):

Здесь и далее все схемы взяты из оригинала статьи
Здесь и далее все схемы взяты из оригинала статьи

Сценарии использования туннелей*:

  • Предоставление зашифрованных каналов для протоколов, передающих данные «открытым текстом».
  • Открытие бэкдоров в частные сети.
  • Обход межсетевых экранов.

*. Примечание

Перечень дополняется. Не стесняйтесь предлагать примеры или исправления на GitHub.

Проброс портов

Перенаправляет порт из одной системы (локальной или удаленной) в другую.

Проброс локального порта

Проброс локальных портов позволяет перенаправить трафик с SSH-клиента на целевой хост через SSH-сервер. Другими словами, можно получить доступ к удаленным сервисам по зашифрованному соединению так, как будто они локальные. Примеры использования:

  • доступ к удаленному сервису (Redis, Memcached и т. д.) по внутреннему IP-адресу;
  • локальный доступ к ресурсам, размещенным в частной сети;
  • прозрачное проксирование запроса к удаленному сервису.

Проброс удаленного порта

Проброс удаленного порта позволяет направить трафик с SSH-сервера в пункт назначения либо через SSH-клиент, либо через другой удаленный хост. Открывает пользователям в публичных сетях доступ к ресурсам в частных сетях. Примеры использования:

  • открытие доступа к локальному серверу разработки через публичную сеть;
  • предоставление доступа с ограничением по IP-адресу к удаленному ресурсу в частной сети.

Динамический проброс портов

При динамической переадресации портов на SSH-клиенте поднимается SOCKS-прокси для перенаправления TCP-трафика через SSH-сервер на удаленный хост.

Пересылка с системных (privileged) портов

Для пересылки трафика с системных портов (1–1023) необходимо запустить SSH с правами суперпользователя в системе, на которой открывается порт.

sudo ssh -L 80:example.com:80 ssh-server

Флаги командной строки SSH

Ниже приведены несколько полезных флагов при создании туннелей:

-f # переводит процесс ssh в фоновый режим;
-n # предотвращает чтение из STDIN;
-N # не выполнять удаленные команды. Полезно, если нужно только перенаправить порты;
-T # отменяет переназначение терминала.

Вот пример команды для создания SSH-туннеля в фоновом режиме и проброса локального порта через SSH-сервер:

ssh -fnNT -L 127.0.0.1:8080:example.org:80 ssh-server

Для краткости примеры ниже приводятся без флагов командной строки.

Проброс локального порта

Перенаправление соединений с порта локальной системы на порт удаленного хоста:

ssh -L 127.0.0.1:8080:example.org:80 ssh-server

Перенаправляет локальные подключения к 127.0.0.1:8080 на 80-й порт example.org через SSH-сервер. Трафик между локальной системой и SSH-сервером идет по SSH-туннелю. Трафик между SSH-сервером и example.org — нет. С точки зрения example.org трафик идет от SSH-сервера.

ssh -L 8080:example.org:80 ssh-server
ssh -L *:8080:example.org:80 ssh-server

Команды выше открывают доступ к example.org:80 через SSH-туннель для подключений на порт 8080 на всех интерфейсах локальной системы.

ssh -L 192.168.0.1:5432:127.0.0.1:5432 ssh-server

Переадресует соединения с 192.168.0.1:5432 в локальной системе на 127.0.0.1:5432 на SSH-сервере. Обратите внимание, что здесь 127.0.0.1 — localhost с точки зрения SSH-сервера.

Конфигурации SSH

Убедитесь, что на SSH-сервере включена переадресация TCP (по умолчанию так и должно быть). Проверьте запись в файле /etc/ssh/sshd_config:

AllowTcpForwarding yes

При переадресации портов на интерфейсы, отличные от 127.0.0.1, в локальной системе необходимо включить GatewayPorts (в /etc/ssh/ssh_config или в командной строке):

GatewayPorts yes

Сценарии использования

Подходит для случаев, когда требуется защищенное соединение для доступа к удаленному сервису, который работает с незашифрованными данными. Например, Redis и Memcached используют протоколы на основе plaintext-данных.

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

Проброс удаленного порта

Пробрасывает порт на удаленной системе в другую систему.

ssh -R 8080:localhost:80 ssh-server

Перенаправляет трафик с порта 8080 SSH-сервера для всех интерфейсов на порт localhost:80 на локальном компьютере. Если один из интерфейсов смотрит в Интернет, трафик, адресуемый на порт 8080, будет перенаправляться на локальную систему.

ssh -R 1.2.3.4:8080:localhost:80 ssh-server

Переадресует трафик с порта 8080 SSH-сервера на localhost:80 в локальной системе, при этом доступ ко входу в SSH-туннель со стороны сервера разрешен только с IP-адреса 1.2.3.4 (обратите внимание: директиву GatewayPorts необходимо установить в clientspecified).

ssh -R 8080:example.org:80 ssh-server

Переадресует трафик с порта 8080 SSH-сервера для всех интерфейсов на localhost:80 в локальной системе. Далее трафик из локальной системы направляется на example.org:80. С точки зрения example.org источником трафика выступает локальная система.

Конфигурация SSH-сервера

SSH-сервер конфигурируется в файле /etc/ssh/sshd_config.

По умолчанию переадресуемые порты недоступны для доступа из Интернета. Для переадресации публичного интернет-трафика на локальный компьютер добавьте в sshd_config на удаленном сервере такую строку:

GatewayPorts yes

Также в sshd_config можно указать, каким клиентам разрешен доступ:

GatewayPorts clientspecified

Динамический проброс портов

Перенаправление трафика с нескольких портов на удаленный сервер.

ssh -D 3000 ssh-server

Команда выше поднимает SOCKS-прокси на порту 3000 для всех интерфейсов в локальной системе. Теперь трафик, отправленный через прокси-сервер на SSH-сервер, можно адресовать на любой порт или конечный хост. По умолчанию используется протокол SOCKS5, поддерживающий TCP и UDP.

ssh -D 127.0.0.1:3000 ssh-server

Поднимает SOCKS-прокси на 127.0.0.1:3000 в локальной системе.

При работающем SOCKS-прокси можно настроить браузер на его использование для доступа к ресурсам так, как будто соединения исходят от SSH-сервера. Например, если у SSH-сервера есть доступ к другим серверам в частной сети, с помощью SOCKS-прокси можно заходить на эти серверы локально (словно вы находитесь в той же сети), и не нужно настраивать VPN.

Работу SOCKS-прокси можно проверить командой:

curl -x socks5://127.0.0.1:12345 https://example.org

Конфигурация SSH-клиента

SSH-клиент настраивается в файле /etc/ssh/ssh_config.

Включите GatewayPorts в системе, чтобы открыть доступ другим интерфейсам к SOCKS-прокси:

GatewayPorts yes

Поскольку GatewayPorts конфигурируется на SSH-клиенте, вместо ssh_config для настройки можно использовать параметры командной строки:

ssh -o GatewayPorts=yes -D 3000 ssh-server

Jump-хосты и команды прокси-сервера

Прозрачное подключение к удаленному хосту через промежуточные.

ssh -J user1@jump-host user2@remote-host
ssh -o "ProxyJump user1@jump-host" user2@remote-host

Устанавливает SSH-соединение с jump-хостом и переадресуют трафик на удаленный хост. 

Подключается к удаленному хосту через промежуточный jump-хост. Приведенная выше команда должна сработать сразу, если у jump-хоста уже есть SSH-доступ к удаленному хосту. Если нет, можно использовать agent forwarding для проброса SSH-ключа с локального компьютера на удаленный хост.

ssh -J jump-host1,jump-host2 ssh-server

Можно указать несколько jump-хостов через запятую.

ssh -o ProxyCommand="nc -X 5 -x localhost:3000 %h %p" user@remote-host

Подключение к удаленному серверу через SOCKS5 с использованием netcat. С точки зрения сервера, IP-адрес отправителя принадлежит прокси-хосту. При этом для SSH-соединения используется сквозное шифрование, так что прокси-хост видит только зашифрованный трафик между локальной системой и удаленным хостом.

Конфигурация SSH-клиента

SSH-клиент конфигурируется в файле /etc/ssh/ssh_config.

Для подключения agent forwarding можно добавить локальный SSH-ключ к локальному SSH-агенту с помощью ssh-add:

ssh-add

Надежные SSH-туннели

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

По умолчанию TCP-соединение, используемое для создания SSH-туннеля, может разрываться после некоторого периода бездействия. Чтобы это предотвратить, нужно настроить сервер (/etc/ssh/sshd_config) на отправку heartbeat-сообщений:

ClientAliveInterval 15
ClientAliveCountMax 4

На отсылку таких сообщений также можно настроить клиент (/etc/ssh/ssh_config):

ServerAliveInterval 15
ServerAliveCountMax 4

Использование AutoSSH

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

AutoSSH принимает те же аргументы для настройки переадресации портов, что и SSH:

autossh -R 2222:localhost:22 ssh-server

Эта команда создает туннель, способный восстанавливаться после сетевых сбоев. По умолчанию AutoSSH открывает дополнительные порты на SSH-клиенте/сервере для проверки работоспособности (healthcheck). Если трафик не проходит между healthcheck-портами, AutoSSH перезапускает туннель.

autossh -R 2222:localhost:22 \
  -M 0 \
  -o "ServerAliveInterval 10" -o "ServerAliveCountMax 3" \
  remote-host

Флаг -M 0 отключает healthcheck-порты (за проверку работоспособности в этом случае отвечает SSH-клиент). В примере выше сервер должен посылать сигналы каждые 10 секунд. Если не проходят три подряд сигнала, SSH-клиент завершает работу, а AutoSSH поднимает новый туннель.

Дополнительные примеры и сценарии использования

Прозрачный доступ к удаленному ресурсу в частной сети.

Предположим, в частной сети есть Git-репозиторий, доступ к которому возможен только через выделенный сервер в этой сети. Сервер не подключен к Интернету. Есть прямой доступ к серверу, но нет VPN-доступа к частной сети.

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

ssh -L 127.0.0.1:22:127.0.0.1:2222 intermediate-host

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

ssh -p 2222 user@localhost

Для большего удобства можно добавить несколько директив в локальный ~/.ssh/config:

Host git.private.network
  HostName git.private.network
  ForwardAgent yes
  ProxyCommand ssh private nc %h %p

Host private
  HostName localhost
  Port 2222
  User private-user
  ForwardAgent yes
  ProxyCommand ssh tunnel@intermediate-host nc %h %p

В результате пользователь получает доступ к локальному Git-репозиторию, как если бы находился в частной сети.

Previous Story

4 способа сбросить пароль root на хосте
VMWare ESXi

Next Story

LXC

Latest from Blog

Zabbix – Docker – Raspberry Pi

Для начала установим Portainer – веб-интерфейс для управления docker-контейнерами. Бесплатно, удобно, подойдет новичкам в docker. Установка

Сетевая папка/диск в Linux

x.x.x.x адрес шары /mnt/shara точка монтирования user пользователь с доступом к шаре 1234 пароль пользователя Для

Памятка SSH

В статье описаны продвинутые функций OpenSSH, которые позволяют сильно упростить жизнь системным администраторам и программистам, которые

0 £0.00