Контроль доступу офісного VPN: дозволяйте лише необхідне (не мережа‑до‑мережі)

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

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

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

Принцип: VPN — не телепорт у вашу локальну мережу

«Офісний VPN» часто сприймають як магічний кабель: підключив віддалений ноутбук — і «в офісі». Така ментальна модель породжує повний мережа‑до‑мережі доступ, широкі маршрути та правила фаєрволу «any‑to‑any».
Це також робить реагування на інциденти нестерпним.

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

Правильна модель: VPN — це контрольований в’їзд до невеликого набору сервісів. Ці сервіси можуть жити у вашій LAN,
у DMZ/VPN‑сегменті або в хмарних мережах. Але в’їзд не має вести до «всіх адрес RFC1918».

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

Модель загроз простими словами: що ви захищаєте

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

Віддалені кінцеві точки — це хаос. Вони подорожують. Підключаються до кав’ярні Wi‑Fi. Запускають браузерні розширення, які були «безкоштовними» не випадково.
Якщо одна кінцева точка скомпрометована, і ваш VPN ставить її в ту ж L2/L3 досяжність, що файлові сервери, принтери, гіпервізори, бекап‑коробки
і «тимчасові» адмін‑консолі, ви просто дали нападнику приватну автомагістраль.

2) Випадковий доступ: чесна помилка, яка все одно болить

Більшість «неавторизованих доступів» у корпоративних мережах — це не каптурний зловмисник.
Це розробник, який запускає скрипт на 10.0.0.0/8, бо так швидше, ніж шукати правильну IP‑адресу.
Це постачальник, який «тільки перевіряє» хост, до якого не мав доступу.
Дизайн VPN з мінімальними привілеями запобігає і зловмисності, і помилкам.

3) Протечки маршрутів і накладання підмереж

Якщо ви коли‑небудь об’єднували дві компанії або додавали новий хмарний VPC, ви зустрічали антигероя:
перекриття простору RFC1918. При широких VPN‑маршрутах стає невизначено, яку саме «10.0.12.0/24» ви мали на увазі,
і іноді працює неправильний шлях — аж до моменту, коли не працює, і ви витрачаєте вихідні на порівняння таблиць маршрутів.

4) DNS як вектор доступу

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

5) Операційна відмова: модель доступу, яку не можна відлагодити

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

Парафразована ідея (приписують): «Сподівання — не стратегія.» — часто зустрічається в опер‑культурі.
Якою б вам не була фраза, вона підходить: не сподівайтеся, що широкий доступ через VPN залишиться безпечним.

Історичний контекст та цікаві факти (бо ми їх постійно перевчимо)

  1. VPN стали масовими як «розширення периметра» у 1990‑х/початку 2000‑х, коли офіси мали чітку межу «всередині/зовні», а віддалений доступ був рідкістю.
  2. IPsec був створений для безпеки мереж‑до‑мережі, а не для доступу на рівні окремих додатків — тому «повна досяжність підмереж» є природним (але застарілим) результатом.
  3. Розділення тунелю (split tunneling) раніше вважали єрессю, бо воно руйнувало історію «весь трафік через головний офіс» для інспекції; сьогодні часто необхідне для продуктивності та SaaS‑реальності.
  4. NAT ускладнив злиття: перекриття RFC1918 терпіли, бо NAT «вирішував» проблему, аж доки не спробуєш з’єднати дві NAT‑насичені середовища через VPN і все не зіткнеться.
  5. Ранній віддалений доступ концентрував довіру у VPN‑шлюзі; сучасні дизайни розподіляють довіру на постачальники ідентичності, перевірки стану пристрою та проксі на рівні додатків.
  6. «Плоскі мережі» колись були нормою, бо внутрішні загрози були недооцінені; програм‑шифри та викрадення облікових даних зробили внутрішню сегментацію обов’язковою.
  7. WireGuard популяризував підхід «маршрут як політика»: його AllowedIPs — і маршрутизація, і контроль доступу одночасно, що елегантно і легко поранити себе.
  8. DNS зі змінним поданням (split‑horizon) не новий, але VPN зробив його всюдисущим: внутрішні імена стали залежністю, і неправильний DNS‑скоп став частою витоком.
  9. Хмарні мережі просунули мислення «сервіс перш за все»: security groups і L7‑gateway змусили команди називати, до чого вони підключаються, а не лише яка підмережа існує.

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

Референсні архітектури, що уникають повного мережа‑до‑мережі

Архітектура A: «VPN у сегмент сервісів», а не VPN у всю LAN

Розташуйте термінатор VPN (WireGuard, OpenVPN, IPsec gateway) у виділеній підмережі/VLAN для VPN.
Звідти дозволяйте вихід тільки до потрібних сервісів: jump host для квитків, Git, CI, кілька внутрішніх API, можливо RDP/SSH до бастіону.
За замовчуванням забороняйте все інше.

