Лучшая практика для запуска службы Linux от имени другого пользователя

141

По умолчанию службы запускаются во rootвремя загрузки на моем RHEL-сервере. Если я правильно помню, то же самое верно и для других дистрибутивов Linux, которые используют сценарии инициализации в /etc/init.d.

Как вы думаете, как лучше всего запустить процессы от имени (статического) пользователя по моему выбору?

Единственный метод, к которому я пришел, - это использовать что-то вроде:

 su my_user -c 'daemon my_cmd &>/dev/null &'

Но это кажется немного неопрятным ...

Есть ли какая-то магия, которая обеспечивает простой механизм автоматического запуска служб от имени других пользователей без полномочий root?

РЕДАКТИРОВАТЬ: Я должен был сказать, что процессы, которые я запускаю в этом случае, являются либо сценариями Python, либо программами Java. Я бы предпочел не писать вокруг них родную оболочку, поэтому, к сожалению, я не могу вызвать setuid (), как предлагает Блэк .

Джеймс Брэди
источник
Python не предоставляет доступ к семейству системных вызовов setuid ()? Это кажется серьезным недостатком по сравнению с Perl.
Джонатан Леффлер,
12
Вау, да: os.setuid (uid). Каждый день - школьный день!
Джеймс Брэди,

Ответы:

67

В Debian мы используем start-stop-daemonутилиту, которая обрабатывает pid-файлы, меняет пользователя, переводит демон в фоновый режим и многое другое.

Я не знаком с RedHat, но daemonутилита, которую вы уже используете (которая определена в /etc/init.d/functions, btw.), Везде упоминается как эквивалент start-stop-daemon, так что либо она может изменить uid вашей программы, либо способ, которым вы это делаете. это уже правильный.

Если посмотреть в сети, есть несколько готовых оберток, которые можно использовать. Некоторые из них могут быть уже упакованы в RedHat. Взгляните daemonize, например.


источник
Х-реф интересный. У меня есть собственная программа daemonize, очень похожая; не выполняет pidfile или lockfile, устанавливает umask. У меня есть отдельная программа root SUID для установки UID, GID, EUID, EGID и вспомогательных групп (называемых asroot). Я использую 'asroot [opts] - env ​​-i [env] daemonize [opts] - command [opts] »
Джонатан Леффлер
(продолжение): стандартная программа env POSIX не принимает '-' между настройкой среды и выполняемой командой (утомительно, но так).
Джонатан Леффлер,
4
Как можно использовать функцию демона из /etc/init.d/functions в сценарии выскочки? Не могли бы вы показать пример?
Meglio
10
По Debian см /etc/init.d/skeleton. Добавить переменные UID, GID и do_start()использовать:start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid $UID:$GID -- $DAEMON_ARGS
Джонатан Бен-Аврахам,
Я заметил, что daemon()он определен /etc/rc.d/init.d/functionкак в моих RHEL, так и в CentOS.
quickshiftin
53

Изучив все предложения здесь, я обнаружил несколько вещей, которые, надеюсь, будут полезны другим на моем месте:

  1. hop правильно указывает мне на /etc/init.d/functions: daemonфункция уже позволяет вам установить альтернативного пользователя:

    daemon --user=my_user my_cmd &>/dev/null &
    

    Это реализуется заключением вызова процесса в оболочку runuser- подробнее об этом позже.

  2. Джонатан Леффлер прав: в Python есть setuid:

    import os
    os.setuid(501) # UID of my_user is 501
    

    Однако я все еще не думаю, что вы можете установить uid из JVM.

  3. Ни один, suни runuser изящный способ не обработать случай, когда вы просите запустить команду от имени пользователя, которым вы уже являетесь. Например:

    [my_user@my_host]$ id
    uid=500(my_user) gid=500(my_user) groups=500(my_user)
    [my_user@my_host]$ su my_user -c "id"
    Password: # don't want to be prompted!
    uid=500(my_user) gid=500(my_user) groups=500(my_user)
    

Чтобы обойти такое поведение suи runuser, я изменил свой сценарий инициализации на что-то вроде:

if [[ "$USER" == "my_user" ]]
then
    daemon my_cmd &>/dev/null &
else
    daemon --user=my_user my_cmd &>/dev/null &
fi

Спасибо всем за помощь!

Джеймс Брэди
источник
5
  • Некоторые демоны (например, apache) делают это сами, вызывая setuid ()
  • Вы можете использовать флаг setuid-file для запуска процесса от имени другого пользователя.
  • Конечно, упомянутое вами решение тоже работает.

Если вы собираетесь написать свой собственный демон, я рекомендую вызвать setuid (). Таким образом, ваш процесс может

  1. Используйте его привилегии root (например, открывайте файлы журналов, создавайте файлы pid).
  2. Отбросьте его привилегии root в определенный момент во время запуска.
Черный
источник
3

Просто чтобы добавить еще кое-что, на что следует обратить внимание:

  • Sudo в сценарии init.d бесполезен, так как ему нужен tty ("sudo: извините, у вас должен быть tty для запуска sudo")
  • Если вы демонизируете Java-приложение, вы можете рассмотреть возможность использования Java Service Wrapper (который предоставляет механизм для установки идентификатора пользователя)
  • Другой альтернативой может быть su --session-command = [cmd] [user]
pdeschen
источник
3

на виртуальной машине CENTOS (Red Hat) для svn server: отредактировано, /etc/init.d/svnserver чтобы изменить pid на то, что svn может писать:

pidfile=${PIDFILE-/home/svn/run/svnserve.pid}

и добавлена ​​опция --user=svn:

daemon --pidfile=${pidfile} --user=svn $exec $args

Исходный файл pidfile был /var/run/svnserve.pid. Демон не запустился, потому что только root мог писать туда.

 These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart
Dulcana
источник
3
Это создает уязвимость для повышения привилегий. Пользователь svn теперь может помещать произвольные PID в файл /home/svn/run/svnserve.pid, который будет уничтожен вместо процесса svn при остановке или перезапуске службы svn.
rbu
2

На что следует обратить внимание:

  • Как вы упомянули, su запросит пароль, если вы уже являетесь целевым пользователем.
  • Точно так же setuid (2) завершится ошибкой, если вы уже являетесь целевым пользователем (в некоторых ОС).
  • setuid (2) не устанавливает привилегии или элементы управления ресурсами, определенные в /etc/limits.conf (Linux) или / etc / user_attr (Solaris)
  • Если вы пойдете по маршруту setgid (2) / setuid (2), не забудьте вызвать initgroups (3) - подробнее об этом здесь

Обычно я использую / sbin / su для переключения на соответствующего пользователя перед запуском демонов.

глина
источник
2

Почему бы не попробовать следующее в сценарии инициализации:

setuid $USER application_name

У меня это сработало.

cyberJar
источник
3
Это доступно не во всех дистрибутивах. Я пробовал на RHEL 7:setuid: command not found
Cocowalla
0

Мне нужно было запустить приложение Spring .jar как службу, и я нашел простой способ запустить его от имени конкретного пользователя:

Я изменил владельца и группу своего jar-файла на пользователя, от имени которого я хотел работать. Затем сделал символическую ссылку на эту банку в init.d и запустил службу.

Так:

#chown myuser:myuser /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar

#ln -s /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar /etc/init.d/springApp

#service springApp start

#ps aux | grep java
myuser    9970  5.0  9.9 4071348 386132 ?      Sl   09:38   0:21 /bin/java -Dsun.misc.URLClassPath.disableJarChecking=true -jar /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar
Сомаиа Кумбера
источник