Docker-Container-Security: Images, Runtime, Secrets
OWASP
0x00
Security · Docker · Container · DevSecOps
Docker-Container-Security: Images, Runtime, Secrets
Vom Root-Container zur gehärteten Produktionsumgebung

Container teilen sich den Kernel des Hosts und sind deshalb kein automatischer Sicherheitsgewinn gegenüber klassischen Servern. Dieser Artikel zeigt, wie minimale Base-Images, Non-Root-User, automatisiertes Vulnerability-Scanning in der CI-Pipeline, sichere Secrets-Verwaltung ohne Image-Layer-Leaks und eine gehärtete Runtime mit Read-Only-Filesystem und reduzierten Linux-Capabilities Docker-Deployments für Magento- und PHP-Projekte spürbar sicherer machen.

17 Min. Lesezeit Trivy · BuildKit Secrets · Capabilities Docker · Kubernetes · Magento 2.4.8

1. Warum Container-Security anders ist als klassische Server-Security

Ein weit verbreiteter Irrglaube lautet, Container seien von Natur aus isoliert wie eine virtuelle Maschine. Tatsächlich teilen sich alle Container auf einem Host denselben Linux-Kernel - die Isolation entsteht über Namespaces und Cgroups, nicht über eine eigene Hardware-Virtualisierung. Ein Kernel-Exploit oder eine fehlkonfigurierte Capability kann deshalb potenziell aus dem Container ausbrechen und den Host oder andere Container kompromittieren. Diese geteilte Angriffsfläche unterscheidet Container-Security fundamental von der klassischen Server-Härtung, bei der jede VM ihren eigenen Kernel besitzt.

Für Magento- und PHP-Deployments bedeutet das: Die Sicherheit eines Containers hängt nicht nur vom Anwendungscode ab, sondern gleichermaßen vom Base-Image, der Build-Pipeline und der Runtime-Konfiguration. Ein produktiver php-fpm-Container, der als Root läuft, mit einem veralteten Debian-Base-Image und offenen Capabilities, ist selbst bei fehlerfreiem Anwendungscode ein erhebliches Risiko. Die vier Ebenen Image, Build, Secrets und Runtime müssen deshalb einzeln betrachtet und gehärtet werden, statt sich auf die Annahme zu verlassen, "Container sind ohnehin isoliert".

Der CIS Docker Benchmark und die OWASP Docker Security Cheat Sheet fassen diese Ebenen strukturiert zusammen und dienen als Referenz für automatisierte Audits, etwa mit Tools wie docker-bench-security. Wer diese Checklisten einmalig manuell abarbeitet statt sie in die CI-Pipeline zu integrieren, verliert den Schutz spätestens beim nächsten Base-Image-Update.

2. Minimale Base-Images: Alpine, Distroless und Multi-Stage-Builds

Jedes zusätzliche Paket in einem Base-Image ist potenzielle Angriffsfläche: eine ungenutzte Shell, ein Paketmanager, veraltete Bibliotheken mit bekannten CVEs. Ein vollwertiges ubuntu- oder debian-Image bringt hunderte Pakete mit, von denen eine Web-Anwendung meist nur eine Handvoll tatsächlich braucht. alpine-basierte Images reduzieren die Angriffsfläche auf wenige Megabyte, da sie musl libc und BusyBox statt eines vollständigen GNU-Userlands verwenden. Für PHP-Anwendungen mit vielen Compiled Extensions ist Alpine wegen der abweichenden libc manchmal aufwendiger zu bauen, bietet aber die kleinste praktikable Angriffsfläche.

Distroless-Images von Google gehen noch weiter: Sie enthalten ausschließlich die Anwendung und ihre Laufzeitabhängigkeiten, ganz ohne Shell, Paketmanager oder Coreutils. Ein Angreifer, der Remote Code Execution erreicht, findet in einem Distroless-Container keine sh oder curl vor, um Folgeaktionen wie das Nachladen weiterer Payloads auszuführen. Der Nachteil: Debugging im laufenden Container ist praktisch unmöglich, weshalb Distroless meist nur für den finalen Produktions-Layer sinnvoll ist.

Multi-Stage-Builds sind der Schlüssel, um beide Ansätze praktikabel zu machen: Composer-Installation, Asset-Kompilierung und Build-Werkzeuge laufen in einer Build-Stage mit vollem Toolset, während nur die fertigen Artefakte in ein minimales Runtime-Image kopiert werden. So landen Build-Abhängigkeiten wie git, Compiler oder Composer selbst niemals im finalen Produktions-Image.


