Могат ли клиентите на два OpenVPN сървъра да се достигат взаимно?
Два OpenVPN сървъра създават два пула от клиенти, а не една мрежа. Маршрутизирайте между тях с отделни подмрежи, взаимни маршрути и ясна граница на доверие.
Изграждането на втори OpenVPN сървър ви дава второ място за свързване на клиенти и нищо повече. То не поставя тези клиенти в мрежата на първия сървър, а опцията client-to-client променя само препращането в рамките на един сървърен процес. Двата пула стават една мрежа, когато маршрутизирате между тях умишлено, с отговорник за всяка посока. Всичко по-долу предполага режим TUN в потребителско пространство с изключено вътрешно препращане, така че ядрото взема решението.
Митът: един списък с акаунти, една мрежа
Удостоверяването и достижимостта се смесват, защото и двете живеят в конфигурацията на сървъра. Потребител, който може да влезе през който и да е от двата шлюза, отвън изглежда като потребител в една система с две врати. Вътре всеки сървър раздава адреси от своя пул и инсталира маршрути само за клиентите, които обслужва. Затова клиент на шлюз A, който изпрати пакет до клиент на шлюз B, иска дестинация, за която собственият му сървър никога не е чувал. Пакетът тръгва по маршрута по подразбиране на A, напуска тунела и пристига на защитна стена, която никога не е била помолена да го пропусне.
Следователно добавянето на втори сървър не добавя резервиране, откриване или споделен broadcast домейн. То добавя маршрутизирана мрежа, която се нуждае от план, а планът започва с адресиране.
Дайте на всеки шлюз собствен пул и транзитен адрес
Два диапазона, които не могат да се застъпват с нищо друго, плюс малка транзитна връзка между хостовете — това е целият план за адресиране. Дръжте транзита в частен сегмент, който контролирате, и запишете числата, преди някой сървър да отдаде наем.
| Gateway | Client pool | Transit address |
|---|---|---|
| gateway-a | 10.64.10.0/24 | 172.28.44.1/30 |
| gateway-b | 10.64.20.0/24 | 172.28.44.2/30 |
Устоявайте на изкушението да дадете на двата сървъра един и същ пул, за да останат профилите идентични. Маршрут в ядрото не може да каже кой от двата хоста в момента притежава произволен адрес в споделен диапазон, затова таблицата за маршрутизация ще сочи към единия шлюз, а клиентът може да е свързан с другия. Имената на интерфейсите са локални конвенции, а не споделено състояние. Двата хоста тук наричат тунелното устройство tun0, а транзитната връзка — transit0, което е наред, защото нито един пакет не носи тези имена.
Инсталирайте маршрута от двете страни
Всеки шлюз се нуждае от маршрут до пула на другия през транзитния адрес, а препращането трябва да е включено, за да действа който и да е като хоп. Първо потвърдете текущата таблица, после добавете записа и го запазете през мрежовия мениджър на хоста, а не чрез hook за повторно свързване.
sysctl net.ipv4.ip_forward
ip route add 10.64.20.0/24 via 172.28.44.2 dev transit0
ip route get 10.64.20.37
Огледално направете същото на другия хост с разменени пулове. Многократното добавяне на същия маршрут от несвързан скрипт е начинът, по който хостът се сдобива с няколко копия и загадъчна промяна следващия път, когато някой прочете таблицата. Ако транзитната връзка сама е тунел, маршрутът сочи към топологията на този тунел и хопът трябва да преживее повторното му свързване. Транзитен адрес, който изчезне за тридесет секунди, отнася със себе си пътя между пуловете, което е свойство на дизайна, което си струва да се заяви, а не да се открие.
Изпратете маршрута на клиента, без да симулирате собственост
Клиентите се нуждаят от маршрут до отдалечения пул, иначе собствената им операционна система изпраща пакета към шлюза по подразбиране и тунелът никога не го вижда. Конфигурацията на сървъра е естественото място да го достави.
push "route 10.64.20.0 255.255.255.0"
Поставете огледалния ред в конфигурацията на другия сървър, после свържете отново тестов клиент и прочетете таблицата му. Клиент, който игнорира изтласканите маршрути, се нуждае от собствена одобрена конфигурация, а маршрут, който така и не пристига, не е контрол на достъпа. Не давайте на клиент iroute за целия пул на другия шлюз. Тази директива съществува за подмрежа зад един свързан клиент и използването ѝ, за да се прикрие липсващ маршрут между шлюзовете, създава сървър, който вярва, че притежава адреси, до които не може да достигне.
Докажете една заявка и откажете друга
Изберете реална операция, например HTTPS от клиент на 10.64.10.21 към услуга на 10.64.20.37, и разрешете точно нея на двата хоста. Всяка защитна стена приема заявката от входящата си страна и проследения отговор от страната на връщането; собствената политика на услугата на дестинацията все още трябва да я приеме.
iptables -A FORWARD -i tun0 -o transit0 -s 10.64.10.21 -d 10.64.20.37 -p tcp --dport 443 -j ACCEPT
iptables -A FORWARD -i transit0 -o tun0 -d 10.64.10.21 -s 10.64.20.37 -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED -j ACCEPT
При взаимни маршрути NAT на източника е ненужен и тук активно вреден: транслирането на източника скрива кой клиент е направил заявката и осуетява политиката, базирана на източник, от страната на дестинацията. Проверете дали съществуващо правило за маскарад за изход към интернет не хваща и този път. След това тествайте отказа. Услуга, която трябва да остане локална за пул B, трябва да остане недостъпна от пул A, а двойките клиенти на един и същ шлюз също трябва да се тестват, тъй като политиката за препращане, която току-що променихте, се отнася и за тях.
Още една корекция на мисловния модел: транзитната връзка носи дешифрирани вътрешни пакети, така че е граница на доверие, а не частна гаранция. Ако пресича мрежа, която не контролирате, защитете този хоп с одобрен криптиран тунел и маршрутизирайте през реалната му топология. Крайното TLS все още удостоверява приложението само по себе си, затова вътрешната услуга трябва да продължи да го използва.