Браузер, использующий уже установленный Linux VPN, не открывает /dev/net/tun. Он открывает сокет, а ядро решает, через какой интерфейс уходят пакеты этого сокета. Процесс, создавший туннель, выполняет другую работу, чем процесс, чей трафик он переносит. Разделение этих двух ролей отвечает на большинство вопросов о правах ещё до того, как их задают.

Проследите один пакет от сокета до туннеля

Обычное приложение вызывает connect или send, и ядро ищет маршрут к назначению. Если выбранный маршрут указывает на интерфейс туннеля, пакет ставится в очередь устройства, которое читает демон VPN. Демон шифрует его и отправляет наружу через физический интерфейс. Каждая стрелка в этом описании — место, где можно ответить на вопрос о правах.

Ничто на этом пути не требует, чтобы приложение знало об устройстве. Демон держит файловый дескриптор и выполняет операции с интерфейсом, а приложение видит только обычный сетевой API.

Нарисуйте две половины один раз, и вопросы о правах станет проще разместить. Верхняя половина — мир приложений, нижняя принадлежит демону.

Решите, кому нужно устройство, а кому нет

Создание интерфейса TUN или подключение к нему требует доступа к устройству и вдобавок возможности его настроить, поэтому поддерживаемый VPN-сервис начинает с прав администрирования сети или использует привилегированного помощника. Это требование принадлежит демону. Оно ничего не говорит о браузере, клиенте базы данных или средстве передачи файлов. Сервису, которому нужна эта возможность, она нужна для собственного шага настройки, а не для его клиентов.

Когда маршрут и политика на месте, обычный процесс использует полученный путь через свои обычные вызовы сокетов. Ему не нужен узел устройства и не нужен root.

Изменение прав устройства — не способ дать приложению доступ к назначению. Оно лишь переносит границу устройства в другое место.

Проверьте пространство имён, в котором приложение реально работает

Контейнер или второе сетевое пространство имён даёт своим процессам отдельный набор интерфейсов и таблицу маршрутов. Туннель на хосте не появляется там автоматически, и никакие изменения прав устройства этого не меняют. Приложение просто будет маршрутизировать через то, что предоставляет это пространство имён. Поэтому образ контейнера не может случайно унаследовать туннель хоста.

Проверьте с помощью ip netns list и ip -n NAME route или посмотрев ссылку пространства имён процесса. Ответ обычно виден одной командой.

Двум пользователям на одном хосте тоже можно дать разные пути политикой. Это сетевое решение, а не доказательство владения устройством.

Отделите возможности от сетевой политики

Некоторым инструментам нужно больше, чем сокет. Захват пакетов требует сырого сокета, а изменение маршрутов — административных прав. Это отдельные операции с отдельными разрешениями, и выдачу одного не стоит читать как общее требование для использования VPN.

Программа, реализующая собственный туннель, — третий случай. Она действительно открывает TUN, потому что берёт на себя роль демона, поэтому ей нужны его привилегии.

Назовите операцию, прежде чем называть привилегию. Обычно их легче разделить, чем кажется.

Проверьте разделение двумя учётными записями

Подключите туннель как сервис, затем запустите приложение как обычный пользователь и подтвердите, что оно достигает приватного ресурса. Проверьте ip route get для назначения из оболочки этого пользователя, чтобы увидеть, какой интерфейс выбран. Если маршрут верен, а соединение всё равно не работает, проблема в политике, а не в привилегии.

Получающийся дизайн — минимальные привилегии с явной границей: один компонент владеет настройкой и ресурсами туннеля, рабочие нагрузки сохраняют обычные учётные записи, а сетевая политика решает, что может пройти. Запуск всего от root обрушивает эти роли, ничего не объясняя.

Похожие статьи