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 файла като постоянно изискване без бележка, която го обяснява.

Запишете причината до всяка възможност: коя операция я е изисквала и какво се чупи без нея. Тази бележка преживява обновявания на образа и е разликата между прегледан списък с привилегии и такъв, който е израснал чрез копиране и поставяне.

Подобни статии