VPN і переадресація портів: безпечно відкривати сервіси, не перетворюючи VPN на діру

Було корисно?

Біль: потрібно опублікувати «ще один внутрішній сервіс» для кількох віддалених користувачів. Мережна команда каже «поставте його за VPN». Хтось інший пропонує «просто переадресуйте порт». Наступного ранку ваш VPN стає найдорожчим бекдором у світі — достатньо широким для латерального переміщення, brute force і випадкового витоку даних.

Це польовий посібник для тих, хто керує реальними системами: як поєднати доступ через VPN і переадресацію портів, не перетворивши приватну мережу на м’який, пористий периметр. Ми конкретизуємо маршрутизацію, NAT, фаєрволи, ідентифікацію, логування та режими відмов. І зробимо це з командами, які ви можете виконати сьогодні.

Ментальна модель: VPN — це мережа, а не магічна мітка

VPN — це не «безпека». VPN — це набір мережевих шляхів і рішень довіри. Коли ви даєте пристрою доступ через VPN, ви дозволяєте йому відправляти пакети у ваше середовище. Усе інше — деталі: маршрутизація, шифрування, автентифікація, фільтрація, спостережність і незаперечна істина, що скомпрометований клієнт тепер знаходиться «всередині» всього, що ви відкрили.

Переадресація портів звучить як акуратний компроміс: «ми перенаправимо порт 443 з VPN-шлюзу на внутрішній сервіс. До нього дістатися можуть лише користувачі VPN. Готово». Проблема в тому, що переадресація рідко буває єдиною зміною. Середовища накопичують винятки: тут маршрут для зручності, там «тимчасова» дірка у фаєрволі, занадто широкі AllowedIPs у WireGuard тому, що хтось втомився відлагоджувати. Через шість місяців ніхто не пам’ятає, чому VPN-шлюз має доступ до половини приватних підмереж.

Ось упереджена відправна точка:

  • Переважно відкривайте на рівні застосунку, а не мережі. Reverse proxy з автентифікацією кращий за сирий доступ L3.
  • Переважно явні allowlist-и замість припущеної довіри. «На VPN» — це не allowlist.
  • Переважно вузька зона ураження замість хитромудрих трюків з переадресацією. Якщо ви не можете пояснити маршрутизацію за дві хвилини, ви не зможете управляти нею о 3-й ранку.

VPN + переадресація портів може бути безпечним. Але лише якщо ви ставитесь до нього як до побудови міні-мережевого краю в компанії: найменші привілеї, чіткі потоки і жорсткі межі.

Факти та історичний контекст, що формують сьогоднішні помилки з VPN

Це не тривіально. Воно пояснює, чому «швидкі VPN-виправлення» постійно виштовхують ризик у продакшн.

  1. VPN популяризували модель «тверда оболонка, м’який центр». Ранні корпоративні VPN припускали довірену внутрішню LAN; після підключення ви фактично були «всередині». Ця модель застаріла.
  2. NAT став стандартним ковдрою безпеки у 2000-х. NAT ніколи не був спроектований як фаєрвол, але він навчив операторів ототожнювати «не маршрутизується публічно» з «безпечно».
  3. IPsec спочатку створювали для site-to-site. Багато реалізацій IPsec припускають стабільні мережі й чіткі підмережі; навішування клієнтського доступу призводить до хаотичного розростання політик.
  4. OpenVPN нормалізував «push routes» клієнтам. Це зручно — і небезпечно просто штовхати широкий доступ (або налаштування DNS), не усвідомлюючи масштабу.
  5. WireGuard навмисно уникає функцій політик. Він швидкий і простий, але це означає, що контроль доступу потрібно реалізовувати у фаєрволах і маршрутизації, а не в VPN-протоколі.
  6. Hairpin NAT існує через те, що реальні користувачі чинять дивно. Люди зберігають закладки на публічні імена й використовують їх внутрішньо; якщо ви не врахуєте трафік «власний до власного», ви будете налагоджувати привидів.
  7. Переадресація портів старша за хмару. Це класичний адміністраторський хак з ери невеликих офісних роутерів. Він працює — поки не знадобиться аудит і сегментація.
  8. Zero Trust не вбив VPN; він його переформулював. Кращі сучасні VPN — це контрольований транспорт плюс політики, що враховують ідентичність, а не тунель у королівство.

Історія породжує звички. Ваше завдання — зламати ті, що перетворюють «віддалений доступ» на «віддалене скомпрометування».

Безпечніші патерни для відкриття сервісів через VPN

Патерн A: Reverse proxy на краю VPN (рекомендовано)

Поставте reverse proxy (nginx, HAProxy, Envoy, Caddy — вибирайте свій коктейль) на VPN-шлюзі або на виділеному хості «VPN edge». Завершуйте TLS там. Вимагайте сильної автентифікації (mTLS, OIDC, SSO). Пересилайте до внутрішніх сервісів у приватних мережах. VPN надає транспорт; проксі — ідентичність і політику.