Ключова думка: підмережа VPN — це мережа клієнтів, а не рівноправна LAN. Не маршрутизовуйте віддалених користувачів безпосередньо у «corp‑lan».
Маршрузуйте їх у «vpn‑clients», потім фаєрволом дозвольте конкретні місця призначення.

Архітектура B: Доступ за додатком через бастіони та проксі (нудно, але ефективно)

Якщо користувачам потрібен адмін‑доступ, їм не потрібна вся адмін‑мережа. Їм потрібен jump host з MFA, логуванням і коротким списком дозволених вихідних цілей.
SSH‑бастіони, RDP‑шлюзи та HTTP‑reverse‑proxy — це стара техніка. Саме тому вона працює.

VPN стає способом доступу до контрольної точки (бастіон/проксі), а не універсальним маршрутом до всього.
Коли ви це приймаєте, політика фаєрволу стає меншою, а аудит — простішим.

Архітектура C: Ідентифікаційно‑чутливий доступ (коли можливо)

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

Архітектура D: Справжній site‑to‑site, але жорстко обмежений і задокументований

Іноді дійсно потрібне з’єднання site‑to‑site: принтери філій, промислові контролери або застарілі системи, які не можуть працювати через проксі.
Добре. Але вам усе ще не потрібен «будь‑яка підмережа до будь‑якої підмережі».
Запишіть точні префікси, які мають бути досяжні, і примусьте це контролюватися в маршрутизації та шарах фаєрволу.

Жарт №1: «Тимчасовий повний тунель any‑any VPN» — як «тимчасовий продакшн‑адмінський пароль». Він існує вічно і росте зуби.

Контроли, які справді працюють: маршрутизація, фаєрвол, ідентичність, DNS

1) Маршрутизація: обирайте явні префікси, а не «все приватне»

Найпоширеніший режим відмови — рекламування широких внутрішніх ділянок клієнтам VPN з міркувань зручності:
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16. Не робіть так.
Це не маршрутизація; це відмова від відповідальності.

Робіть натомість:

  • Анонсуйте лише потрібні підмережі сервісів (або ще краще — IP‑адреси сервісів).
  • Тримайте список коротким; якщо він зростає, це архітектурна проблема, а не проблема маршрутів.
  • Для WireGuard використовуйте AllowedIPs як суворий allowlist.
  • Для OpenVPN штовхайте лише ті маршрути, які маєте намір (push "route ..."), і за замовчуванням блоковуйте client‑to‑client, якщо це не потрібно.

2) Фаєрвол: за замовчуванням забороняйте, потім дозволяйте за призначенням і портом

Маршрути визначають, що досяжно. Фаєрвол визначає, що дозволено. Потрібні обидва, бо маршрути мають звичку змінюватися,
і «досяжне» — це набагато ширший набір, ніж «має використовуватися».

Базовий підхід:

  • Визначте діапазон адрес клієнтів VPN (наприклад, 10.250.0.0/24).
  • Дозвольте цьому джерелу лише конкретні призначення/порти.
  • Логуйте відмови (селективно; не DDoS‑те свій логінг‑пайплайн).
  • Блокуйте east‑west в межах VPN‑пулу, якщо ви свідомо не підтримуєте peer‑трафік.

3) Ідентичність і стан пристрою: VPN має знати, хто підключається

Правила лише за IP крихкі. Прив’язуйте доступ до ідентичності де можливо:

  • Персональні сертифікати (OpenVPN), персональні ключі WireGuard, або рішення VPN з інтеграцією SSO.
  • Короткоживучі облікові дані, якщо інструменти це підтримують.
  • Перевірки стану пристрою (керований пристрій, шифрування диска, версія ОС), якщо середовище може їх примусити.

Навіть якщо ви не можете зробити «zero trust» повністю, хоча б знайте, кому належить ключ,
і відкликайте його без розсилок по всій компанії.

4) DNS: розділення зон скальпелем, а не лопатою

Клієнтам VPN часто потрібен внутрішній DNS для підмножини зон. Надавайте їм ті зони, а не весь корпоративний простір імен.
Якщо ваше VPN‑рішення може робити умовну пересилку (conditional forwarding) — пересилайте лише corp.example до внутрішніх резолверів.
Інакше будьте обережні: штовхання внутрішніх DNS‑серверів клієнтам може ненавмисно направити всі DNS‑запити через VPN і створити проблеми приватності, продуктивності та налагодження.

5) Спостережуваність: логувати важливе і робити це доступним для запитів

Вам потрібно швидко відповісти на запит:

  • Хто підключився? Звідки? З яким пристроєм/ключем?
  • Які маршрути були призначені?
  • Що дозволено/заблоковано на фаєрволі?
  • Які DNS‑запити були зроблені (принаймні для внутрішніх зон)?

