Найкраща практика для запуску служби Linux як іншого користувача


141

Служби за замовчуванням починаються rootз моменту завантаження у вікні RHEL. Якщо я пам'ятаю правильно, те ж саме стосується інших дистрибутивів Linux, які використовують скрипти init в /etc/init.d.

Як ви вважаєте, що це найкращий спосіб замість того, щоб процеси запускалися як (статичний) користувач, який я вибрав?

Єдиний метод, до якого я прийшов, - це використовувати щось на кшталт:

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

Але це здається трохи неохайним ...

Чи є якась магія підтягнута, що забезпечує простий механізм автоматичного запуску сервісів, як інші, некористувальні користувачі?

EDIT: Я мав би сказати, що процеси, які я запускаю в цьому випадку, це або сценарії 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, наприклад.


X-ref цікавий. У мене є своя програма демонізування, дуже схожа; не робить pidfile або lockfile, не встановлює umask. У мене є окрема коренева програма SUID для встановлення груп UID, GID, EUID, EGID та aux (називається asroot). Я використовую 'asroot [opts] - env ​​-i [env] daemonize [opts] - команда [opts]'
Джонатан Леффлер

(продовження): стандартна програма ENIX ENV не приймає '-' між налаштуванням середовища та виконаною командою (невдало, але так).
Джонатан Леффлер

4
Як можна використовувати функцію daemon з /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 встановлено:

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

    Я все ще не думаю, що ви можете налаштувати зсередини 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, я змінив свій сценарій init на щось на кшталт:

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. Скористайтеся його кореневими привілеями (наприклад, відкрийте файли журналу, створіть pid-файли).
  2. Опустіть його кореневі привілеї в певний момент під час запуску.

3

Просто додайте ще деякі речі, на які слід стежити:

  • Судо в скрипті init.d не корисний, оскільки йому потрібен tty ("sudo: вибачте, ти повинен мати tty для запуску sudo")
  • Якщо ви демонструєте програму java, ви можете розглянути можливість використання Java Service Wrapper (який забезпечує механізм встановлення ідентифікатора користувача)
  • Іншою альтернативою може бути su --session-command = [cmd] [user]

3

на віртуальній машині CENTOS (Red Hat) для сервера svn: відредаговано, /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. Демон не запускав becaseu, там може писати тільки root.

 These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart

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), не забудьте зателефонувати в підгрупи (3) - більше про це тут

Зазвичай я використовую / sbin / su для переходу до відповідного користувача перед запуском демонів.


2

Чому б не спробувати наступне у сценарії init:

setuid $USER application_name

Це працювало для мене.


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.