Чому це добре:

  • Експозиція сервісу відбувається на рівні застосунку; можна застосовувати правила по шляху/хосту.
  • Можна логувати запити, обмежувати швидкість і блокувати очевидний шум.
  • Можна прив’язати доступ до однієї внутрішньої цілі замість відкриття маршрутизації до підмережі.

Патерн B: Переадресовувати тільки на одну внутрішню IP:port з прикріпленням фаєрвола

Якщо мусите переадресовувати сирі TCP/UDP, робіть це вузько. Прив’яжіть переадресацію порту до однієї внутрішньої цілі, а потім прив’яжіть фаєрвол так, щоб тільки IP клієнтів VPN (або ще вже allowlist) могли дістатися цього порту на шлюзі.

Саме тут оператори лінуються: вони роблять DNAT, але забувають правила фільтрації. DNAT без фільтра — це «політика випадково».

Патерн C: Використовуйте bastion / jump host для адміністративних протоколів

Адмін-доступ (SSH, RDP, бази даних) має проходити через jump host, а не через випадкові переадресовані порти. Хороший bastion дає вам:

  • Автентифікацію по користувачеві і логи сесій.
  • Єдину точку затору для загартування і моніторингу.
  • Місце для застосування MFA без винаходження велосипеда.

Патерн D: Split tunnel з явними маршрутами, а не «все через VPN»

Full-tunnel VPN підходить, якщо ви ним добре керуєте, але він збільшує зону ураження, коли ви цього не робите. Split tunnel з явною маршрутизацією тільки до потрібних ресурсів зменшує ризик і навантаження на підтримку (менше тикетів «VPN ламає мій Zoom»).

Патерн E: Не відкривати сервіс зовсім — реплікувати його

Для деяких робочих навантажень найбезпечніша експозиція — відсутня експозиція. Реплікуйте лише для читання дані в DMZ-сервіс або публікуйте через спеціальне API з авторизацією. Це «нудна архітектура», що уникає хитрої переадресації.

Реалістична перевірка: якщо ваш план залежить від «нікому не буде сканувати цей порт, бо він у VPN», ви побудували систему безпеки на надії й стяжках.

Модель загроз: як VPN + переадресація йдуть не так

1) Латеральне переміщення від скомпрометованого клієнта

Клієнт VPN зазвичай є найменш контрольованим середовищем, яке ви маєте: особисті ноутбуки, мобільні пристрої, машини підрядників. Якщо один із них скомпрометовано і має широкий доступ через VPN, атакуючий може виконувати сканування внутрішньої мережі, красти креденшіали і ставати в pivot. Переадресація портів може підсилити це, роблячи внутрішні сервіси простішими для доступу через один відомий шлюз.

2) «Тимчасові» правила, що стають постійними

Правила переадресації й виключення у фаєрволі мають більший період життя, ніж ваша терплячість. Якщо немає автоматизації й рев’ю, виключення живуть вічно. І вони накопичуються.

3) Несумісність автентифікації: мережевий доступ vs автентифікація застосунку

VPN автентифікує пристрій або користувача до мережі. Ваш застосунок автентифікує користувачів (або не автентифікує). Якщо ви відкрили сервіс, який припускає «LAN = довірено», ви щойно телепортували це припущення на кожного клієнта VPN.

4) Плутанина DNS та несподіванки з name-based virtual hosting

Користувачі звертаються до сервісу за публічним ім’ям; ваша переадресація або reverse proxy покладаються на SNI/Host headers; хтось тестує по IP; раптом все працює для одних клієнтів і не працює для інших. Дизайн DNS тут важить більше, ніж хотілося б.

5) Path MTU і баги фрагментації, що проявляються лише в продакшн

Инкапсуляція VPN зменшує ефективний MTU. Деякі шляхи блокує ICMP «Fragmentation Needed», і тоді TLS-з’єднання загадково зависають. Переадресований трафік успадковує ці проблеми.

6) Неправильно масшабовані маршрути (AllowedIPs, push routes або статичні маршрути)

Класика. Ви мали намір дозволити доступ до 10.20.30.40:443. Хтось штовхнув 10.20.0.0/16 «для зручності». Ваш VPN щойно став тіньовою корпоративною мережею.

Жарт №1: NAT — як повітряно-бульбашкова плівка: змушує відчувати себе у безпеці, але якщо стрибнути з даху — день все одно буде поганим.

Оперативний принцип: поводьтеся з VPN-шлюзом як з edge інтернету

Навіть якщо підключаються лише «довірені користувачі», оперуйте VPN-шлюзом так, ніби він піддається ворожому трафіку:

  • Загартована ОС, мінімум пакетів.
  • Строгий фаєрвол з політикою deny за замовчуванням.
  • Структуровані логи, що відправляються поза хостом.
  • Обмеження швидкості там, де можливо.
  • Конфіг у вигляді коду; зміни переглядаються.

Практичні завдання з командами: перевірити, обмежити, переадресувати, спостерігати

Ці завдання написані для Linux‑наших VPN-шлюзів. Команди передбачають, що у вас є root або sudo. Для кожного: що виконати, що означає вивід і яке рішення ухвалити.