Якщо ваша відповідь: «можливо, ми зможемо grep‑нути VPN‑сервер», — ви в одному інциденті від знайомства з «можливо».

Практичні завдання (команди, виводи, рішення)

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

Завдання 1: Підтвердіть, які маршрути рекламуватиме VPN‑сервер

cr0x@server:~$ sudo ip route show
default via 203.0.113.1 dev eth0 proto static
10.0.10.0/24 dev lan0 proto kernel scope link src 10.0.10.1
10.250.0.0/24 dev wg0 proto kernel scope link src 10.250.0.1
172.16.50.0/24 via 10.0.10.2 dev lan0 proto static

Що це означає: Сервер має локальну LAN 10.0.10.0/24, пул VPN 10.250.0.0/24 і маршрутизовану підмережу 172.16.50.0/24.
Це маршрутизація на боці сервера, не «пушені» маршрути клієнту, але підказує, що ви можете включати.

Рішення: Якщо на шлюзі ви бачите широкі маршрути (наприклад, 10.0.0.0/8), зупиніться і обґрунтуйте їх.
Звузьте до підмереж, що містять лише сервіси, які ви плануєте відкрити.

Завдання 2: Для WireGuard — перелічіть peers і їх AllowedIPs (ваша реальна політика доступу)

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

peer: M4x9Vt2g9bBv7hPpP3c0...
  preshared key: (hidden)
  endpoint: 198.51.100.24:53321
  allowed ips: 10.250.0.10/32, 10.0.30.15/32
  latest handshake: 1 minute, 12 seconds ago
  transfer: 128.21 MiB received, 44.02 MiB sent

peer: Q7u1kL0pZz2nWc3aY1r5...
  endpoint: 203.0.113.77:59610
  allowed ips: 10.250.0.11/32, 10.0.40.0/24
  latest handshake: 2 hours, 4 minutes ago
  transfer: 2.10 MiB received, 1.54 MiB sent

Що це означає: Peer 1 може маршрутизуватися до одного внутрішнього хоста 10.0.30.15.
Peer 2 має доступ до цілої підмережі 10.0.40.0/24. Це різниця в політиці, яку варто документувати.

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

Завдання 3: Перевірте, чи увімкнено IP‑форвардинг (і чи має бути увімкнений)

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

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

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

Завдання 4: Перегляньте nftables‑політику, щоб забезпечити default‑deny для форвардингу з VPN

cr0x@server:~$ sudo nft list ruleset
table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;
    iif "lo" accept
    ct state established,related accept
    tcp dport { 22, 51820 } accept
  }

  chain forward {
    type filter hook forward priority 0; policy drop;
    ct state established,related accept
    iif "wg0" oif "lan0" ip daddr 10.0.30.15 tcp dport 443 accept
    iif "wg0" oif "lan0" ip daddr 10.0.40.0/24 tcp dport 5432 accept
  }

  chain output {
    type filter hook output priority 0; policy accept;
  }
}

Що це означає: Форвардинг за замовчуванням drop. Є два явні дозволи: HTTPS до одного хоста і Postgres до однієї підмережі.
Це форма, яку ви хочете: вузькі виключення, читабельні правила.

Рішення: Якщо політика в forward‑ланці — accept, ви випадково робите «повний мережа‑до‑мережі».
Змініть на drop і перераховуйте, що має бути досяжне.

Завдання 5: Визначте, до чого клієнти VPN намагаються (і чому не можуть) дістатися

cr0x@server:~$ sudo nft add rule inet filter forward iif "wg0" counter log prefix "VPN-FWD-DROP " level info drop
cr0x@server:~$ sudo journalctl -n 5 -k
Aug 14 10:21:19 gw kernel: VPN-FWD-DROP IN=wg0 OUT=lan0 SRC=10.250.0.11 DST=10.0.10.25 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=0 DF PROTO=TCP SPT=51234 DPT=445 WINDOW=64240 SYN
Aug 14 10:21:20 gw kernel: VPN-FWD-DROP IN=wg0 OUT=lan0 SRC=10.250.0.11 DST=10.0.10.53 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=0 DF PROTO=UDP SPT=55911 DPT=53

Що це означає: Клієнт намагався SMB (445) до 10.0.10.25 і DNS до 10.0.10.53, і обидва були відкинуті.
Це або несанкціонований доступ (добре), або відсутнє правило (також добре виявити рано).

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

Завдання 6: Перевірте поведінку NAT (NAT може приховати проблеми, а іноді й створити їх)

cr0x@server:~$ sudo nft list table ip nat
table ip nat {
  chain postrouting {
    type nat hook postrouting priority srcnat; policy accept;
    oif "lan0" ip saddr 10.250.0.0/24 masquerade
  }
}

Що це означає: Трафік клієнтів VPN до LAN маскарадиться. LAN‑хости бачитимуть IP шлюзу, а не IP клієнта.
Це може спростити маршрутизацію на боці LAN, але руйнує можливість атрибуції по клієнтах на ресурсі призначення.