# Dockerfile: hardened multi-stage build for a PHP/Magento application
# Stage 1: build stage with full toolset, never shipped to production
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
# Install dependencies without dev packages and without running scripts yet
RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist

FROM php:8.4-fpm-alpine AS app
WORKDIR /var/www/html

# Install only the runtime extensions actually required, then remove build tools
RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS icu-dev libzip-dev \
    && docker-php-ext-install intl pdo_mysql opcache \
    && apk del .build-deps

COPY --from=vendor /app/vendor ./vendor
COPY . .
RUN composer dump-autoload --optimize --no-dev

# Create a dedicated non-root user instead of running as root
RUN addgroup -g 1000 appuser \
    && adduser -D -u 1000 -G appuser appuser \
    && chown -R appuser:appuser /var/www/html

USER appuser
EXPOSE 9000
CMD ["php-fpm", "-F"]

3. Niemals als Root: USER-Direktive und Rootless-Runtimes

Ohne explizite USER-Direktive läuft ein Container-Prozess standardmäßig als Root, mit UID 0. Das ist innerhalb des Container-Namespace zunächst "nur" der Root des Containers, doch bei einem Kernel-Bug oder einer fehlerhaft konfigurierten Volume-Mount kann UID 0 im Container mit UID 0 auf dem Host zusammenfallen. Ein Angreifer, der über eine Anwendungsschwachstelle Code-Ausführung erreicht, hat als Root im Container deutlich mehr Möglichkeiten für Privilege Escalation als ein Prozess, der von vornherein mit einer unprivilegierten UID läuft.

Die Lösung ist unspektakulär, aber wirksam: Im Dockerfile einen dedizierten Nutzer mit fester UID/GID anlegen, alle benötigten Dateien diesem Nutzer zuweisen und vor dem CMD/ENTRYPOINT per USER-Direktive auf ihn wechseln. Wichtig ist, die UID explizit zu setzen (etwa 1000) statt sie dem System zu überlassen, damit sie in Kubernetes-securityContext-Regeln oder Volume-Permissions vorhersehbar bleibt. Ports unter 1024 lassen sich als Non-Root-Prozess nicht binden, weshalb produktive PHP-FPM- oder Node-Container meist auf Ports wie 8080 oder 9000 lauschen und ein vorgeschalteter Reverse Proxy die Port-Terminierung übernimmt.

Auf Host-Ebene ergänzt Rootless Docker oder Podman diesen Schutz: Der Container-Daemon selbst läuft dabei ohne Root-Rechte und mappt Container-UIDs über User-Namespaces auf unprivilegierte Host-UIDs. Selbst wenn ein Angreifer im Container Root wird, landet er auf dem Host in einem unprivilegierten UID-Bereich ohne Zugriff auf kritische Systemressourcen. Podman unterstützt Rootless-Betrieb nativ, für Docker ist seit Version 20.10 ein Rootless-Mode offiziell verfügbar.

4. Image-Scanning in der CI-Pipeline mit Trivy und Grype

Selbst ein sorgfältig gebautes Image erbt Schwachstellen aus seinen Basis-Layern und installierten Paketen - neue CVEs werden täglich veröffentlicht, auch für Pakete, die zum Build-Zeitpunkt als sicher galten. Trivy (Aqua Security) und Grype (Anchore) sind Open-Source-Scanner, die ein fertiges Image gegen aktuelle CVE-Datenbanken prüfen und dabei sowohl OS-Pakete als auch Anwendungsabhängigkeiten wie Composer- oder npm-Pakete erfassen. Beide Tools lassen sich als einfacher CLI-Aufruf in jede CI-Pipeline integrieren, ohne dass ein separater Server-Dienst nötig ist.

Entscheidend ist, das Scanning nicht nur zu protokollieren, sondern den Build bei kritischen Funden aktiv fehlschlagen zu lassen. Trivy unterstützt dafür einen --exit-code-Parameter in Kombination mit --severity, sodass nur HIGH- und CRITICAL-Befunde den Pipeline-Abbruch auslösen, während niedrigere Schweregrade lediglich dokumentiert werden. Diese Abstufung verhindert "Alert Fatigue" durch hunderte Low-Severity-Meldungen und lenkt die Aufmerksamkeit auf tatsächlich ausnutzbare Schwachstellen.

