Running upstart jobs as unprivileged users

143

34

What's the canonical way to have an upstart job change its userid and run the script as an unprivileged user?

Obviously one can use su or sudo, but this seems hacky (and can generate needless log lines).

aaronsw

Posted 2009-03-11T14:26:58.487

Reputation: 1 627

Answers

109

With upstart v1.4, setuid and setgid are supported natively in config file.

qsun

Posted 2009-03-11T14:26:58.487

Reputation: 1 191

Best answer if you have Upstart >= 1.4. You should bookmark the 'su' solution though as it can be handy when you need it. – tiktak – 2014-07-11T21:54:09.977

5For the record, initctl --version to find your current version of upstart. – Mahn – 2014-08-29T12:14:38.907

5Annoyingly, the Amazon Linux distro on AWS uses RHEL 6's upstart version (0.6.5 !!!!) so anyone using that will have to use the 'su' solution. – Asfand Qazi – 2016-02-02T16:35:24.797

As an example, add the following line to your upstart script: setuid www-data – J0hnG4lt – 2016-08-01T21:17:08.190

7

See the cookbook for specifics on this: http://upstart.ubuntu.com/cookbook/#run-a-job-as-a-different-user

– Jason Navarrete – 2012-10-25T16:32:37.020

10In other words, it's supported in Precise (12.04) and newer. – Edward Anderson – 2013-01-19T03:24:29.857

8In other words, is not supported in centos 6 – socketpair – 2013-12-26T06:43:28.113

86

Asking on the #upstart channel on freenode, the official take on the matter is:

A future release of Upstart will have native support for that, but for now, you can use something like:

exec su -s /bin/sh -c 'exec "$0" "$@"' username -- /path/to/command [parameters...]

Roman Gaufman

Posted 2009-03-11T14:26:58.487

Reputation: 961

That's some fancy shell magic, +1. – Steve Kehlet – 2014-08-04T16:56:13.807

7This didn't work for me on CentOS 6 (Upstart 0.6.5). There are a series of forks (4 deep I think) initiated by su that means that expect fork and even expect daemon don't catch the final PID. – Mark Lakata – 2014-08-27T21:54:33.363

2I used this on Amazon Linux (Upstart 0.6.5) to boot up a Jenkins process (which does not daemonize itself, thankfully) and it worked! I had to change it a little to redirect standard output to a log file and set some environment variables, but it worked! My version looks like: exec su -s /bin/sh -c 'HOME=/foo/bar exec "$0" "$@" &>/var/log/foobar.log' username -- /path/to/command [parameters...] – Asfand Qazi – 2016-02-02T17:05:22.450

For CentOS 6, check out hxysayhi's answer below. It resolves the issue Mark Lakata identified – bitsoflogic – 2020-01-21T15:41:00.973

7This is the only answer that worked on Amazon Linue EC2 (I tried all variations of sudo and su, including --session-command, -c, ad nauseum); none of them allowed the process to be stopped once started; thanks so much for this. – Kato – 2011-12-02T10:42:31.280

17

How about using start-stop-daemon?

exec start-stop-daemon --start --chuid daemonuser --exec /bin/server_cmd

From Upstart cookbook:

The recommended method for Debian and Ubuntu systems is to use the helper utility start-stop-daemon. […] start-stop-daemon does not impose PAM ("Pluggable Authentication Module") limits to the process it starts.

Note: start-stop-daemon not supported in RHEL.

Jason R. Coombs

Posted 2009-03-11T14:26:58.487

Reputation: 1 952

2You can also use the group, if you need it. With --chuid daemonuser:daemongroup – Evgeny – 2011-05-30T15:33:08.307

13

There are several ways to do it, all with slightly different semantics, particularly relating to group membership:

  • setuidgid will put you in the group you specify.

    • The original daemontools' setuidgid will put you only in that group, so you won't be able to access files belonging to other groups you're a member of.
    • The setuidgid from daemontools-encore and the setuidgid from the nosh toolset both have an -s (a.k.a. --supplementary) option which will put you in that group, and also put you in all of the supplementary groups for the user that you specify.
  • Using newgrp once you've become the less privileged user will add a single group to your groupset, but also creates a new subshell, making it tricky to use inside scripts.

  • start-stop-daemon preserves your group membership, and does a whole lot more than just setuid/setgid.

  • chpst -u username:group1:group2:group3... commandname will let you specify exactly what group memberships to adopt, but (in Ubuntu) it only comes with the runit package, which is an alternative to upstart.

  • su -c commandname username picks up all of username's group memberships, as does sudo -u username commandname, so they're probably the route to least astonishment.