Рішення: Уникайте NAT для середовищ, чутливих до аудиту/адміністрування. Віддавайте перевагу маршрутизованим пулам VPN з явними відповідними маршрутами, щоб логи показували реальні IP клієнтів.
Якщо NAT необхідний (старі обмеження), компенсуйте логуванням на шлюзі і відображенням користувачів.

Завдання 7: Перевірте витоки маршрутів до клієнтів (приклад OpenVPN через status)

cr0x@server:~$ sudo tail -n 12 /var/log/openvpn/status.log
OpenVPN CLIENT LIST
Updated,2025-08-14 10:20:10
Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since
alice,198.51.100.24:53321,134507892,46158212,2025-08-14 08:12:03

ROUTING TABLE
Virtual Address,Common Name,Real Address,Last Ref
10.250.0.10,alice,198.51.100.24:53321,2025-08-14 10:20:09
GLOBAL STATS
Max bcast/mcast queue length,0
END

Що це означає: Ви бачите, який користувач має який VPN‑IP. Це мінімум, потрібний для кореляції під час інциденту.

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

Завдання 8: Підтвердіть конфігурацію DNS на шляху клієнта (який резолвер використовується)

cr0x@server:~$ resolvectl status
Global
       Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub

Link 3 (wg0)
    Current Scopes: DNS
         Protocols: +DefaultRoute
Current DNS Server: 10.0.10.53
       DNS Servers: 10.0.10.53
        DNS Domain: corp.example

Що це означає: Лише corp.example перенаправляється до внутрішнього DNS через інтерфейс wg0.
Це умовне обмеження DNS; воно запобігає захопленню всіх DNS‑запитів в офіс.

Рішення: Якщо ви бачите внутрішній DNS налаштованим глобально без доменного обмеження, очікуйте дивних явищ: збої SaaS‑логінів, порушення captive‑portal, і складну для налагодження затримку.
Виправте обмеження до того, як користувачі «полагодять» це самі, жорстко прописавши публічні резолвери.

Завдання 9: Доведіть досяжність проти дозволу (ping працює, TCP — ні)

cr0x@server:~$ ping -c 2 10.0.30.15
PING 10.0.30.15 (10.0.30.15) 56(84) bytes of data.
64 bytes from 10.0.30.15: icmp_seq=1 ttl=63 time=3.21 ms
64 bytes from 10.0.30.15: icmp_seq=2 ttl=63 time=3.08 ms

--- 10.0.30.15 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
cr0x@server:~$ nc -vz 10.0.30.15 443
Connection to 10.0.30.15 443 port [tcp/https] succeeded!

Що це означає: І ICMP, і TCP/443 дозволені, тож сервіс досяжний і дозволений.
Якщо ping працює, а TCP терпне — ймовірно проблема у фаєрволі/SG/політиці додатку. Якщо ping не проходить, а TCP є — хтось фільтрує ICMP (це нормально, але будьте послідовними).

Рішення: Використовуйте ICMP лише як грубий індикатор. Рішення приймайте на основі порту реального застосунку.

Завдання 10: Визначте, яка сторона відкидає пакети за допомогою tcpdump

cr0x@server:~$ sudo tcpdump -ni wg0 host 10.0.30.15 and tcp port 443 -c 3
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on wg0, link-type RAW (Raw IP), snapshot length 262144 bytes
10:24:10.102345 IP 10.250.0.10.51522 > 10.0.30.15.443: Flags [S], seq 1987654321, win 64240, options [mss 1360,sackOK,TS val 123 ecr 0,nop,wscale 7], length 0
10:24:11.110221 IP 10.250.0.10.51522 > 10.0.30.15.443: Flags [S], seq 1987654321, win 64240, options [mss 1360,sackOK,TS val 1123 ecr 0,nop,wscale 7], length 0
10:24:13.126019 IP 10.250.0.10.51522 > 10.0.30.15.443: Flags [S], seq 1987654321, win 64240, options [mss 1360,sackOK,TS val 3123 ecr 0,nop,wscale 7], length 0

Що це означає: SYN приходять на wg0, але жодного SYN‑ACK не видно назад (принаймні на wg0).
Або форвардинг/фаєрвол блокує, або зворотний маршрут зламаний, або призначення недоступне/відмовляє.

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

Завдання 11: Перевірка накладання підмереж і «тіньових маршрутів»

cr0x@server:~$ ip route get 10.0.40.10
10.0.40.10 via 10.0.10.2 dev lan0 src 10.0.10.1 uid 0
    cache

Що це означає: Трафік до 10.0.40.10 йде через 10.0.10.2. Якщо ви чекали, що він буде локальним або через інший роутер — маєте невідповідність маршрутів.

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

Завдання 12: Перевірте MTU і виявлення проблем фрагментації