Завдання 1: Підтвердити стан IP forwarding (бо «forwarding» — це не відчуття)

cr0x@server:~$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0

Значення: ядро не форвардить IPv4‑пакети між інтерфейсами. DNAT‑правила можуть все одно перезаписувати, але маршрутизація не пропустить трафік через шлюз як очікується.

Рішення: Якщо це VPN-шлюз, який мусить маршрутизувати/форвардити — встановіть 1 і збережіть назавжди. Якщо маршрутизація не повинна відбуватись — тримайте 0 і перегляньте дизайн.

Завдання 2: Перевірити ефективний MTU на VPN‑інтерфейсі (тиха загроза для TLS)

cr0x@server:~$ ip link show dev wg0
5: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/none

Значення: WireGuard часто за замовчуванням має mtu 1420; ваша підлягаюча мережа може потребувати меншого. Якщо бачите MTU 1500 і тунелюєте через PPPoE/LTE — чекайте проблем.

Рішення: Якщо є періодичні підвисання, протестуйте з меншим MTU (наприклад 1380) і перевірте PMTU (Завдання 11).

Завдання 3: Перевірити, якими маршрутами шлюз дістатиметься до внутрішнього сервісу

cr0x@server:~$ ip route get 10.20.30.40
10.20.30.40 via 10.20.0.1 dev eth1 src 10.20.0.10 uid 0
    cache

Значення: шлюз відправляє трафік до 10.20.30.40 через 10.20.0.1 на eth1 із джерелом 10.20.0.10.

Рішення: Якщо маршрут вказує на невірний інтерфейс — виправте маршрутизацію перед тим, як торкатись NAT. DNAT не врятує поганий маршрут.

Завдання 4: Підтвердити, що сервіс слухає на внутрішньому хості

cr0x@server:~$ ss -lntp | head
State  Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0      4096   0.0.0.0:22        0.0.0.0:*     users:(("sshd",pid=911,fd=3))
LISTEN 0      512    10.20.30.40:443   0.0.0.0:*     users:(("nginx",pid=1220,fd=6))

Значення: nginx слухає на 10.20.30.40:443. Чудово. Якщо воно слухає лише на 127.0.0.1, переадресація до нього не спрацює, якщо ви не робите форвард на самому хості.

Рішення: Якщо сервіс не слухає там, де очікували — виправте адресу бинду в застосунку перед налагодженням мережі.

Завдання 5: Перевірити політику фаєрволу за замовчуванням (якщо ACCEPT скрізь — ви граєтесь у рулетку)

cr0x@server:~$ sudo iptables -S | head -n 12
-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT
-N VPN_IN
-N VPN_FWD
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i wg0 -j VPN_IN
-A FORWARD -i wg0 -j VPN_FWD

Значення: deny за замовчуванням для INPUT і FORWARD з виділеними ланцюжками для VPN. Це позиція, якої ви хочете на шлюзі.

Рішення: Якщо INPUT/FORWARD за замовчуванням ACCEPT — плануйте контрольовану міграцію до deny. Почніть з додавання явних allow, потім переключайте політику під час вікна обслуговування.

Завдання 6: Створити вузьку DNAT‑переадресацію (VPN IP:8443 → internal 10.20.30.40:443)

cr0x@server:~$ sudo iptables -t nat -A PREROUTING -i wg0 -p tcp --dport 8443 -j DNAT --to-destination 10.20.30.40:443
cr0x@server:~$ sudo iptables -t nat -A POSTROUTING -o eth1 -p tcp -d 10.20.30.40 --dport 443 -j MASQUERADE
cr0x@server:~$ sudo iptables -A FORWARD -i wg0 -o eth1 -p tcp -d 10.20.30.40 --dport 443 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT
cr0x@server:~$ sudo iptables -A FORWARD -i eth1 -o wg0 -p tcp -s 10.20.30.40 --sport 443 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Значення: PREROUTING змінює призначення для трафіку, що приходить від VPN. POSTROUTING робить маскарадування, щоб внутрішній хост відповідав через шлюз, навіть якщо він не знає підмереж VPN‑клієнтів.

Рішення: Переважайте маршрутизацію без маскараду, коли можливо (чистіше, зберігає IP клієнта), але якщо не можна додати маршрути в внутрішній мережі — MASQUERADE прагматичний. Задокументуйте: це впливає на логування і аудит.

Завдання 7: Обмежити, хто може користуватись переадресацією (allowlist підмережі клієнтів VPN або конкретні IP)

cr0x@server:~$ sudo iptables -I FORWARD 1 -i wg0 -p tcp -s 10.66.0.0/24 -d 10.20.30.40 --dport 443 -j ACCEPT
cr0x@server:~$ sudo iptables -I FORWARD 2 -i wg0 -p tcp -d 10.20.30.40 --dport 443 -j DROP

Значення: лише клієнти з 10.66.0.0/24 можуть дістатися внутрішнього сервісу; інші блокуються, навіть якщо DNAT відбувається.

