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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/394984/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:49:24  来源:igfitidea点击:

Best practice to run Linux service as a different user

linuxsysadminrhelinit.d

提问by James Brady

Services default to starting as rootat 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.

root在我的 RHEL 机器上,服务默认在启动时启动。如果我没记错的话,其他使用 .init 脚本的 Linux 发行版也是如此/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?

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

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 Blacksuggests.

编辑:我应该说我在这个实例中启动的进程是 Python 脚本或 Java 程序。我宁愿不为它们编写本机包装器,因此不幸的是,我无法像Black建议的那样调用setuid()

采纳答案by Black

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

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

I'm not familiar with RedHat, but the daemonutility 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.

我不熟悉 RedHat,但是daemon您已经在使用的实用程序(在 中定义/etc/init.d/functions,顺便说一句。)在任何地方都被提及为等效于start-stop-daemon,因此它也可以更改您的程序的 uid,或者您这样做的方式这已经是正确的了。

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.

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

回答by Black

  • Some daemons (e.g. apache) do this by themselves by calling setuid()
  • You could use the setuid-file flagto run the process as a different user.
  • Of course, the solution you mentioned works as well.
  • 一些守护进程(例如 apache)通过调用setuid()自行完成此操作
  • 您可以使用setuid-file 标志以不同的用户身份运行该进程。
  • 当然,你提到的解决方案也有效。

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

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

  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.
  1. 使用它的root 权限(例如打开日志文件,创建pid 文件)。
  2. 在启动期间的某个时刻删除其 root 权限。

回答by James Brady

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. hopis right to point me back at /etc/init.d/functions: the daemonfunction 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 Leffleris 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 sunor runusergracefully 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)
    
  1. hop是正确地指出我/etc/init.d/functions:该 daemon功能已经允许您设置备用用户:

    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
    

    但是,我仍然认为您不能从 JVM 内部设置 uid。

  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)
    

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

为了解决suand 的这种行为runuser,我已将我的 init 脚本更改为以下内容:

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!

感谢你的帮助!

回答by claymation

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

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

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

回答by pdeschen

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

回答by cyberJar

Why not try the following in the init script:

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

setuid $USER application_name

It worked for me.

它对我有用。

回答by dulcana

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

在用于 svn 服务器的 CENTOS(红帽)虚拟机上:编辑/etc/init.d/svnserver以将 pid 更改为 svn 可以写入的内容:

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

and added option --user=svn:

并添加了选项--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.

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

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

回答by Somaiah Kumbera

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

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

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.

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

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