p2p туннель средсвами ssh

Тунель - способ установления безопасного соединения между двумя конечными точками в сети (Point - to - Point или p2p).

Суть туннелирования:

  • зашифровать исходный трафик (в том числе информацию о получателе и отправителе);
  • передать его на сервер, используя незащищенную сеть;
  • произвести расшифровку;
  • отправить данные адресату. Point-to-Point тунель

С точки зрения операционной системы это выглядит следующим образом:

  1. Клиент устанавливает ssh подключение к серверу;
  2. Сервер авторизует Клиента;
  3. Клиент и Сервер создают виртуальные устройства (TUN) в операционной системе и назначают им ip адреса локальной и удаленной стороны.

В качестве транспортного уровня используется ранее установленное ssh подключение и в случае его обрыва (или завершения процесса ssh, обслуживающее это соединение) - связь с сервером будет потеряна.

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

Главное преимущество ssh перед другими средствами организации туннелей - его распространенность. В каждом linux дистрибутиве он включен в стандартную поставку. Среди основных сценариев можно выделить следующие:

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

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

Конфигурация систем

Параметры конфигурации компьютеров, между которыми будет произведено подключение:

Клиент:

IP адрес: 192.168.1.50  Маска сети: 255.255.255.0

Таблица маршрутизации:
Destination   Gateway        Genmask        Flags Metric Ref Use Iface   
192.168.1.0   0.0.0.0        255.255.255.0  U     1      0   0   eth0
169.254.0.0   0.0.0.0        255.255.0.0    U     1000   0   0   eth0
0.0.0.0       192.168.1.100  0.0.0.0        UG    0      0   0   eth0

Сервер:

IP адрес: 81.28.170.12  Маска сети: 255.255.192.0

Таблица маршрутизации:
Destination   Gateway        Genmask        Flags Metric Ref Use Iface   
81.28.170.0   0.0.0.0        255.255.255.0  U     1      0   0   eth0
169.254.0.0   0.0.0.0        255.255.0.0    U     1000   0   0   eth0
0.0.0.0       81.28.170.100  0.0.0.20        UG    0      0   0   eth0

169.254.0.0 — zeroconf маршрут.

Настройка сервера

Открывать root доступ, даже при условии запрета авторизации по паролю, очень опасно. В случае компрометации ключа (или пароля), злоумышленник получит полный доступ к вашему серверу. Поэтому необходимо создать пользователя с ограниченными правами доступа и сгенерировать для него ключ удаленной авторизации. Таким образом, даже в случае компрометации ключа, контроль над сервером не будет утрачен и урон будет значительно меньшим.

# Добавляем пользователя vpn
root@server:/# useradd -mU vpn
# Создаем папку .ssh, в которой ssh будет искать публичную часть ключа
root@server:/# mkdir /home/vpn/.ssh
# Генерируем ключ
root@server:/# ssh-keygen -t rsa -b 2048
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): /home/vpn/.ssh/vpn-17012
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/vpn/.ssh/vpn-17012.
Your public key has been saved in /home/vpn/.ssh/vpn-17012.pub.
The key fingerprint is:
d3:dc:72:21:c9:7e:58:5b:46:38:e7:a7:3a:06:73:0d root@server
The key's randomart image is:
+--[ RSA 2048]----+
|             ..  |
|         . .o..  |
|          + o+o  |
|         + =E=. .|
|        S * =o o |
|         .o+. o  |
|           + .   |
|            +    |
|           . .   |
+-----------------+
# Добавляем публичную часть ключа в список разрешенных к авторизации
root@server:/# cat /home/vpn/.ssh/vpn-17012.pub >> /home/vpn/.ssh/authorized_keys
# Копируем приватную часть ключа в /tmp/
root@server:/# cp /home/vpn/.ssh/vpn-17012 /tmp/
root@server:/#

*Для удобства при генерации ключа используется имя пользователя и часть ip адреса или доменного имени сервера.
**Файл <user home>/.ssh/authorized_keys - стандартное место хранения публичной части ключа, используемого при авторизации.
***Последняя команда (cp /home/vpn/.ssh/vpn-17012 /tmp/) копирует приватную часть ключа в папку /tmp, чтобы позднее его можно было скопировать на клиента.

