Защитна стена, която допуска само VPN порта, не е едно правило. Това са три отделни решения, които случайно засягат един и същ номер на порт: веригата за вход решава какво може да достигне до локален процес, веригата за препращане решава какво може да премине през хоста от името на клиентите на тунела, а таблицата NAT пренаписва адреса на източника на изхода. Сгрешете едно от тях и резултатът рядко е чисто прекъсване. Получавате хост, който приема клиенти, но не зарежда нищо, или хост, който изглежда заключен, докато някой не прочете реда на веригите.

Единственият порт, който не може да се затвори

Слушателят на VPN трябва да приема връзки от адреси, които не можете да предвидите, така че по определение е публична услуга. Това е единственото изключение, върху което е изграден дизайнът: един UDP порт за OpenVPN, един UDP порт за WireGuard, един TCP порт за SSL VPN. Всичко останало принадлежи зад тунела, което означава, че услугите на приложенията трябва да се свързват с адреса на тунела или с loopback, а не с всички интерфейси.

Свързването обаче не е налагане. Процес, свързан с 0.0.0.0, е достъпен само ако правило го допуска, а политиката по подразбиране е резервата за трафик, който не е съвпаднал с нито едно правило, не правилото, което управлява порта. Разрешение, поставено над вашето отхвърляне, пак е разрешение, а преместването на услуга от публичния адрес е самостоятелно подобрение, а не заместител на веригата.

Вход, препращане и NAT отговарят на различни въпроси

Входящият трафик е предназначен за самия хост, така че там живеят слушателят на VPN и административният път. Трафикът за препращане преминава през хоста и клиентите на тунела се нуждаят от него плюс net.ipv4.ip_forward=1. Класическата полуработеща конфигурация допуска изходящия поток и забравя обратната посока, така че клиентът завършва ръкостискането и след това нищо не се зарежда; правило conntrack за установен и свързан трафик покрива тази посока.

NAT е третият въпрос. Без пренаписване в postrouting препращаните пакети излизат с частния адрес на тунела и се отхвърлят по-горе по веригата, защото никоя мрежа отвъд хоста не знае как да маршрутизира пула обратно. Префиксът на източника в това правило трябва да съвпада с пула на VPN, а не със собствения адрес на хоста, и същото важи за правилото за препращане, което посочва подмрежата на клиентите.

IPv6 е втора политика, а не нещо добавено после. Хост със строга верига за IPv4 и отворена политика на ip6tables не е затворил нищо; услугите остават достъпни през другото семейство. Или огледалете набора от правила с ip6tables, или съзнателно изключете IPv6 на публичния интерфейс и запишете кой вариант сте избрали.

Базова линия, която се чете с един поглед

Започнете с отхвърляне и добавете само това, от което хостът се нуждае. Първо loopback и отговорите, после административният път, после слушателят на тунела, после политиката за препращане за клиентите:

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p udp --dport 1194 -m conntrack --ctstate NEW -j ACCEPT
sysctl -w net.ipv4.ip_forward=1
iptables -A FORWARD -i tun0 -o eth0 -s 10.8.0.0/24 -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

Имената на интерфейсите, портът и пулът са заместители; прочетете ги от сървъра, вместо да ги копирате. Запазването на резултата е толкова важно, колкото и записването му, защото набор от правила, който живее само в паметта, изчезва при следващото рестартиране и тихо отваря хоста отново. Направете го постоянен с механизма на дистрибуцията и пазете копие извън машината за деня, в който машината не зареди.

Затваряне на последния порт без загуба на хоста

В дизайна има уловка. Ако SSH съществува само през тунела, провалена VPN услуга отнася SSH със себе си и единственият път назад може да е конзола, която никога не сте отваряли. Преди да затворите последния публичен порт, потвърдете, че тази конзола съществува и че наистина можете да я използвате, или оставете един тесен административен път, който не зависи от тунела: SSH от фиксиран адрес, само ключове, автентикация с парола изключена.

Прилагайте промяната от вече установена сесия, а не през връзката, която ще филтрирате. Планирайте връщане назад, за да изтече грешката, вместо да стане постоянна, например задача systemd-run --on-active=10min, която възстановява предишния набор от правила, и дръжте втора SSH сесия отворена, докато тествате първата. След това проверете, че задачата за връщане наистина се задейства, защото непровереното възстановяване е същото като липса на възстановяване.

Проверете пътя, не скрипта

Четете заредените правила, а не файла, който е трябвало да ги зареди. От оторизиран външен хост потвърдете, че отговарят само предвидените портове; отвътре в тунела потвърдете, че услугите, които сте искали да публикувате, са достъпни. Политика за отказ по подразбиране, която блокира и трафика на тунела, изглежда идентична с работещо заключване, докато някой не се опита да го използва.

iptables -S
iptables -t nat -S
ss -lntup
ip -4 addr show

Запишете разрешения порт, пула на клиентите, интерфейса на тунела, административния източник и процедурата за конзолата до конфигурацията. Следващата промяна в пула или името на интерфейса трябва да бъде съгласувана и във филтъра, и в правилото NAT, иначе хостът се връща в полуотворено състояние, без никой да забележи.

Един навик струва повече от набора от правила: след всяка промяна докажете пътя за препращане със заявка от клиент, а пътя за възстановяване — с втора сесия. Заключване, което не сте използвали, е хипотеза.

Подобни статии