How to Grant Non-Root User Permissions for Specific Systemd Service Management


10 views

When deploying game servers or other services on Linux systems, security best practices dictate running them under unprivileged users. However, this creates a permissions paradox when those same users need to manage their own services through systemd.

The modern solution leverages Polkit (formerly PolicyKit), which provides fine-grained control over privileged operations. We'll create a custom policy that grants limited systemctl permissions exclusively for the target service.

# /etc/polkit-1/rules.d/10-gameserver.rules
polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.systemd1.manage-units" &&
        action.lookup("unit") == "game-server.service" &&
        subject.user == "gamesrv") {
        return polkit.Result.YES;
    }
});

For systems without Polkit or when needing simpler deployment:

# /etc/sudoers.d/gameserver
gamesrv ALL=(root) NOPASSWD: /bin/systemctl start game-server.service
gamesrv ALL=(root) NOPASSWD: /bin/systemctl stop game-server.service
gamesrv ALL=(root) NOPASSWD: /bin/systemctl restart game-server.service
gamesrv ALL=(root) NOPASSWD: /bin/systemctl status game-server.service

After implementing either solution, test with:

sudo -u gamesrv systemctl status game-server.service
sudo -u gamesrv systemctl restart game-server.service

When running game servers on Linux systems, we often face a security vs convenience dilemma. The service needs to run under an unprivileged user account (like gamesrv) for security, but performing service operations (start/stop/restart) traditionally requires root privileges.

The modern approach uses Polkit (formerly PolicyKit) to grant fine-grained permissions. Create a Polkit rule file at /etc/polkit-1/rules.d/10-gameserver.rules:

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

For systems without Polkit, create a sudoers entry in /etc/sudoers.d/gameserver:

gamesrv ALL=(root) NOPASSWD: /bin/systemctl start game-server.service
gamesrv ALL=(root) NOPASSWD: /bin/systemctl stop game-server.service
gamesrv ALL=(root) NOPASSWD: /bin/systemctl restart game-server.service
gamesrv ALL=(root) NOPASSWD: /bin/systemctl status game-server.service

After applying either method, test the configuration as the gamesrv user:

sudo -u gamesrv systemctl restart game-server.service
# Or with Polkit:
sudo -u gamesrv pkexec systemctl restart game-server.service
  • Always limit permissions to specific services
  • Consider adding IP restrictions if allowing remote management
  • Regularly audit permission files
  • Prefer Polkit over sudo when possible for finer control

For programmatic control without systemctl, you can use DBUS directly:

dbus-send --system --dest=org.freedesktop.systemd1 \
    --type=method_call --print-reply \
    /org/freedesktop/systemd1 \
    org.freedesktop.systemd1.Manager.RestartUnit \
    string:"game-server.service" string:"replace"