Рішення: Звужуйте ще більше, коли можна: індивідуальні IP клієнтів, не цілі підмережі. Якщо потрібно «деяким користувачам так, деяким ні» — перестаньте покладатися лише на IP‑політику і додайте автентифікацію на рівні застосунку.

Завдання 8: Підтвердити, що лічильники NAT і фільтрації інкрементуються (докажіть, що трафік потрапляє у ваші правила)

cr0x@server:~$ sudo iptables -t nat -L PREROUTING -n -v | head
Chain PREROUTING (policy ACCEPT 120 packets, 9200 bytes)
 pkts bytes target     prot opt in  out  source      destination
   12   720 DNAT       tcp  --  wg0 *    0.0.0.0/0   0.0.0.0/0    tcp dpt:8443 to:10.20.30.40:443

Значення: лічильники pkts/bytes показують, чи використовується правило. Нульові лічильники означають, що трафік не приходить на wg0, не TCP або не по dport 8443.

Рішення: Якщо під час тесту лічильники не рухаються — припиніть гадати і прослідкуйте шлях: вибір інтерфейсу, маршрутизація на клієнті і чи справді клієнт на VPN.

Завдання 9: Перевірити AllowedIPs у WireGuard (типова помилка надто широкого доступу)

cr0x@server:~$ sudo wg show wg0
interface: wg0
  public key: 8qGk...redacted
  listening port: 51820

peer: 7n9H...redacted
  endpoint: 203.0.113.50:53122
  allowed ips: 10.66.0.10/32
  latest handshake: 1 minute, 2 seconds ago
  transfer: 188.22 KiB received, 412.91 KiB sent

Значення: цьому peer дозволено джерело лише 10.66.0.10/32. Добре. Якщо бачите «0.0.0.0/0» або велику приватну підмережу — ви надали набагато більше доступу, ніж думаєте.

Рішення: Тримайте AllowedIPs вузькими на серверній стороні. Використовуйте правила фаєрволу у будь‑якому випадку. Розглядайте AllowedIPs як перший бар’єр, а не єдиний.

Завдання 10: Захопити пакети, щоб довести, де вони вмирають (tcpdump — сироватка правди)

cr0x@server:~$ sudo tcpdump -ni wg0 tcp port 8443 -c 5
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on wg0, link-type RAW (Raw IP), snapshot length 262144 bytes
12:04:11.112233 IP 10.66.0.10.51512 > 10.66.0.1.8443: Flags [S], seq 39192812, win 64240, options [mss 1360,sackOK,TS val 9911 ecr 0,nop,wscale 7], length 0
12:04:12.113244 IP 10.66.0.10.51512 > 10.66.0.1.8443: Flags [S], seq 39192812, win 64240, options [mss 1360,sackOK,TS val 10911 ecr 0,nop,wscale 7], length 0

Значення: SYN‑пакети доходять до шлюзу. Якщо ви не бачите SYN‑ACK назад — шлюз не форвардить правильно, внутрішній хост недосяжний або зворотний трафік зламаний.

Рішення: Запустіть другий захват на eth1: tcpdump -ni eth1 host 10.20.30.40 and tcp port 443. Якщо бачите SYN на wg0, але нічого на eth1 — проблема у NAT/фільтрі/маршрутах на шлюзі.

Завдання 11: Протестувати path MTU з перспективи VPN‑клієнта

cr0x@server:~$ ping -M do -s 1372 -c 3 10.66.0.1
PING 10.66.0.1 (10.66.0.1) 1372(1400) bytes of data.
1380 bytes from 10.66.0.1: icmp_seq=1 ttl=64 time=32.1 ms
1380 bytes from 10.66.0.1: icmp_seq=2 ttl=64 time=31.8 ms
1380 bytes from 10.66.0.1: icmp_seq=3 ttl=64 time=32.5 ms

--- 10.66.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms

Значення: шлях підтримує принаймні 1400‑байтові пакети без фрагментації. Якщо це не вдається — зменшіть MTU на wg0 та/або виправте upstream, що блокує ICMP.

Рішення: Якщо ви налагоджуєте «деякий HTTPS працює, великі завантаження падають» — MTU перша підозра. Виправте його, перш ніж звинувачувати TLS.

Завдання 12: Перевірити rp_filter при маршрутизації між інтерфейсами

cr0x@server:~$ sysctl net.ipv4.conf.all.rp_filter
net.ipv4.conf.all.rp_filter = 1

Значення: строгий rp_filter може скидати пакети при асиметричній маршрутизації (поширено з VPN і кількома інтерфейсами).

Рішення: На VPN‑шлюзі, що робить форвардинг/NAT, встановіть rp_filter у 0 або 2 (loose) залежно від дизайну. Робіть це свідомо; документуйте чому.

Завдання 13: Підтвердити тиск на таблицю conntrack (форвардинг падає під навантаженням)

cr0x@server:~$ sudo conntrack -S
cpu=0 found=1287 invalid=4 ignore=0 insert=4218 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0

Значення: insert_failed і drop вказують на виснаження conntrack або тиск. Навіть «маленький» VPN‑шлюз може впасти, коли всі перепідключаються після мережевих флапів.

