Обучение

Обучение

Life-Hack

5) SSH VPN Tunnel

TCP port forwarding — это отличная возможность. Но что если нам нужно больше? Доступ по UDP, доступ к множеству портов и хостов, доступ к динамическим портам? Ответ очевиден — VPN. И всемогущий SSH начиная с версии 4.3 и здесь придет нам на помощь.


Забегая вперед скажу: этот функционал SSH хорошо работает если вам нужно временное решение для каких-то административных задач. Для построения постоянных VPN этот вариант далеко не самый подходящий, т. к. он предполагает TCP-over-TCP, что плохо скажется на скорости соединения.


Еще про TCP forwarding

А вот TCP port forwarding с помощью SSH, если его достаточно, во многих случаях выиграет по производительности у VPN, т. к. при TCP port forwarding передаются только данные приложения, а не исходные пакеты целиком вместе с заголовками, см. ссылку: http://blog.backslasher.net/ssh-openvpn-tunneling.html


Настройка SSH-сервера:

PermitTunnel в настройках sshd по-умолчанию выключен, его нужно включить в /etc/ssh/sshd_config:

PermitTunnel yes

или

PermitTunnel point-to-point


ВАЖНО: для поднятия нового сетевого интерфейса туннеля и на ssh-клиенте, и на ssh-сервере необходимы права суперпользователя. Можно долго спорить о том, насколько это небезопасно, но в большинстве случаев на ssh-сервере достаточно настройки:


PermitRootLogin without-password


Таким образом вы запрещаете вход root по паролю, а разрешаете только другими средствами, например, по ключу RSA, что гораздо безопаснее.


Перезапускаем sshd:

sudo service sshd restart # centos

или

/etc/init.d/ssh restart # (debian/ubuntu)


Туннель поднимается при использовании магического ключа -w:


host1# sudo ssh -w 5:5 root@host2


Где 5:5 — номер интерфейса на локальной машине и на удаленной соответственно. Здесь вас может смутить, что ifconfig не выдаст в списке интерфейса «tun5». Это потому что он в состоянии «down», а вот если вызвать «ifconfig -a» или «ifconfig tun5», то интерфейс будет виден:


host1# ifconfig tun5

tun5 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 

POINTOPOINT NOARP MULTICAST MTU:1500 Metric:1

RX packets:0 errors:0 dropped:0 overruns:0 frame:0

TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:500 

RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)


Назначаем интерфейсам IP-адреса и поднимаем их:


host1# sudo ifconfig tun5 192.168.150.101/24 pointopoint 192.168.150.102

host2# sudo ifconfig tun5 192.168.150.102/24 pointopoint 192.168.150.101


Если есть файрвол, не забываем разрешить соединения с интерфейса tun5:


host1# # сохраняем исходные правила файрвола

host1# sudo iptables-save > /tmp/iptables.rules.orig

host1# sudo iptables -I INPUT 1 -i tun5 -j ACCEPT

host2# # сохраняем исходные правила файрвола

host2# sudo iptables-save > /tmp/iptables.rules.orig

host2# sudo iptables -I INPUT 1 -i tun5 -j ACCEPT


На host1 это делать необязательно, здесь это сделано лишь для того чтобы ping работал в обе стороны.


Наслаждаемся пингом:


host1# ping 192.168.150.102

host2# ping 192.168.150.101


Если рассмотреть более ранний пример с PostgreSQL, то теперь схема будет такая:

А команда для подключения к серверу PostgreSQL будет выглядеть так:


host1# psql -h 192.168.150.102 -U postgres


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


host2# # разрешаем IP forwarding

host2# sudo sysctl -w net.ipv4.ip_forward=1

host2# # разрешаем IP forwarding с host1

host2# sudo iptables -I FORWARD 1 -s 192.168.150.101 -j ACCEPT

host2# # разрешаем IP forwarding на host1

host2# sudo iptables -I FORWARD 1 -d 192.168.150.101 -j ACCEPT

host2# # маскируем IP адрес host1

host2# sudo iptables -t nat -A POSTROUTING -s 192.168.150.101 -j MASQUERADE


host1# # Предположим, у host2 есть доступ к сети 192.168.2.x, куда нам нужно попасть с host1

host1# # Прописываем host2 как шлюз в сеть 192.168.2.x

host1# sudo ip route add 192.168.2.0/24 via 192.168.150.2

host1# # Наслаждаемся доступом в сеть с host1

host1# ping 192.168.2.1


После окончания работы не забываем вернуть net.ipv4.ip_forward и файрвол в исходное состояние.


host1# sudo iptables-restore < /tmp/iptables.rules.orig

host2# sudo iptables-restore < /tmp/iptables.rules.orig


Под спойлером более интересный случай с временным расшариванием Интернета

Допустим, нужно настроить сервер в закрытой сети, где доступ в Интернет запрещен, но тем не менее у вас туда есть лазейка — доступ через один ssh-сервер или цепочку ssh-серверов. Предположим, для настройки сервера вам нужен на нем доступ в Интернет. Тогда проще самостоятельно настроить временный доступ в Интернет на требующем настройки сервере, чем просить это сделать обслуживающий персонал.


