feat(install): make the control-plane manager user configurable

sudo_user_name (the real manager — owns the install, runs the runtime, baked as
__MANAGER__ into the root helpers) was hardcoded to 'libreportal'. Make it
configurable, consistent with the relocatable roots:

- --manager-user=NAME flag + LP_MANAGER_USER env (default libreportal); resolved
  early in init.sh and in scripts/source/paths.sh (so the standalone processors
  get it too), validated as a real Linux username in libreportalValidatePaths.
- Baked everywhere it must be stable: the helpers + CLI wrapper (CHECK_USER now
  __MANAGER__, exports LP_MANAGER_USER) via the install-time sed; the systemd unit
  exports LP_MANAGER_USER=<manager>. User creation (initUsers), the sudoers
  drop-in, and ~35 call sites already used $sudo_user_name, so they follow.
- Fix the stray manager-name literals: install_crowdsec.sh chown, the
  check_install_type fallback. (Brand/identity strings like the backup
  engine:libreportal tag are left — they're not the username.)

Verified: resolves default/env/flag; wrapper bakes a custom name (admin) with no
placeholders left; validation rejects invalid usernames. The footprint paths
(/etc, /usr/local) stay fixed by design.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
librelad 2026-05-25 17:47:05 +01:00
parent f56bbda2a8
commit b47e20133d
5 changed files with 33 additions and 8 deletions

27
init.sh
View File

@ -21,6 +21,8 @@
# (Also: LP_CONTAINERS_DIR.) Put on its own disk if wanted.
# --backups-dir=PATH Root for backup repos. Default /libreportal-backups.
# (Also: LP_BACKUPS_DIR.) Point at a separate disk/mount.
# --manager-user=NAME Control-plane manager user (owns the install, runs the
# runtime). Default libreportal. (Also: LP_MANAGER_USER.)
# --allow-home Permit a containers/backups root inside /home/<user>
# (needs rootless o+x traversal of that home — a privacy
# trade-off; refused without this flag).
@ -109,7 +111,11 @@ init_skip_docker_images=false
init_allow_home=false
install_param="init"
sudo_user_name=libreportal
# Control-plane manager user — configurable via --manager-user= / LP_MANAGER_USER
# (default libreportal). Resolved early here (sudo_bashrc needs it); re-resolved
# after flag parsing in libreportalDerivePaths, and baked into the helpers/unit/
# wrapper at install (the __MANAGER__ placeholder).
sudo_user_name="${LP_MANAGER_USER:-libreportal}"
sshd_config="/etc/ssh/sshd_config"
sudo_bashrc="/home/$sudo_user_name/.bashrc"
hosts_file="/etc/hosts"
@ -159,6 +165,10 @@ libreportalDerivePaths() {
install_scripts_dir="$script_dir/scripts/"
containers_dir="$LP_CONTAINERS_DIR/"
backup_dir="$LP_BACKUPS_DIR"
# Control-plane manager user (configurable; default libreportal).
sudo_user_name="${LP_MANAGER_USER:-${sudo_user_name:-libreportal}}"
sudo_bashrc="/home/$sudo_user_name/.bashrc"
}
libreportalDerivePaths
@ -167,6 +177,12 @@ libreportalDerivePaths
# an unsafe choice; the root helpers also re-check at runtime (defence in depth).
libreportalValidatePaths() {
local pair name d
# Manager username: must be a valid Linux username (it becomes a real account,
# a sudoers drop-in name, and the baked __MANAGER__ in the root helpers).
if [[ ! "$sudo_user_name" =~ ^[a-z_][a-z0-9_-]*$ ]]; then
isError "Invalid manager user '$sudo_user_name' — use lowercase letters, digits, '_' or '-' (must start with a letter or '_')."
exit 1
fi
for pair in "system:$LP_SYSTEM_DIR" "containers:$LP_CONTAINERS_DIR" "backups:$LP_BACKUPS_DIR"; do
name="${pair%%:*}"; d="${pair#*:}"
case "$d" in
@ -239,6 +255,7 @@ for ((i=1; i<=$#; i++)); do
--system-dir=*) LP_SYSTEM_DIR="${!i#*=}"; ((init_shift_count++)) ;;
--containers-dir=*) LP_CONTAINERS_DIR="${!i#*=}"; ((init_shift_count++)) ;;
--backups-dir=*) LP_BACKUPS_DIR="${!i#*=}"; ((init_shift_count++)) ;;
--manager-user=*) LP_MANAGER_USER="${!i#*=}"; ((init_shift_count++)) ;;
--allow-home) init_allow_home=true; ((init_shift_count++)) ;;
esac
done
@ -1108,7 +1125,9 @@ sudo tee -a "$command_script" >/dev/null <<'EOF'
# LibrePortal Command Start
# LibrePortal Command Version 1.4
CHECK_USER="libreportal"
# Manager user baked at install (the __MANAGER__ placeholder); unbaked keeps "__".
CHECK_USER="__MANAGER__"; [[ "$CHECK_USER" == *"__"* ]] && CHECK_USER="libreportal"
LP_MANAGER_USER="$CHECK_USER"; export LP_MANAGER_USER
CURRENT_USER=$(whoami)
# Check if the script is run by the specified user
@ -1401,8 +1420,10 @@ else
fi
# LibrePortal Command End
EOF
# Bake the three roots into the (root-owned) wrapper, same as the helpers.
# Bake the manager name + three roots into the (root-owned) wrapper, same as
# the helpers.
sudo sed -i \
-e "s/__MANAGER__/${sudo_user_name}/g" \
-e "s#__SYSTEM_DIR__#${LP_SYSTEM_DIR}#g" \
-e "s#__CONTAINERS_DIR__#${LP_CONTAINERS_DIR}#g" \
-e "s#__BACKUPS_DIR__#${LP_BACKUPS_DIR}#g" \