Ein oft übersehener Punkt: Scanning muss wiederholt stattfinden, nicht nur beim Build. Ein Image, das heute sauber durch den Scan läuft, kann in vier Wochen durch neu veröffentlichte CVEs als verwundbar gelten, obwohl sich am Image selbst nichts geändert hat. Registries wie Harbor oder AWS ECR bieten deshalb kontinuierliches Re-Scanning bereits gepushter Images an, und Dependabot-ähnliche Tools können automatisch Pull Requests für aktualisierte Base-Images erstellen.


# CI pipeline step: scan an image and fail the build on HIGH/CRITICAL findings

# Trivy: scan the built image, exit with code 1 on high or critical CVEs
trivy image \
  --severity HIGH,CRITICAL \
  --exit-code 1 \
  --ignore-unfixed \
  --format table \
  registry.example.com/mironsoft/magento-app:${CI_COMMIT_SHA}

# Grype: equivalent scan with a fail-build threshold
grype registry.example.com/mironsoft/magento-app:${CI_COMMIT_SHA} \
  --fail-on high \
  --only-fixed

# Export a machine-readable report for later triage and auditing
trivy image \
  --format json \
  --output trivy-report.json \
  registry.example.com/mironsoft/magento-app:${CI_COMMIT_SHA}

5. Warum Secrets in Image-Layern nie wirklich weg sind

Ein klassischer Fehler: Ein Datenbank-Passwort oder API-Token wird per ENV-Direktive oder als ARG in einem RUN-Befehl übergeben, etwa um während des Builds Composer-Pakete aus einem privaten Repository zu laden. Selbst wenn eine spätere Anweisung die Datei mit dem Secret wieder löscht, bleibt der Wert im entsprechenden Image-Layer für immer erhalten, weil Docker-Layer unveränderliche Diffs sind. Jeder, der Zugriff auf das Image hat, kann den Wert mit einem einfachen Befehl extrahieren, unabhängig davon, ob die Datei im finalen Dateisystem noch existiert.

docker history --no-trunc zeigt jeden Build-Layer inklusive der ausgeführten Befehle im Klartext, und docker save gefolgt vom Entpacken des Tar-Archivs legt jeden einzelnen Layer offen - inklusive gelöschter Dateien in vorherigen Layern. Ein per ARG DB_PASSWORD übergebenes Secret landet damit faktisch im Image, selbst wenn es im laufenden Container nie als Environment-Variable sichtbar ist. Dieses Risiko betrifft nicht nur öffentliche Registries: Auch ein intern gehostetes Image kann von jedem eingesehen werden, der Pull-Rechte auf die Registry hat, was in größeren Teams schnell eine breite Angriffsfläche ergibt.

Die praktische Konsequenz: Secrets dürfen niemals über ENV, ARG oder eine im Image verbleibende Datei in den Build- oder Laufzeit-Kontext gelangen. Stattdessen braucht es Mechanismen, die ein Secret ausschließlich temporär während des Builds oder erst beim Container-Start bereitstellen, ohne es in einem persistenten Layer zu hinterlassen.

6. BuildKit-Secrets und sichere Runtime-Secret-Injection

Docker BuildKit löst das Build-Zeit-Problem mit dedizierten Secret-Mounts. Über --secret id=npmrc,src=./secret_file beim docker build-Aufruf und RUN --mount=type=secret,id=npmrc im Dockerfile wird das Secret nur für die Dauer dieses einzelnen RUN-Befehls in einem temporären, nicht-persistenten Dateisystem gemountet. Es landet weder in der Build-History noch in einem Image-Layer, weil BuildKit den Mount-Inhalt explizit vom Layer-Diff ausschließt. Das ist der korrekte Weg, um etwa private Composer-Repository-Zugangsdaten während composer install bereitzustellen.

Für Laufzeit-Secrets, also Datenbank-Zugangsdaten, API-Keys oder JWT-Signing-Keys, gilt eine andere Regel: Sie gehören grundsätzlich nicht ins Image, sondern werden erst beim Container-Start injiziert. Docker Swarm und Kubernetes bieten dafür native Secret-Objekte, die als temporäre, im RAM gehaltene Dateien in den Container gemountet werden, typischerweise unter /run/secrets/. In produktiven Kubernetes-Clustern ergänzen externe Secret-Manager wie HashiCorp Vault oder AWS Secrets Manager diesen Mechanismus um Rotation, Audit-Logging und feingranulare Zugriffskontrolle.

