Container nicht als root betreiben - USER im Dockerfile setzen
Container nicht als root betreiben - USER im Dockerfile setzen
Standardmäßig laufen Container-Prozesse als root (UID 0) — das ist unnötig und vergößert die Angriffsfläche erheblich.
Das Problem
docker run nginx id # uid=0(root) gid=0(root)
Ein Prozess als root im Container bedeutet: Wenn der Prozess kompromittiert wird, hat der Angreifer root-Rechte innerhalb des Containers. Je nach Setup (Docker-Socket, falsch konfigurierte Volumes) kann das auf den Host eskalieren.
USER im Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# Benutzer erstellen (Alpine)
RUN addgroup -g 1000 -S app && \
adduser -u 1000 -S app -G app
# Dateien dem neuen User übergeben
RUN chown -R app:app /app
# Ab hier als app-User
USER app
EXPOSE 3000
CMD ["node", "server.js"]
Debian/Ubuntu-Basis:
RUN groupadd -g 1000 app && \
useradd -u 1000 -g app -s /bin/sh -m app
USER app
Direkter UID/GID (ohne Named User):
USER 1000:1000
Volume-Permission-Problem
Das häufigste Problem beim Non-Root-Betrieb: gemountete Host-Verzeichnisse gehören root oder einem anderen User.
# Host-Verzeichnis erstellen und korrekt berechtigen
mkdir -p ./data
sudo chown 1000:1000 ./data
Oder im Dockerfile den Ordner anlegen (bevor USER gesetzt wird):
RUN mkdir -p /app/data && chown -R app:app /app/data
USER app
--user Flag zur Laufzeit
docker run --user 1000:1000 myimage
docker run --user app myimage
# In Compose
services:
app:
image: myimage
user: "1000:1000"
Überschreibt den im Dockerfile gesetzten USER.
Welche UID wählen?
- 1000: Typische UID des ersten Nicht-Root-Users auf Linux-Systemen
- Nicht 0: Niemals root
- Nicht < 100: Systembenutzer-Bereich vermeiden
- Konsistent: Gleiche UID im Container und auf dem Host (für Volume-Permissions)
Root nur für Setup, dann wechseln
Manche Operationen beim Start brauchen root (Port < 1024 binden, bestimmte Kernel-Features). Pattern: als root starten, dann zu unprivilegiertem User wechseln:
# Alles als root installieren
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
# Dann auf unprivilegierten User wechseln
RUN chown -R nginx:nginx /var/cache/nginx /var/run /var/log/nginx
USER nginx
Privilegierte Ports ohne root
Ports unter 1024 brauchen normalerweise root. Alternativen:
# Capability hinzufügen statt root
docker run --cap-add NET_BIND_SERVICE --user 1000 myapp
Oder die App intern auf Port 3000 lauschen lassen und einen Reverse Proxy auf Port 80/443 davor schalten — die bessere Lösung.
Prüfen ob Non-Root funktioniert
docker run myimage id
docker run myimage whoami
docker run myimage ls -la /app # Dateieigentümer prüfen
Non-Root-Container sind in fast allen Fällen einfach umzusetzen. Der Aufwand ist gering, der Sicherheitsgewinn real.