Теперь, когда пользователь создан, необходимо заранее создать TUN устройство, которое будет доступно для чтения и записи пользователю vpn (создание любого устройства /dev/* требует наличия прав администратора). Для этого необходимо создать systemd netdev и network файлы.

Создайте файл /etc/systemd/system/network/30-vpn-17012.netdev со следующим содержанием:

[NetDev]
Name=tun0
Kind=tun

[Tun]
Group=vpn

и файл /etc/systemd/network/30-vpn-17012.network:

[Match]
Name=tun0

[Address]
Address=172.17.0.1/30
Peer=172.17.0.2/30

[Network]
Address=172.17.0.1/30

[Route]
Gateway=172.17.0.1
Destination=192.168.1.0/24

С помощью этих двух файлов сервис systemd-networkd сконфигурирует:

  • TUNTAP устройство /dev/tun0 в режиме TUN;
  • Разрешит доступ к нему пользователям, состоящим в группе vpn;
  • Назначит ip адрес интерфейсу и добавит маршрут для подсети клиента (секция Route).

Чтобы изменения вступили в силу, перезапустите сервис systemd-networkd:

root@server:/# systemctl restart systemd-networkd
# Убеждаемся в правильной конфигурации TUN устройства
root@server:/# ifconfig tun0
tun0: flags=4241<UP,POINTOPOINT,NOARP,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.255.252  destination 172.17.0.2 
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
# Проверяем таблицу маршрутизации
root@server:/# route -n
Kernel IP routing table
Destination   Gateway        Genmask         Flags Metric Ref Use Iface   
81.28.170.0   0.0.0.0        255.255.255.0   U     1      0   0   eth0
169.254.0.0   0.0.0.0        255.255.0.0     U     1000   0   0   eth0
0.0.0.0       81.28.170.100  0.0.0.0         UG    0      0   0   eth0
192.168.1.0   0.0.0.0        255.255.255.0   U     0      0   0   tun0
172.17.0.0    0.0.0.0        255.255.255.252 U     0      0   0   tun0

root@server:/#

*Последняя команда (route -n) показывает параметры маршрутизации пакетов. Один из них - подсеть 192.168.1.0/24, указывающая на интерфейс tun0. С помощью неё трафик будет возвращаться на клиента.

Следующим шагом необходимо перенастроить демон ssh. По умолчанию, тунелирование запрещено в конфигурации сервера ssh. Чтобы его включить, необходимо отредактировать файл /etc/ssh/sshd_config:

# Запрещает авторизацию для root
PermitRootLogin no

# Список пользователей, которым разрешена авторизация. Указывается через пробел
AllowUsers vpn alex

# По умолчанию PermitTunnel установлен в `no`
PermitTunnel yes 

*Пользователю alex также разрешено удаленное подключение к серверу. При настройке клиента копирование ключа будет произведено от имени этого пользователя.

Чтобы изменения вступили в силу, перезапустите сервис sshd:

root@server:/# systemctl restart sshd
root@server:/#

Последнее изменение, которое необходимо выполнить на сервере - разрешить пересылку пакетов между интерфейсами. Для этого необходимо изменить параметр ядра операционной системы net.ipv4.ip_forward, изменив файл /etc/sysctl.conf:

# Значение 0 отключает возможность пересылки пакетов между интерфейсами
net.ipv4.ip_forward = 1

И перечитайть настройки ядра:

root@server:/# sysctl -f|grep "net.ipv4.ip_forward"
net.ipv4.ip_forward = 1
root@server:/#
Настройка клиента

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

# Добавляем пользователя vpn-17012
root@client:/# useradd -mU vpn-17012
# Создаем папку .ssh, в которой ssh клиент будет хранить приватный ключ сервера
root@client:/# mkdir /home/vpn-17012/.ssh
# Копируем приватный ключ с сервера
root@client:/# scp alex@81.28.170.12://tmp/vpn-17012 /home/vpn-17012/.ssh/
alex@81.28.170.12's password: 
vpn-17012                                                  100%   51     0.1KB/s   0.1KB/s   00:00
# Меняем права доступа ключа
root@client:/# chown vpn-17012:vpn-17012 /home/vpn/vpn-17012/.ssh/vpn-170-12
root@client:/# chmod 600 /home/vpn-17012/.ssh/vpn-17012
root@client:/# 

*Для удобства при создании пользователя используется имя пользователя и часть ip адреса сервера.
**Команды chown и chmod нужны для изменения прав доступа к ключу.

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

Создайте файл /etc/systemd/system/network/30-vpn-17012.netdev со следующим содержанием:

[NetDev]
Name=tun0
Kind=tun

[Tun]
Group=vpn-17012

и файл /etc/systemd/network/30-vpn-17012.network:

[Match]
Name=tun0

[Address]
Address=172.17.0.2/30
Peer=172.17.0.1/30

[Network]
Address=172.17.0.1/30

С помощью этих двух файлов сервис systemd-networkd сконфигурирует:

  • TUNTAP устройство /dev/tun0 в режиме TUN;
  • Разрешит доступ к нему пользователям, состоящим в группе vpn-17012;
  • Назначит ip адрес интерфейсу и добавит маршрут до сервера.

Чтобы изменения вступили в силу, перезапустите сервис systemd-networkd:

root@client:/# systemctl restart systemd-networkd
# Убеждаемся в правильной конфигурации TUN устройства
root@client:/# ifconfig tun0
tun0: flags=4241<UP,POINTOPOINT,NOARP,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.255.252  destination 172.17.0.1
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
# Проверяем таблицу маршрутизации
root@client:/# route -n
Kernel IP routing table
Destination   Gateway        Genmask         Flags Metric Ref Use Iface
192.168.1.0   0.0.0.0        255.255.255.0   U     1      0   0   eth0
169.254.0.0   0.0.0.0        255.255.0.0     U     1000   0   0   eth0
0.0.0.0       192.168.1.100  0.0.0.0         UG    0      0   0   eth0
172.17.0.1    0.0.0.0        255.255.255.255 UH    0      0   0   tun0

root@client:/#

*Последняя команда показывает параметры маршрутизации пакетов. Один из них - 172.17.0.1, указывающий на интерфейс tun0. С помощью него трафик будет отправляться на сервер.

Как и в случае с сервером, необходимо перенастроить демон ssh. Отредактировуйте файл /etc/ssh/sshd_config:

# Запрещает авторизацию для root
PermitRootLogin no

# По умолчанию PermitTunnel установлен в `no`
PermitTunnel yes 

* Обратите внимание, на клиенте пользователю vpn-17012 авторизация запрещена.

Чтобы изменения вступили в силу, перезапустите сервис sshd:

root@client:/# systemctl restart sshd

Последнее изменение, которое необходимо выполнить на клиенте - разрешить пересылку пакетов между интерфейсами. Для этого необходимо изменить параметр ядра операционной системы net.ipv4.ip_forward, отредактируя файл /etc/sysctl.conf:

# Значение 0 отключает возможность пересылки пакетов между интерфейсами
net.ipv4.ip_forward = 1

И применить настройки ядра:

root@client:/# sysctl -f|grep "net.ipv4.ip_forward"
net.ipv4.ip_forward = 1
root@client:/#
Подключение клиента к серверу

Подключение клиента к серверу, в режиме туннелирования осуществляется коммандой:

root@client:/# su vpn-17012
vpn-17012@client:/# ssh -NCT -w 0:0 vpn@81.28.170.12 -p 22 -i /home/vpn-17012/.ssh/vpn-17012

*Процесс подключения не перейдет в режим демона. Чтобы его остановить нажмите CTRL + C.
**Параметр N - запрещает выполнение удаленной команды, С - включает компрессию, и Т - отключает использование псевдо терминала.
***Параметр -w 0:0 - включает режим туннелирования (локальный:удаленный - номер локального и удаленного tun устройства).

Для проверки соединения откройте другой терминал и наберите в нем комманду:

root@client:/# ping -c 4 172.17.0.1
PING 172.17.0.1 (172.17.0.1) 56(84) bytes of data.
64 bytes from 172.17.0.1: icmp_seq=1 ttl=64 time=0.015 ms
64 bytes from 172.17.0.1: icmp_seq=2 ttl=64 time=0.022 ms
64 bytes from 172.17.0.1: icmp_seq=3 ttl=64 time=0.030 ms
64 bytes from 172.17.0.1: icmp_seq=4 ttl=64 time=0.031 ms

--- 172.17.0.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2998ms
rtt min/avg/max/mdev = 0.015/0.024/0.031/0.008 ms
root@client:/#

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

Создайте файл /etc/systemd/system/vpn-17012.service:

[Unit]
Description=ssh vpn@81.28.170.12
After=network-online.target
Requires=network-online.target

[Service]
Restart=always
RestartSec=15
User=vpn-17012
ExecStart=/usr/bin/ssh -NCT -w 0:0 vpn@81.28.170.12 -p 22 -i /home/vpn-17012/.ssh/vpn-17012

[Install]
WantedBy=multi-user.target

Запустите его и добавьте в автозагрузку:

root@client:/# systemctl enable vpn-17012
Created symlink from /etc/systemd/system/multi-user.target.wants/vpn-17012.service to /etc/systemd/system/vpn-17012.service.
root@client:/# systemctl start vpn-17012
root@client:/#

После этого, в случае обрыва связи, systemd автоматически будет перезапускать ssh подключение.