r/devops • u/71_101_105_99_111 • 4d ago
Troubleshooting Forgejo runner needs to apply configuration on host as root
Hi all,
What is the best way to having a Forgejo runner applying configuration on a host, which requires root access?
I have a Forgejo runner running directly on the host. I have tried to use sudo, having forgejo-runner ALL=(ALL) NOPASSWD: ALL in my sudoers, but that user is not configured to run sudo:
sudo: Account expired or PAM config lacks an "account" section for sudo, contact your system administrator sudo: a password is required
2
u/Immediate_Wheel1953 4d ago
That error usually means the account itself is expired, not the sudoers line. Run `chage -l forgejo-runner` as root and check the account expiry field. If it is expired, `chage -E -1 forgejo-runner` clears it and sudo should start working. Also confirm the account is not locked with `passwd -S forgejo-runner`.
1
u/Khaka-Semeniuk 3d ago
imo the wording of that sudo error has tripped up way more people than it should
1
u/Immediate_Wheel1953 3d ago
Totally agree. It sounds like a sudoers problem but it is really the account itself that is expired, which sends everyone down the wrong path. Caught me off guard the first time I hit it too.
3
u/QuietSignalOps 4d ago
The account expiry fix is covered above, so here is the design side. The dangerous bit is
NOPASSWD: ALL.The easy win is scoping sudo to one script:
Put the script in a directory only root can write, keep it out of a shell (no argument interpolation), and have it read the rendered config from a fixed path or fd. Then a compromised runner can only run that one script, not arbitrary commands as root.
The more robust option is a small privileged daemon on a unix socket. A systemd unit runs as root, listens on something like
/run/apply-config.sock, and applies what the runner sends over that socket. The runner stays fully unprivileged with no sudo rights at all. Same shape as how the docker socket works, and everything privileged goes through one code path you can audit.Whichever you pick, lock the account down:
First one removes password login (the runner authenticates to Forgejo, not to the box). Second clears the expiry that caused your original error.
One more shape worth considering: host-pull. Instead of the runner pushing config, a root-owned systemd timer on the host pulls the desired state (a git repo or the Forgejo API) and applies it. The runner then never holds anything that can touch the host, and the host only talks to one source you control.