Рекомендуется запускать службу Linux от имени другого пользователя
Вопрос
Службы по умолчанию запускаются как root
во время загрузки на моем RHEL box.Если я правильно помню, то же самое верно и для других дистрибутивов Linux, которые используют сценарии инициализации в /etc/init.d
.
Как вы думаете, какой лучший способ вместо этого запустить процессы от имени (статического) пользователя по моему выбору?
Единственный метод, к которому я пришел, состоял в том, чтобы использовать что-то вроде:
su my_user -c 'daemon my_cmd &>/dev/null &'
Но это кажется немного неопрятным...
Есть ли какая-то скрытая магия, которая обеспечивает простой механизм автоматического запуска служб от имени других пользователей, не имеющих прав root?
Редактировать: Я должен был сказать, что процессы, которые я запускаю в этом экземпляре, являются либо скриптами Python, либо программами Java.Я бы предпочел не писать собственную оболочку вокруг них, поэтому, к сожалению, я не могу вызвать setuid() установить идентификатор() как Черный предполагает.
Решение
В Debian мы используем start-stop-daemon
утилита, которая обрабатывает pid-файлы, меняет пользователя, переводит демон в фоновый режим и многое другое.
Я не знаком с RedHat, но daemon
утилита, которую вы уже используете (которая определена в /etc/init.d/functions
, кстати.) упоминается везде как эквивалент start-stop-daemon
, так что либо это также может изменить uid вашей программы, либо способ, которым вы это делаете, уже правильный.
Если вы поищете в сети, то найдете несколько готовых оберток, которые вы можете использовать.Некоторые из них могут быть даже уже упакованы в RedHat.Взгляните на daemonize
, например.
Другие советы
Просмотрев все приведенные здесь предложения, я обнаружил несколько вещей, которые, я надеюсь, будут полезны другим на моем месте:
хоп правильно указывать мне назад на
/etc/init.d/functions
:вdaemon
функция уже позволяет вам установить альтернативного пользователя:daemon --user=my_user my_cmd &>/dev/null &
Это реализуется путем обертывания вызова процесса с
runuser
- подробнее об этом позже.Джонатан Леффлер это правильно:в Python есть setuid:
import os os.setuid(501) # UID of my_user is 501
Я все еще не думаю, что вы можете setuid однако изнутри JVM.
Ни то , ни другое
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
Спасибо всем за вашу помощь!
- Некоторые демоны (напримерapache) делают это сами, вызывая setuid() установить идентификатор()
- Вы могли бы использовать setuid-флаг файла запустить процесс от имени другого пользователя.
- Конечно, упомянутое вами решение также работает.
Если вы намерены написать свой собственный демон, то я рекомендую вызвать setuid().Таким образом, ваш процесс может
- Используйте его привилегии root (напримероткройте файлы журнала, создайте файлы pid).
- Сбросьте его привилегии root в определенный момент во время запуска.
Просто чтобы добавить еще кое-что, на что следует обратить внимание:
- Sudo в скрипте init.d никуда не годится, так как для него нужен tty ("sudo:извините, у вас должен быть tty для запуска sudo ")
- Если вы демонизируете java-приложение, возможно, вам захочется рассмотреть Java Service Wrapper (который предоставляет механизм для установки идентификатора пользователя).
- Другой альтернативой могло бы быть su --session-command=[cmd] [пользователь]
на виртуальной машине 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
Исходный pid - файл был /var/run/svnserve.pid
.Демон не запустился, потому что писать туда мог только root.
These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart
Некоторые вещи, на которые следует обратить внимание:
- Как вы упомянули, su запросит пароль, если вы уже являетесь целевым пользователем
- Аналогично, setuid(2) завершится ошибкой, если вы уже являетесь целевым пользователем (в некоторых операционных системах).
- setuid(2) не устанавливает привилегии или элементы управления ресурсами, определенные в /etc/limits.conf (Linux) или /etc/user_attr (Solaris)
- Если вы идете по маршруту setgid(2) / setuid(2), не забудьте вызвать initgroups(3) - подробнее об этом здесь
Обычно я использую /sbin / su для переключения на соответствующего пользователя перед запуском демонов.
Почему бы не попробовать следующее в сценарии инициализации:
setuid $USER application_name
У меня это сработало.
Мне нужно было запустить приложение Spring .jar как сервис, и я нашел простой способ запустить его от имени конкретного пользователя:
Я сменил владельца и группу моего 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