server-up/docker-entrypoint.sh
Ramon a7b00fc82b
All checks were successful
Deploy server-up (dev) / deploy (push) Successful in 16m58s
setpriv wil per capability een eigen teken
`+chown,dac_override,fowner` kwam door elke stringtest heen maar werd door
setpriv geweigerd met "bad capability string", waarna de container niet meer
opstartte. Alleen de CI-stap in een echte container zag dit.

- CAPS is nu +chown,+dac_override,+fowner
- de test laat de echte setpriv over de string oordelen in plaats van hem te
  vergelijken met een verwachte tekst; met de oude waarde faalt hij

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
2026-08-02 22:29:01 +02:00

115 lines
5.3 KiB
Bash
Executable file

#!/bin/sh
# Start Server Up onder een gewone gebruiker in plaats van als root.
#
# Waarom dit niet gewoon `user:` in compose is: Docker maakt het `su-data`-volume
# als root aan. Een container die meteen als uid 1000 start kan daar niet in
# schrijven en komt niet eens tot de configuratie. Dit script begint dus als
# root, zet klaar wat klaargezet moet worden, en zakt daarna pas af.
#
# En waarom `setpriv` en niet `gosu`: een proces dat met setuid afzakt verliest
# zijn capabilities. Server Up moet daarna nog steeds bestanden kunnen chownen
# (bij het verhuizen van mappen en het terugzetten van backups) en appdata van
# andere gebruikers kunnen lezen (bij het maken van backups). `setpriv` kan die
# rechten als *ambient* capability meegeven, zodat ze de overgang overleven.
#
# SU_UID leeg of 0 → alles blijft zoals het was: draaien als root.
set -e
log() { printf ' %s\n' "$1" >&2; }
SU_UID="${SU_UID:-0}"
SU_GID="${SU_GID:-$SU_UID}"
case "$SU_UID:$SU_GID" in
*[!0-9:]*)
log "SU_UID/SU_GID moeten getallen zijn ('$SU_UID:$SU_GID'); ik negeer ze."
exec "$@" ;;
esac
# ── Als root draaien: het gedrag van vóór deze versie ────────────────────────
if [ "$SU_UID" = "0" ] || [ -z "$SU_UID" ]; then
exec "$@"
fi
# Zelf al niet-root? Dan is er niets om af te zakken en missen we de rechten om
# iets klaar te zetten. Gewoon doorgaan is beter dan weigeren.
if [ "$(id -u)" != "0" ]; then
log "Draait al als uid $(id -u); SU_UID wordt genegeerd."
exec "$@"
fi
# ── Een naam bij het nummer ──────────────────────────────────────────────────
# git en ssh willen een echte gebruiker in /etc/passwd met een $HOME, anders
# komt er "No such device or address" uit een clone.
if ! getent group "$SU_GID" >/dev/null 2>&1; then
groupadd --gid "$SU_GID" serverup 2>/dev/null || true
fi
if ! getent passwd "$SU_UID" >/dev/null 2>&1; then
useradd --uid "$SU_UID" --gid "$SU_GID" --no-create-home \
--home-dir /data --shell /usr/sbin/nologin serverup 2>/dev/null || true
fi
GEBRUIKER="$(getent passwd "$SU_UID" | cut -d: -f1)"
GEBRUIKER="${GEBRUIKER:-$SU_UID}"
# ── Wat van ons is, overnemen ────────────────────────────────────────────────
# /data is het volume met de configuratie, het auditlog en de git-cache.
chown -R "$SU_UID:$SU_GID" /data 2>/dev/null || log "Kon /data niet overnemen."
cp -n /root/.gitconfig /data/.gitconfig 2>/dev/null || true
chown "$SU_UID:$SU_GID" /data/.gitconfig 2>/dev/null || true
# De stacks en de backups maakt Server Up zelf aan, dus die mogen van hem zijn.
#
# appdata NIET. Die mappen zijn van de apps: postgres draait als 999, een
# linuxserver-image als de PUID die jij hebt ingevuld. Er een chown overheen
# halen breekt precies die containers. Server Up leest ze via CAP_DAC_OVERRIDE.
if [ -n "$BASE_DIR" ]; then
for sub in stacks backups; do
[ -d "$BASE_DIR/$sub" ] || continue
chown -R "$SU_UID:$SU_GID" "$BASE_DIR/$sub" 2>/dev/null \
|| log "Kon $BASE_DIR/$sub niet overnemen."
done
fi
# ── Bij de docker-socket kunnen ──────────────────────────────────────────────
# De gid daarvan verschilt per host, dus die lezen we hier uit in plaats van hem
# in compose te moeten hardcoderen. De gebruiker wordt lid van die groep, want
# `setpriv --groups` en `--init-groups` sluiten elkaar uit — via /etc/group
# krijgen we allebei.
# Overschrijfbaar voor rootless Docker en Podman, die de socket elders zetten.
SOCK="${SU_DOCKER_SOCK:-/var/run/docker.sock}"
if [ -S "$SOCK" ]; then
SOCK_GID="$(stat -c %g "$SOCK" 2>/dev/null || echo '')"
if [ -n "$SOCK_GID" ] && [ "$SOCK_GID" != "$SU_GID" ]; then
SOCK_GROEP="$(getent group "$SOCK_GID" | cut -d: -f1)"
if [ -z "$SOCK_GROEP" ]; then
SOCK_GROEP=dockersock
groupadd --gid "$SOCK_GID" "$SOCK_GROEP" 2>/dev/null || true
fi
usermod -aG "$SOCK_GROEP" "$GEBRUIKER" 2>/dev/null \
|| log "Kon $GEBRUIKER niet in groep $SOCK_GROEP zetten."
fi
else
log "Geen docker-socket op $SOCK; Server Up kan straks niets starten."
fi
# ── Afzakken ─────────────────────────────────────────────────────────────────
# chown → eigenaarschap meenemen bij het verhuizen van mappen en het
# terugzetten van backups
# dac_override, fowner → appdata lezen die van een andere gebruiker is
#
# Alle drie zitten al in de standaardset van Docker; er komt hier dus geen
# enkel recht bij dat de container niet al had. Wat weggaat is de rest van root.
#
# Elke capability krijgt zijn eigen teken: setpriv leest "+a,b" niet als "+a,+b"
# maar weigert het met "bad capability string".
CAPS="+chown,+dac_override,+fowner"
if ! command -v setpriv >/dev/null 2>&1; then
log "setpriv ontbreekt in dit image; ik draai als root verder."
exec "$@"
fi
log "Server Up draait als $GEBRUIKER ($SU_UID:$SU_GID)."
export HOME=/data
exec setpriv --reuid "$SU_UID" --regid "$SU_GID" --init-groups \
--inh-caps "$CAPS" --ambient-caps "$CAPS" "$@"