以不同用户身份运行 Linux 服务的最佳实践
题
服务默认启动为 root
在我的 RHEL 机器上启动时。如果我没记错的话,其他使用 init 脚本的 Linux 发行版也是如此。 /etc/init.d
.
您认为让进程以我选择的(静态)用户身份运行的最佳方法是什么?
我到达的唯一方法是使用类似的东西:
su my_user -c 'daemon my_cmd &>/dev/null &'
但这似乎有点不整洁......
是否有一些隐藏的魔法可以提供一种简单的机制来像其他非 root 用户一样自动启动服务?
编辑: 我应该说,我在这个实例中启动的进程要么是 Python 脚本,要么是 Java 程序。我不想围绕它们编写本机包装器,所以不幸的是我无法调用 setuid() 作为 黑色的 建议。
解决方案
在Debian我们使用start-stop-daemon
工具,它处理的PID文件,改变了用户,把守护到背景等等。
我不熟悉红帽,而是你已经在使用(在daemon
定义,顺便说一句。)的/etc/init.d/functions
效用处处提及相当于start-stop-daemon
,所以无论它也可以改变你的程序的UID ,或者你做的方式已经是正确的。
如果你看看周围净,有可以使用几种现成的包装。有的甚至可能已经打包在红帽。看看 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
但是,我仍然认为您无法从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 权限。
只是添加一些其他需要注意的事情:
- init.d 脚本中的 Sudo 不好,因为它需要 tty (“sudo:抱歉,您必须有 tty 才能运行 sudo”)
- 如果您正在守护 Java 应用程序,您可能需要考虑 Java Service Wrapper(它提供了设置用户 ID 的机制)
- 另一种选择可能是 su --session-command=[cmd] [用户]
上的CENTOS(红帽)虚拟机为SVN服务器:
编辑/etc/init.d/svnserver
更改svn的可以写入的PID的东西:
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
需要注意的一些事项:
- 正如您提到的,如果您已经是目标用户,su 将提示输入密码
- 同样,如果您已经是目标用户(在某些操作系统上),setuid(2) 将失败
- setuid(2) 不会安装 /etc/limits.conf (Linux) 或 /etc/user_attr (Solaris) 中定义的权限或资源控制
- 如果您采用 setgid(2)/setuid(2) 路线,请不要忘记调用 initgroups(3) ——有关此的更多信息 这里
我通常在启动守护程序之前使用 /sbin/su 切换到适当的用户。
为什么不尝试在init脚本如下:
setuid $USER application_name
这为我工作。
我需要运行一个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