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

Що охоплює можливість

У межах свого простору імен процес із NET_ADMIN може піднімати й опускати інтерфейси, призначати адреси, додавати й видаляти маршрути та писати правила міжмережевого екрана, тобто групу операцій, яку capabilities(7) збирає під цією можливістю. Він також може налаштовувати параметри рівня інтерфейсу, що керують тим, як ядро ставить трафік у чергу та фільтрує його. Клієнту VPN зазвичай потрібні кілька з них під час запуску і більше нічого після. Тому більшість образів просять ширший доступ, ніж використовують.

Операції за межами цього простору імен не охоплюються, а суміжні привілеї окремі. Читання й запис необроблених пакетів належить NET_RAW, а створення пристрою tun потребує і можливості, і доступу до вузла пристрою. Процес без пристрою отримує помилку дозволу, яка виглядає як мережева проблема, але нею не є.

Простір імен визначає радіус ураження

Контейнер у власній мостовій мережі досягає свого loopback, своїх інтерфейсів і своєї таблиці маршрутизації. Надання там NET_ADMIN дозволяє клієнту VPN побудувати тунель, не торкаючись рішень маршрутизації хоста, і саме це розташування передбачає більшість образів контейнерів.

Перемкніть цей контейнер на мережу хоста, і те саме надання тепер редагує маршрути хоста та його міжмережевий екран, бо окремого простору імен більше не залишилося. Клієнт, який мав керувати одним тунелем, може тоді перенаправити трафік усієї машини, а помилка в його скрипті демонтажу залишає на хості правила, яких ніхто не писав. У самій можливості нічого не змінилося; змінився контекст. Тому той самий файл compose поводиться по-різному на двох хостах.

Три передумови, що зливаються в одну

Збої запуску в контейнерах VPN зазвичай стосуються однієї з трьох окремих речей: можливості, тунельного пристрою та підтримки протоколу ядром. Надання всіх трьох одразу працює, але й робить наступний збій неможливим для віднесення. Мінімальний фрагмент compose надає можливість і явно передає вузол пристрою:

services:
  vpn:
    image: example/vpn-client:latest
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1

Читайте документацію самого образу про те, які sysctl йому потрібні, бо sysctl у контейнері може вимагати додаткового привілею або налаштування на рівні хоста. Там, де образ підтримує лише режим простору користувача, пристрій узагалі не потрібен, і список можливостей відповідно скорочується.

Надавайте вузьку операцію, а не режим

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

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

Секрети належать до окремого рішення. Наявність NET_ADMIN нічого не каже про те, яку ідентичність партнера представляє клієнт, які облікові дані завантажує і як вони змінюються. Мережеве адміністрування не дає довіри.

Перевірте зміну й запишіть, навіщо існує надання

Перш ніж налагоджувати тунель, переконайтеся, що контейнер справді отримав. Перевірка нижче повідомляє додані можливості та режим мережі, а потім показує, як список інтерфейсів виглядає зсередини:

docker inspect --format '{{.HostConfig.CapAdd}} {{.HostConfig.NetworkMode}} {{.HostConfig.Privileged}}' vpn
docker exec vpn sh -c 'grep CapEff /proc/self/status'
docker exec vpn ip -br addr
docker exec vpn ip route

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

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

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

Схожі статті