Is your feature request related to a problem? Please describe.
I am deploying Pi-hole in a hardened Kubernetes environment following security best practices:
-
readOnlyRootFilesystem: true -
runAsNonRoot: true(User 1000) -
capabilities: drop: ["ALL"](with specific adds likeNET_BIND_SERVICEhandled by the runtime)
The current src/bash_functions.sh script assumes a mutable filesystem and root privileges, causing the container to crash loop or fail startup in these environments.
Detailed Analysis of Blockers
Based on the current src/bash_functions.sh, I have identified 5 specific conflict areas:
1. Crash Loop on Capability Check (fix_capabilities)
-
Location:
fix_capabilitiesfunction. -
Problem: The script attempts
setcapon thepihole-FTLbinary. On a Read-Only Root Filesystem (RORFS), this fails. The script explicitly checksif [[ $ret -ne 0 ...and exits with status 1. -
Context: In Kubernetes, capabilities are often granted to the process by the runtime (CRI-O/Containerd). The binary file itself does not need the attributes set if the process is already privileged.
2. Hardcoded Crontab Modification (start_cron)
-
Location:
start_cronfunction. -
Problem: The script runs
sed -ion/crontab.txt(located at root) to randomize schedule times. This fails on RORFS because the file is not writable.
3. Mandatory Internal Cron Daemon (start_cron)
-
Location:
start_cronfunction. -
Problem: The script unconditionally starts
/usr/sbin/crond. Hardened K8s deployments often prefer using nativeCronJobresources to manage updates/rotation externally rather than running a multi-process container. Also crond normally needs suid permission.
4. MacVendor DB Permission Check (ftl_config)
-
Location:
ftl_configfunction. -
Problem: The fallback logic attempts
chown pihole:pihole /macvendor.dbif the custom file env var is not set. This fails on RORFS.
5. UID/GID Modification on Startup (set_uid_gid)
-
Location:
set_uid_gidfunction. -
Problem: The script unconditionally runs
usermodandgroupmodif the env vars differ from the current user. -
Context: On a RORFS,
/etc/passwdcannot be modified. Furthermore, a container running as non-root (UID 1000) lacks the permission to execute these commands.
Proposed Solution
I propose updating src/bash_functions.sh to support "Smart Detection" where possible, with "Opt-In Skips" as fallbacks.
1. Capabilities:
-
Smart Fix: Before failing on
setcap, checkcapsh --print(if available) to see if the required capabilities are effectively present on the process. -
Fallback: Add a
SKIP_SETCAP_CHECKenvironment variable to bypass theexit 1failure.
2. Crontab:
- Smart Fix: Detect if
/crontab.txtis writable. If not, copy it to/tmp/crontab.txt(which is usually writable in K8s), perform thesedmodification there, and pointcrondto the new location.
3. Internal Cron:
- Feature: Add
SKIP_INTERNAL_CRON=trueenvironment variable to skip thestart_cronfunction entirely for users managing jobs externally.
4. MacVendor DB:
- Smart Fix: Wrap the permissions change in a check:
[ -w /macvendor.db ] && chown ....
5. UID/GID:
- Smart Fix: Only attempt
usermod/groupmodif the script is running as root (id -u == 0). If running as non-root, assume the container runtime has handled the User ID mapping (e.g. K8srunAsUser).
Additional Context
These changes would allow Pi-hole to run natively in OpenShift and "Restricted" Kubernetes namespaces without requiring dangerous privileges (allowPrivilegeEscalation: true) or writable root filesystems.