Two small NS8 usability suggestions: runagent on root's PATH, and documenting the *.local template override

Both came up while debugging something unrelated. Neither is a defect — both are places where NS8 behaves correctly but leaves you guessing.

Disclaimer: worked out together with an AI assistant (Claude); it did the analysis, I ran the commands and provided the output.


1. runagent is not on root’s PATH when you arrive via sudo

What you see:

[root@node03 ~]# runagent -l
-bash: runagent: command not found
[root@node03 ~]# ls -l /usr/local/bin/runagent
-rwxr-xr-x. 1 root root ... /usr/local/bin/runagent

The binary is there. The PATH is not:

/root/.local/bin:/root/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin

Cause is the stock RHEL/AlmaLinux line in /etc/sudoers:

Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin

/usr/local/bin is not in it, and NS8 installs runagent exactly there. So anyone who reaches root via sudo — which is the normal path on a cloud-init installed node — cannot call runagent by name, while someone logging in as root directly can. That asymmetry is confusing, and the usual workaround found in older threads is to type the full path or switch to the admin user, neither of which fixes the cause.

/etc/profile.d/runagent.sh already exists and does set PATH, but only inside the agent environment (AGENT_STATE_DIR set) — it does not cover an interactive root shell.

Fix, as root:

echo 'Defaults secure_path = /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin' > /etc/sudoers.d/99-secure-path
chmod 0440 /etc/sudoers.d/99-secure-path
visudo -c

Keep the existing root shell open until you have verified sudo -i still works.

Suggestion: ship this drop-in with the node installation, or extend /etc/profile.d/runagent.sh to also cover interactive root shells. It would save a recurring stumble for anyone following documentation that says “run runagent -m <module>”.


2. The *.local template override deserves to be documented

If you need a configuration parameter that a module does not expose as a setting, the obvious move is to edit the generated file — for SOGo that is ~/.config/state/config/sogo.conf, bind-mounted into the container. That change survives exactly until the next module restart, because ExecStartPre=runagent expand-configuration regenerates the file every time. Easy to lose an hour to.

The supported mechanism is already in place. expand-configuration checks for a user-supplied Jinja2 template first:

if os.path.exists("templates/sogo.conf.local"):
    template = jenv_custom.get_template('sogo.conf.local')
else:
    template = jenv.get_template('sogo.conf')

So the durable way to change a parameter is:

runagent -m sogo1 bash -c 'cp $AGENT_INSTALL_DIR/templates/sogo.conf \
  $AGENT_INSTALL_DIR/state/templates/sogo.conf.local'
# edit state/templates/sogo.conf.local, then:
runagent -m sogo1 systemctl --user restart sogo-app

The same pattern applies to SOGo.conf.local and cron.conf.local, and the state/templates directory is created by the unit itself (mkdir -p {config,backups,templates}), so it is clearly intended for this.

Caveat worth stating alongside it: the copy is a snapshot. If the shipped template changes in a module update, your .local version does not follow, and you may silently miss new parameters.

Suggestion: document this in the module/developer documentation, ideally with the caveat above. It is a genuinely good design — it is just not discoverable unless you read expand-configuration.

Best regards,
Thorsten

Yes, it seems sudo filters out some PATH components as an additional security measure.

To consistently initialize root’s environment when escalating privileges from a normal user, please use:

sudo su -

This is definitely something to add to the documentation.

Yes, correct, and just a side node:
Typically I enter by sudo -i as I am used to on other systems … :innocent:

Same here. I was never able to figure out why it worked if I used sudo su -, but not sudo -i.

I know that sudo -i and sudo su - is different and it defiantly has got something to do with the path - one takes over the environment of the calling user, the other does not. Give me a second, I ask my brain.

My brain (claude) answered - the environment claim is wrong. sudo -i and sudo su - both simulate a fresh login and both throw away the calling user’s environment. The variant that inherits the caller’s environment is sudo su (no dash) or sudo -s — that’s the one that leaves you as root with HOME=/home/you and root-owned files in your own dotfiles afterwards.

What actually differs between sudo -i and sudo su - is the number of layers involved:

sudo -i — one layer: sudo execs the target user’s shell as a login shell.

  • One PAM stack: /etc/pam.d/sudo (some distros add sudo-i).
  • sudo builds the environment itself under env_reset: sets HOME, SHELL, USER, LOGNAME, MAIL, and sets PATH from secure_path in sudoers if that’s defined. Anything listed in env_keep (e.g. TERM, DISPLAY) survives.
  • Then the login shell sources /etc/profile and the target user’s profile files.

sudo su - — two layers: sudo runs su, su runs the login shell.

  • Two PAM stacks: /etc/pam.d/sudo, then /etc/pam.d/su. pam_env, pam_limits, pam_systemd run a second time, so ulimits and the systemd session context can end up different.
  • The environment sudo prepared for su is then discarded again by su -, which applies its own rules: PATH comes from ENV_SUPATH (uid 0) or ENV_PATH in /etc/login.defs, not from sudoers secure_path. Whatever you kept via env_keep is gone.
  • Then the login shell sources the profile files.

So your instinct about PATH points at something real, but the mechanism is the source of PATH, not inheritance from the caller: sudoers secure_path for sudo -i versus login.defs for sudo su -. Whether you actually see a difference depends on the distro, because /etc/profile frequently rewrites PATH for uid 0 afterwards and can flatten the difference. Compare with echo $PATH on the machine in question rather than assuming.

Two more practical points:

  • Authorization: sudo -i needs only a sudo rule. sudo su - additionally needs your rule to permit running su. A sudoers rule that allows /bin/su is effectively unrestricted, which is why some sites forbid it.
  • sudo -i cmd runs cmd through the login shell directly; sudo su - -c 'cmd' puts you through two rounds of quoting.

sudo -i is the one to use. sudo su - is mostly a habit carried over from environments where sudo rules were shaped that way.

…except with NS8, where it doesn’t work.