Допустим, есть доступ по ssh с вашей рабочей машины host1 на сервер host2, с него — на host3, а уже оттуда — на нужный вам host4. Тогда делаем TCP forwarding для ssh (если с host1 вы сразу можете соединиться с host4, пропустите этот шаг):


host1# ssh -L 2222:localhost:2222 host2

host2# ssh -L 2222:host4:22 host3


Далее, соединяемся с host4 и поднимаем интерфейс tun5:


host1# sudo ssh -p 2222 -w 5:5 root@localhost

host1# # или если host4 доступен сразу: sudo ssh -w 5:5 root@host4

host1# sudo ifconfig tun5 192.168.150.101/24 pointopoint 192.168.150.102

host4# sudo ifconfig tun5 192.168.150.102/24 pointopoint 192.168.150.101


Смотрим таблицу маршрутизации на host4, допустим видим следующее:


host4# route -n

Kernel IP routing table

Destination Gateway Genmask Flags Metric Ref Use Iface

192.168.150.0 0.0.0.0 255.255.255.0 U 0 0 0 tun5

192.168.56.0 0.0.0.0 255.255.255.0 U 1 0 0 eth0

0.0.0.0 192.168.56.254 0.0.0.0 UG 0 0 0 eth0


ВАЖНО! Далее нам скорее всего захочется сделать маршрутом по-умолчанию интерфейс tun5 со шлюзом 192.168.150.101, через который будет доступен Интернет. Поэтому на данном этапе важно точно знать, какие маршруты нужно дописать, чтобы заменить маршрут по-умолчанию. Это важно, поскольку довольно часто маршруты на отдельные сети не прописывают отдельно, а просто задают маршрут по-умолчанию (0.0.0.0/0) со шлюзом, через который и идет весь межсетевой трафик. Более того, вполне вероятно что ваше ssh-соединение с сервером также использует исходный шлюз по-умолчанию.


Для простоты в данном примере предположим, что никаких маршрутов кроме 192.168.56.0/24 серверу для нормального функционирования не нужно и что предыдущий ssh-хост host3 имеет IP-адрес из этой же сети.


Запоминаем и записываем куда-нибудь исходную маршрутную таблицу со шлюзом по-умолчанию:

host4# route -n > routes.orig


Настраиваем наш host1 для работы в качестве шлюза в Интернет для host4:


host1# # разрешаем IP forwarding

host1# sudo sysctl -w net.ipv4.ip_forward=1

host1# # сохраняем исходные правила файрвола

host1# sudo iptables-save > /tmp/iptables.rules.orig

host1# # разрешаем IP forwarding с host4

host1# sudo iptables -I FORWARD 1 -s 192.168.150.102 -j ACCEPT

host1# # разрешаем IP forwarding на host4

host1# sudo iptables -I FORWARD 1 -d 192.168.150.102 -j ACCEPT

host1# # маскируем IP адрес host4

host1# sudo iptables -t nat -A POSTROUTING -s 192.168.150.102 -j MASQUERADE


На всякий случай можно прописать серые сети на шлюз из текущего маршрута по-умолчанию

Если не прописаны:

sudo ip route add 192.168.0.0/16 via 192.168.56.254

sudo ip route add 10.0.0.0/8 via 192.168.56.254

sudo ip route add 172.16.0.0/12 via 192.168.56.254



Изменяем маршрут по-умолчанию на host4 (ОСТОРОЖНО, см. предупреждение выше!):


host4# sudo ip route replace default via 192.168.150.101

host4# route -n

Kernel IP routing table

Destination Gateway Genmask Flags Metric Ref Use Iface

192.168.150.0 0.0.0.0 255.255.255.0 U 0 0 0 tun5

192.168.56.0 0.0.0.0 255.255.255.0 U 1 0 0 eth0

0.0.0.0 192.168.150.101 0.0.0.0 UG 0 0 0 tun5


Если весь Интернет нам не нужен, а только конкретные IP-адреса/маски, то можно маршрут по-умолчанию не менять, а дописать только нужные нам адреса через шлюз на tun5.


Проверяем, что есть Интернет:


host4# ping 8.8.8.8


Отлично. Осталось настроить DNS. Есть множество способов это сделать, проще всего отредактировать файл /etc/resolv.conf и добавить туда строчки:


nameserver 8.8.8.8

nameserver 8.8.4.4


После этого Интернет должен быть полностью доступен:


host4# ping ya.ru


После окончания работы не забываем вернуть все в исходное состояние:


host1# # восстанавливаем правила файрвола на host1

host1# sudo iptables-restore < /tmp/iptables.rules.orig

host1# # не забудьте восстановить также значение net.ipv4.ip_forward


host2# # восстановите маршрут по-умолчанию на host4:

host2# sudo ip route replace default via 192.168.56.254

host2# # и уберите добавленные ранее DNS-сервера из /etc/resolv.conf