Jason Holt

Posted 2009-03-11T14:26:58.487

Reputation: 131

8

Use setuidgid from the package daemontools.

Documentation here: http://cr.yp.to/daemontools/setuidgid.html

aaronsw

Posted 2009-03-11T14:26:58.487

Reputation: 1 627

7daemontools isn't a prerequisite of upstart, so this doesn't seem like the 'canonical' answer – Adam Nelson – 2010-01-08T21:52:15.940

2Further, daemontools is in universe (ubuntu 10.04), and upstart is in main. – jtimberman – 2010-08-14T18:18:23.560

4

On an Ubuntu 10.10 instance on Amazon EC2, I had better luck with the start-stop-daemon command.

I also struggled with some of the other upstart stanzas. I am calling a python application with a specific virtualenv and some parameters to my executed program.

The following is what worked for me.

script
  export PYTHONPATH=.:/home/ubuntu/.local/lib/python2.7/site-packages/:/home/ubuntu/python/lib/python2.7/site-packages/
  exec start-stop-daemon --start  --chuid ubuntu --exec /home/ubuntu/python_envs/MyProj/bin/python /home/ubuntu/www/MyProj/MyProj.py -- --config-file-dir=/home/ubuntu/www/MyProj/config/ >> /home/ubuntu/startup.log 2>&1 &
end script

The PYTHONPATH is to get some packages installed from source into the PYTHON module path when this upstart job runs. I had to do everything in absolute paths because the chdir stanza didn't seem to do work.

Jesse Smith

Posted 2009-03-11T14:26:58.487

Reputation: 201

I have also had problems with env variables used with exec start-stop-daemon. – Thomas Bratt – 2013-08-06T11:30:29.723

3

I was using CentOS 6, and I could not get the recommended hack (for Upstart 0.6.5) to work for me, nor the 'su' trick because the number of forks involved (4 I think) was not tracked by 'expect fork' or 'expect daemon'.

I eventually just did

chown user:group executable
chmod +s executable

(ie set the setuid bit and change the ownership).

It may not be the safest method, but for an internal R&D project, it didn't matter in our case.

Mark Lakata

Posted 2009-03-11T14:26:58.487

Reputation: 4 260

If you were to do a chmod 1700 or at least a chmod u+sx,go-x in there instead of just +s, it'd qualify as "secure enough." :) – dannysauer – 2015-10-02T22:33:21.930

1

In CentOS 6, upstart 0.6.5, the following is what worked for me.

script

    exec su user_name << EOF
        exec /path/to/command [parameters...]
EOF

end script

or :

script

    exec su user_name << EOF
       ..... what you want to do ....
EOF

end script

When use

exec su -s /bin/sh -c 'exec "$0" "$@"' username -- /path/to/command [parameters...]

the job process can't be stopped by initclt stop . I think the reason is:

1. the job forked and the main process is not tracked.
2. the main process changed its process group,because of `su -c`

hxysayhi

Posted 2009-03-11T14:26:58.487

Reputation: 111

0

There is a third possibility depending on what you are trying to accomplish. You may be able to loosen the access controls on the files/devices in question. This can allow an unprivileged user to mount or access items that they normally wouldn't be allowed to. Just be sure you aren't giving away the keys to the kingdom in the process.

You can also change the timeout of the sudo password cache. But I don't recommend it unless your machine is physically secure (i.e., you believe that it's unlikely that a passer-by would attempt to gain sudo access).

There's a good reason that there are very few ways to perform privileged actions and that they perform needless necessary logging. Loose restrictions would be a security hazard for your system, and a lack of logging would mean there's no way to know what happened when you've been compromised.

If the size of your log files is a concern then something is probably wrong. Sudo generates only one line per use under normal conditions.

Chris Nava

Posted 2009-03-11T14:26:58.487

Reputation: 7 009