Рішення: Якщо ростуть падіння — збільшіть ліміти conntrack, зменшіть stateful‑правила де безпечно, або масштабуйтесь горизонтально. І припиніть використовувати VPN‑шлюз як загальний NAT‑хост для всього підряд.

Завдання 14: Підтвердити, хто підключений і наскільки недавно (бо бувають «привиди»)

cr0x@server:~$ sudo wg show wg0 latest-handshakes
7n9H...redacted	1735292801
j2Qa...redacted	0

Значення: «0» у latest handshake означає, що peer ніколи не підключався з моменту підняття інтерфейсу (або ротації ключів). Епохові відмітки можна перетворити на людський час.

Рішення: Якщо користувач стверджує «VPN підключено», але ви не бачите handshake — ви налагоджуєте клієнта, NAT traversal або невідповідність ключів, а не переадресацію портів.

Завдання 15: Перевірити логування відхиленого трафіку (якщо не бачите дропи — не зможете керувати)

cr0x@server:~$ sudo iptables -A FORWARD -i wg0 -j LOG --log-prefix "VPN-FWD-DROP " --log-level 4
cr0x@server:~$ sudo iptables -A FORWARD -i wg0 -j DROP
cr0x@server:~$ sudo journalctl -k -n 3
Dec 27 12:08:01 vpn-gw kernel: VPN-FWD-DROP IN=wg0 OUT=eth1 SRC=10.66.0.50 DST=10.20.30.40 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=51422 DF PROTO=TCP SPT=51580 DPT=443 WINDOW=64240 RES=0x00 SYN URGP=0

Значення: лог ядра показує, що було відхилено: хто (SRC), що (DST/DPT) і куди намагався потрапити (OUT інтерфейс).

Рішення: Якщо вмикаєте логування — обмежте його швидкість. Інакше один галасливий хост перетворить ваші логи на denial of wallet.

Завдання 16: Швидка перевірка «воно працює?» з VPN‑клієнта: curl із збереженим SNI/Host

