diff --git a/containers/grafana/scripts/grafana_install_hooks.sh b/containers/grafana/scripts/grafana_install_hooks.sh index 79467b4..cb1f097 100644 --- a/containers/grafana/scripts/grafana_install_hooks.sh +++ b/containers/grafana/scripts/grafana_install_hooks.sh @@ -15,9 +15,16 @@ grafana_install_pre() grafana_install_post_start() { local app_name="$1" + # The DIRECTORY, not its contents. Grafana runs as uid 472, which rootless + # maps to a subuid this user has no authority over; it needs write on the dir + # itself to create grafana.db and its plugin/png dirs on first boot, and from + # then on those files are its own. `chmod -R` walked them as the docker + # install user and failed per file with "Operation not permitted", failing the + # step on every reinstall — while a fresh install passed, because the dir was + # still empty. Grafana's files must keep Grafana's ownership regardless. if [ -d "${containers_dir}grafana/grafana_storage" ]; then local result - result=$(runFileOp chmod -R 777 "${containers_dir}grafana/grafana_storage") + result=$(runFileOp chmod 0777 "${containers_dir}grafana/grafana_storage") checkSuccess "Set permissions to grafana_storage folder." fi } diff --git a/containers/prometheus/scripts/prometheus_install_hooks.sh b/containers/prometheus/scripts/prometheus_install_hooks.sh index ec0752e..0129839 100644 --- a/containers/prometheus/scripts/prometheus_install_hooks.sh +++ b/containers/prometheus/scripts/prometheus_install_hooks.sh @@ -26,14 +26,36 @@ prometheus_install_post_start() if [ -f "${containers_dir}prometheus/prometheus/prometheus.yml" ]; then updateFileOwnership "${containers_dir}prometheus/prometheus/prometheus.yml" $docker_install_user $docker_install_user fi + # Prometheus runs as nobody (65534) inside the container, which rootless maps + # to a subuid outside this user's authority (65534 -> 296605 here). Two + # different needs, and the old blanket `chmod -R 777` on both got the second + # one wrong: + # + # prometheus/ config, READ-only to the container. a+rX is enough — world + # WRITE on a config the container obeys is not something to + # hand out, and -R is safe here because nothing but LibrePortal + # writes this dir. go-w is included so the fix actually lands on + # installs the old 777 already touched: a+rX only ADDS bits, so + # without it every existing prometheus.yml stays world-writable + # by any local user. Everything here is written through + # runFileOp — i.e. by the owner — so owner-write is all it needs. + # + # prom_data/ the container's own store. It needs write on the DIRECTORY to + # create prom_data/data on first boot; everything under that is + # created by, and belongs to, prometheus itself. Recursing into + # it meant chmod'ing files owned by 296605 as the docker install + # user: "Operation not permitted" per file and a failed step on + # every REINSTALL (a fresh install passed only because the dir + # was still empty). Those files must keep prometheus's ownership + # anyway — that is what lets it write them. if [ -d "${containers_dir}prometheus/prometheus" ]; then local result - result=$(runFileOp chmod -R 777 "${containers_dir}prometheus/prometheus") + result=$(runFileOp chmod -R a+rX,go-w "${containers_dir}prometheus/prometheus") checkSuccess "Set permissions to prometheus folder." fi if [ -d "${containers_dir}prometheus/prom_data" ]; then local result - result=$(runFileOp chmod -R 777 "${containers_dir}prometheus/prom_data") + result=$(runFileOp chmod 0777 "${containers_dir}prometheus/prom_data") checkSuccess "Set permissions to prom_data folder." fi } diff --git a/scripts/function/permission/ownership/file.sh b/scripts/function/permission/ownership/file.sh index 55c94cf..fcd6214 100755 --- a/scripts/function/permission/ownership/file.sh +++ b/scripts/function/permission/ownership/file.sh @@ -1,13 +1,25 @@ #!/bin/bash -updateFileOwnership() +# Set owner:group on a single file under the data plane. +# +# runFileOp, not runSystem: the scoped sudoers grants the manager root for the +# fixed LibrePortal helpers and systemctl/ufw/nft/sysctl only — never a bare +# `sudo chown`, since that is root-equivalent (chown /etc/sudoers). `runSystem +# chown` therefore could not succeed on any correctly-installed system; it was +# denied every time, and because the result feeds checkSuccess it printed a red +# ✗ Error on every prometheus install. runFileOp runs as the owner of the data +# plane (the docker install user under rootless, the manager under rooted), which +# is exactly who may set these. +# +# Ownership that genuinely needs root — establishing the /docker model, reclaiming +# a root-owned file — belongs in the libreportal-ownership helper instead. +updateFileOwnership() { local file="$1" local file_name=$(basename "$file") - local clean_dir=$(echo "$file" | sed 's#//*#/#g') local user_name_1="$2" local user_name_2="$3" - local result; result=$(runSystem chown $user_name_1:$user_name_2 "$file") - checkSuccess "Updating $file_name with $user_name ownership" + local result; result=$(runFileOp chown "$user_name_1:$user_name_2" "$file") + checkSuccess "Updating $file_name with $user_name_1 ownership" }