Eine praktikable Faustregel für Teams ohne vollständige Secret-Manager-Infrastruktur: Environment-Variablen, die zur Laufzeit über die Orchestrierungsplattform (nicht über das Image) gesetzt werden, sind akzeptabel, solange sie nicht in Logs oder Fehlerausgaben landen. Niemals akzeptabel ist ein Secret, das als ENV-Zeile im Dockerfile steht oder in eine committete .env-Datei eingebacken wird, die dann per COPY ins Image wandert.


# BuildKit secret mount: use a credential at build time without leaking it into a layer

# Enable BuildKit explicitly for this build
export DOCKER_BUILDKIT=1

# Pass the secret file reference on the CLI, it is never written into the build context
docker build \
  --secret id=composer_auth,src=./auth.json \
  -t registry.example.com/mironsoft/magento-app:latest .

# Dockerfile excerpt: mount the secret only for the duration of this RUN instruction
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./

# The secret is mounted at /run/secrets/composer_auth and never persisted in a layer
RUN --mount=type=secret,id=composer_auth,target=/root/.composer/auth.json \
    composer install --no-dev --no-scripts --prefer-dist

7. Read-Only-Root-Filesystem und tmpfs für Schreibzugriffe

Die meisten produktiven Anwendungscontainer müssen nach dem Deployment keine Dateien im Container-Dateisystem verändern - Konfiguration kommt über Environment-Variablen oder gemountete ConfigMaps, Code wird beim Build eingebrannt. Ein Container, der zur Laufzeit als schreibgeschützt (read_only: true bzw. --read-only) läuft, verhindert damit eine ganze Klasse von Post-Exploitation-Techniken: Ein Angreifer, der über eine Anwendungslücke Code einschleusen will, kann keine Webshell auf die Festplatte schreiben, keine Binärdatei nachladen und keine Log-Dateien manipulieren, um Spuren zu verwischen.

In der Praxis benötigen einzelne Verzeichnisse trotzdem Schreibzugriff, etwa PHP-Sessions, temporäre Upload-Dateien oder Cache-Verzeichnisse wie Magentos var/. Diese Pfade werden gezielt als tmpfs-Mounts bereitgestellt: ein In-Memory-Dateisystem, das beim Container-Neustart automatisch geleert wird und niemals auf die persistente Festplatte des Hosts durchschlägt. Diese Kombination, schreibgeschütztes Root-Filesystem plus gezielte tmpfs-Ausnahmen, ist die sicherste praktikable Konfiguration für zustandslose Anwendungscontainer und wird sowohl von Docker Compose als auch von Kubernetes-securityContext-Regeln nativ unterstützt.

8. Linux-Capabilities droppen und no-new-privileges erzwingen

Linux-Capabilities unterteilen die traditionell binäre Root/Non-Root-Unterscheidung in granulare Rechte wie CAP_NET_BIND_SERVICE (Ports unter 1024 binden), CAP_SYS_ADMIN (weitreichende Systemadministration) oder CAP_CHOWN (Dateibesitz ändern). Docker vergibt standardmäßig ein Set von rund 14 Capabilities an jeden Container, von denen die allermeisten Web-Anwendungen keine einzige tatsächlich benötigen. Die sichere Grundregel lautet deshalb: Alle Capabilities pauschal droppen (cap_drop: ALL) und nur die explizit benötigten wieder hinzufügen (cap_add), statt sich auf die Docker-Defaults zu verlassen.

Ergänzend verhindert no-new-privileges: true (bzw. security_opt: no-new-privileges:true), dass ein Prozess im Container über setuid-Binaries oder ähnliche Mechanismen zur Laufzeit zusätzliche Rechte erlangt, selbst wenn eine ausnutzbare setuid-Datei im Image vorhanden wäre. Diese Einstellung ist ein Kernel-Flag und wirkt unabhängig von der Capability-Konfiguration als zusätzliche Verteidigungsschicht. In Kombination mit einem Read-Only-Filesystem, einem Non-Root-User und minimalen Capabilities entsteht ein Container, der selbst bei einer erfolgreichen Anwendungs-Kompromittierung nur einen sehr eingeschränkten Bewegungsspielraum für den Angreifer bietet.


