以不同用户身份运行Linux服务的最佳实践

时间:2008-12-27 13:14:48

标签: linux sysadmin rhel init.d

服务默认在我的RHEL框启动时以root开头。如果我没记错的话,对于使用/etc/init.d中的init脚本的其他Linux发行版也是如此。

您认为将流程作为我选择的(静态)用户运行的最佳方式是什么?

我到达的唯一方法是使用类似的东西:

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

但这似乎有些不整洁......

是否有一些隐藏的魔法可以像其他非root用户一样自动启动服务?

编辑:我应该说我在这个实例中启动的进程是Python脚本或Java程序。我宁愿不在它们周围写一个原生包装,所以很遗憾我无法按setuid()建议调用Black

8 个答案:

答案 0 :(得分:67)

在Debian上,我们使用start-stop-daemon实用程序,它处理pid文件,更改用户,将守护程序置于后台等等。

我不熟悉RedHat,但是你已经使用的daemon实用程序(在/etc/init.d/functions,btw。中定义)在任何地方都被提及,相当于start-stop-daemon ,所以要么它也可以改变你的程序的uid,或者你的方式已经是正确的。

如果您环顾网络,可以使用几种现成的包装纸。有些甚至可能已经包装在RedHat中。例如,请查看daemonize

答案 1 :(得分:53)

在查看了这里的所有建议之后,我发现了一些我希望对我这些人有用的东西:

  1. hop指责我是正确的 在/etc/init.d/functionsdaemon功能已经允许你 设置备用用户:

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

    这是通过包装来实现的 使用runuser进行流程调用 - 更多关于这一点。

  2. Jonathan Leffler是对的: Python中有setuid:

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

    我仍然认为你不能setuid 但是,从JVM内部开始。

  3. surunuser都不是 优雅地处理你的情况 要求以用户身份运行命令 已经是。 E.g:

    [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)
    
  4. 要解决surunuser的行为,我已将init脚本更改为:

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

    感谢大家的帮助!

答案 2 :(得分:5)

  • 有些守护进程(例如apache)通过调用setuid()
  • 自行完成此操作
  • 您可以使用setuid-file flag以不同的用户身份运行该流程。
  • 当然,您提到的解决方案也适用。

如果您打算编写自己的守护程序,那么我建议调用setuid()。 这样,您的流程就可以

  1. 利用其root权限(例如,打开日志文件,创建pid文件)。
  2. 在启动期间的某个时刻删除其root权限。

答案 3 :(得分:3)

添加一些其他注意事项:

  • 在init.d脚本中的Sudo不好,因为它需要一个tty(“sudo:抱歉,你必须有一个tty来运行sudo”)
  • 如果您正在守护Java应用程序,您可能需要考虑Java Service Wrapper(它提供了一种设置用户ID的机制)
  • 另一种选择可能是 su --session-command = [cmd] [user]

答案 4 :(得分:3)

在用于svn服务器的CENTOS(Red Hat)虚拟机上: 编辑/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

答案 5 :(得分:2)

需要注意的一些事项:

  • 如您所述,如果您已经是目标用户,则su会提示输入密码
  • 同样,如果您已经是目标用户(在某些操作系统上),setuid(2)将失败
  • setuid(2)不安装/etc/limits.conf(Linux)或/ etc / user_attr(Solaris)中定义的权限或资源控制
  • 如果你去了setgid(2)/ setuid(2)路线,别忘了拨打initgroups(3) - 更多关于此here

我通常在启动守护进程之前使用/ sbin / su切换到适当的用户。

答案 6 :(得分:2)

为什么不在init脚本中尝试以下操作:

setuid $USER application_name

它对我有用。

答案 7 :(得分:0)

我需要将Spring .jar应用程序作为服务运行,并找到了一种以特定用户身份运行它的简单方法:

我将jar文件的所有者和组更改为我想要运行的用户。 然后在init.d中对这个jar进行符号链接并启动该服务。

所以:

#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