Linux

Есть ли способ для некорневых процессов привязаться к «привилегированным» портам в Linux?

Очень раздражает это ограничение на моей системе для разработки, когда там никогда не будет других пользователей, кроме меня.

Я знаю о стандартных обходных путях, но ни один из них не делает именно то, что я хочу:

  1. authbind (версия в тестировании Debian, 1.0, поддерживает только IPv4)

  2. использование цели iptables REDIRECT для перенаправления низкого порта на высокий порт (таблица «nat» еще не реализована для ip6tables, IPv6 версии iptables)

  3. sudo (запуск от имени root это то, чего я пытаюсь избежать)

  4. SELinux (или аналогичный). (Это просто мой dev box, я не хочу вводить много дополнительных сложностей).

Есть ли какая-то простая переменная sysctl, позволяющая не-корневым процессам связываться с «привилегированными» портами (порты менее 1024) в Linux?

Ответ 1

Есть возможность CAP_NET_BIND_SERVICE. Если у вас свежее ядро, то действительно возможно использовать это для запуска службы не от имени root, но с привязкой низких портов. Короткий ответ заключается в следующем:

setcap 'ap_net_bind_service=+ep' /path/to/program

 И тогда любая программа, выполняемая после запуска данной команды, будет иметь возможность CAP_NET_BIND_SERVICE. setcap находится в debian пакете libcap2-bin.

Теперь о предостережениях:

Вам понадобится по крайней мере ядро версии 2.6.24.

Это не будет работать, если ваш файл является скриптом. е. использует строку #! для запуска интерпретатора). В этом случае, насколько я понимаю, вам придется применить возможность к самому исполняемому файлу интерпретатора, что, конечно, нарушает безопасность, поскольку любая программа, использующая этот интерпретатор, будет иметь такую возможность. Я не смог найти никакого чистого и простого способа обойти эту проблему.

Linux отключит LD_LIBRARY_PATH на любой программе, имеющей повышенные привилегии, такие как setcap или suid. Так что, если ваша программа использует свой собственный .../lib/, вам, возможно, придется рассмотреть другой вариант, например, переадресацию портов.

Ресурсы:

  1. man-страница capabilities(7). Прочитайте ее внимательно, если собираетесь использовать capabilities в производственной среде. Здесь подробно описано, как наследуются возможности при вызове exec();

  2. страница руководства setcap;

  3. «Привязка портов ниже 1024 без root в GNU/Linux»: Документ, который впервые навел меня на setcap.

Примечание: RHEL впервые добавил это в версии 6.

Ответ 2

Стандартный способ сделать их «setuid», чтобы они запускались как root; затем они отбрасывают привилегии root, как только привязываются к порту, но до того, как начинают принимать соединения к нему. Вы можете найти хорошие примеры этого в исходных текстах Apache и INN. Также Lighttpd еще один хороший пример.

Другой пример Postfix, который использует несколько демонов, взаимодействующих через каналы, и только один или два из них (которые почти ничего не делают, кроме приема или передачи байтов) работают от имени root, а остальные с более низкими привилегиями.

Ответ 3

Почему-то никто не упоминает о понижении sysctl net.ipv4.ip_unprivileged_port_start до нужного вам значения. Пример: Нам нужно привязать наше приложение к 443 порту.

sysctl net.ipv4.ip_unprivileged_port_start=443

 Некоторые могут сказать, что существует потенциальная проблема безопасности: непривилегированные пользователи теперь могут связываться с другими привилегированными портами (444-1024). Но вы можете легко решить эту проблему с помощью iptables, блокируя другие порты:

iptables -I INPUT -p tcp --dport 444:1024 -j DROP

iptables -I INPUT -p udp --dport 444:1024 -j DROP

 Сравнение с другими методами. Этот метод:

  1. с некоторого момента является даже более безопасным, чем установка CAP_NET_BIND_SERVICE/setuid, поскольку приложение не устанавливает setuid вообще, даже частично (возможности на самом деле есть). Например, чтобы поймать coredump приложения с поддержкой возможностей, вам нужно будет изменить sysctl fs.suid_dumpable (что приводит к другим потенциальным проблемам безопасности). Также, когда CAP/suid установлен, каталог /proc/PID принадлежит root, поэтому ваш не-root пользователь не будет иметь полной информации/контроля запущенного процесса, например, пользователь не сможет (в общем случае) определить, какие соединения принадлежат приложению через /proc/PID/fd/ (netstat -aptn | grep PID);

  2. имеет недостаток с точки зрения безопасности: пока ваше приложение (или любое другое приложение, использующее порты 443-1024) по каким-то причинам не работает, другое приложение может занять этот порт. Однако эта проблема также может быть применена к CAP/suid (в случае, если вы установили его на интерпретаторе, например, java/nodejs) и iptables-redirect. Используйте метод systemd-socket, чтобы исключить эту проблему. Используйте метод authbind, чтобы разрешить привязку только для специальных пользователей;

  3. не требует установки CAP/suid каждый раз при развертывании новой версии приложения;

  4. не требует поддержки/модификации приложения, как метод systemd-socket;

  5. не требует пересборки ядра (если запущенная версия поддерживает эту настройку sysctl);

  6. не делает LD_PRELOAD, как метод authbind/privbind, что потенциально может повлиять на производительность, безопасность, поведение. В остальном authbind действительно гибкий и безопасный метод;

  7. превосходит метод iptables REDIRECT/DNAT, поскольку не требует трансляции адресов, отслеживания состояния соединения и т. д. Это заметно только на высоконагруженных системах.