cr0x@server:~$ ip link show wg0
6: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/none
cr0x@server:~$ ping -M do -s 1380 -c 2 10.0.30.15
PING 10.0.30.15 (10.0.30.15) 1380(1408) bytes of data.
1388 bytes from 10.0.30.15: icmp_seq=1 ttl=63 time=3.45 ms
1388 bytes from 10.0.30.15: icmp_seq=2 ttl=63 time=3.39 ms

--- 10.0.30.15 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms

Що це означає: MTU на wg0 — 1420. Завантаження 1380 байт з DF працює; ймовірно ви не побачите проблем PMTUD для типової роботи.
Якщо це не проходить, великі TLS‑пакети можуть зависати, і користувачі скаржитимуться «підключається, але зависає».

Рішення: Якщо бачите MTU‑чорні діри, зменшіть MTU VPN і обмежте TCP MSS на шлюзі.
Не «вирішуйте» це дозволом повного доступу до LAN; це не вирішення, це капітуляція.

Завдання 13: Підтвердіть, що трафік між клієнтами заблокований (запобігання латерального руху між клієнтами)

cr0x@server:~$ sudo nft list chain inet filter forward
table inet filter {
  chain forward {
    type filter hook forward priority 0; policy drop;
    ct state established,related accept
    iif "wg0" oif "lan0" ip daddr 10.0.30.15 tcp dport 443 accept
    iif "wg0" oif "lan0" ip daddr 10.0.40.0/24 tcp dport 5432 accept
  }
}

Що це означає: Немає правила, що дозволяє iif wg0oif wg0. Клієнти VPN не можуть спілкуватися один з одним через шлюз.
Це добре: один скомпрометований ноутбук не може просто просканувати інші у VPN‑пулі.

Рішення: Дозволяйте peer‑to‑peer трафік лише якщо є чітка продуктова потреба (наприклад, інструменти спільного програмування) і план стримування.

Завдання 14: Переконайтеся, що логи показують ідентичність, а не лише IP (перевірка мапінгу WireGuard)

cr0x@server:~$ sudo grep -R "M4x9Vt2g9bBv7hPpP3c0" -n /etc/wireguard/
 /etc/wireguard/wg0.conf:18:PublicKey = M4x9Vt2g9bBv7hPpP3c0...
 /etc/wireguard/wg0.conf:19:# owner=alice purpose=vendor-api access=10.0.30.15:443

Що це означає: Ключ peer аннотований власником і призначенням. Це не красиво, але операційно безцінно.

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

Жарт №2: Найшвидший спосіб вивчити мережі — дозволити 10.0.0.0/8 через VPN і почекати перший інцидент.
Другий найшвидший — цього не робити.

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

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

Перше: тунель піднятий і стабільний?

  • Перевірте стан хендшейку/підключення (wg show / OpenVPN status / стан IPsec SA).
  • Пошукайте часті перепідключення (зазвичай таймаути NAT, роумінг кінцевих точок або проблеми MTU).
  • Підтвердіть, що клієнт отримав очікуваний VPN‑IP.

Друге: чи правильний маршрут до конкретного призначення?

  • З клієнта: перевірте, що маршрут до IP сервісу використовує VPN‑інтерфейс.
  • З шлюзу: ip route get <dest> і впевніться, що він вказує туди, куди ви думаєте.
  • Слідкуйте за накладанням підмереж і випадковими більш‑специфічними маршрутами.

Третє: фаєрвол дозволяє точну кортеж (src, dst, proto, port)?

  • На шлюзі: перевірте правила forward і лічильники.
  • Тимчасово додайте правило з логуванням, щоб побачити, що намагаються зробити.
  • Підтвердіть, що фаєрвол на боці призначення/security groups також дозволяють пул VPN.

Четверте: DNS і ім’я‑орієнтована маршрутизація

  • Розділіть ім’я сервісу з клієнта і впевніться, що воно повертає потрібний IP (внутрішній чи зовнішній).
  • Підтвердіть, що лише потрібні внутрішні зони спрямовуються до внутрішніх резолверів.
  • Якщо користувачі скаржаться «деякі сайти ламаються», підозрюйте повний тунель DNS‑захоплення або таймаути DNS через VPN.

П’яте: MTU і «вона таймаутиться лише на великих відповідях»

  • Запустіть DF‑ping, щоб знайти безпечний розмір корисного навантаження.
  • Зафіксуйте MSS, якщо потрібно.
  • Симптоми часто виглядають як «сторінка входу завантажується, а потім крутиться без кінця».

Шосте: додаток та автентифікація

  • Коли транспорт/маршрути/фаєрвол/DNS у порядку, дебагуйте сам сервіс (TLS, auth, логи додатку).
  • Не звинувачуйте VPN у 401. Він невинний, поки не доведено протилежне.

Три корпоративні міні‑історії з польових боїв

