observability: run as container root 0:0, not 1000:1000

Measured the rootless mapping: container root IS the invoking user
(dank, owner of the /opt data dirs); the images' default users (loki
10001, prometheus nobody, grafana 472) map to subuids that own nothing.
1000:1000 was the wrong direction.
This commit is contained in:
Frank committed 2026-08-22 03:45:06 -07:00
1 parent 11a713e05d
commit 816986139f
2 files changed
+19 -15

No files matched your search

+12 -9
View File
@@ -103,9 +103,10 @@ services:
image: docker.io/prom/prometheus:latest image: docker.io/prom/prometheus:latest
container_name: prometheus container_name: prometheus
restart: unless-stopped restart: unless-stopped
# Rootless: container uid 1000 maps to the invoking user, so the # Rootless: container root maps to the invoking user (dank), which
# container can write its /opt/prometheus/data bind mount. # owns /opt/prometheus/data. The image's default user (nobody) maps to
user: "1000:1000" # a subuid that cannot write it.
user: "0:0"
command: command:
- --config.file=/etc/prometheus/prometheus.yml - --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus - --storage.tsdb.path=/prometheus
@@ -126,9 +127,10 @@ services:
image: docker.io/grafana/grafana:latest image: docker.io/grafana/grafana:latest
container_name: grafana container_name: grafana
restart: unless-stopped restart: unless-stopped
# Rootless: container uid 1000 maps to the invoking user, so the # Rootless: container root maps to the invoking user (dank), which
# container can write its /opt/grafana/data bind mount. # owns /opt/grafana/data. The image's default user (472) maps to a
user: "1000:1000" # subuid that cannot write it.
user: "0:0"
environment: environment:
GF_SERVER_ROOT_URL: "https://grafana.franksdank.cloud" GF_SERVER_ROOT_URL: "https://grafana.franksdank.cloud"
GF_SECURITY_ADMIN_USER: "${GRAFANA_ADMIN_USER}" GF_SECURITY_ADMIN_USER: "${GRAFANA_ADMIN_USER}"
@@ -150,9 +152,10 @@ services:
image: docker.io/grafana/loki:latest image: docker.io/grafana/loki:latest
container_name: loki container_name: loki
restart: unless-stopped restart: unless-stopped
# Rootless: container uid 1000 maps to the invoking user, so the # Rootless: container root maps to the invoking user (dank), which
# container can write its /opt/loki/data bind mount. # owns /opt/loki/data. The image's default user (10001) maps to a
user: "1000:1000" # subuid that cannot write it.
user: "0:0"
command: ["-config.file=/etc/loki/loki-config.yaml"] command: ["-config.file=/etc/loki/loki-config.yaml"]
ports: ports:
- "3100:3100" - "3100:3100"
+7 -6
View File
@@ -119,10 +119,11 @@ CADDYFILE="$REPO_ROOT/dankclaw/Caddyfile"
! grep -nE '^\s*-\s*"?http' "$REPO_ROOT/shared/prometheus/prometheus.yml" ! grep -nE '^\s*-\s*"?http' "$REPO_ROOT/shared/prometheus/prometheus.yml"
} }
@test "observability containers run as the host user (rootless uid mapping)" { @test "observability containers run as container root (rootless = host user)" {
# Rootless podman maps container uid 1000 to the invoking user, so # In rootless podman, container root maps to the invoking user (dank),
# 1000:1000 lets these containers write their /opt data dirs. Container # which owns the /opt data dirs. The images' default users (loki 10001,
# root would map to a subuid that owns nothing under /opt. # prometheus nobody, grafana 472) map to subuids that own nothing under
# /opt and cannot write the data dirs.
local compose="$REPO_ROOT/dankclaw/compose.yaml" local compose="$REPO_ROOT/dankclaw/compose.yaml"
local svc block local svc block
for svc in prometheus loki grafana; do for svc in prometheus loki grafana; do
@@ -130,8 +131,8 @@ CADDYFILE="$REPO_ROOT/dankclaw/Caddyfile"
$0 ~ s { inblk = 1; next } $0 ~ s { inblk = 1; next }
inblk && /^ [a-z]/ { inblk = 0 } inblk && /^ [a-z]/ { inblk = 0 }
inblk' "$compose") inblk' "$compose")
echo "$block" | grep -q 'user: "1000:1000"' || { echo "$block" | grep -q 'user: "0:0"' || {
echo "service $svc does not run as user 1000:1000"; return 1; echo "service $svc does not run as user 0:0"; return 1;
} }
done done
} }