Не дайте клієнтам VPN дістатися одне одного в тунелі
Дістатися сервісу — це маршрут, дістатися іншого клієнта — це політика. Знайдіть точку пересилання, яка вирішує трафік між партнерами, а потім доведіть заборону з клієнта.
Два клієнти можуть обидва відкрити проміжний хост і все ж не мати жодного діла одне до одного. Дістатися сервісу — рішення про пересилання, а дістатися партнера — рішення політики, і більшість стеків VPN тримають їх в окремих об'єктах. Ніщо з налаштованого для першого не забезпечує друге. Тож завдання не в тому, щоб додати правило, а в тому, щоб знайти об'єкт, який на цьому сервері вирішує трафік між партнерами, записати заборону там і довести її з клієнта.
Маршрут до спільного сервісу — не дозвіл між партнерами
Оголошення клієнтської підмережі повідомляє партнеру, як покласти пакет на дріт у бік адреси іншого клієнта. Чи буде пакет доставлено, вирішується пізніше тим, що його пересилає. На шлюзі Linux це ланцюг FORWARD; усередині демона в просторі користувача — власна таблиця сеансів тунелю. Маршрут відповідає на досяжність і залишає дозвіл недоторканим.
Тому перевірка ізоляції, яка читає лише маршрути, нічого не доводить. /24 можна надіслати кожному клієнту, тоді як кожен пакет між партнерами відкидається на гачку пересилання. Небезпечний випадок — зворотний: немає явного правила, дозвільне налаштування за замовчуванням і ізоляція, що існує лише тому, що її ніхто не перевіряв.
Запишіть вимогу одним рядком, перш ніж відкрити термінал. Досягайте блоку сервісів і проміжного хоста, не досягайте нічого іншого всередині блоку клієнтів.
З'ясуйте, хто насправді пересилає пакет партнера
Дві поведінки сервера виглядають з боку клієнта однаково і вимагають різних правил. Або ядро знову пересилає пакет з інтерфейсу тунелю, або демон копіює його між сеансами, і ядро його ніколи не бачить.
WireGuard належить до першої групи: у нього немає перемикача між партнерами, тому пакет від 10.8.0.4 до 10.8.0.5 приходить на wg0, потрапляє на гачок пересилання і знову маршрутизується з wg0, коли AllowedIPs покриває обидві адреси. OpenVPN — друга група, щойно в конфігурації сервера задано client-to-client, бо ця директива передає пакет між сеансами в просторі користувача. Перш ніж щось писати, перевірте завантажену конфігурацію на цю директиву. Правило ядра, яке ніколи не бачить трафіку, не відрізнити від робочого правила, і саме так розгортання залишається зовсім без ізоляції.
Читайте чинну конфігурацію, а не файл, який ви вважаєте завантаженим, бо пакунки дистрибутивів приносять власні включення. Якщо пересилає демон, заборона належить його власним засобам керування для кожного клієнта, а брандмауер хоста фільтрує лише трафік до хоста. Якщо пересилає ядро, гачок пересилання — єдине місце, що має значення.
Маршрутизовані та перекладені розгортання потребують ще однієї перевірки: джерело, яке бачить віддалений клієнт, може бути не тим, якого ви чекаєте. Тоді правило, що відповідає клієнтській підмережі, не відповідає нічому. Запишіть адресу, що виживає після трансляції, перш ніж писати збіг, і віддавайте перевагу збігу за парою інтерфейсів, а не здогадкам про адреси NAT.
Дайте кожній адресі окремо відкличну ідентичність
Ізоляція руйнується, щойно два пристрої ділять одне посвідчення. Правило, прив'язане до цієї ідентичності, не може їх розділити, а відкликання загубленого ноутбука відкликає всю групу. Сертифікати на пристрій або ключі на партнера тримають відкликання локальним, а політику читабельною, бо кожна адреса відповідає рівно одній людині чи машині. Там, де проєкт цього не може, скажіть це в настанові, а не називайте правило дрібнозернистим.
Розподіл адрес має узгоджуватися з політикою. Зарезервуйте блок для сервісів, блок для клієнтів і видавайте адреси клієнтів із пулу, який ви контролюєте, а не з діапазону «хто перший прийшов». Якщо сервер транслює або мостить, тримайте таблицю відображення поруч із конфігурацією, бо саме вона потрібна наступному читачеві, щоб вивести правило заново.
Поставте заборону там, де пакет перетинає тунель
На шлюзі, який пересилає трафік WireGuard, випадок покривають два правила: дозволити блок сервісів, потім відкинути решту блоку клієнтів. Пара інтерфейсів важлива не менше адрес, бо збіг лише за призначенням ловить і трафік з LAN. Завантажуйте їх у цьому порядку, щоб дозвіл оцінювався першим.
З nftables пара потрапляє в наявну таблицю inet filter, спершу дозвіл, потім відкидання. Обидва збіги прив'язують пару інтерфейсів і адреси.
nft add rule inet filter forward iifname "wg0" oifname "wg0" ip saddr 10.8.0.0/24 ip daddr 10.8.2.0/24 accept
nft add rule inet filter forward iifname "wg0" oifname "wg0" ip saddr 10.8.0.0/24 ip daddr 10.8.0.0/24 drop
Після завантаження прочитайте ланцюг назад, замість того щоб довіряти коду виходу, і підтвердіть, що обидва правила стоять у задуманому порядку. Додайте відповідні правила ip6 для пулу IPv6, інакше пара v4 — лише оздоба на двостековому тунелі. Якщо сервер уже має дозвільну політику пересилання, додайте відкидання, а не замінюйте ланцюг повністю.
Коли на OpenVPN увімкнено client-to-client, ці правила пересилання ніколи не збігаються з трафіком між партнерами, і заборона має жити у власних засобах керування демона. Залиште правила ядра для трафіку до хоста, але не вважайте їх засобом ізоляції.
Доведіть заборону з клієнта, а не з сервера
Перевірка зі шлюзу нічого не доводить, бо локально створений трафік іде шляхом виходу і ніколи не перетинає гачок пересилання. Використайте двох справжніх клієнтів: один має дістатися сервісу, інший має бути відхилений. Спершу запустіть випадок дозволу, щоб зламаний тунель не прийняли за робочу політику.
З дозволеного клієнта підтвердьте, що сервіс відповідає на своєму порту. З того самого клієнта спробуйте адресу партнера і чекайте тихого відкидання, а не відмови:
ping -c 3 -W 2 10.8.0.5
nc -z -w 2 10.8.0.5 22
nft list chain inet filter forward
iptables -vnL FORWARD
ping -6 -c 3 -W 2 fd00:8::5
Відкинутий пакет і партнер поза мережею виглядають однаково як тайм-аут, тож перевірте лічильники, перш ніж робити висновки. Підтвердьте, що лічильник правила відкидання зростає, поки партнер вочевидь доступний. Повторіть через IPv6, де відсутнє правило ip6 залишає заборону v4 ефективною на вигляд. Запишіть прийняті та відхилені результати в настанову з датою, бо наступна міграція знову виведе правило.