В зависимости от ситуации, я бы выбирал между sysctl, CAP, authbind и iptables-redirect.

Ответ 4

Быстрый ответ взять копию последней (пока еще не выпущенной) версии libcap из git и скомпилировать ее. Скопируйте полученный бинарник progs/capsh куда-нибудь (/usr/local/bin хороший выбор), а затем, как root, запустите вашу программу с помощью:

/usr/local/bin/capsh --keep=1 --user='your-service-user-name' \

    --inh='cap_net_bind_service' --addamb='cap_net_bind_service' \ 

    -- -c 'your-program'

 Теперь по порядку:

  1. Объявляем, что при смене пользователя мы хотим сохранить наши текущие наборы возможностей.

  2. Переключение пользователя и группы на «your-service-user-name».

  3. Добавляем возможность cap_net_bind_service к унаследованным и амбиентным наборам возможностей.

  4. Форкинг bash -c 'your-command' (поскольку capsh автоматически запускает bash с аргументами после --).

Во-первых, мы работаем от имени root, поэтому по умолчанию мы получаем полный набор возможностей. Сюда входит возможность переключения uid и gid с помощью системных вызовов setuid и setgid. Однако, как правило, когда программа делает это, она теряет свой набор возможностей это делается для того, чтобы старый способ сброса root с помощью setuid все еще работал. Флаг --keep=1 указывает capsh на выполнение системного вызова prctl(PR_SET_KEEPCAPS), который отключает сброс возможностей при смене пользователя. Фактическая смена пользователя в capsh происходит с помощью флага --user, который запускает setuid и setgid.

Следующая проблема, которую нам нужно решить, — как установить возможности таким образом, чтобы они сохранялись и после того, когда процесс породит дочерние процессы. Система возможностей всегда имела «унаследованный» набор возможностей, который представляет собой «набор возможностей, сохраняющийся при выполнении execve(2)» [capabilities(7)]. Хотя это звучит так, как будто решает нашу проблему (просто установите для cap_net_bind_service значение inherited, верно?), на самом деле это применимо только для привилегированных процессов, а наш процесс уже не является привилегированным, потому что мы уже сменили пользователя (с помощью флага --user).

Новый набор возможностей ambient позволяет обойти эту проблему это «набор возможностей, которые сохраняются при выполнении execve(2) программы, которая не является привилегированной». Если поместить cap_net_bind_service в набор ambient, когда capsh выполнит нашу серверную программу, наша программа унаследует эту возможность и сможет привязывать слушателей к низким портам.

Если вам интересно узнать больше, страница руководства по возможностям объясняет это очень подробно. Запуск capsh через strace также очень информативен!

Ответ 5

Еще две простые возможности:

Существует старое решение проблемы «демон, который связывается на низком порту и передает управление вашему демону». Оно называется inetd (или xinetd). 

Минусы:

  1. ваш демон должен общаться по stdin/stdout (если вы не управляете демоном если у вас нет исходников, — то это, возможно, будет проблемой, хотя некоторые сервисы могут иметь флаг совместимости с inetd);

  2. для каждого соединения создается новый процесс демона;

  3. это одно лишнее звено в цепи.

Плюсы:

  1. доступен на любом старом UNIX;

  2. как только ваш сисадмин настроил конфигурацию, вы можете продолжать разработку (когда вы пересобираете своего демона, вы можете потерять возможности setcap, и тогда вам придется вернуться к своему администратору);

  3. демону не нужно беспокоиться о сетевых запросах, он просто должен общаться по stdin/stdout;

  4. можно настроить выполнение вашего демона от имени пользователя, не являющегося пользователем root, по желанию.

Другая альтернатива: взломанный прокси (netcat или даже что-то более надежное) с привилегированного порта на какой-то произвольный порт с большим номером, где вы можете запустить целевого демона (netcat, очевидно, не является производственным решением). Таким образом, вы сможете продолжать использовать сетевую версию вашего сервера, вам понадобится только root/sudo для запуска прокси (при загрузке), и вы не будете полагаться на сложные/потенциально опасные возможности.

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

Linux

Есть ли альтернатива /dev/urandom?

Linux

Как выбрать, какой Apache MPM использовать?

Linux

Как запустить сценарий оболочки при запуске системы

Linux

Как узнать, взломан ли мой Linux-сервер?