cr0x@server:~$ curl -vk https://10.66.0.1:8443/health
*   Trying 10.66.0.1:8443...
* Connected to 10.66.0.1 (10.66.0.1) port 8443
> GET /health HTTP/1.1
> Host: 10.66.0.1:8443
> User-Agent: curl/7.81.0
> Accept: */*
< HTTP/1.1 200 OK
< Content-Type: text/plain
ok

Значення: TCP‑підключення встановлено і ви отримали HTTP 200. Якщо виникають TLS‑попередження — можливо ви потрапляєте на неправильний віртуальний хост або імена сертифіката не співпадають.

Рішення: Для сервісів із іменами тестуйте з реальним hostname через --resolve і правильним SNI, або використовуйте reverse proxy, що послідовно завершує TLS.

Жарт №2: Переадресація портів — як «ще одне виключення» у фінансах: усі погоджуються, що воно маленьке, поки їх не підсумувати.

Три корпоративні міні-історії з фронту

Міні-історія 1: Інцидент через неправильне припущення («користувачі VPN довірені»)

Середнє за розмірами підприємство тримало VPN для віддалених співробітників і підрядників. Профіль VPN був доступний через внутрішній портал; автентифікацію вважали «достатньо сильною», а мережева команда прирівнювала клієнтів VPN до on‑site. Коли потрібно було віддалено дістатися до нового адмін‑порталу, вони переадресували його з VPN‑шлюзу на сервер застосунку. Без додаткової автентифікації. «Це внутрішнє».

Через місяці ноутбук підрядника було скомпрометовано через розширення браузера, яке не мало місця на робочій машині. Атакувальний не потребував ніякого zero‑day проти VPN. Він просто чекав, поки підрядник підключиться, і сканував доступний з клієнта адресний простір. Переадресований адмін‑портал було легко знайти: відкритий порт, передбачуваний шлях і довіра до «LAN» заголовків.

Атакувальник створив обліковий запис із підвищеними правами, потім перейшов до інших систем, використавши кешовані креденшіали, до яких портал мав доступ. Порушення не було «через VPN». Воно сталося через припущення, що мережеве розташування означає ідентичність.

Виправлення не було героїчним. Додали автентифікацію на рівні застосунку, вимагали MFA для адмін‑функцій, звузили AllowedIPs у VPN і замінили широкий «доступ підрядників» на доступ по сервісу через reverse proxy. Найефективніша зміна була культурна: все, що доступне з VPN, трактували як інтернет‑експонований сервіс з логами й обмеженнями швидкості.

Міні-історія 2: Оптимізація, яка повернулась бумерангом (MASQUERADE скрізь)

Інша організація не хотіла торкатися внутрішньої маршрутизації. Команда VPN вирішила MASQUERADE‑ити весь трафік клієнтів VPN, що йшов у внутрішню мережу. Воно відразу запрацювало: ніяких змін на внутрішніх маршрутизаторах, ніяких правок на застарілих серверах, і кількість звернень у допомогу впала.

Потім служба безпеки попросила аудит: «Хто заходив у фінансовий застосунок у вівторок?» Логи застосунка показували лише IP VPN‑шлюзу. Кожен користувач виглядав однаково. Команда спробувала компенсувати це підняттям логування на шлюзі, але отримала дві проблеми: величезні логи і все одно недостатній контекст на рівні застосунку.

Інша несподівана проблема проявилась тихо: ліміти швидкості на деяких внутрішніх сервісах спрацювали несподівано. З точки зору сервісу весь трафік ішов з одного хоста. Сервіс почав лімітувати шлюз, і раптом «VPN повільний» став щоденним скаргом. Вони оптимізували маршрути — і оптимізували себе в проблему видимості і справедливого розподілу.

Відкат був частковим. MASQUERADE зберегли лише для однієї застарілої підмережі, яка не могла приймати маршрути. Для всього іншого додали маршрути, щоб внутрішні сервіси бачили реальні IP клієнтів. Reverse proxy перед чутливими застосунками також інжектував ідентичність автентифікованого користувача в заголовки (з суворою валідацією), тож аудит знову став осмисленим.

Міні-історія 3: Нудна, але правильна практика, що врятувала день (deny за замовчуванням + рев’ю змін)

Компанія з репутацією «повільної» мала звичку, яка здавалась дратівливою — допоки не врятувала їх: кожна зміна фаєрволу VPN проходила через репозиторій, peer review і деплой автоматикою. Їхній шлюз мав політику deny за замовчуванням. Переадресації були явними, і кожна мала посилання на тикет у коментарі.

Одного дня розробник попросив швидку переадресацію, щоб вендор дістався staging webhook. Поспішливий оператор відкрив правило — на неправильному порту — і натиснув. Пайплайн деплою зловив це, бо unit‑тести для політик фаєрволу перевіряли, що існують лише дозволені порти для того класу сервісу. Зміна була відхилена раніше, ніж потрапила в прод.

Оператор виправив правило і спробував знову. Цього разу пройшло і деплой відбувся, і вендор отримав доступ. Через два тижні автоматичний сканер з боку вендора почав збоїти і вдарив по endpoint агресивно. Метрики шлюзу показали сплеск; стандартні rate limits reverse proxy його поглинули; а логи фаєрволу зробили очевидним, який саме перенаправлений сервіс галасує.

Ніяких героїчних дій. Ніякої бойової кімнати. Просто дисциплінований контроль змін, deny за замовчуванням і інструментація. «Повільна» команда релізила швидше, бо не витрачала час на виправлення уникнених помилок.

Цитата про надійність (перефразована думка): John Allspaw підкреслював, що інциденти виникають через взаємодію систем, а не «людську помилку», і вчитися важливіше, ніж карати.

План швидкої діагностики

Це потік «не марнуй годину». Мета — знайти вузьке місце — маршрутизація, фаєрвол, NAT, сервіс або MTU — мінімальною кількістю кроків.

Перший крок: доведіть, що клієнт реально в VPN і цілиться в правильне місце

  • На шлюзі: перевірте handshake (wg show wg0) і недавні пакети на wg0 (tcpdump -ni wg0).
  • На клієнті: підтвердьте маршрут до адреси/порту переадресації (клієнтська команда ip route get).
  • Якщо немає handshake або пакетів: це не переадресація портів. Це конфіг клієнта, ключі або NAT traversal.

Другий крок: перевірте, чи точка прийняття рішення про переадресацію (DNAT + фільтр) спрацьовує

  • Перевірте лічильники NAT: iptables -t nat -L PREROUTING -n -v.
  • Перевірте лічильники/логи FORWARD: iptables -L FORWARD -n -v і логи ядра на предмет дропів.
  • Якщо лічильники не рухаються: неправильний інтерфейс, порт, протокол або трафік не доходить.

Третій крок: перевірте зворотний шлях (найпоширеніша причина «працює частково»)

  • Захопіть пакети на внутрішньому інтерфейсі: чи виходить трафік від шлюзу до сервісу?
  • Захопіть на стороні повернення: чи повертаються відповіді?
  • Якщо відповіді не повертаються: відсутній маршрут назад до підмережі VPN‑клієнтів, rp_filter їх відкидає або проблема з state tracking.

Четвертий крок: перевірте MTU, якщо симптоми — «підключення є, передача зависає»

  • Запустіть PMTU‑тести (Завдання 11).
  • Шукайте зависання TLS‑handshake, зависання великих запитів або непослідовну поведінку між мережами.

П’ятий крок: перевірте ємність і таблиці стану

  • Conntrack drops, CPU‑насичення або черги на шлюзі можуть маскуватися під «мережеві проблеми».
  • Почніть з: conntrack -S, top і лічильників помилок інтерфейсів (ip -s link).

Поширені помилки (симптом → причина → виправлення)

1) «Працює у мене на Wi‑Fi, падає на мобільному»

Симптом: деякі клієнти підключаються, інші зависають на TLS або великих запитах.

Причина: занадто великий MTU для деяких шляхів; ICMP «fragmentation needed» блокується; наклад тунелю VPN штовхає пакети за межу.

Виправлення: зменшіть MTU інтерфейсу VPN (WireGuard: встановіть MTU=1380), переконайтесь, що ICMP дозволено, перевірте PMTU пінгами і реальними передачами.

2) «Порт відкритий на шлюзі, але сервіс недосяжний»

Симптом: SYN доходить на VPN‑інтерфейс; відповіді немає; лічильники NAT інкрементуються, але внутрішній сервіс ніколи не бачить трафік.

Причина: ланцюжок FORWARD відкидає трафік; відсутнє правило для NEW-з’єднань; неправильний інтерфейс у правилі фаєрволу; або IP forwarding вимкнено.

Виправлення: увімкніть net.ipv4.ip_forward=1, додайте явний FORWARD allow з conntrack state і перевірте лічильники та tcpdump на обох інтерфейсах.

3) «Переадресація працює, але логи сервісу бачать лише IP шлюзу»

Симптом: трейси аудиту застосунку показують один клієнтський IP (шлюз).

Причина: MASQUERADE/SNAT приховує IP клієнта, щоб уникнути додавання маршрутів.

Виправлення: додайте правильні маршрути, щоб сервіс міг відповідати підмережам VPN‑клієнтів без SNAT, або завершуйте на reverse proxy, що може передати ідентичність користувача і залогувати її.

4) «Переадресація працює деякий час, потім помирає під навантаженням»

Симптом: переривчасті дропи, нові з’єднання не вдаються, існуючі «лобатіють».

Причина: виснаження таблиці conntrack або CPU‑насичення на шлюзі; занадто багато stateful‑правил; агресивне логування.

Виправлення: підніміть ліміти conntrack, зменшіть логування або обмежте його, масштабуйтесь, і припиніть перетворювати VPN‑шлюз на загальний NAT‑апарат.

5) «Користувач дістає набагато більше, ніж потрібно»

Симптом: клієнт VPN сканує внутрішні підмережі або дістає незв’язані сервіси.

Причина: надто широкі AllowedIPs/push routes; дозволяючі правила FORWARD; політика за замовчуванням ACCEPT.

Виправлення: звузьте AllowedIPs, впровадьте deny за замовчуванням у FORWARD, додайте per‑destination allow‑правила і протестуйте з клієнта сканування того, що має бути заблоковано.

6) «DNS‑ім’я працює внутрішньо, але не через VPN (або навпаки)»

Симптом: по IP працює; по імені не працює; або лише деякі користувачі резолвлять правильну адресу.

Причина: split DNS не налаштовано; клієнт використовує публічний DNS; сервіс вимагає SNI/Host header; hairpin NAT не опрацьовано.

Виправлення: надайте DNS через VPN, використовуйте узгоджені імена хостів і надавайте перевагу termination reverse proxy, де TLS/SNI‑поведінка детермінована.

Чеклісти / покроковий план

Покроковий план: безпечно відкрити один внутрішній HTTPS сервіс для користувачів VPN

  1. Визначте патерн експозиції. Якщо це користувацький HTTP(S), використайте reverse proxy на VPN‑краю. Якщо це сирий протокол — розгляньте bastion замість переадресації порту.
  2. Визначте мінімальну аудиторію. Конкретні користувачі, пристрої або невелика підмережа клієнтів VPN. Запишіть перед тим, як чіпати iptables.
  3. Визначте мінімальну ціль. Одна внутрішня IP:port, не підмережа.
  4. Затвердьте позицію шлюзу. Deny за замовчуванням на INPUT і FORWARD. Дозвольте established/related. Дозвольте лише порт VPN inbound з інтернет‑інтерфейсу.
  5. Реалізуйте переадресацію з явними правилами фільтрації. Сам DNAT — не політика. Додайте FORWARD allow‑правила, що точно відповідають намірам.
  6. Визначте SNAT vs routed return. Переважайте routed return (збереження IP клієнта). Використовуйте SNAT лише коли потрібно, і зафіксуйте наслідки для аудиту.
  7. Застосуйте автентифікацію на рівні застосунку. Якщо застосунок припускає «LAN = довірено», виправте застосунок або поставте попереду щось, що примусить ідентифікацію.
  8. Інструментуйте choke points. Лічильники фаєрволу, логи дропів ядра (з rate‑limit), метрики handshake VPN і логи запитів на проксі.
  9. Протестуйте режими відмов. З VPN‑клієнта: перевірте доступ дозволений, заблокований і цілі, що «не мають маршруту».
  10. Оперируйте зміни. Покладіть конфіг фаєрволу/VPN у VCS, вимагайте рев’ю і забезпечте план відкату.

Чекліст безпеки: «не перетворіть VPN на діру»

  • AllowedIPs/pushed routes — мінімальні для кожного peer.
  • Політика FORWARD — DROP; явні allow‑правила для кожного відкритого сервісу.
  • Ніякої переадресації з VPN в «усю внутрішню мережу», якщо це не обґрунтовано й сегментовано.
  • Адмін‑протоколи йдуть через bastion; ніяких випадкових RDP/SSH‑переадресацій.
  • Логування присутнє для: підключень VPN, дропів фаєрволу та доступу до відкритих сервісів.
  • Rate limits на відкриті кінці (краще через проксі).
  • Ротація ключів і відкликання облікових даних — практика, а не теорія.

Чекліст надійності: зберігайте налагоджуваність

  • Одна діаграма, що показує інтерфейси, підмережі і напрямки потоків.
  • Одне місце, щоб перевіряти «чи користувач реально підключений» (handshake).
  • Визначені точки для packet capture (wg інтерфейс, внутрішній інтерфейс).
  • Документовані рішення щодо MTU.
  • Контроль змін: хто змінив що, коли і чому.

Питання й відповіді

1) Чи автоматично безпечно поміщати сервіс «за VPN»?

Ні. Це змінює аудиторію з «інтернет» на «будь‑який, хто може автентифікуватись у VPN (або скомпрометувати клієнта VPN)». Вам все ще потрібна автентифікація застосунку, сегментація і логування.

2) Що обрати: переадресацію портів чи reverse proxy?

Reverse proxy для HTTP(S) майже завжди кращий. Переадресація портів прийнятна для вузьких, добре відомих протоколів, але її складніше автентифікувати й спостерігати чисто.

3) Яка найбільша помилка при експозиції через WireGuard?

Надто широкі AllowedIPs і припущення, що це замінює політику фаєрволу. WireGuard навмисне мінімальний; контроль доступу потрібно впроваджувати через маршрути та фаєрволи.

4) Чи можу я уникнути SNAT/MASQUERADE і все одно зробити переадресацію?

Так, якщо внутрішній сервіс (або його дефолтний шлюз) має маршрут назад до підмережі клієнтів VPN через VPN‑шлюз. Це чистий дизайн. SNAT — це скорочення з компромісами для аудиту.

5) Як не дозволити підрядникам сканувати всю мережу після підключення до VPN?

Давайте їм доступ по сервісу: вузькі AllowedIPs, deny за замовчуванням у FORWARD і явні allow‑правила лише до потрібних сервісів. Для веб‑застосунків ставте їх за автентифікованим reverse proxy.

6) Що вибрати: split tunnel чи full tunnel?

Split tunnel зменшує зону ураження і проблеми підтримки, але вимагає хорошої маршрутизації. Full tunnel централізує контроль egress, але збільшує залежність від VPN і робить відмови гучнішими. Обирайте, виходячи з моделі загроз і оперативної зрілості.

7) Чому «SYN доходить до шлюзу» не гарантує, що сервіс досяжний?

Тому що DNAT може спрацювати, але FORWARD‑правила можуть його відкидати, IP forwarding може бути вимкнений, шлюз може неправильно маршрутизувати або зворотний трафік не матиме шляху назад.

8) Як зробити це аудитуємим?

Переважайте маршрути, щоб внутрішні сервіси бачили реальні IP клієнтів. Використовуйте reverse proxy, що логуватиме автентифіковану ідентичність користувача. Централізуйте логи поза шлюзом. Не покладайтесь на NAT‑логи як єдиний слід аудиту.

9) Чи потрібен hairpin NAT?

Лише якщо VPN‑клієнти користуються публічним hostname, що резолвиться у публічну IP, яка петляє назад через той самий шлюз. Якщо ви контролюєте DNS, split DNS зазвичай чистіше, ніж hairpin‑хакі.

10) Який правильний спосіб розгортати зміни, щоб не зламати всіх?

Стадіруйте правила з лічильниками і логуванням спочатку, тестуйте з одним пілотним peer, потім розширюйте. Використовуйте конфіг як код і план відкату. Шлюз — не місце для «ковбойських» деплоїв.

Висновок: наступні кроки, які можна відправити в прод

VPN плюс переадресація портів не є за своєю суттю необдуманими. Вони стають такими, коли «на VPN» замінює реальні політики, або коли переадресацію сприймають як галочку в налаштуваннях маршрутизатора замість серйозного сервісу на краю продакшн.

Зробіть наступне:

  1. Виберіть один патерн експозиції для кожного сервісу: reverse proxy для HTTP(S), bastion для адміністрування, вузька переадресація лише коли необхідно.
  2. Звузьте до мінімуму досяжність: мінімальні AllowedIPs, deny за замовчуванням у FORWARD, явні per‑destination правила.
  3. Свідомо вирішіть про SNAT vs routed return і задокументуйте наслідки для аудиту.
  4. Додайте видимість: лічильники, логи дропів (з rate‑limit), моніторинг handshake і логи запитів.
  5. Попрактикуйте план швидкої діагностики один раз, поки ви не горите.

Якщо ви не можете пояснити, хто що може дістати, через який інтерфейс і чому зворотний трафік повертається правильно — продовжуйте працювати. Це не перфекціонізм. Це експлуатація мережі без перетворення VPN на генератор інцидентів.

← Попередня
Права панель змісту для документації: липка, scroll-margin і підсвічування активного розділу
Наступна →
Відсутня прошивка після встановлення Debian 13: правильно відновлюємо підтримку NIC і HBA

Залишити коментар