Best practice to run Linux service as a different user

元气小坏坏 提交于 2019-11-27 09:59:20

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.

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

Black
  • 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.

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]
dulcana

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

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.

Why not try the following in the init script:

setuid $USER application_name

It worked for me.

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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!