# docker-compose.yaml: hardened runtime configuration for a production PHP service
services:
  php-fpm:
    image: registry.example.com/mironsoft/magento-app:latest
    read_only: true
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    tmpfs:
      - /var/www/html/var/cache:size=256m,mode=1777
      - /var/www/html/var/session:size=64m,mode=1777
      - /tmp:size=64m,mode=1777
    environment:
      - APP_ENV=production
    networks:
      - internal
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 512M

{
  "SchemaVersion": 2,
  "ArtifactName": "registry.example.com/mironsoft/magento-app:1.4.2",
  "ArtifactType": "container_image",
  "Results": [
    {
      "Target": "magento-app (alpine 3.19.1)",
      "Class": "os-pkgs",
      "Type": "alpine",
      "Vulnerabilities": [
        {
          "VulnerabilityID": "CVE-2024-9143",
          "PkgName": "openssl",
          "InstalledVersion": "3.1.4-r5",
          "FixedVersion": "3.1.5-r0",
          "Severity": "HIGH",
          "Title": "openssl: Low-level GF(2^m) elliptic curve API out-of-bounds write",
          "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2024-9143"
        },
        {
          "VulnerabilityID": "CVE-2023-45853",
          "PkgName": "zlib",
          "InstalledVersion": "1.3-r0",
          "FixedVersion": "1.3.1-r0",
          "Severity": "CRITICAL",
          "Title": "zlib: integer overflow in MiniZip leading to heap buffer overflow",
          "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2023-45853"
        }
      ]
    }
  ]
}

9. Unsicher vs. sicher: Docker-Patterns im Vergleich

Die folgenden Muster tauchen in unzähligen produktiven Docker-Setups auf, obwohl jedes einzelne davon einen bekannten, gut dokumentierten Härtungsschritt hat. Die Tabelle stellt das jeweils unsichere Standardverhalten der sicheren Alternative gegenüber.

Bereich Unsicheres Pattern Sicheres Pattern
Base-Image Vollwertiges debian/ubuntu ohne Version-Pinning alpine oder distroless mit fixem Tag/Digest
Prozess-User Kein USER, Prozess läuft als Root (UID 0) USER mit fester Non-Root-UID im Dockerfile
Secrets ARG/ENV mit Zugangsdaten im Dockerfile BuildKit --mount=type=secret, Runtime-Injection
Dateisystem Vollständig beschreibbares Root-Filesystem read_only: true + gezielte tmpfs-Mounts
Capabilities Docker-Default-Set von ~14 Capabilities aktiv cap_drop: ALL, nur benötigte cap_add
Vulnerability-Checks Kein Scanning oder nur manuell bei Bedarf Trivy/Grype in CI mit Fail-on-Critical

Auffällig ist, dass keines dieser sicheren Patterns nennenswerten Mehraufwand im laufenden Betrieb bedeutet - der gesamte Aufwand liegt in der einmaligen Konfiguration von Dockerfile, CI-Pipeline und Compose- bzw. Kubernetes-Manifest. Wer diese sechs Punkte als Checkliste in ein Dockerfile-Template und eine CI-Pipeline-Vorlage gießt, erhält die Härtung für jedes neue Projekt automatisch.

Mironsoft

Docker- und Container-Security für Magento- und PHP-Projekte

Container-Setup professionell härten lassen?

Wir prüfen eure Dockerfiles, CI-Pipelines und Compose- bzw. Kubernetes-Manifeste auf Base-Images, Root-Prozesse, Secrets-Handling und Runtime-Härtung und setzen die Optimierungen strukturiert um.

Container-Security-Audit

Dockerfile-Review, CIS-Benchmark-Check, Vulnerability-Scan-Setup

Secrets-Management

BuildKit-Secrets, Vault-Integration, Rotation ohne Downtime

CI/CD-Hardening

Trivy/Grype-Integration mit Fail-on-Critical in eurer Pipeline

10. Zusammenfassung

Docker-Container-Security ist kein einzelner Schalter, sondern die konsequente Absicherung von vier zusammenhängenden Ebenen: Ein minimales Base-Image (Alpine oder Distroless) reduziert die Angriffsfläche von vornherein, ein expliziter Non-Root-User verhindert, dass eine Anwendungslücke direkt zu Root-Rechten im Container führt, automatisiertes Scanning mit Trivy oder Grype in der CI-Pipeline fängt bekannte CVEs vor dem Deployment ab, und eine gehärtete Runtime-Konfiguration mit Read-Only-Filesystem und minimalen Linux-Capabilities begrenzt den Schaden, falls eine Schwachstelle trotzdem ausgenutzt wird.

Der wichtigste Denkfehler, den es zu vermeiden gilt: Secrets, die einmal in einem Image-Layer gelandet sind, lassen sich nicht nachträglich sicher entfernen - der einzige verlässliche Schutz ist, sie von Anfang an über BuildKit-Secret-Mounts oder Runtime-Injection niemals in einen Layer gelangen zu lassen. Wer diese fünf Bausteine, minimales Image, Non-Root-User, kontinuierliches Scanning, layer-freie Secrets und Runtime-Härtung, in ein wiederverwendbares Dockerfile- und Pipeline-Template gießt, erreicht ein solides Sicherheitsniveau für jedes neue Projekt, ohne bei jedem Deployment neu darüber nachzudenken.

Docker-Container-Security - Das Wichtigste auf einen Blick

Minimale Images

Alpine oder Distroless statt vollwertiger Distributionen, Build-Tools über Multi-Stage-Builds aus dem Runtime-Image fernhalten.

Non-Root-User

Feste UID/GID per USER-Direktive, Rootless Docker/Podman auf Host-Ebene als zusätzliche Schutzschicht.

Scanning & Secrets

Trivy/Grype mit Fail-on-Critical in der CI, Secrets ausschließlich über BuildKit-Mounts oder Runtime-Injection.

Runtime-Härtung

read_only: true mit tmpfs-Ausnahmen, cap_drop: ALL und no-new-privileges:true.

11. FAQ: Docker-Container-Security

1Warum sind Container nicht automatisch sicher isoliert?
Container teilen sich den Kernel des Hosts und trennen Prozesse über Namespaces und Cgroups, nicht über eine eigene Hardware-Virtualisierung. Ein Kernel-Exploit kann deshalb potenziell aus dem Container ausbrechen.
2Was ist der Vorteil von Alpine- oder Distroless-Images?
Deutlich weniger Pakete, teils ganz ohne Shell oder Paketmanager. Das reduziert sowohl die Zahl potenzieller CVEs als auch die Werkzeuge für einen Angreifer nach Code-Ausführung.
3Wieso soll ein Container niemals als Root laufen?
UID 0 im Container kann bei Kernel-Bugs oder fehlerhafter Volume-Konfiguration zu Root-Rechten auf dem Host führen. Eine feste Non-Root-UID per USER-Direktive reduziert dieses Risiko strukturell.
4Was prüfen Tools wie Trivy und Grype konkret?
Sie gleichen OS-Pakete und Anwendungsabhängigkeiten gegen aktuelle CVE-Datenbanken ab und melden Schweregrad sowie, falls vorhanden, die Version mit dem Fix.
5Warum bleibt ein per ENV gesetztes Secret im Image erhalten?
Docker-Layer sind unveränderliche Diffs. Ein Wert bleibt im Layer bestehen, selbst wenn eine spätere Anweisung die zugehörige Datei löscht, und lässt sich mit docker history extrahieren.
6Wie funktionieren BuildKit-Secrets im Unterschied zu ARG oder ENV?
BuildKit mountet ein Secret nur für die Dauer eines einzelnen RUN-Befehls in ein temporäres Dateisystem. Der Wert landet weder in der Build-History noch in einem Image-Layer.
7Was bringt ein Read-Only-Root-Filesystem konkret?
Verhindert, dass ein Angreifer nach Code-Ausführung eine Webshell speichert oder Binärdateien nachlädt. Benötigte Schreibpfade werden gezielt über tmpfs-Mounts bereitgestellt.
8Was sind Linux-Capabilities und warum sollte man sie droppen?
Sie unterteilen Root-Rechte in granulare Einzelrechte wie CAP_NET_BIND_SERVICE. Docker vergibt standardmäßig rund 14 Capabilities, meist ungenutzt. cap_drop: ALL plus gezieltes cap_add minimiert die Rechte.
9Was bewirkt die Option no-new-privileges?
Verhindert, dass ein Prozess über setuid-Binaries zur Laufzeit zusätzliche Rechte erlangt. Ein Kernel-Flag, das unabhängig von der Capability-Konfiguration wirkt.
10Reicht es, das Image-Scanning einmalig beim Build durchzuführen?
Nein. Neue CVEs erscheinen fortlaufend, sodass ein heute sauberes Image in wenigen Wochen verwundbar sein kann. Kontinuierliches Re-Scanning bereits gepushter Images in der Registry ist notwendig.