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.