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


2 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"