Нічого так не оживляє рутинний проєкт VPN, як виявлення, що обидві сторони використовують 10.0.0.0/8. Раптом кожний маршрут — це обманка, половина пакетів летить не туди, а хтось питає, чому «VPN підключено», але база даних досі недоступна.
NAT через VPN — це зрілий спосіб з’єднати перекриті мережі, не перейменовуючи всю інфраструктуру сьогодні. Це не «чисте» рішення, але часто найменш поганий варіант, що тримає продакшн стабільним, поки ви купуєте час для правильної ієрархії IP-адрес.
Суть проблеми: перекриття мереж і неоднозначність маршрутизації
Коли дві мережі використовують однаковий IP-простір, маршрутизація стає неоднозначною. Якщо Сайт A — 10.20.0.0/16, а Сайт B також 10.20.0.0/16, ваш маршрутизатор не може відрізнити «віддалений 10.20.1.10» від «локального 10.20.1.10». VPN-тунель цього не виправляє. VPN — це лише канал; маршрутизація все одно вирішує, куди йдуть пакети.
У дизайнах без перекриттів ви анонсуєте маршрути (статичні, BGP, OSPF тощо) і трафік тече. У випадку перекриттів анонс маршрутів стає небезпечним. Ваші хости можуть спробувати дістатися «віддалених» адрес через ARP локально. Або ви можете загубити трафік, вибравши «неправильний» маршрут через пріоритет метрик. Гірше: може здаватися, що з одного боку все гаразд, а з іншого — ні, що породжує ті інциденти, які перетворюють розуми людей на суп.
NAT через VPN обходить неоднозначність, транслюючи одну сторону (іноді обидві) в унікальний «віртуальний» діапазон адрес для перетину тунелю. Внутрішня адресація залишається незмінною. Тунель бачить світ без перекриттів. Маршрутизація знову стає детермінованою.
Дві прості правила, щоб не помилитися:
- Ви не виправляєте перекриття; ви його ізолюєте. NAT — це шар сумісності, а не панацея.
- Якщо можете безпечно перенумерувати — зробіть це. NAT через VPN — це те, що роблять, коли «безпечно» недоступне цього кварталу.
Факти та історія, що пояснюють, чому це повторюється
- RFC 1918 (1996) визначив приватний IPv4-простір (
10/8,172.16/12,192.168/16), через що «просто використовувати 10.x» стало корпоративним рефлексом. - NAT став масовим наприкінці 1990-х, коли страх виснаження IPv4 поєднався з реаліями зростання підприємств. Він вирішив проблему адрес, але нормалізував повторне використання адрес.
- IPsec задумувався з уявленням про кінцеву ідентичність IP; NAT був незручним сусідом, через що з’явився NAT-T (NAT traversal) для перенесення ESP у UDP.
- Багато компаній копіювали діапазони з лабораторій вендорів (
10.0.0.0/8та192.168.0.0/16), бо «в демо працювало», а потім масштабували помилку на тисячі підмереж. - Злиття та поглинання — фабрика перекриттів: дві зрілі мережі стикаються, кожна впевнена, що її
10.0.0.0/8— єдина правильна. - Дефолтні VPC в хмарах (наприклад,
10.0.0.0/16) зробили перекриття ще ймовірнішим, коли команди створювали середовища без централізованого IPAM. - Carrier-grade NAT навчила покоління сприймати трансляцію як норму, навіть якщо це ламає протоколи, які вбудовують IP у payload.
- Деякі промислові та легасі-системи захардкоджують IP в конфігах, ліцензіях або ACL, перетворюючи перенумерацію на «питання до юридичного», а не на інженерну задачу.
Одна перефразована ідея, варта уваги: paraphrased idea
від Richard Cook (операції та безпека): системи працюють тому, що люди адаптуються; відмови трапляються, коли складність перевищує ці адаптації.
Шаблони проєктування: як NAT через VPN реалізують у реальних системах
Шаблон 1: Односторонній NAT з «аліас-підмережею» (найпоширеніший, найменш заплутаний)
Виберіть невикористовуваний «аліасний» CIDR, який існує лише як ціль трансляції. Приклад:
- Сайт A реальний:
10.20.0.0/16 - Сайт B реальний:
10.20.0.0/16(так, такий самий) - Аліас для Сайту B, видимий з Сайту A:
172.31.20.0/24(або більший)
Сайт A маршрутизує 172.31.20.0/24 у VPN. На VPN-краю Сайту B ви робите DNAT 172.31.20.x → 10.20.x, а також SNAT для зворотного трафіку, щоб він повертався зі 172.31.20.x. Це робить сесії симетричними і маршрутизованими.
Коли використовувати: коли лише одна сторона має доступ до іншої, або коли ви можете терпіти асиметричну «реальну vs аліас» адресацію у конфігах.
Шаблон 2: Двосторонній NAT (два аліасні простори)
Якщо обидві сторони перекриваються і обидві повинні ініціювати з’єднання, зазвичай потрібні два аліасні простори:
- Аліас для A, видимий з B:
172.31.10.0/24 - Аліас для B, видимий з A:
172.31.20.0/24
Це повністю уникає питання «хто такий 10.20.1.10?» через тунель. Але це також подвоює кількість елементів, отже подвоює і способи помилитися.
Шаблон 3: NAT лише для конкретних сервісів (схематичний NAT)
Іноді вам не потрібне «мережеве з’єднання», а потрібне «TCP/5432 від аплікації до БД». У таких випадках транслюйте лише VIP-адреси сервісів:
- Створіть маленький аліасний діапазон (навіть /32)
- DNAT цих аліасів на реальні сервери
- Обмежте політики фаєрвола лише на ці порти
Це зменшує радіус ураження. Це також змушує документувати залежності — завжди популярне, аж поки не попросиш когось це зробити.
Шаблон 4: Проксі на рівні застосунку замість NAT (коли NAT вас зламає)
Деякі протоколи ненавидять NAT. SIP, деякі режими FTP, дивні ліцензійні демони та все, що вбудовує IP у payload, можуть поводитися так, ніби зараз 2003 рік. Якщо застосунок ламається, перестаньте сперечатися з пакетами — використайте проксі:
- HTTP(S): reverse proxy або forward proxy
- Бази даних: TCP-проксі з health checks
- SSH: bastion / jump host
Проксі вимагають експлуатаційних зусиль, але можуть врятувати від нюансів трансляції, особливо для протоколів з багатьма з’єднаннями.
Шаблон 5: «Протікання маршрутів» з VRF (уникати NAT, коли перекриття «організаційне»)
Якщо перекриття виникло через логічне розділення мереж, VRF іноді вирішує проблему без NAT, дозволяючи зберігати однакові префікси в різних таблицях маршрутизації. Це елегантно на потужних маршрутизаторах і жахливо на випадковому Linux-VM, що діє як VPN-шлюз. Використовуйте, якщо ви вже керуєте VRF і ваші кінцеві точки VPN підтримують їх чисто.
Жарт №1: NAT — як скотч: міцний, універсальний і якось завжди присутній на місці злочину.
Як обрати підхід (і що ви насправді обмінюєте)
Ваш вибір здебільшого про три напруження:
- Операційна ясність проти швидкості: перенумерація — ясна і майбутньо-стійка, але повільна. NAT — швидкий, але ви будете його дебажити о 2:00 ранку.
- Симетрія проти простоти: односторонній NAT простіший, але може здивувати «іншу» сторону. Двосторонній NAT — симетричніший, але складніший.
- Спостережуваність проти непрозорості: трансляція може ховати початкові IP, якщо ви не логируєте conntrack/NAT-мапінги та не зберігаєте контекст у логах.
Використайте це як практичну рубрику:
- Якщо це міст для злиття з багатьма сервісами і невідомими залежностями: почніть з схематичного NAT або проксі. Розширюйте тільки коли зрозумієте трафік.
- Якщо це один застосунок → одна залежність: робіть NAT для сервісного VIP. Не NATьте цілі підмережі «бо так простіше».
- Якщо це довготривале підключення з багатьма ініціаторами в обох напрямках: розгляньте двосторонній NAT, але також заплануйте перенумерацію. NAT не має становитися архітектурою.
Прохід пакета: що відбувається з одним TCP-з’єднанням
Приклад: аплікація на Сайті A (10.20.5.10) потребує Postgres на Сайті B (10.20.8.25). Є перекриття, тому ми даємо B аліасну IP 172.31.20.25, яку буде використовувати A.
- Аплікація підключається:
10.20.5.10:54012→172.31.20.25:5432. - Маршрутизація на Сайті A відправляє
172.31.20.0/24до VPN-шлюзу, у тунель. - VPN-шлюз Сайту B DNAT переписує призначення:
172.31.20.25→10.20.8.25. - VPN-шлюз Сайту B SNAT (важливо) переписує джерело на стабільний аліас (або IP шлюзу), щоб повернення пакетів обов’язково проходило через шлюз і могло бути коректно розтрансляоване.
- Сервер відповідає на SNAT-адресу, а не безпосередньо на
10.20.5.10(що локально неоднозначно й ймовірно неправильно). - Шлюз розтранслює на шляху назад, щоб аплікація бачила відповіді від
172.31.20.25, зберігаючи консистентність сесії.
Якщо пропустити крок SNAT, отримаєте класичний випадок «SYN пройшов, SYN-ACK зник». Це не таємниця. Це асиметрична маршрутизація, спричинена вашим оптимізмом.
Практичні завдання: команди, виходи та рішення, які ви приймаєте
Мета тут не в тому, щоб запускати команди заради спорту. Кожне завдання відповідає на питання, і кожна відповідь змушує прийняти рішення.
Завдання 1: Підтвердити, що перекриття реальне (і який масштаб проблеми)
cr0x@server:~$ ip -br addr
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 10.20.5.254/24
wg0 UP 10.99.0.1/24
Що це означає: Ви бачите локальні підмережі. Цей хост у 10.20.5.0/24.
Рішення: Якщо віддалий бік також використовує 10.20.0.0/16 або подібне, ви не зможете маршрутизувати його напряму. Потрібен NAT, VRF або перенумерація.
Завдання 2: Перевірити маршрут до аліасної підмережі (чи втекає трафік у VPN?)
cr0x@server:~$ ip route get 172.31.20.25
172.31.20.25 dev wg0 src 10.99.0.1 uid 0
cache
Що це означає: Трафік до аліасної IP піде у wg0.
Рішення: Якщо вивід показує dev eth0 або локальний шлюз, ви не використовуєте тунель. Виправте маршрутизацію до застосування NAT.
Завдання 3: Перевірити рукостискання VPN і останній трафік (приклад WireGuard)
cr0x@server:~$ sudo wg show
interface: wg0
public key: fM0...redacted
listening port: 51820
peer: 8kQ...redacted
endpoint: 198.51.100.10:51820
allowed ips: 172.31.20.0/24
latest handshake: 1 minute, 12 seconds ago
transfer: 128.34 MiB received, 141.02 MiB sent
Що це означає: Рукостискання свіже; AllowedIPs включає аліасну підмережу. Лічильники трафіку рухаються.
Рішення: Якщо latest handshake — «never», зупиніться. У вас проблема з VPN, а не з NAT.
Завдання 4: Підтвердити, що IP-форвардінг увімкнено (найнудніша передумова)
cr0x@server:~$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
Що це означає: Linux маршрутизуватиме пакети.
Рішення: Якщо 0, увімкніть та збережіть у /etc/sysctl.d/*.conf. Без форвардінга NAT-правила можуть бути ідеальними й нічого не робити.
Завдання 5: Перевірити політику фаєрвола на форвардінг (nftables)
cr0x@server:~$ sudo nft list ruleset | sed -n '1,120p'
table inet filter {
chain forward {
type filter hook forward priority filter; policy drop;
iifname "wg0" oifname "eth0" ip daddr 10.20.8.25 tcp dport 5432 accept
iifname "eth0" oifname "wg0" ct state established,related accept
}
}
Що це означає: За замовчуванням drop, явний дозвіл для Postgres і правило для established/related у зворотному напрямку.
Рішення: Якщо ви не бачите правила established/related для зворотного напрямку, ви отримаєте односторонній трафік і звинуватите NAT. Не робіть цього.
Завдання 6: Переглянути правила NAT (nftables)
cr0x@server:~$ sudo nft list table ip nat
table ip nat {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
iifname "wg0" ip daddr 172.31.20.25 dnat to 10.20.8.25
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname "eth0" ip daddr 10.20.8.25 snat to 10.20.5.254
}
}
Що це означає: DNAT переводить аліас у реальний. SNAT примушує відповіді повертатися через шлюз.
Рішення: Якщо SNAT відсутній, додайте його або використайте загальніший SNAT/masquerade для потоку аліас→реальний. Інакше зворотній трафік може обійти шлюз.
Завдання 7: Спостерігати conntrack-пости під час тестування (чи транслюються сесії?)
cr0x@server:~$ sudo conntrack -L | grep 5432 | head
tcp 6 431999 ESTABLISHED src=10.20.5.10 dst=172.31.20.25 sport=54012 dport=5432 src=10.20.8.25 dst=10.20.5.254 sport=5432 dport=54012 [ASSURED] mark=0 use=1
Що це означає: Ви бачите і початковий кортеж, і трансляцію. Шлях відповіді прив’язаний до IP шлюзу (10.20.5.254) через SNAT.
Рішення: Якщо conntrack нічого не показує під час тестування, ваші пакети не доходять до шлюзу. Перевірте маршрути та AllowedIPs/селектори.
Завдання 8: Захоплення пакетів на обох інтерфейсах (доказ, де воно «помирає»)
cr0x@server:~$ sudo tcpdump -ni wg0 host 172.31.20.25 and tcp port 5432 -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
IP 10.20.5.10.54012 > 172.31.20.25.5432: Flags [S], seq 221733, win 64240, options [mss 1380,sackOK,TS val 123 ecr 0,nop,wscale 7], length 0
IP 10.20.5.10.54012 > 172.31.20.25.5432: Flags [S], seq 221733, win 64240, options [mss 1380,sackOK,TS val 1123 ecr 0,nop,wscale 7], length 0
Що це означає: SYN-и потрапляють у тунельний інтерфейс. Якщо ви ніколи не бачите SYN-ACK, проблема після входу в тунель (DNAT, фаєрвол, сервер, зворотне маршрутизування).
Рішення: Тоді знімайте трафік на eth0, щоб підтвердити, що DNAT відбулося.
cr0x@server:~$ sudo tcpdump -ni eth0 host 10.20.8.25 and tcp port 5432 -c 5
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP 10.20.5.254.54012 > 10.20.8.25.5432: Flags [S], seq 221733, win 64240, options [mss 1460,sackOK,TS val 555 ecr 0,nop,wscale 7], length 0
Що це означає: SNAT і DNAT працюють. Сервер бачить IP шлюзу як джерело.
Рішення: Якщо сервер вимагає реальний IP клієнта для ACL, потрібна автентифікація на рівні застосунку, PROXY protocol (де підтримується) або інша стратегія логування. NAT ховатиме клієнтів, якщо ви цього не сплануєте.
Завдання 9: Перевірити зворотну фільтрацію шляху (silent dropper)
cr0x@server:~$ sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.eth0.rp_filter
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
Що це означає: Увімкнено доволі строгий rp_filter. При асиметрії й NAT rp_filter може скидати дійсні пакети.
Рішення: Якщо бачите випадкові дропи, встановіть rp_filter у 2 (loose) на відповідних інтерфейсах або переробіть маршрутизацію, щоб зберегти симетрію. Не вимикайте глобально, якщо не розумієте ризиків.
Завдання 10: Перевірити MTU і поведінку PMTUD (VPN + NAT люблять фрагментацію)
cr0x@server:~$ ping -M do -s 1420 172.31.20.25 -c 3
PING 172.31.20.25 (172.31.20.25) 1420(1448) bytes of data.
ping: local error: message too long, mtu=1420
ping: local error: message too long, mtu=1420
ping: local error: message too long, mtu=1420
--- 172.31.20.25 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2041ms
Що це означає: Ваш path MTU нижчий, ніж ви припускали. Інкапсуляція VPN додає накладні витрати; NAT-пристрої та фаєрволи іноді неправильно обробляють ICMP «fragmentation-needed» повідомлення.
Рішення: Зменшіть MTU тунелю (наприклад, у WireGuard), зажміть MSS на краю або виправте обробку ICMP. Якщо TCP-сесії гальмують під навантаженням, а маленькі ping-и працюють, MTU — головний підозрюваний.
Завдання 11: Трасування маршруту з TCP SYN до реального сервісу (доказ L3 проти L4)
cr0x@server:~$ sudo traceroute -T -p 5432 172.31.20.25 -n
traceroute to 172.31.20.25 (172.31.20.25), 30 hops max, 60 byte packets
1 10.99.0.2 12.112 ms 11.901 ms 11.774 ms
2 172.31.20.25 24.310 ms 24.221 ms 24.105 ms
Що це означає: Ви доходите до аліасної кінцевої точки за два хопи (peer тунелю, потім ціль). Це не гарантує, що порт відкритий, але підтверджує, що маршрутизація в порядку.
Рішення: Якщо traceroute зупиняється на хопі 1, ваші AllowedIPs/селектори або маршрути до тунелю неправильні. Не чіпайте налаштування сервера ще.
Завдання 12: Перевірити, що сервіс насправді слухає (на боці призначення)
cr0x@server:~$ sudo ss -lntp | grep 5432
LISTEN 0 4096 0.0.0.0:5432 0.0.0.0:* users:(("postgres",pid=1442,fd=6))
Що це означає: Postgres слухає на всіх інтерфейсах.
Рішення: Якщо він прив’язаний до 127.0.0.1 або до конкретного IP, що не відповідає DNAT-цілі — виправте це спочатку. NAT не підключиться до того, що не слухає.
Завдання 13: Підтвердити маршрут сервера назад до шлюзу (щоб уникнути обходу)
cr0x@server:~$ ip route get 10.20.5.254
10.20.5.254 via 10.20.8.1 dev eth0 src 10.20.8.25 uid 0
cache
Що це означає: Сервер поверне пакети до свого локального маршрутизатора, який має дістатися до NAT-шлюзу (залежно від топології). Якщо NAT-шлюз L2-суміжний, ви можете побачити dev eth0 напряму.
Рішення: Якщо сервер має більш прямий маршрут назад до підмережі клієнта, може виникнути асиметричне повернення. Розгляньте політичну маршрутизацію або забезпечення, щоб SNAT використовував адресу, яка примушує повернення через шлюз.
Завдання 14: Перевірити лічильники NAT, щоб підтвердити збіги (nftables counters)
cr0x@server:~$ sudo nft -a list chain ip nat prerouting
table ip nat {
chain prerouting { # handle 2
type nat hook prerouting priority dstnat; policy accept;
iifname "wg0" ip daddr 172.31.20.25 counter packets 128 bytes 7680 dnat to 10.20.8.25 # handle 12
}
}
Що це означає: DNAT-правило співпадає. Лічильники зростають під час тестування.
Рішення: Якщо лічильники лишаються нульовими, або трафік не прибуває, або умова матчу неправильна (ім’я інтерфейсу, IP призначення, сімейство адрес). Виправте умови матчу перед тим, як вигадувати нові правила.
Завдання 15: Перевірити селектори IPsec (policy-based VPN може «з’їсти» NAT-дизайн)
cr0x@server:~$ sudo ip xfrm policy
src 172.31.20.0/24 dst 10.20.8.0/24
dir out priority 1000 ptype main
tmpl src 203.0.113.2 dst 198.51.100.2 proto esp reqid 1 mode tunnel
src 10.20.8.0/24 dst 172.31.20.0/24
dir in priority 1000 ptype main
tmpl src 198.51.100.2 dst 203.0.113.2 proto esp reqid 1 mode tunnel
Що це означає: Політики ядра визначають, що шифрується. Якщо ваш аліасний діапазон не в селекторах, пакети не потраплять у тунель, навіть якщо маршрути існують.
Рішення: Оновіть селектори (на обох кінцях), щоб вони відповідали post-NAT адресам, які бачить тунель. Для policy-based IPsec NAT і селектори повинні збігатися, інакше ви будете гнатися за примарами.
Завдання 16: Тест з хоста аплікації з явним джерелом (доказ, хто транслюється)
cr0x@server:~$ psql "host=172.31.20.25 port=5432 user=app dbname=appdb connect_timeout=3" -c "select 1;"
?column?
----------
1
(1 row)
Що це означає: End-to-end шлях працює для реального протоколу. Успіх ICMP не рахується; успіх застосунку — рахується.
Рішення: Якщо psql не вдається, але TCP SYN/SYN-ACK працює, дивіться автентифікацію (pg_hba.conf), TLS SNI/сертифікати або L7-очікування, що включають IPи.
Швидкий план діагностики
Коли хтось каже «VPN підключений, але сервіс недоступний», не блукайте. Виконайте це по порядку. Припиніть, щойно знайдете невідповідність.
Перший крок: Тунель реальний і чи є трафік, що може його використовувати?
- WireGuard:
sudo wg show→ рукостискання свіже? Лічильники трафіку рухаються? - IPsec: перевірте SA і політики → чи селектори включають аліасний піддіапазон?
- Маршрутизація:
ip route get <alias-ip>→ чи вибирає вона тунельний інтерфейс?
Якщо будь-який з цих пунктів не проходить, правила NAT не мають значення.
Другий крок: Чи пакети транслюються і форвардяться?
sysctl net.ipv4.ip_forward→ має бути 1- Лічильники NAT (nftables/iptables) → чи DNAT/SNAT-правила співпадають?
conntrack -L→ чи існує запис для потоку?
Якщо DNAT спрацьовує, але SNAT ні, очікуйте втрату SYN-ACK і таймаути.
Третій крок: Чи змушуєте ви зворотній трафік повертатися через шлюз?
- Захоплення на внутрішньому інтерфейсі: чи бачите відповіді сервера до SNAT-джерела?
- Перевірте rp_filter; часто потрібен loose режим на межах NAT.
- Підтвердіть маршрут сервера до SNAT-адреси.
Четвертий крок: Чи готовий застосунок відповідати?
- Порт відкритий, сервіс слухає, TLS імена коректні, ACL оновлені для SNAT-джерел.
- Тестуйте реальними клієнтськими інструментами (psql, curl, ldapsearch). Ping — піднімає мораль, але не валідатор.
Типові помилки: симптом → корінна причина → виправлення
1) Симптом: «SYN виходить, нічого не повертається»
Корінна причина: Відсутній SNAT, тому сервер відповідає на початковий IP клієнта і відповідь йде звичайним маршрутом, минаючи VPN-шлюз (асиметричне повернення).
Виправлення: Додайте SNAT/masquerade на VPN-шлюзі для аліасних потоків або використайте політичну маршрутизацію, щоб змусити повернення через шлюз.
2) Симптом: Деякі порти працюють, інші загадково зависають
Корінна причина: Правила фаєрвола для форвардінгу дозволяють тестовий порт, але не фактичні потоки застосунку, або стан conntrack не дозволяється назад.
Виправлення: Розглядайте форвардінг як окрему політику. Дозвольте established/related в обох напрямках. Переконайтесь, що лічильники на конкретному правилі зростають.
3) Симптом: Працює для дрібних запитів, гине при великих передаваннях
Корінна причина: MTU/PMTUD проблеми через інкапсуляцію; ICMP «fragmentation needed» блокується; MSS не зажато.
Виправлення: Зменшіть MTU тунелю і/або зажміть MSS на SYN-пакетах. Дозвольте ICMP для PMTUD або прийміть, що будете тонко налаштовувати MTU.
4) Симптом: Випадкові відключення під навантаженням, особливо на мультигомованих шлюзах
Корінна причина: Reverse path filtering скидaє пакети, що не відповідають строгим очікуванням маршруту після NAT.
Виправлення: Встановіть rp_filter у loose (2) на релевантних інтерфейсах; де можливо, зберігайте симетрію маршруту.
5) Симптом: «VPN підключено, але ніхто не дістає аліасну підмережу»
Корінна причина: Policy-based IPsec селектори не включають аліасний діапазон, тому трафік ніколи не потрапляє у тунель.
Виправлення: Оновіть селектори, щоб відповідали post-NAT адресам. Для route-based IPsec перевірте VTI-маршрутизацію.
6) Симптом: Логи застосунку показують неправдивий IP клієнта, і шлюз потрапляє під rate-limit
Корінна причина: SNAT зводить багато клієнтів до одного IP; L7-системи сприймають це як одного «шумного» клієнта.
Виправлення: Віддавайте перевагу пулу SNAT по клієнту, PROXY protocol де підтримується, або переміщайтеся на застосунковий проксі, що зберігає ідентичність клієнта.
7) Симптом: DNS працює, але підключення до імен призводить до локальних машин
Корінна причина: Split-brain DNS повертає перекриті A-записи; клієнти резолвлять у 10.x і підключаються локально.
Виправлення: Публікуйте аліасні IP у DNS-поданні, яке використовує віддалий бік, або використайте умовне переспрямування DNS до зони, що повертає аліасні адреси.
8) Симптом: Нові NAT-правила «працюють» у тесті, а потім ламаються через тиждень
Корінна причина: Виснаження таблиці conntrack або NAT-правила залежать від динамічних імен інтерфейсів/адрес, які змінюються.
Виправлення: Моніторте використання conntrack, налаштуйте розміри, зафіксуйте імена інтерфейсів і уникайте крихких матчів. Робіть правила явними і переглядайте їх як код.
Три корпоративні міні-історії (з яких вчаться)
Міні-історія №1: Інцидент через неправильне припущення
Компанія A купила меншу організацію і потрібне було «швидке підключення», щоб фінанси могли тягнути дані для закриття місяця. Обидві сторони природньо використовували 10.0.0.0/8. Мережна команда зробила акуратний аліасний діапазон і налаштувала DNAT на віддаленому VPN-шлюзі. Базові тести пройшли: ping, traceroute, навіть швидке TCP-з’єднання до порту бази даних.
О 9:05 ранку, у день закриття, ETL-джоби запустилися і одразу зависли. Захоплення пакетів показало SYN і SYN-ACK, потім довгі паузи. Команда ескалувала до вендора VPN, бо так роблять, коли втомлені і трохи ображені реальністю.
Неправильне припущення: «Якщо DNAT працює, то трафік назад знайде свій шлях». Ні. База даних відповідала на оригінальний клієнтський IP (який все ще перекривався), і відповідь доставлялася локальному хосту з тією ж адресою на боці бази. Іноді той хост існував і відправляв RST. Іноді ні, і відповіді зникали. Мережа, у певному сенсі, робила саме те, що їй наказали.
Виправлення було простим і ефективним: SNAT на VPN-шлюзі для трансльованих потоків, щоб змусити все повернення через ту саму коробку. Коли сесії стали симетричними, ETL-джоби пройшли. Ніхто не дякував NAT, але всі перестали кричати на VPN-концентратор.
Після цього вони зробили те, що мали б зробити раніше: задокументували один packet walk з обома трансляціями і зробили «перевірку симетрії» частиною рев’ю змін. Інцидент спричинений не складністю, а тим, що пропустили нудні частини складності.
Міні-історія №2: Оптимізація, що повернулася бумерангом
Компанія B мала довготривалий NAT-міст через IPsec між двома датацентрами з перекритими lab-мережами. Це було не гарно, але стабільно. Потім хтось помітив високе завантаження CPU на VPN-шлюзах під піковими навантаженнями і вирішив оптимізувати: «Зменшимо тиск на conntrack, зробивши ширші NAT-правила і менше state-entry.»
Вони замінили набір вузьких SNAT-правил на велике masquerade, фактично транслюючи більше трафіку, ніж планувалося. CPU знизився. Запланували святкування. Через два дні системи моніторингу безпеки загорілися: IDS показувало стрибок «латерального руху» через тунель. Це було хибне спрацювання — але дороге.
Повернення бумерангом — це втрата спостережуваності. З ширшим masquerade кілька внутрішніх систем злилися в одну трансльовану ідентичність. Логи стали неоднозначними. Алерти, що раніше прив’язували події до конкретних джерел, тепер вказували на «NAT-шлюз», що є мережевим «хтось».
Гірше: система rate-limit на віддаленому боці бачила один джерело, що масово штурмує API, і почала обмежувати його — обмежуючи всіх. Оптимізація поліпшила один метрик (CPU) ціною іншого (ясність діагностики) і випадково викликала тротлінг.
Відкат відновив вузькі трансляції. Реальне рішення було більш зрілим: масштабувати шлюзи, збільшити ліміти conntrack з моніторингом і тримати зони NAT максимально вузькими. Проблеми продуктивності часто вирішуються потужністю і архітектурою, а не тим, що робить ваші логи марними.
Міні-історія №3: Нудна, але правильна практика, що врятувала день
Компанія C працювала в регульованому середовищі зі вкрай строгим контролем змін. Інженери бурчали, поки одного дня це не врятувало їх. Треба було підключити on-prem середовище до cloud VPC, який мав — сюрприз — перекриття з внутрішнім сегментом shared services.
Команда запропонувала NAT через VPN з аліасним діапазоном. Перед імплементацією вони зробили три нудні речі: зарезервували аліасний діапазон в IPAM (навіть якщо він «віртуальний»), написали односторінковий packet walk і створили синтетичний моніторинг з обох сторін з використанням аліасних адрес. Вони також додали conntrack і NAT-лічильники до свого ранбуку.
Під час cutover бракувало правила фаєрвола для зворотних established-з’єднань. Синтетичний чек впав миттєво, і лічильники NAT показали DNAT-хіти, але жодного зворотного трафіку. Клієнти нічого не помітили, бо команда спіймала це за кілька хвилин, а не годин.
Найкраще в постмортемі: там не було героїки. Був чекліст, лічильник і графік. Це та «нудьга», до якої варто прагнути.
Жарт №2: Якщо ви коли-небудь відчуваєте себе непотрібним, згадайте, що існує «тимчасове» NAT-правило з 2017 року, яке досі маршрутизовує трафік payroll.
Контрольні списки / покроковий план
Покроковий план для NAT через VPN, що не зіпсує вам життя пізніше
- Визначте бізнес-скоп. Перелічіть точні сервіси та порти. Якщо список — «все», ви збираєтеся побудувати другу мережу. Зупиніться і переобговоріть.
- Оберіть аліасні CIDR навмисно. Використайте діапазони, що не конфліктуватимуть з жодною стороною зараз або можливим розширенням. Зарезервуйте їх в IPAM, як серйозно.
- Вирішіть: односторонній чи двосторонній NAT. Односторонній простіший операційно. Двосторонній дає єдність для двосторонніх ініціаторів, але складніший для розуміння.
- Оберіть точку трансляції. Робіть NAT на VPN-шлюзі, якщо потрібен симетричний зворотний трафік і централізований контроль. Уникайте «NAT розсипаного по випадкових хостах».
- Напишіть packet walk. Один діаграм, один приклад потоку, обидві трансляції показані. Якщо не можете пояснити — не зможете це оперувати.
- Реалізуйте маршрути/селектори спочатку. Переконайтеся, що аліасні CIDR маршрутизуються в тунель і дозволені WireGuard AllowedIPs або IPsec селекторами.
- Реалізуйте правила фаєрвола для форвардінгу другими. Почніть з явного дозволу потрібних портів і established/related. За замовчуванням drop — нормально, якщо дисципліна є.
- Реалізуйте DNAT + SNAT разом. Трактуйте їх як пару для stateful сервісів. DNAT без SNAT — пастка, якщо ви не впевнені, що зворотні маршрути зафіксовані.
- Інструментуйте межі. Збирайте: лічильники NAT, використання conntrack, байти тунелю, інтерфейсні дропи. Алармуйте за змінами, а не лише за падіннями.
- Тестуйте на L7. Використовуйте реальні клієнтські інструменти. Для HTTP перевіряйте заголовки і TLS-імена. Для БД — виконайте реальний запит.
- План відкоту. Бути хоробрим — не стратегія відкоту. Тримайте старі маршрути та політики готовими до відновлення.
- Встановіть дату декомісії. NAT через VPN має тенденцію ставати постійним, якщо не запланувати перенумерацію або чисте інтегрування мереж.
Чекліст перед зміною (тримайте у голові)
- Аліасний CIDR зарезервований і задокументований
- Маршрути/AllowedIPs/селектори включають аліасний CIDR
- DNAT і SNAT правила переглянуті на предмет симетрії
- Форвард фаєрвола дозволяє потрібні порти + established/related
- rp_filter оцінено (loose там, де потрібно)
- План MTU (явний MTU тунелю або MSS clamp)
- Моніторинг і синтетичні тести готові
- План відкоту протестований (хоча б у лабораторії)
FAQ
1) Чи завжди потрібен SNAT при DNAT через VPN?
Не завжди, але припускайте «так», поки не доведете навпаки. Якщо хост призначення може deterministично повертати трафік через той самий шлюз (без обхідних маршрутів), SNAT можна пропустити. У перекритих мережах детермінізм повернення рідкісний. Використовуйте SNAT, щоб забезпечити симетрію.
2) Чи можна вирішити перекриття шляхом анонсу більш конкретних маршрутів?
Якщо перекриття ідентичне (обидва мають 10.20.0.0/16), більш специфічні записи не виправлять ідентичність адрес на хостах. Можна виграти на рівні роутерів, а потім програти через ARP і локальну маршрутизацію. Зазвичай вирішення — NAT або VRF; справжнє вирішення — перенумерація.
3) Чи має аліасний діапазон бути RFC1918 чи може виглядати як публічний простір?
Використовуйте RFC1918, якщо у вас немає дуже контрольованого середовища і вагомої причини інакше. Публічні-виглядаючі адреси можуть «витекти» у логи, моніторинг або сторонні сервіси і заплутати інцидент-референс. Мета — унікальність і внутрішня зрозумілість, а не імітація інтернету.
4) У чому різниця між NAT через VPN і NAT traversal (NAT-T)?
NAT-T — це про проходження IPsec через NAT-пристрій на шляху шляхом інкапсуляції ESP у UDP. NAT через VPN — це коли ви свідомо транслюєте адреси, щоб вирішити перекриття або політичні обмеження. Схожі акроніми, зовсім різні проблеми.
5) Чи може WireGuard робити NAT за мене?
WireGuard — це маршрутизація/крипто; сам по собі NAT він не реалізує. Ви робите NAT через nftables/iptables на шлюзі. AllowedIPs у WireGuard діє як механізм маршрутизації/фільтрації, і легко його неправильно налаштувати при додаванні аліасних діапазонів.
6) Як зберегти видимість реального IP клієнта в логах і ACL?
У чистому SNAT цього зазвичай не зробиш; це суть SNAT. Варіанти: пул SNAT по клієнту, застосункові проксі, що зберігають ідентичність, або протокольно-специфічні рішення (як PROXY protocol), де підтримується.
7) Чи погана ідея двосторонній NAT?
Він не зло, але його легко неправильно зрозуміти. Якщо потрібно підтримувати ініціацію з обох сторін і ви не можете перенумерувати — двосторонній NAT може бути правильним рішенням. Він вимагає кращої документації, жорсткішого моніторингу і уважнішого DNS/відкриття сервісів.
8) Чи вирішує IPv6 цю проблему?
IPv6 зменшує тиск на адреси і має знизити ймовірність перекриттів, але реальність включає легасі-системи і часткові впровадження. Також люди можуть перекривати ULA-префікси, якщо трактують адресацію як рекомендацію. Проблема дисципліни не зникне сама собою.
9) Чому DNS стає особливою бурею з аліасами NAT?
Тому що імена — це спільні концепти, а IP — ні. Якщо «db.internal» резолвиться у 10.20.8.25 на одній стороні і це ж адреса існує локально на іншій, клієнти впевнено підключаться не туди. Використовуйте split-horizon DNS або окремі аліасні імена, що резолвяться у аліасні IP для крос-сайтного використання.
10) Як довго можна тримати NAT через VPN?
Технічно: роками. Операційно: поки ви не забудете, як воно працює, і не доведеться змінювати під тиском. Призначте власника, тримайте моніторинг і план виходу (перенумерація, VRF або чисте мережеве інтегрування).
Висновок: наступні кроки, що не зіпсують вам тиждень
NAT через VPN — прагматичний інструмент для хаотичного світу: злиття, shadow IT, дефолтні CIDR у хмарі і «ми наведемо лад пізніше». Він працює, якщо поважати дві речі: симетрію і обсяг. Зробіть повернення трафіку детермінованим. Транслюйте лише те, що необхідно. Інструментуйте все, до чого торкаєтеся.
Наступні кроки, які можна зробити негайно:
- Вибрати і зарезервувати аліасні CIDR в IPAM (навіть якщо вони «віртуальні»).
- Написати односторінковий packet walk для одного критичного потоку, включно з DNAT і SNAT.
- Імплементувати лічильники NAT та моніторинг conntrack на VPN-шлюзах.
- Побудувати синтетичний чек, що використовує аліасні адреси з обох сторін і голосно падає.
- Запланувати незручну зустріч про перенумерацію, бо NAT — не план на відхід на пенсію.