Інцидент через невірне припущення: «Це лише dev‑підмережа»

Середня компанія розгорнула WireGuard для підрядників, що працювали над міграцією. Мережевий інженер зробив «розумно»: додав 10.20.0.0/16 до AllowedIPs, бо це була «dev‑середовище».
Усі мали доступ до dev‑кластеру і внутрішнього Git. Квитки перестали надходити.

Припущення було, що 10.20.0.0/16 — виключно dev. Колись так і було. Потім хтось додав «тимчасові» управлінські кінцеві точки в цей діапазон:
віртуалізаційну консоль, UI резервного копіювання і старий моніторинговий сервер з локальними обліковими записами.
Ніхто не оновив політику VPN, бо ніхто не пам’ятав, що політика VPN існує як політика.

Лептоп підрядника був інфікований через експлойт браузера. Нападник не мусив «ламати VPN».
Він просто використав тунель підрядника і просканував досяжні IP.
Знайшов UI бекапу. Спробував credential stuffing. Пощастило.

Післяінцидентний розбір був болючим, але прояснювальним: VPN не був неправильно налаштований; він був недоописаний.
«Dev‑підмережа» — це історія, яку люди собі розповідали, а не забезпечена межа. Вони виправили це, перемістивши відкриті сервіси за бастіон і замінивши маршрут /16 на півдюжини /32.
Також вони призначили власників для кожного дозволеного призначення. Раптово «тимчасові» кінцеві точки перестали бути невидимими.

Оптимізація, що повернулася бумерангом: централізація всього через офіс

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

Перші симптоми були непомітні: відеодзвінки «інколи підвисають», великі завантаження файлів «інколи падають», і люди звинувачують свій домашній Wi‑Fi, бо так роблять усі.
Потім зміна розгорнулась ширше. DNS сповільнився, бо всі запити йшли в офіс.
SaaS‑сервіси почали застосовувати rate‑limiting, бо запити виглядали з однієї‑двох egress IP.

Команда безпеки відповіла додаванням нових правил інспекції. Затримка зросла ще більше.
Зрештою on‑call інженер отримав проклятий тикет: «VPN працює, але інтернет неможливий».
Це не мережевий пазл; це архітектура, що збирає борг.

Вони відкотили до split tunneling для інтернет‑трафіку і зберегли лише вузький набір внутрішніх маршрутів.
Для інспекції застосували контролі на кінцевих точках і на шарі додатків там, де можливо.
Урок: штовхати весь трафік через одне місце — це азарт на доступність. Доступність — частина безпеки, навіть якщо таблиця відповідності не схвалює.

Нудна, але правильна практика, що врятувала день: явні allowlist‑и й нотатки змін

Компанія, близька до фінансів, мала строгий підхід: VPN‑користувачі отримували виділений пул, а forward‑ланка фаєрвола була default‑deny.
Кожне правило дозволу мало три метадані: власник сервісу, бізнес‑призначення і дату рев’ю/закінчення.
Звучало бюрократично, поки не стало рятівним.

Партнер повідомив, що несподівано може дістатися внутрішнього сервісу, якого не мав би бачити. Паніка почалася.
On‑call інженер не почав «вимикати VPN». Він перевірив лічильники у forward‑ланці і побачив хіти по недавно доданому правилу.
Коментар правила містив тікет і власника.

Власник підтвердив: під час вікна техобслуговування вони тимчасово розширили доступ з /32 до /24 «щоб полегшити тестування», і забули повернути.
Оскільки правило було анотоване і зміна відслідковувана, виправлення зайняло хвилини: повернути правило до /32 і задеплоїти.

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

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

1) «Я тепер бачу все на 10.x»

Симптом: Користувач VPN може переглядати шаринги, сторінки адміністрування принтерів і випадкові інтерфейси, не згадані в вимогах.

Корінна причина: Широкі маршрути, пушені клієнтам, і дозволяюча політика форвардингу (часто default‑accept) на VPN‑шлюзі.

Виправлення: Приберіть широкі анонси маршрутів; встановіть forward policy в drop; додайте явні дозволи за призначенням і портом. Заблокуйте client‑to‑client, якщо не потрібно.

2) «VPN працює, але один внутрішній додаток недосяжний»

Симптом: Тунель піднятий, DNS резолвить, але TCP до конкретного сервісу таймаутиться.

Корінна причина: Відсутній allow у фаєрволі для того сервісу/порту, або фаєрвол на боці призначення не допускає пул VPN.

Виправлення: Перевірте кортеж у forward‑правилах; перегляньте лічильники/логи; додайте мінімальний allow; оновіть ACL на боці призначення. Уникайте відкривання цілих підмереж «щоб протестувати».

3) «Все повільно по VPN; Zoom гине; SaaS ламається»

Симптом: Після підключення падає інтернет‑продуктивність; SaaS поводиться непередбачувано.

