Using PolicyKit to allow non-root users to start and stop a service

8.9k Views Asked by At

I have a requirement to allow non-root users to start and stop a service. It was recommended to me to use PolicyKit rather than sudoers.d, which I am familiar with.

As I have no experience with PolicyKit, I thought I would experiment and create a rule to allow non-root users to start and stop the Docker service. I have created a file, /etc/polkit-1/rules.d/10-docker.rules containing:

polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.systemd1.manage-units" &&
        action.lookup("unit") == "docker.service")
    {
        return polkit.Result.YES;
    }
})

However, whenever I execute systemctl start|stop|restart docker.service, I keep getting prompted for a password. What am I missing?

Also, I would like to limit non-root users to control this service who are in a specific group e.g. blah. How do I incorporate this into my rule?

My target OS is RHEL 7.7.

3

There are 3 best solutions below

0
On

/etc/polkit-1/rules.d/10-docker.rules

polkit.addRule(function(action, subject) {
  if (action.id == "org.freedesktop.systemd1.manage-units" &&
    action.lookup("unit") == "docker.service")  &&
    subject.isInGroup("mygroup"))
    {
      return polkit.Result.YES;
    }
})

Also you need to run visudo and add these lines

%mygroup ALL= NOPASSWD: /usr/bin/systemctl restart docker.service
%mygroup ALL= NOPASSWD: /usr/bin/systemctl stop docker.service
%mygroup ALL= NOPASSWD: /usr/bin/systemctl start docker.service
%mygroup ALL= NOPASSWD: /usr/bin/systemctl status docker.servicee

Tutorial: https://keshavarzreza.ir/create-linux-systemd-service-runable-for-non-root-users/

0
On

As pointed out by Simão, the unit information is not supplied to polkit by systemd on RHEL 7. One way around the problem is to use pkexec to wrap the call to systemctl. You would need a wrapper script for your specific service, then have the rules apply to pkexec. The users would execute the command

pkexec /path/to/script

and the polkit rule would look something like this:

  polkit.addRule( 
  function(action,subject)
  {
    if ( (action.id == "org.freedesktop.policykit.exec") &&
         (action.lookup("user") == "root") &&
         (action.lookup("program") == "/path/to/script") &&
         (subject.isInGroup("someGroup") ) )
      return polkit.Result.YES;

    return polkit.Result.NOT_HANDLED;
  }
);

In a practical sense, this just re-creates sudo and scripts using the polkit framework. Whether this is "better" than using sudo is a value judgement I'll leave to others.

0
On

On CentOS7, action does not have access to the unit information. This was introduced on a later systemd version, v226.

https://github.com/systemd/systemd/commit/88ced61bf9673407f4b15bf51b1b408fd78c149d

I was also hit by this. You will need to allow the user to manage all units or go back to the stone age of having shell scripts on sudoers.

Also, I would like to limit non-root users to control this service who are in a specific group e.g. blah. How do I incorporate this into my rule?

Use subject.isInGroup("group").

See: