Docker Security
Security ist ein wichtiges, jedoch auch schwieriges Thema. Es muss kontinuierlich geprüft und angepasst werden. Hier sind 4 "Best Practices" auf deren Grundlage aufgebaut werden können.
1. Minimale, offizielle Images verwenden​
Verwende so kleine Basis-Images wie möglich (z. B. node:alpine oder
distroless).
- Vorteil: Ein kleineres Image hat eine geringere Angriffsfläche, da unnötige Tools wie Shells, Paketmanager oder Editoren fehlen.
- Effekt: Weniger SicherheitslĂĽcken und schnellere Downloads.
- 3rd-Party Images mit Vorsicht verwenden. Natürlich könnten die Schadsoftware einschläusen!
Beispiel​
Anstatt einem ubuntu image noch node zu installieren, kann direkt das
offizielle node image verwendet werden. Diese gibt es fast fĂĽr alle
Programmiersprachen und auch Systeme wie nginx.
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
CMD ["node", "index.js"]
2. Multistage Images​
Nutze mehrere FROM-Anweisungen in einem Dockerfile, um Build-Tools vom fertigen Image zu trennen.
- Vorteil: Du installierst Compiler, Header und Caches in der ersten Stufe ("Build"), kopierst aber nur die fertigen Binärdateien in die finale, schlanke Stufe.
- Effekt: Dein produktives Image enthält keinen Quellcode oder Build-Werkzeuge, die Angreifern helfen könnten.
Beispiel​
Hier wird zuerst die Node Applikation in einem node:20 Image gebaut und dann
in ein produktives node:20-slim image kopiert. Dadurch entfallen die Build
dependencies.
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
COPY server.js ./
RUN npm install
# Stage 2: Production stage "slim!"
FROM node:20-slim
WORKDIR /app
COPY /app .
EXPOSE 3000
CMD ["npm", "start"]
3. Kein Root User verwenden​
Container laufen standardmässig als root. Erstelle stattdessen einen dedizierten
Benutzer (z. B. mit useradd) und wechsle mit USER im Dockerfile.
- Vorteil: Falls ein Angreifer eine LĂĽcke in deiner App findet, landet er in einer Umgebung mit minimalen Rechten (Least Privilege).
- Effekt: Er kann keine Systemdateien ändern und ein "Ausbruch" auf das Host-System wird massiv erschwert.
Beispiel​
Hier wird einem offiziellen Ubuntu Image ein user appuser erstellt und verwendet.
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y curl \
&& curl -fsSL https://deb.nodesource.com | bash - \
&& apt-get install -y nodejs && rm -rf /var/lib/apt/lists/*
# Eigenen Benutzer und Gruppe anlegen und verwenden
RUN adduser --system --group --home /home/appuser appuser
WORKDIR /app
RUN chown appuser:appuser /app # Rechte setzen
USER appuser # User appuser verwenden
COPY package*.json ./ # Berechtigungen geben
RUN npm install --production
COPY . .
CMD ["node", "index.js"] # App starten
4. Keine Secrets im Code​
Speichere Passwörter, API-Keys oder Zertifikate niemals im Quellcode oder direkt im Dockerfile (ENV).
- Vorteil: Secrets bleiben ausserhalb deines Git-Repositorys und der Image-Layer (wo sie mit docker history sichtbar wären).
- Lösung: Nutze Tools wie fnox, Docker Secrets zusammen mit Umgebungsvariablen, die erst zur Laufzeit sicher injiziert werden.
Beispiele​
Fnox​
fnox init
# Ein Secret verschlĂĽsselt hinzufĂĽgen (wird in fnox.toml gespeichert)
fnox set DB_PASSWORD "mein-super-geheimes-passwort"
# fnox entschlĂĽsselt DB_PASSWORD und ĂĽbergibt es an Docker
fnox exec -- docker run -d \
--name meine-app \
-e DB_PASSWORD \
mein-node-image
Locale Datei​
# Datei mit Secret erstellen, Achtung: Bash-History leeren!
echo "MY_PASSWORD=super-geheim-123" > .env.secret
# Container starten und die Datei einbinden
docker run -d \
--name meine-app \
--env-file .env.secret \
mein-node-image
Docker Secrets​
# Datei mit Secret erstellen, Achtung: Bash-History leeren!
echo "MY_PASSWORD=super-geheim-123" > .password.txt
services:
app:
image: mein-node-image
secrets:
- db_password
secrets:
db_password:
file: ./password.txt