Корінна причина: Повний тунель плюс DNS‑hairpin через HQ; концентрація egress IP тригерить контролі SaaS; шлюз стає вузьким місцем.

Виправлення: Застосуйте split tunneling для інтернету; пушьте лише внутрішні маршрути; обмежте DNS до внутрішніх зон; якщо потрібна інспекція — використовуйте контролі на кінцевих точках і селективні проксі.

4) «Працює для деяких користувачів, але не для інших»

Симптом: Те саме налаштування, різні результати в різних користувачів.

Корінна причина: Різниця NAT/фаєрволів у мережах клієнтів, MTU‑чорні діри або непослідовні per‑user маршрути/AllowedIPs.

Виправлення: Порівняйте конфіги peers; тестуйте MTU DF‑ping; розгляньте keepalives; уникайте персонофікованих «сніжинок» маршрутів, якщо вони не документовані і не потрібні.

5) «Ми не можемо сказати, хто що доступав»

Симптом: Логи показують лише IP шлюзу через NAT, або користувачі ділять ключі.

Корінна причина: Маскарадування приховує IP клієнта; відсутні персональні облікові дані; слабка кореляція логів.

Виправлення: Віддавайте перевагу маршрутизованим пулам без NAT; застосовуйте персональні ключі/сертифікати; анотуйте ключі; логируйте підключення/відключення з ідентичністю і призначеним IP.

6) «Після злиття VPN зламався і зараз маршрути флапають»

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

Корінна причина: Перекриття RFC1918 при з’єднанні через VPN; неоднозначні маршрути; split‑horizon DNS не синхронізований з реальною досяжністю.

Виправлення: Перенумеруйте, якщо можливо; інакше використовуйте NAT на чітких межах з потужним логуванням; зробіть маршрути більш специфічними; вирівняйте DNS‑види з реальною досяжністю мереж.

7) «Клієнти VPN можуть сканувати один одного»

Симптом: Клієнт може підключатися до відкритих портів іншого клієнта через VPN‑IP.

Корінна причина: Дозволений client‑to‑client (OpenVPN client-to-client увімкнено, або правила форварду дозволяють wg0→wg0).

Виправлення: Вимкніть client‑to‑client; заблокуйте wg0→wg0 форвардинг; якщо потрібен peer‑трафік, застосуйте явну політику і розгляньте окремі пули/групи.

Контрольні списки / покроковий план

Покроково: міграція від повного мережа‑до‑мережі до VPN з мінімальними привілеями

  1. Перелічіть, що користувачі реально потребують

    • Пишіть застосунки/сервіси, а не підмережі. «Git через HTTPS», «RDP до jump host», «Postgres до звітної БД».
    • Визначте власників для кожного сервісу і бізнес‑причину.
  2. Визначте виділений пул клієнтів VPN і сегмент

    • Виберіть незаперечний діапазон (наприклад, 10.250.0.0/24).
    • Маршрузуйте його правильно (без NAT, якщо можна уникнути).
  3. Увімкніть default‑deny для форвардингу з VPN

    • Політика forward — drop, allow established/related.
    • Явно дозволяйте мінімальні призначення/порти.
  4. Зменште маршрути, пушені клієнтам

    • Для WireGuard: звужуйте AllowedIPs по peer/групі.
    • Для OpenVPN: пуште лише конкретні маршрути.
  5. Помістіть адмін‑доступ за бастіонами

    • Віддавайте перевагу SSH/RDP‑шлюзам з MFA і логуванням.
    • Дозвольте bastion → target, а не client → target.
  6. Скопуйте DNS

    • Лише внутрішні зони; уникайте примусу всього DNS через VPN, якщо не потрібно.
    • Забезпечте, щоб внутрішні імена повертали IP, до яких VPN‑клієнти можуть дістатися (без «мертвих» split‑horizon записів).
  7. Додайте мапінг і гігієну ключів

    • Персональні ключі/сертифікати, ніяких спільних секретів.
    • Анотируйте власність, призначення і дату перегляду поруч із конфігом.
  8. Додайте логування, яке ви справді будете використовувати

    • Події підключення + призначений IP, відмови фаєрволу (пробні), DNS‑запити для внутрішніх зон (якщо можливо).
    • Зробіть пошук можливим за користувачем, VPN‑IP і призначенням.
  9. Розгортайте поетапно

    • Почніть із пілотної групи і топ‑5 сервісів.
    • Тримайте старий широкий доступ за аварійним тумблером, але з датою закінчення для цього тумблера.
  10. Проведіть tabletop‑дрил інцидентів

    • Практика: «ключ підрядника скомпрометовано, до чого вони можуть дістатися?»
    • Якщо відповідь «більшість LAN» — ви ще не закінчили.

