Ви закрили сервер. Принаймні вам так здається. IPv4 виглядає чистим, UFW показує «active», і завдання в системі закрите. Потім сканер заходить на вашу IPv6‑адресу і знаходить SSH, endpoint для метрик і щось, про що ви взагалі забули.
Це тихий режим відмови для dual-stack: ви захищаєте старий інтернет, а новий лишаєте на ґанку з запасним ключем під килимком. Ubuntu 24.04 тут не «винахідливо погана». Вона просто достатньо сучасна, щоби IPv6 з’являвся рутинно, тоді як операційні звички щодо нього часто залишилися в 2012 році.
Справжня проблема: «файрвол увімкнено» не є висловом
Файрволи не бінарні. Це купа правил на різних шарах:
- Ядерний фільтр пакетів (nftables в Ubuntu 24.04; може ще ховатися legacy iptables).
- Обгортка хост‑файрвола (UFW поширений, але це не магія).
- Поведінка прив’язки сервісу (слухати на
0.0.0.0проти::має значення). - systemd sockets, які запускають демони за потреби.
- Хмарні security groups / ACL / edge‑фаєрволи, що можуть по-різному трактувати IPv6.
- Фактична IPv6‑адресація (global, temporary, privacy‑адреси, SLAAC, RA).
Коли команди кажуть «ми увімкнули UFW», вони часто мають на увазі «ми увімкнули фільтрацію IPv4 для портів, про які ми пам’ятали». Тим часом хост має глобальну досяжну IPv6‑адресу, а ваша політика для IPv6 або відсутня, або лояльна, або просто не застосовується до потрібної таблиці/хуку.
Думка з позицією: якщо ви керуєте публічним хостом на Ubuntu 24.04, IPv6 має бути пріоритетом. Або явним чином захистіть його, або планомовано відключіть. «Ігнорувати» — це просто повільніший варіант «бути зламаним».
Факти й контекст: чому IPv6 продовжує дивувати команди
Трохи історії допомагає, бо багато сьогоднішніх експлуатаційних помилок — це вчорашні проєктні рішення, що зустріли сьогоднішні налаштування за замовчуванням.
- IPv6 став стандартом у кінці 1990‑х (ера RFC 2460), але широке впровадження зайняло десятиліття, тож багато команд набули звичок керуватися тільки IPv4.
- IPv6 відновив end‑to‑end адресацію як «нормальний» шаблон; NAT тут не вимога дизайну. Це означає, що «NAT як кордон безпеки» зникає.
- Більшість Linux‑сервісів трактують
::як «слухати всі інтерфейси», що включає IPv6 і часто поведінку з IPv4‑mapped залежно від sysctls і налаштувань додатка. - Dual‑stack — це не перехідний нюанс; це робочий стан в багатьох організаціях. Вимкнення IPv6 часто ламає внутрішні сервіси (SSO, телеметрія, mirror‑сервери) несподіваними способами.
- nftables замінив iptables як сучасний фреймворк Linux‑фаєрвола; обгортки та міграції можуть залишити «правила, що існують», але не відповідають трафіку, який ви очікуєте.
- Провайдери хмари часто призначають IPv6 за замовчуванням або роблять це в один клік. Security groups можуть мати окремі IPv6‑секції, які ніхто не заповнює.
- IPv6 має кілька просторів адрес (link‑local, ULA, global). Link‑local завжди є; global може з’являтися автоматично через Router Advertisements або cloud‑конфіг.
- Існують privacy/temporary IPv6‑адреси, які можуть обертатись, що руйнує припущення «прикріпити хост до відомої IP» для клієнтів і моніторингу.
- Деякі інструменти сканування і скрипти комплаєнсу все ще за замовчуванням використовують IPv4. Це створює «зелені панелі», тоді як реальна вразливість живе на v6.
Цитата, яка має бути на кожній стіні операційників, бо це майже вся історія файрвола IPv6 в одному рядку: «Сподівання — не стратегія.»
— Gene Kranz
Модель загроз простими словами: як виникає діра
Найпоширеніша конфігурація, яку я бачу в аудитах, виглядає так:
- UFW увімкнений, додані правила для IPv4‑портів: 22, 80, 443, можливо 9100 заблокований.
- IPv6 увімкнено за замовчуванням (бо так), і хост має глобальну IPv6‑адресу.
- Або:
- UFW IPv6 вимкнений, тому він ніколи не пише v6‑правила, або
- UFW генерує v6‑правила, але nftables насправді не застосовує їх так, як ви очікуєте (рідше, але трапляється), або
- У вас є allow‑все «тимчасове» v6‑правило, яке стало постійним.
- Сервіси прив’язані до
::і доступні по v6 навіть якщо ви тестували лише v4.
Атакувальникам не потрібна креативність. Їм потрібна ваша передбачуваність. А «ми захистили IPv4» — це передбачувано.
Жарт №1: IPv6 — це як друга вхідні двері у вашому будинку, про яку ви не знали — але вона ще й має неоновий напис «WELCOME».
Швидкий план діагностики (робіть це перш за все)
Коли ви підозрюєте «забутий IPv6‑фаєрвол», ви хочете отримати відповіді за хвилини, а не вступати у філософські дебати про мережі. Ось порядок, який найшвидше знаходить вузьке місце.
По‑перше: доведіть, що хост справді має досяжний IPv6
- Чи має сервер глобальну IPv6‑адресу?
- Чи є дефолтний маршрут для IPv6?
- Чи можете ви дістатися до інтернету через IPv6?
По‑друге: перелікуйте, що слухає на IPv6
- Визначте сокети, прив’язані до
::або до глобальної IPv6. - Перевірте systemd socket units, які можуть створювати слухачів навіть коли «сервіс зупинено».
По‑третє: перевірте, чи пакетний фільтр застосовує політику для IPv6
- Стан UFW для v6 і чи існують його правила.
- nftables ruleset: чи є chain для input в сімействі
ip6? Чи встановлено default drop? - Подивіться лічильники під час генерації трафіку (пакети мають інкрементуватися на очікуваному правилі).
По‑четверте: тестуйте зовні, dual‑stack, з реальної мережі
- Проскануйте IPv6‑адресу з хоста поза вашим периметром мережі.
- Підтвердіть, що «закрито» насправді означає «фільтрується/блоковано», а не просто «немає сервісу на IPv4».
Практичні завдання: команди, очікуваний вивід і рішення (dual-stack)
Нижче реальні завдання оператора. Кожне містить команду, що означає вивід і яке рішення прийняти. Виконуйте в порядку, якщо діагностуєте; вибірково, якщо ви вже знаєте, де гниль.
Завдання 1: Підтвердити IPv6‑адреси і область
cr0x@server:~$ ip -6 addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
inet6 fe80::5054:ff:fe12:3456/64 scope link
valid_lft forever preferred_lft forever
inet6 2001:db8:1234:5678:5054:ff:fe12:3456/64 scope global dynamic
valid_lft 86395sec preferred_lft 14395sec
Значення: Якщо ви бачите scope global, ви досяжні по IPv6 за умови, що маршрутизація це дозволяє. Link‑local (fe80::) сам по собі не означає інтернет‑експозицію.
Рішення: Якщо global є і це небажано, ви або (a) негайно закриваєте правила файрвола для IPv6, або (b) правильно відключаєте IPv6 (розділ нижче) з аналізом впливу.
Завдання 2: Перевірити маршрутизацію IPv6 і дефолтний маршрут
cr0x@server:~$ ip -6 route show
2001:db8:1234:5678::/64 dev enp1s0 proto ra metric 100 pref medium
fe80::/64 dev enp1s0 proto kernel metric 256 pref medium
default via fe80::1 dev enp1s0 proto ra metric 100 pref medium
Значення: default via означає, що хост може відправляти IPv6‑трафік назовні. Якщо дефолтного маршруту немає, inbound іноді може працювати в деяких середовищах, але зазвичай з інтернету не дістає.
Рішення: Дефолтний маршрут присутній → трактуйте експозицію як реальну й невідкладну.
Завдання 3: Перевірити IPv6‑з’єднання
cr0x@server:~$ ping -6 -c 2 ipv6.google.com
PING ipv6.google.com(2607:f8b0:4005:80a::200e) 56 data bytes
64 bytes from 2607:f8b0:4005:80a::200e: icmp_seq=1 ttl=117 time=12.3 ms
64 bytes from 2607:f8b0:4005:80a::200e: icmp_seq=2 ttl=117 time=12.1 ms
--- ipv6.google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
Значення: Вихідний IPv6 працює. В багатьох мережах, якщо вихідний працює, inbound — лише в один фаєрвол‑промах.
Рішення: Продовжуйте аудит слухачів і файрвола; не припускайте, що upstream вас блокує.
Завдання 4: Перелік слухаючих сокетів з видимістю IPv6
cr0x@server:~$ sudo ss -lntup
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
tcp LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1123,fd=3))
tcp LISTEN 0 4096 [::]:22 [::]:* users:(("sshd",pid=1123,fd=4))
tcp LISTEN 0 4096 [::]:9100 [::]:* users:(("node_exporter",pid=1337,fd=3))
tcp LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:* users:(("grafana",pid=1450,fd=9))
tcp LISTEN 0 4096 [::]:80 [::]:* users:(("nginx",pid=1200,fd=6))
Значення: Будь‑який слухач [::]:PORT досяжний по IPv6 (залежно від файрвола). Зауважте, що 127.0.0.1:8080 — лише loopback і не експонується.
Рішення: Для кожного [::] слухача вирішіть: має бути публічним, приватним чи лише локальним? Якщо він не повинен бути публічним — виправте прив’язку І/А файрвол.
Завдання 5: Перевірити налаштування IPv6 у UFW
cr0x@server:~$ sudo grep -n '^IPV6=' /etc/default/ufw
7:IPV6=yes
Значення: Якщо IPV6=no, UFW не керуватиме v6‑правилами. Якщо yes, UFW згенерує набори правил як для v4, так і для v6.
Рішення: Якщо no і вам потрібен IPv6: змініть на yes, потім перезавантажте UFW і валідуйте. Якщо ви хочете повністю відключити IPv6, не просто міняйте UFW; опрацюйте sysctls/netplan і прив’язки застосунків.
Завдання 6: Інспектувати стан UFW з деталізацією
cr0x@server:~$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN 203.0.113.0/24
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN 2001:db8:feed::/48
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6)
Значення: Наявність правил «(v6)» добра; це означає, що UFW принаймні випускає політику для IPv6. Але «Anywhere (v6)» — це реальний вибір, а не значення за замовчуванням, яке слід приймати сліпо.
Рішення: Якщо ви не планували публічний IPv6 для 80/443/22 — звужуйте правила негайно. Якщо UFW не показує жодних v6‑записів — вважайте це червоним попередженням.
Завдання 7: Перевірити, чи nftables має покриття по IPv6
cr0x@server:~$ sudo nft list ruleset
table inet ufw {
chain input {
type filter hook input priority filter; policy drop;
iif "lo" accept
ct state established,related accept
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
tcp dport 22 ip saddr 203.0.113.0/24 accept
tcp dport 22 ip6 saddr 2001:db8:feed::/48 accept
tcp dport { 80, 443 } accept
counter packets 12345 bytes 987654
reject with icmpx type admin-prohibited
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
Значення: Одна table inet з ip і ip6 відповідностями — гарна практика. Зауважте default policy drop на input. Також помітні явні дозволи для ICMP/ICMPv6.
Рішення: Якщо ви бачите лише table ip і нічого для IPv6, ви ймовірно фільтруєте тільки IPv4. Виправляйте, увімкнувши IPv6 в UFW або написавши явні nftables‑правила для ip6 / inet.
Завдання 8: Подивіться лічильники nftables під час генерації IPv6‑трафіку
cr0x@server:~$ sudo nft -a list chain inet ufw input
table inet ufw {
chain input {
type filter hook input priority filter; policy drop;
iif "lo" accept
ct state established,related accept
ip6 nexthdr ipv6-icmp accept
tcp dport 22 ip6 saddr 2001:db8:feed::/48 accept # handle 14
tcp dport { 80, 443 } accept # handle 15
reject with icmpx type admin-prohibited # handle 16
}
}
Значення: # handle дозволяє спостерігати лічильники, якщо ви додаєте counter або якщо ланцюг вже їх містить. Якщо ви не бачите інкременту лічильників під час тесту, можливо ви дивитесь не на той ruleset або трафік обходить правила (рідко, але можливо при policy routing або інших хуках).
Рішення: Якщо лічильники не рухаються під час відомої спроби inbound, підтвердіть, який backend файрвола активний і чи інша система не керує nftables.
Завдання 9: Підтвердити, який backend UFW використовує
cr0x@server:~$ sudo ufw version
ufw 0.36.2
Copyright 2008-2023 Canonical Ltd.
Backend: nf_tables
Значення: Якщо написано Backend: nf_tables, UFW генерує nftables‑правила. Якщо бачите legacy iptables — у вас може бути split‑brain фільтрації.
Рішення: Стандартизувати: оберіть nf_tables і приберіть/зупиніть legacy‑скрипти, що досі викликають iptables напряму.
Завдання 10: Виявити legacy iptables‑правила, що дають хибне відчуття безпеки
cr0x@server:~$ sudo iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
Значення: Якщо політики legacy iptables — ACCEPT, тоді ви думаєте «deny by default», але це не обов’язково помилка — бо nftables може робити реальну фільтрацію. Проте це підказка, що ви в одному кроці від інциденту через міграцію.
Рішення: Якщо ви використовуєте nftables, не покладайтеся на вивід iptables для впевненості. Якщо щось все ще встановлює iptables‑правила — або мігруйте, або видаліть це.
Завдання 11: Перевірити sysctl для IPv6, що впливає на прив’язку і прийом
cr0x@server:~$ sysctl net.ipv6.conf.all.disable_ipv6 net.ipv6.conf.default.disable_ipv6 net.ipv6.bindv6only
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.bindv6only = 0
Значення: IPv6 увімкнено. net.ipv6.bindv6only=0 означає, що IPv6‑сокети можуть приймати IPv4‑mapped трафік в деяких випадках; це залежить від застосунку і опцій сокета.
Рішення: Не «виправляйте» експозицію через перемикання sysctls, якщо ви не протестували поведінку застосунків. Віддавайте перевагу файрволу і виправленням прив’язок.
Завдання 12: Виявити сервіси, що прив’язані на всі інтерфейси і не повинні
cr0x@server:~$ systemctl status node_exporter.service --no-pager
● node_exporter.service - Prometheus Node Exporter
Loaded: loaded (/lib/systemd/system/node_exporter.service; enabled; preset: enabled)
Active: active (running) since Mon 2025-12-30 10:18:42 UTC; 2h 11min ago
Main PID: 1337 (node_exporter)
Tasks: 4 (limit: 9382)
Memory: 9.8M
CPU: 2.1s
CGroup: /system.slice/node_exporter.service
└─1337 /usr/bin/node_exporter --web.listen-address=:9100
Значення: --web.listen-address=:9100 — це «слухати все», що включає IPv6 на багатьох системах. Часто це не те, що ви хочете на хості, видимому з інтернету.
Рішення: Прив’язуйте exporters до IP управління, localhost з reverse proxy або файрволте їх тільки для ваших scrapers — як по IPv4, так і по IPv6.
Завдання 13: Переконатися, що systemd socket activation не створює несподіваних слухачів
cr0x@server:~$ systemctl list-sockets --all --no-pager
LISTEN UNIT ACTIVATES
[::]:22 ssh.socket ssh.service
127.0.0.53%lo:53 systemd-resolved.socket systemd-resolved.service
/var/run/dbus/system_bus_socket dbus.socket dbus.service
Значення: Якщо ви бачите socket‑unit, що слухає на [::], ядро приймає з’єднання навіть якщо сервіс здається зупиненим; systemd запустить його за потреби.
Рішення: Якщо ви мали намір вимкнути порт — відключайте socket‑unit, а не лише сервіс.
Завдання 14: Зовнішнє IPv6‑сканування з іншого хоста (реальність оператора)
cr0x@server:~$ nmap -6 -Pn -p 22,80,443,9100 2001:db8:1234:5678:5054:ff:fe12:3456
Starting Nmap 7.94 ( https://nmap.org ) at 2025-12-30 12:35 UTC
Nmap scan report for 2001:db8:1234:5678:5054:ff:fe12:3456
Host is up (0.021s latency).
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
9100/tcp filtered jetdirect
Nmap done: 1 IP address (1 host up) scanned in 3.11 seconds
Значення: open означає досяжний і відповідає. filtered означає, що файрвол блокує (добре, якщо це задумано). Якщо ви очікували, що 22 має бути обмежений, і бачите його відкритим — це вся проблема.
Рішення: Трактуйте зовнішні результати сканування як істину. Вирівняйте правила файрвола і прив’язки сервісів до тих пір, поки скан не відповідатиме вашій бажаній експозиції.
Завдання 15: Швидка перевірка процесів, що слухають, і їхніх пакетів
cr0x@server:~$ sudo lsof -nP -iTCP -sTCP:LISTEN | head
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1123 root 3u IPv4 32249 0t0 TCP *:22 (LISTEN)
sshd 1123 root 4u IPv6 32251 0t0 TCP *:22 (LISTEN)
nginx 1200 root 6u IPv6 32999 0t0 TCP *:80 (LISTEN)
node_expo 1337 node 3u IPv6 33301 0t0 TCP *:9100 (LISTEN)
Значення: lsof дає вам ім’я процесу та PID; не треба гадати, який сервіс за яким портом стоїть.
Рішення: Якщо слухач незрозумілий — не лише файрвольте. Ідентифікуйте його, видаліть або ізолюйте — «таємні демони» перетворюють «тимчасовий дебаг» на «постійний інцидент».
UFW, nftables і реальність Ubuntu 24.04
Ubuntu 24.04 живе в світі nftables. Це добре. nftables більш послідовний, підтримує сімейство inet (один ruleset для v4+v6) і це те, що вам потрібно для сучасних хостів.
UFW все ще підходить — якщо ви розглядаєте його як компілятор політики і валідуєте вивід. Де люди помиляються — вони припускають, що output UFW означає застосування. Зазвичай так і є, але «зазвичай» — не SLO.
Зробіть політику IPv6 явною (навіть якщо ви нічого не дозволяєте)
Якщо ви використовуєте UFW, не залишайте IPv6 як прихований дефолт. Практично вам потрібні три речі:
- IPV6=yes в
/etc/default/ufw, щоб UFW генерував v6‑правила. - За замовчуванням deny incoming для обох стеків.
- Явні allow‑правила для портів і джерел, які ви плануєте для обох стеків.
Надавайте перевагу правилам «allow from» над глобальними allow
На IPv6 спокуса дозволити широко через «це складно». Насправді не складно; просто незвично.
Якщо SSH для адміністраторів — то SSH лише для мереж адміністраторів. Це стосується IPv6 також. Якщо у вас немає стабільних адміністративних IPv6‑діапазонів, вирішіть це через VPN/bastion, а не відкривання SSH для всього світу.
ICMPv6 — не опціональна «трубка»
Люди люблять блокувати ICMP. Вони чують «ping» і думають «розвідка». З IPv6 блокування ICMPv6 ламає реальні механізми протоколу: Path MTU discovery, Neighbor Discovery, Router Advertisements в деяких середовищах. Ваша «стелс» позиція перетворюється на «випадкові відмови».
Жарт №2: Блокувати ICMPv6, щоб «бути в безпеці», — це як перерізати гальмівні трубки, щоб уникнути перевищення швидкості.
Коли писати nftables напряму
Якщо у вас складне середовище — контейнери, кілька інтерфейсів, policy routing, сувора сегментація — можливо, ви переростаєте UFW. Це не провал. Це зрілість.
Aле якщо ви пишете nftables напряму, беріть на себе весь lifecycle: розгортання правил, атомарне завантаження, бекапи та CI‑перевірки. «Ручне редагування live правил файрвола о 2 ранку» — традиція, яку треба припинити.
systemd sockets: «сервіс не запущений» — брехня
В Ubuntu systemd може слухати порт від імені сервісу і запускати цей сервіс лише коли прибуде з’єднання. Це socket activation. Це ефективно. Але це також джерело плутанини під час аудиту безпеки.
Режим відмови: хтось зупиняє ssh.service і думає, що SSH вимкнено. Але ssh.socket усе ще слухає. Порт залишається досяжним. Сканер не вражений.
Операційне правило: якщо порт відкритий — він відкритий. «Але сервіс був зупинений» — не захист, а визнання того, що ви не перевірили рівень сокетів.
Використовуйте systemctl list-sockets, ідентифікуйте слухачі на [::] і відключайте їх, якщо порт не має існувати.
Хмара та upstream фільтрація: не делегуйте мислення
У корпоративному світі експозиція IPv6 часто походить від розсинхронізованих upstream‑контролів:
- Security group має IPv4‑правила налаштовані коректно.
- IPv6‑правила порожні (що іноді означає «дозволити все» залежно від платформи), або налаштовані інша команда, або просто забуті.
- Host‑фаєрвол вважає, що upstream блокує; upstream вважає, що host‑фаєрвол блокує.
Єдина стабільна стратегія — захист у глибину з явними v6‑контролями на кожному шарі. Host‑фаєрвол має бути коректним навіть якщо upstream помиляється, бо upstream рано чи пізно помилиться.
Також: якщо ви використовуєте керовані load balancer‑и, перевірте, як вони обробляють IPv6‑termination і підключення до бекендів. Ви можете мати ідеально захищений хост, але експонувати адміністрування через IPv6‑слухач на неправильному інтерфейсі, якщо ваша внутрішня мережа dual‑stack.
Три корпоративні міні‑історії (анонімізовано, болісно реалістично)
1) Інцидент через хибне припущення: «У нас тут не використовують IPv6»
Компанія експлуатувала флот Ubuntu VM за edge‑фаєрволом. Все було «лише IPv4» за діаграмою мережі. Позиція безпеки була побудована навколо цього: правила UFW були орієнтовані на IPv4, і сканери комплаєнсу перевіряли лише A‑записи.
Під час pen‑тесту тестувальник запитав IPv6‑діапазони. У відповідь — знизу плечима. «Ми не використовуємо IPv6». Тестувальнику не потрібні були діапазони; йому потрібне було одне ім’я хоста і резолвер, що повертає AAAA.
Виявилось, що VPC в хмарі мав IPv6 увімкнений місяці тому для окремого проєкту. Деякі сабнети автоматично призначали IPv6‑адреси. Ніхто не сказав опс‑команді, бо зміна «не торкалася продакшену». Вона не торкалася — поки хтось не глянув.
Висновки були прозаїчні та жорсткі: SSH відкритий для світу по IPv6, staging панель адміністрування прив’язана до ::, і метрики без авторизації. Ніхто цього не експлуатував; не треба було. Звіт уже був достатній.
Виправлення не було героїчним. Вони увімкнули UFW для IPv6, віддзеркалили allow‑лісти, звузили прив’язки сервісів і додали двостекові сканування в CI. Найважче було культурне: визнати, що «ми не використовуємо IPv6» ніколи не було фактом — лише неперевіреною вірою.
2) Оптимізація, що вдарила назад: «Давайте спростимо правила файрвола»
Платформ‑команда хотіла менше зайвих елементів. Вони втомилися від UFW як «ще однієї абстракції», тому перейшли на мінімальний nftables ruleset. Одна таблиця, один ланцюг, default accept. Вони покладалися на upstream security groups. Чисто. Елегантно. Швидко.
Потім був production‑інцидент: періодичні збої в підключеннях для підмножини клієнтів, що використовували IPv6. Оперативник припустив проблему з load balancer. Ні. Файрвол дозволяв inbound, але return‑traffic підлягав окремому policy routing зміненню, а ICMPv6 потрібний для PMTU discovery відкидався upstream.
«Оптимізація» видалила local logging і звичку дивитись лічильники. Команда не мала швидкого способу довести, що хост робить. Довелось налагоджувати у темряві, через packet capture, під тиском.
Вони зрештою відкотилися до жорсткішого host‑фаєрвола: default drop inbound, явні allow, явний handling ICMPv6 і логування у помірному режимі. Іронія: менше правил не означало менше складності. Просто складність перемістилася туди, де видимість гірша.
3) Нудна, але правильна практика, яка врятувала день: «Ми скануємо обидва стеки щоразу»
Інша організація мала нудну звичку: кожен pipeline будівництва запускав зовнішнє сканування кандидата хоста по IPv4 та IPv6, з раннера поза production VPC. Це не було модним. Воно було послідовним.
Одного дня оновлення базового образу змінило дефолтну прив’язку сервісу з 127.0.0.1 на ::. Сервіс мав бути внутрішнім, збираним через sidecar proxy. По IPv4 все виглядало норм, через внутрішню маршрутизацію. По IPv6 він став доступним звідки не слід.
Двостековий скан зламав білд. Тікет ніколи не потрапив у продакшен. Нікому не довелося писати інцидент‑репорт або пояснювати перед керівництвом, чому «лише внутрішнє» опинилося в публічному інтернеті.
Ось цінність нудних практик: вони не запобігають кожному збою, але роблять збіги дешевими. Ви хочете дешеві збіги.
Поширені помилки: симптом → корінь → виправлення
1) Симптом: «IPv4‑порти закриті, але IPv6‑скан показує їх відкритими»
Корінь: Відсутні або ліберальні правила для IPv6 (UFW IPv6 вимкнений або nftables не має ip6/inet покриття).
Виправлення: Увімкніть IPv6 в UFW (IPV6=yes), перезавантажте і перевірте, що nftables має table inet або явні ip6 ланцюги з default drop. Перескануйте зовні по IPv6.
2) Симптом: «UFW активний, але IPv6 все ще доступний»
Корінь: Розділення інструментів фаєрвола; UFW управляє nftables, але інший інструмент потім завантажує ліберальний ruleset, або ви дивитесь iptables, коли nftables фактично застосовує.
Виправлення: Інспектуйте nft list ruleset. Переконайтесь, що ваші правила завантажуються при boot і ніхто їх не перезаписує. Стандартизуйте одного менеджера.
3) Симптом: «Я зупинив сервіс, але порт все ще відкритий»
Корінь: systemd socket activation; socket‑unit ще слухає.
Виправлення: Відключіть .socket unit: systemctl disable --now name.socket. Перевірте через ss і зовнішній скан.
4) Симптом: «Після посилення IPv6‑фаєрвола випадкові з’єднання зависають»
Корінь: Надмірне блокування ICMPv6, що ламає PMTU discovery або Neighbor Discovery.
Виправлення: Дозвольте необхідні типи ICMPv6. Якщо використовуєте UFW, переконайтесь, що він дозволяє IPv6‑ICMP. Якщо пишете nftables — явно приймайте ip6 nexthdr ipv6-icmp і пізніше звужуйте правила, якщо треба.
5) Симптом: «Сервіс прив’язаний до 0.0.0.0, чому він на IPv6?»
Корінь: Сервіс окремо прив’язується до IPv6 :: або використовує одиний dual‑stack сокет в залежності від runtime і sysctls.
Виправлення: Підтвердіть за допомогою ss -lntup. Встановіть явні listen‑адреси в конфіг сервісу (v4 і v6 за потреби), або прив’яжіть до конкретного інтерфейсу/IP.
6) Симптом: «Скан комплаєнсу зелений, але дослідник повідомив про IPv6‑експозицію»
Корінь: Інструменти сканування тестували лише IPv4 (або лише DNS A‑записи).
Виправлення: Додайте AAAA‑обізнане виявлення активів і IPv6‑сканування в контролі. Вважайте dual‑stack базою.
7) Симптом: «Ми вимкнули IPv6, і тепер apt чи внутрішні сервіси ламаються»
Корінь: Ваше середовище використовує IPv6 для деяких шляхів (mirror‑и, проксі, SSO, service discovery). Вимкнення IPv6 не завжди «безпечне».
Виправлення: Віддавайте перевагу файрволінгу замість відключення. Якщо потрібно вимкнути — тестуйте в staging з тими ж DNS і proxy‑налаштуваннями.
Контрольні списки / покроковий план
Контрольний список A: Негайна реакція (ви сьогодні знайшли IPv6‑експозицію)
- Ідентифікуйте експоновані IPv6‑адреси:
ip -6 addr. Визначте, які глобальні. - Перелічіть слухачів:
ss -lntup. Зверніть увагу на[::]:PORT. - Блокувати inbound IPv6 на host‑фаєрволі негайно: якщо сумніваєтесь — default deny inbound і дозволити лише SSH з адміністраторських діапазонів.
- Підтвердити застосування:
nft list rulesetі зовнішній сканnmap -6. - Виправити прив’язки: переналаштуйте сервіси слухати лише на потрібних інтерфейсах.
- Залишити логування ввімкненим (помірне): достатньо, щоб бачити, чи ви блокуєте легітимний трафік.
Контрольний список B: Коректне закріплення (щоб це трималося після перезавантажень і оновлень)
- Оберіть одного менеджера файрвола: UFW на nftables або nftables напряму. Не запускайте двох «власників» одночасно.
- Зробіть правила симетричними для обох стеків: кожен inbound allow має існувати і для IPv4, і для IPv6, якщо тільки ви свідомо не відрізняєтеся (рідко).
- Тримайте ICMPv6 функціональним: дозволяйте його вірно.
- Аудитуйте systemd sockets:
systemctl list-sockets; вимикайте несподівані слухачі. - Додавайте двостекове сканування в pipeline: зовнішня точка огляду, зберігайте результати, провал білда при несподіваних відкриттях.
- Документуйте заплановану експозицію: порт, протокол, джерела і обґрунтування. Трактуйте це як контракт API.
Контрольний список C: Якщо ви наполягаєте на відключенні IPv6 (робіть це як доросла людина)
- Інвентаризуйте залежності: використання DNS AAAA, внутрішні сервіси, проксі, моніторинг. Не вгадуйте.
- Вимкніть через sysctl з персистентністю: встановіть
net.ipv6.conf.all.disable_ipv6=1таdefaultу/etc/sysctl.d/, потім reboot‑test. - Перевірте, що воно дійсно вимкнено:
ip -6 addrмає показувати лише::1або нічого на інтерфейсах. - Перевірте сервіси: деякі програми поводяться інакше при відсутності IPv6; тестуйте health checks і клієнтську взаємодію.
Мій упереджений погляд: файрволити зазвичай безпечніше, ніж відключати. Вимкнення IPv6 — це великий молоток, який часто вдаряє вас самих по пальцях пізніше.
FAQ
1) Чому мій сервер взагалі має IPv6? Я цього ніколи не налаштовував.
Бо сучасні мережі часто його надають автоматично (налаштування хмари, Router Advertisements, DHCPv6). Ubuntu охоче його використовує, коли він доступний.
2) Якщо я не публікую AAAA‑записи, я в безпеці?
Ні. Атакувальники можуть знайти IPv6‑адреси різними шляхами: логи, сертифікати, Neighbor Discovery в внутрішніх мережах, метадані хмари або простим скануванням відомих префіксів в деяких середовищах.
3) Чи блокує UFW IPv6 за замовчуванням?
Тільки якщо підтримка IPv6 увімкнена в UFW і згенеровані правила для v6. Перевіряйте /etc/default/ufw і ufw status verbose на наявність «(v6)» правил.
4) Чи слід мені точно дублювати правила IPv4 для IPv6?
Майже завжди — так. Розбіжність має бути усвідомленим архітектурним вибором. Якщо ви не можете пояснити, чому IPv6 більш відкритий, це випадковість.
5) Чому деякі порти показують «filtered» під час IPv6‑сканування?
Зазвичай це означає, що файрвол дропає пакети (добре для «заблоковано»). Це також може бути upstream‑фільтрація. Підтвердіть, перевіривши лічильники і логи host‑фаєрвола.
6) Чи можу я просто виставити IPV6=no в UFW, щоб виправити експозицію?
Зазвичай це погіршить ситуацію: ви кажете UFW перестати керувати IPv6, а не відключаєте IPv6 мережею. IPv6‑адреси і слухачі залишаться; у вас просто буде менше захисту.
7) Яка найпростіша безпечна позиція для IPv6 на публічному веб‑сервері?
За замовчуванням deny inbound. Дозволити 80/443 для всіх на обох стеках. Дозволити SSH лише з адміністративних діапазонів або через VPN/bastion. Дозволити необхідний ICMPv6.
8) Я за load balancer‑ом. Мені потрібен host‑фаєрвол?
Так. Load balancer‑и іноді неправильно конфігуруються, і внутрішні шляхи їх обходять. Host‑фаєрвол — це дешеве страхування і ловить помилки «ми прив’язали до ::».
9) Як дізнатися, чи додаток слухає на IPv6?
Використовуйте ss -lntup і шукайте [::]:PORT або конкретну IPv6‑адресу. Не довіряйте документації застосунку; довіряйте списку сокетів.
10) Чи прийнятне блокування ICMPv6 взагалі?
Не як загальна політика. Ви можете обмежити деякі типи пізніше з обережністю, але потрібно зберегти основний функціонал, інакше ви створите відмови, що виглядають як «випадкова мережна нестабільність».
Наступні кроки, які ви реально можете виконати
Зробіть три речі цього тижня, і ви усунете більшість інцидентів «забутого IPv6‑фаєрвола»:
- Аудит слухачів за допомогою
ss -lntupі завершення або перенастроювання всього, що не повинно бути публічним на[::]. - Зробіть політику файрвола двостековою: підтвердіть, що UFW IPv6 увімкнено (або напишіть nftables‑правила в
inet) і переконайтесь, що inbound default drop існує для обох стеків. - Перевірте зовні з реальним IPv6‑скануванням і збережіть результат. Якщо ви не тестуєте зовні — ви не знаєте.
Ubuntu 24.04 не намагається вас обдурити. Вона просто робить те, що сучасні системи роблять: постачає IPv6 готовим. Ваше завдання — зробити «готово» означати «безпечно», а не «дивно досяжно».