Достъп до услуга на VPN клиент: обратен тунел или DNAT
Достъп до услуга на клиент с OpenVPN без пренасочване на порт: сравнете обратен тунел SSH със сървърен DNAT и трите условия, които решават избора.
Дори лаптоп зад NAT на доставчика може да обслужва колега, стига VPN сървърът да е мястото на среща. Дотам водят два механизма: клиентът се свързва навън и иска от сървъра да държи слушащ порт, или сървърът публикува порт и го превежда в тунела. И двете решават същия проблем с достъпността и се държат различно при отказ, наблюдение и журналиране. Три условия решават кое от тях принадлежи на вашата настройка.
Две форми, едно място на среща
При първата форма клиентът отваря SSH сесия навън и иска от сървъра да слуша на избран порт, като връща всяка връзка обратно през тази сесия. На сървъра нищо не се пренасочва и не се извършва транслация на пакети, затова единствените изисквания са SSH акаунт, разрешено пренасочване и правило на защитната стена за порта. Услугата остава вързана към loopback на клиента, което обикновено е желаното.
ssh -N -R 8081:127.0.0.1:8080 -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 [email protected]
При втората форма публичният порт е на сървъра и той преписва всяка връзка към адреса на клиентския тунел. Това изисква включено IP препращане, транслация на дестинацията при влизане и транслация на източника при излизане и продължава да работи, когато няма SSH сесия. Портът принадлежи на сървъра, а не на сесия, и това е свойството, което решава повечето реални случаи.
Нито една от двете форми не е по-сигурна по устройство. И двете излагат един порт на услуга на всеки, който стигне до публичния адрес на сървъра, и двете зависят от собствената автентикация на услугата.
Условие първо: трябва ли портът да живее по-дълго от сесията
Обратното пренасочване живее точно колкото SSH сесията, която го е създала. Когато връзката падне, слушателят изчезва и колегата вижда отказана връзка, вместо бавен път. Наблюдението на командата с модул на systemd и политика за рестартиране оправя това, а ExitOnForwardFailure=yes прави неуспешното свързване веднага видимо, вместо да остави сесия без пренасочване.
Преведеният порт оцелява при рестартиране, ако правилата са запазени, но зависи от това клиентът да запази същия адрес на тунела. Динамичен пул, който дава на лаптопа друг адрес след повторно свързване, тихо насочва правилото към нищо. Първо запазете адреса на тунела, после напишете правилото и третирайте двете като една промяна.
Ако услугата трябва да отговаря в три часа през нощта без никой да гледа, формата с публикуван от сървъра порт има по-малко движещи се части, защото единственият процес, който трябва да остане, е самият тунел.
Условие второ: кой притежава защитната стена и журналите
Обратната форма държи цялата политика на две места. sshd решава дали изобщо са разрешени отдалечени пренасочвания чрез AllowTcpForwarding, а GatewayPorts решава дали слушателят се свързва към loopback или към всеки адрес. Със стойността по подразбиране no колега извън сървъра не може да стигне до порта, дори пренасочването да е успяло, и това изглежда като счупен тунел, а всъщност е адрес на свързване.
sudo ss -ltn '( sport = :8081 )'
sudo grep -E '^(GatewayPorts|AllowTcpForwarding)' /etc/ssh/sshd_config
Преведената форма изисква включено препращане и две правила, а второто правило е мястото, където повечето рецепти грешат. Ограничаването на транслацията на източника със състоянието conntrack DNAT означава, че се преписват само връзките, създадени от правилото за дестинация, вместо всеки пакет, който сървърът изпраща в тунела.
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8081 -j DNAT --to-destination 10.88.0.6:8080
sudo iptables -t nat -A POSTROUTING -o tun0 -m conntrack --ctstate DNAT -j SNAT --to-source 10.88.0.1
Това преписване също унищожава авторството. След него клиентът вижда всеки повикващ като адреса на сървърния тунел, което сгъва всяко ограничение на скоростта по адрес в една кофа и скрива кой какво е изпратил. Ако авторството е важно, прекратявайте връзката на сървъра или оставете решението за разрешение там и предавайте идентичност в заглавка, на която услугата вярва. Изборът между тези две поправки зависи от това дали услугата въобще чете прокси заглавка.
Условие трето: един порт или много, и кой притежава името
Една услуга на един порт е случаят, в който обратното пренасочване печели по усилие. Трябват ви една команда, един акаунт и едно правило на защитната стена, а почистването е прекратяване на сесията. Няколко услуги на един и същ публичен адрес ви тласкат към формата с публикуван от сървъра порт, защото всяко обратно пренасочване иска свой сървърен порт и множеството расте с всяка услуга.
Имената усложняват още. Обратното пренасочване може да стои зад TCP прокси, което маршрутизира по SNI, докато преведеният порт обикновено е един порт на услуга. Ако услугата сама прекратява TLS и иска оригиналното име на хост, подходът с прокси го запазва, а подходът с DNAT го запазва само ако услугата приема това име на този порт.
Запишете кое от трите условия е решило формата. Иначе следващият човек, който добави втора услуга, ще отвори същото сравнение с по-малко контекст.
Решете, после тествайте отвън
Тествайте пътя от мрежа, която няма маршрут до лаптопа, и наблюдавайте броячите на сървъра, докато заявката тече. Тестването от сървъра към собствения му публичен адрес не доказва нищо тук, защото пакетът се създава локално и никога не стига до входящата кука за транслация, така че тестът може да мине, докато реалният път е счупен.
sudo iptables -t nat -L PREROUTING -n -v
sudo tcpdump -ni any 'tcp port 8081' -c 20
Броячи, които стоят неподвижни, означават, че пакетът никога не е стигнал до правилото, което сочи към доставчика или защитната стена на хоста. Броячи, които се движат, докато услугата отказва, сочат към собствената защитна стена на клиента или адреса, на който услугата слуша. Тунел, който пренася пакета, но не връща нищо, е проблем с маршрута или обратния път, и нито един от тези три изхода не бива да се отстранява чрез редактиране на клиентския адаптер. Запишете кой брояч се е преместил, преди да промените нещо, защото следващият тест се нуждае от тази база.
Щом формата работи, запишете порта, собственика и метода на наблюдение до конфигурацията на тунела. Поправка за достъпност, която съществува само в нечия история на команден ред, е на едно рестартиране от повторен инцидент.