Операційний чек‑лист: додавання нового дозволеного сервісу

  • Власник сервісу погоджує і надає IP/hostname і порт(и).
  • Вирішіть: прямий доступ чи через бастіон/проксі.
  • Підтвердіть, що ACL на боці призначення дозволяють пул VPN (маршрутизований, не NAT‑ований, бажано).
  • Додайте правило фаєрволу з коментарем, що містить власника/призначення і дату рев’ю.
  • Додайте лише потрібний маршрут (намагайтеся /32 або найменшу підмережу, що хостить сервіс).
  • Протестуйте з репрезентативної клієнтської мережі (домашній NAT, мобільний хот‑спот, корпоративний Wi‑Fi).
  • Підтвердіть, що логи показують ідентичність користувача для спроб доступу і відмов.

Чек‑лист безпеки: утримання моделі в щільному стані з часом

  • Квартальний перегляд дозволених призначень по групі/peer.
  • Автоматичне закінчення доступу вендорів, якщо не відновлено.
  • Алертинг на нові широкі оголошення маршрутів або зміни політик за замовчуванням.
  • Блокування відомо небезпечних протоколів (SMB, RPC) для VPN, якщо не явно потрібно і не обмежено.
  • Вимоги до OS і базових засобів безпеки для керованих пристроїв.

Поширені запитання

1) Хіба «повний мережа‑до‑мережі» не простіший і отже безпечніший?

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

2) Split tunneling здається ризикованим. Хіба весь трафік не повинен йти через корпоративні інструменти безпеки?

Якщо ви можете гарантувати пропускну здатність, надійність і правильну інспекцію без розриву SaaS, повний тунель може бути захищеним вибором.
Більшість організацій цього не можуть. Практичний підхід: split tunnel для інтернету, суворі маршрути для внутрішніх сервісів і контроли на кінцевих точках для решти.
Централізація всього через HQ — це щоденна ставка на доступність.

3) Чи можна покладатися тільки на WireGuard AllowedIPs як контроль доступу?

AllowedIPs — необхідний, але не достатній елемент. Це сильний важіль, але вам все одно потрібні правила фаєрволу на шлюзі та ACL на боці призначення.
Захист у кілька шарів важливий, бо хтось зрештою додасть «тимчасовий» маршрут.

4) Чи мають клієнти VPN NATитись до шлюзу?

Уникайте NAT, коли можете: він вбиває атрибуцію на ресурсі призначення і ускладнює аудит.
Використовуйте маршрутизовані пули і навчайте бік LAN повертати трафік до VPN‑пула. NAT іноді необхідний для legacy‑мереж,
але розглядайте його як компроміс і додайте компенсуючі контроли.

5) Як запобігти тому, щоб користувачі VPN не дізнавались внутрішніх імен хостів?

Скопуйте DNS. Не давайте резолвер, що відповідає на всю внутрішню просторову область імен, якщо користувачам потрібна лише одна зона.
Використовуйте conditional forwarding або пер‑лінкове маршрутування DNS і уникайте витоку «mgmt» зон до загальних користувачів.

6) А якщо «додаток використовує динамічні порти»?

Це сильний натяк, що не варто дозволяти додаток безпосередньо через VPN.
Помістіть його за gateway, який нормалізує доступ (проксі, бастіон, публічні фіксовані порти), або перерахуйте експозицію сервісу.
Динамічні порти підходять у контрольованому сегменті; вони неприйнятні як вимога політики VPN.

7) Як працювати з вендорами, що потребують доступ «тільки на тиждень»?

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

8) Яка мінімально життєздатна конфігурація, якщо ми малі та зайняті?

Виділений пул VPN, default‑deny форвардинг і один бастіон для адмін‑доступу.
Додайте невелику кількість явних дозволів сервісів. Анотуйте все з власниками.
Ви можете згодом розвивати ідентифікаційно‑чутливий доступ, але ви не зможете безболісно звузити плоску мережу заднім числом.

9) Як уникнути, щоб мінімальні привілеї не перетворилися на нескінченний пінг‑понг по тікетам?

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

Висновок: практичні наступні кроки

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

Наступні кроки, які можна виконати цього тижня:

  1. Оберіть одну VPN‑групу (вендори або підрядники) і замініть широкі маршрути явними призначеннями.
  2. Переведіть форвардинг на default‑deny і додайте лише потрібні allow‑правила з коментарями і датами рев’ю.
  3. Вирішіть, чи NAT приховує вашу здатність до аудиту; якщо так — плануйте міграцію на маршрутизований пул.
  4. Скопуйте DNS до внутрішніх зон, які дійсно потрібні.
  5. Запишіть «План швидкої діагностики» і тримайте його поруч з on‑call runbook, а не в чиїйсь голові.

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

← Попередня
Ubuntu 24.04: Як посилити SSH, не втративши доступ — прагматичний чекліст
Наступна →
Debian 13: NTP працює, але дрейф не зникає — налаштування апаратного годинника та Chrony (Випадок №79)

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