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

发布于 2024-07-11 11:23:13 字数 592 浏览 15 评论 0原文

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

您认为让进程以我选择的(静态)用户身份运行的最佳方法是什么?

我找到的唯一方法是使用类似的方法:

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

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

是否有一些隐藏的魔法可以提供一种简单的机制来像其他非 root 用户一样自动启动服务?

编辑:我应该说我在这个实例中启动的进程要么是Python脚本,要么是Java程序。 我不想围绕它们编写本机包装器,所以不幸的是我无法调用 setuid() 正如 Black 建议的那样。

Services default to starting as root at boot time on my RHEL box. If I recall correctly, the same is true for other Linux distros which use the init scripts in /etc/init.d.

What do you think is the best way to instead have the processes run as a (static) user of my choosing?

The only method I'd arrived at was to use something like:

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

But this seems a bit untidy...

Is there some bit of magic tucked away that provides an easy mechanism to automatically start services as other, non-root users?

EDIT: I should have said that the processes I'm starting in this instance are either Python scripts or Java programs. I'd rather not write a native wrapper around them, so unfortunately I'm unable to call setuid() as Black suggests.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

天邊彩虹 2024-07-18 11:23:13

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

我不熟悉 RedHat,但提到了您已经在使用的 daemon 实用程序(在 /etc/init.d/functions 中定义,顺便说一句。)无处不在,相当于 start-stop-daemon,因此它也可以更改程序的 uid,或者您执行此操作的方式已经是正确的方式。

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

On Debian we use the start-stop-daemon utility, which handles pid-files, changing the user, putting the daemon into background and much more.

I'm not familiar with RedHat, but the daemon utility that you are already using (which is defined in /etc/init.d/functions, btw.) is mentioned everywhere as the equivalent to start-stop-daemon, so either it can also change the uid of your program, or the way you do it is already the correct one.

If you look around the net, there are several ready-made wrappers that you can use. Some may even be already packaged in RedHat. Have a look at daemonize, for example.

各自安好 2024-07-18 11:23:13

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

  1. hop 正确地指出了我的方向
    /etc/init.d/functions 处:
    daemon 功能已经允许您
    设置备用用户:

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

    这是通过包装来实现的
    使用 runuser 进行流程调用 -
    稍后再详细介绍。

  2. 乔纳森·莱夫勒是正确的:
    Python中有setuid:

    导入操作系统 
      os.setuid(501) # my_user 的 UID 是 501 
      

    我仍然认为你不能setuid
    然而,来自 JVM 内部。

  3. 既不是 su 也不是 runuser
    优雅地处理你的情况
    要求以您的用户身份运行命令
    已经是了。 例如:

    <前><代码>[my_user@my_host]$ id
    uid=500(my_user) gid=500(my_user) 组=500(my_user)
    [my_user@my_host]$ su my_user -c "id"
    密码:# 不想被提示!
    uid=500(my_user) gid=500(my_user) 组=500(my_user)

为了解决 surunuser 的行为,我已将初始化脚本更改为:

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

感谢大家的帮助!

After looking at all the suggestions here, I've discovered a few things which I hope will be useful to others in my position:

  1. hop is right to point me back
    at /etc/init.d/functions: the
    daemon function already allows you
    to set an alternate user:

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

    This is implemented by wrapping the
    process invocation with runuser -
    more on this later.

  2. Jonathan Leffler is right:
    there is setuid in Python:

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

    I still don't think you can setuid
    from inside a JVM, however.

  3. Neither su nor runuser
    gracefully handle the case where you
    ask to run a command as the user you
    already are. 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)
    

To workaround that behaviour of su and runuser, I've changed my init script to something like:

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

Thanks all for your help!

画尸师 2024-07-18 11:23:13
  • 一些守护进程(例如apache)通过调用 setuid() 自己完成此操作,
  • 您可以使用setuid-file 标志 以其他用户身份运行该进程。
  • 当然,你提到的解决方案也是有效的。

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

  1. 利用其 root 权限(例如打开日志文件、创建 pid 文件)。
  2. 在启动过程中的某个时刻删除其 root 权限。
  • Some daemons (e.g. apache) do this by themselves by calling setuid()
  • You could use the setuid-file flag to run the process as a different user.
  • Of course, the solution you mentioned works as well.

If you intend to write your own daemon, then I recommend calling setuid().
This way, your process can

  1. Make use of its root privileges (e.g. open log files, create pid files).
  2. Drop its root privileges at a certain point during startup.
无语# 2024-07-18 11:23:13

只是添加一些其他需要注意的事情:

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

Just to add some other things to watch out for:

  • Sudo in a init.d script is no good since it needs a tty ("sudo: sorry, you must have a tty to run sudo")
  • If you are daemonizing a java application, you might want to consider Java Service Wrapper (which provides a mechanism for setting the user id)
  • Another alternative could be su --session-command=[cmd] [user]
独﹏钓一江月 2024-07-18 11:23:13

在 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

原始 pid 文件是 /var/run/svnserve.pid。 该守护进程没有启动,因为只有 root 可以在那里写入。

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

on a CENTOS (Red Hat) virtual machine for svn server:
edited /etc/init.d/svnserver
to change the pid to something that svn can write:

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

and added option --user=svn:

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

The original pidfile was /var/run/svnserve.pid. The daemon did not start becaseu only root could write there.

 These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart
懒的傷心 2024-07-18 11:23:13

需要注意的一些事情:

  • 正如您所提到的,如果您已经是目标用户,su 将提示输入密码
  • 类似地,如果您已经是目标用户(在某些操作系统上),setuid(2) 将失败 setuid
  • (2) 不会安装 /etc/limits.conf (Linux) 或 /etc/user_attr (Solaris) 中定义的权限或资源控制
  • 如果您采用 setgid(2)/setuid(2) 路线,请不要忘记调用 initgroups(3) - - 更多关于这里

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

Some things to watch out for:

  • As you mentioned, su will prompt for a password if you are already the target user
  • Similarly, setuid(2) will fail if you are already the target user (on some OSs)
  • setuid(2) does not install privileges or resource controls defined in /etc/limits.conf (Linux) or /etc/user_attr (Solaris)
  • If you go the setgid(2)/setuid(2) route, don't forget to call initgroups(3) -- more on this here

I generally use /sbin/su to switch to the appropriate user before starting daemons.

一城柳絮吹成雪 2024-07-18 11:23:13

为什么不在初始化脚本中尝试以下操作:

setuid $USER application_name

它对我有用。

Why not try the following in the init script:

setuid $USER application_name

It worked for me.

睡美人的小仙女 2024-07-18 11:23:13

我需要将 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

I needed to run a Spring .jar application as a service, and found a simple way to run this as a specific user:

I changed the owner and group of my jar file to the user I wanted to run as.
Then symlinked this jar in init.d and started the service.

So:

#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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文