OpenVPN: частный случай p2p соединения

(Оригинал написан для linuxetc.ru) Рассмотрим весьма частный случай применения OpenVPN.

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

  1. Диспетчер, он же центральный хаб "звезды", он же VPN-сервер в стандартной схеме "клиент-сервер".
  2. Client1, по отношению к диспетчеру -- клиент.
  3. Client2, по отношению к диспетчеру -- клиент.
  4. Предполагается, что впоследствии появятся ещё Client3, ..., ClientN, и все они по отношению к диспетчеру будут суть клиенты.

Считается, что VPN между диспетчером и каждым из клиентов уже настроен, то есть классическая "звезда" уже работает.

Требуется обеспечить симметричный p2p VPN-линк между Client1 и Client2. Другими словами, превратить "звезду" в полносвязку.

Когда я приступил к решению данной задачи, то обнаружил, что в интернете практически отсутствуют описания применения OpenVPN в симметричных схемах. Везде тщательно и со вкусом рассматриваются схемы "клиент-сервер", при которых одна определённая сторона ждёт входящих соединений, а другая
инициирует исходящие.

Так как Client1 и Client2 -- это равноправные сервера, делать кого-то формальным сервером не было ни желания, ни особого смысла. С учётом же возможности пояления Client3, ..., ClientN заводить N формальных серверов -- это неизбежно запутаться во всех них.

Внимательное перечитывание man openvpn ("читайте доки -- они рулез!") привело к следующим двум отрывкам:

Example 1: A simple tunnel without security
       On may:

              openvpn --remote june.kg --dev tun1 --ifconfig 10.4.0.1 10.4.0.2
              --verb 9

       On june:

              openvpn --remote may.kg --dev tun1 --ifconfig 10.4.0.2  10.4.0.1
              --verb 9

и чуть ниже:

  Example 3: A tunnel with full TLS-based security
       For this test, we will designate may as the TLS client and june as  the
       TLS  server.   Note  that client or server designation only has meaning
       for the TLS subsystem. It has no  bearing  on  OpenVPN's  peer-to-peer,
       UDP-based communication model.

Когда я понял, что OpenVPN по сути своей совершенно не требует клиент-серверной архитектуры, все дальнейшие действия стали ясны и понятны.

Обратите внимание: в дальнейших примерах части конфигов и имена файлов, уникальные для Client1 и Client2, выделены курсивом

Для Client1:

Создаём файл секретного ключа /etc/openvpn/client1_client2.key:

сd /etc/openvpn
openvpn --genkey --secret client1_client2.key

затем пишем файл /etc/openvpn/client1_to_client2.conf:

remote client2 1234
port 1234
proto udp
ping 10

dev tun
ifconfig 10.10.99.1 10.10.99.2
secret client1_client2.key
comp-lzo

persist-key
persist-tun
verb 3

и добавляем скрипт /etc/init.d/openvpn.client1_to_client2 для запуска нового экземпляра openvpn (для Gentoo);

cd /etc/init.d
ln -s openvpn openvpn.client1_to_client2

Для Client2:

Файл /etc/openvpn/client1_client2.key берём с Client1.

Файл /etc/openvpn/client2_to_client1.conf:

remote client1 1234
port 1234
proto udp
ping 10

dev tun
ifconfig 10.10.99.1 10.10.99.2
secret client1_client2.key
comp-lzo

persist-key
persist-tun
verb 3

Скрипт /etc/init.d/openvpn.client2_to_client1 для запуска нового экземпляра openvpn (опять же для Gentoo);

cd /etc/init.d
ln -s openvpn openvpn.client2_to_client1

Несколько комментариев напоследок:

  1. Для данного соединения выбран порт 1234. Для связи другой пары узлов в этой же полносвязке потребуется, очевидно, другой порт.
  2. В параметрах ifconfig указаны адреса, отсутствующие в местных сетях как Client1, так и Client2. Для связи другой пары узлов в этой же полносвязке потребуется другая пара адресов. Вероятно, имеет смысл брать адреса из одной и той же приватной подсети, например, 10.10.99.0/24 -- их хватит на полносвязку из 126 машин.
  3. Для идентификации выбран способ секретного ключа, чтобы не путаться в сертификатах.