Почему привилегированный режим шире, чем нужно VPN
Привилегированный контейнер даёт устройства и возможности, не связанные с туннелем. Найдите единственное требование за ошибкой, прежде чем использовать его как переключатель.
Контейнер не открывал свой туннель, поэтому добавили привилегированный флаг, и теперь всё работает. Эта последовательность доказала лишь то, что не хватало хотя бы одного разрешения, и ничего не говорит о том, какого именно. Привилегированный режим даёт набор возможностей и доступ к устройствам гораздо шире, чем нужно интерфейсу туннеля.
Что на самом деле меняет флаг
Привилегированный контейнер получает широкие возможности и доступ к устройствам хоста, что является куда большим разрешением, чем требует сетевой путь. Точный набор документирует среда выполнения, а не определяет предание, и документация Docker о запуске контейнеров описывает доступные параметры привилегий. Одного прочтения достаточно, чтобы увидеть: туннель — малая часть целого.
Два более узких требования покрывают большинство контейнеров VPN. Настройка интерфейса требует возможности администрирования сети, а открытие устройства туннеля требует доступа именно к этому узлу устройства. Это отдельные разрешения, и даже оба вместе они всё ещё уже общего варианта. Остальная часть привилегированного набора не имеет отношения к туннелю. Она существует для нагрузок, которым действительно нужен доступ на уровне хоста, а контейнер VPN обычно к ним не относится.
Сопоставьте каждую ошибку одному предусловию
Сообщение об ошибке говорит, какого предусловия не хватает, если прочитать его до подавления. Сообщение об узле устройства называет устройство, сообщение о недопустимой операции называет возможность, а сообщение о модуле или sysctl называет поддержку ядра. У каждого из них своё исправление, и только одно из них является возможностью.
Отсутствующий файл конфигурации остаётся отсутствующим после выдачи всех возможностей, поэтому привилегированный режим иногда не меняет ровным счётом ничего. Контейнер запускается, туннель по-прежнему не работает, а настоящая ошибка никогда не была про разрешения. Поддержка ядра — третий случай и самый легко неверно прочитанный. Модуль, не загруженный на хосте, нельзя загрузить изнутри непривилегированного контейнера, а выдача дополнительных возможностей внутри контейнера не меняет состояние хоста.
Проверяйте требование, а не симптом
Начните с минимального вызова, который документирует образ, запустите его и сохраните точный текст отказа. Затем добавляйте по одному разрешению и отмечайте, какое добавление изменило результат.
ls -l /dev/net/tun
docker run --rm --cap-add NET_ADMIN --device /dev/net/tun image:tag
ip -br link show type tunКонтейнер, который видит устройство и обладает возможностью, но всё равно не работает, сообщает, что проблема в другом месте. Это полезный результат, и привилегированный режим скрыл бы его.
Проверьте также права на устройство на хосте, потому что правильно выданный узел устройства с неверным владельцем группы даёт ту же ошибку, что и отсутствующее разрешение.
Запишите самое узкое работающее разрешение
Запишите каждое устройство и каждую возможность, которые нужны развёртыванию, вместе с ошибкой, которая их оправдала. Именно эта запись позволяет следующему человеку безопасно что-то убрать, и именно её запросит аудитор, когда контейнер будет объявлен привилегированным.
Просмотрите и окружающий контекст, потому что сеть хоста, монтирования хоста и параметры среды выполнения могут каждый расширить влияние выданного разрешения. Изолированный лабораторный вызов, объединяющий всё это, не является производственной конфигурацией, как бы хорошо он ни работал. Проверьте приложение, его поведение в DNS и отказ туннеля, прежде чем объявить развёртывание завершённым. Разрешение создать интерфейс не является политикой выхода, и контейнер, который идеально туннелирует, всё равно маршрутизирует всё, что отправляет приложение.