View File

@ -13,8 +13,7 @@ resolveDockerInstallUser()
else
docker_install_user="$sudo_user_name"
fi
[[ -z "$docker_install_user" ]] && docker_install_user="$sudo_user_name"
[[ -z "$docker_install_user" ]] && docker_install_user="libreportal"
[[ -z "$docker_install_user" ]] && docker_install_user="${sudo_user_name:-libreportal}"
}
checkInstallTypeRequirement()

View File

@ -222,7 +222,7 @@ installCrowdsecHost()
bouncer_key=$(runSystem cscli bouncers add traefik-bouncer -o raw 2>&1 | tail -1)
if [[ -n "$bouncer_key" && "$bouncer_key" != *"error"* ]]; then
echo "$bouncer_key" | sudo tee "$key_file" >/dev/null
sudo chown libreportal:libreportal "$key_file"
sudo chown "$sudo_user_name:$sudo_user_name" "$key_file"
sudo chmod 0600 "$key_file"
checkSuccess "Traefik bouncer API key generated"

View File

@ -60,3 +60,7 @@ containers_dir="$LP_CONTAINERS_DIR/"
# --- Derived: backups tree (container-user-owned; own mount-able) -----------
backup_dir="$LP_BACKUPS_DIR"
# --- Control-plane manager user (configurable; baked into helpers at install) -
# The systemd unit + CLI wrapper export LP_MANAGER_USER; else default libreportal.
sudo_user_name="${LP_MANAGER_USER:-libreportal}"

View File

@ -58,11 +58,12 @@ Type=simple
User=$MANAGER
Group=$MANAGER
WorkingDirectory=$INSTALL_SCRIPTS_DIR
# Relocatable path roots — baked here by root so the processor resolves them
# authoritatively (not via the legacy compat default in paths.sh).
# Relocatable path roots + manager user — baked here by root so the processor
# resolves them authoritatively (not via the legacy compat default in paths.sh).
Environment=LP_SYSTEM_DIR=$SYSTEM_DIR
Environment=LP_CONTAINERS_DIR=$CONTAINERS_DIR
Environment=LP_BACKUPS_DIR=$BACKUPS_DIR
Environment=LP_MANAGER_USER=$MANAGER
ExecStart=$TASK_PROCESSOR start_script
Restart=always
RestartSec=5