SUSE BCI as Container Base Images¶
Einordnung ins Overtime-Projekt
Die Basis-Images für die Overtime-Backend-Services (Django, Worker-Prozesse) bestimmen einen Großteil der Angriffsfläche jedes Containers. Dieses ADR begründet die Wahl von SUSE BCI als Vertrauensbasis für den Python-Runtime-Stack.
1. Kontext & Problemstellung (Deutsch)¶
Jedes Container-Image erbt seine fundamentale Angriffsfläche direkt von seinem Basis-Image. Die in der Open-Source-Welt am häufigsten gewählten Optionen (wie python:slim, ubuntu oder alpine) werden größtenteils von Community-Volunteers gepflegt und über Docker Hub ohne kommerzielle Zusicherungen (SLAs) bereitgestellt.
Diese Intransparenz innerhalb der Software-Lieferkette (Software Supply Chain) kann erhebliches Risiko darstellen. Sicherheitsrelevante Kriterien wie die eindeutige Herkunft von Softwarepaketen (Provenance), garantierte Reaktionszeiten bei kritischen Sicherheitslücken (CVEs) sowie die Auditierbarkeit des Upstream-Herstellers müssen nachweisbar sein.
Zudem führt die Verwendung von Standard-Images oft dazu, dass unnötige Systemwerkzeuge (wie Paketmanager, Shells, Curl oder Compiler) im finalen Produktions-Image verbleiben. Diese Werkzeuge erleichtern Angreifern nach einer erfolgreichen Kompromittierung des Backends die laterale Bewegung innerhalb der Infrastruktur (Post-Exploitation). Es wird daher eine gehärtete, abgesicherte und minimalistische Image-Basis benötigt.
2. Architecture Decision Record (English)¶
ADR-002: SUSE BCI as Container Base Images¶
Status¶
Accepted
Context and Problem Statement¶
Every container image inherits its attack surface from its base. Common choices (python:slim, ubuntu:22.04, alpine) are maintained by community volunteers or Docker Hub with no enterprise SLA. The base image supply chain must be trustworthy, patchable under SLA, auditable (package provenance, CVE response times) and minimal.
Decision Drivers¶
- Predictable CVE patch SLAs.
- Minimal attack surface in the runtime image.
Scratchis not possible due to requirement of Python runtime. - Free version is available with proper versioning
Considered Options¶
- python:3.x-slim (Debian-based, Docker Hub) — Minimal, but lacks an enterprise SLA; Debian security team response time varies.
- ubuntu:22.04 LTS — Strong community and Canonical CVE SLA, but leaves a larger package footprint than needed.
- Wiz / Chainguard / Docker Secure Images — Excellent hardening, but mostly restrict real version pinning to paid tiers, only offering volatile
@latesttags publicly. - SUSE Business Container Images (BCI) — Enterprise SLA, FIPS-capable, full RPM provenance.
Decision Outcome¶
Chosen: SUSE BCI (registry.suse.com/bci/python).
We adopt a two-tier multi-stage build strategy:
python:3.14-base— Used exclusively during the builder stage (containspip, package managers, and compilation tools).python:3.14-micro— Used exclusively during the final runtime stage (stripped to the absolute minimum).
The -micro variant ships without a shell (sh/bash) and without a system package manager (zypper). This eliminates an entire class of post-exploitation lateral movement, as an attacker cannot easily run interactive terminal commands or download malicious diagnostic utilities.
SUSE guarantees commercial CVE patching updates within 72 hours of upstream disclosure. It has SLSA Level 4 and provenance is available. For this project we will just use the free MIT-licensed version though.
Consequences & Trade-offs¶
Positive Consequences¶
- Immense Attack Surface Reduction: The runtime image has no shell, making interactive
docker execsessions impossible for attackers. - Verifiable Provenance: SUSE publishes cryptographically signed RPM SBOMs, enabling vulnerability scanners (like Trivy) to resolve package-level CVEs against verified vendor feeds.
- Registry Independence: When not self-hosting the image, pulling from
registry.suse.combypasses Docker Hub rate limits and ToS changes.
Negative Consequences / Trade-offs¶
- Harder Debugging: The lack of a shell or package manager in the
-microtier means runtime debugging is intentionally obstructed. Debugging must be performed in staging using the-basetier. - Upstream Delay: SUSE BCI updates trail upstream Python point releases by approximately 1–2 weeks. This latency is monitored automatically via Renovate.
3. Multi-Stage Implementation & Code Snippet (English)¶
The following multi-stage Dockerfile template illustrates the practical application of the two-tier SUSE BCI architecture for the Django application:
ARG BUILDER_IMAGE=registry.suse.com/bci/python:3.14-base@sha256:cfe34a1d6a49d7da8c06e8173afb38fc77f23092cadfe088db17ef5a01154936
ARG RUNTIME_IMAGE=registry.suse.com/bci/python:3.14-micro@sha256:3338e229873f5d4659efa0ce04616725367c2972e03ae2cb7140af5775d939e4
# ── build ─────────────────────────────────────────────────────────────────────
FROM ${BUILDER_IMAGE} AS builder
USER root
COPY --from=ghcr.io/astral-sh/uv:0.11.21@sha256:ff07b86af50d4d9391d9daf4ff89ce427bc544f9aae87057e69a1cc0aa369946 /uv /usr/local/bin/uv
WORKDIR /app
COPY pyproject.toml uv.lock ./
# Install deps from the lock file into a fixed venv path
ENV UV_PROJECT_ENVIRONMENT=/opt/venv
ENV PATH="/opt/venv/bin:$PATH"
RUN uv sync --frozen --no-dev
COPY . .
RUN mkdir -p /app/staticfiles && \
DJANGO_SETTINGS_MODULE=config.settings.base python manage.py collectstatic --noinput
RUN mkdir -p /app/prometheus_multiproc
# ── runtime ───────────────────────────────────────────────────────────────────
FROM ${RUNTIME_IMAGE} AS runtime
COPY --chown=65532:65532 --from=builder /opt/venv /opt/venv
COPY --chown=65532:65532 --from=builder /app /app
ENV HOME=/app
ENV PATH="/opt/venv/bin:$PATH"
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PROMETHEUS_MULTIPROC_DIR=/app/prometheus_multiproc
USER 65532:65532
WORKDIR /app
EXPOSE 8000
ENTRYPOINT []
CMD ["/opt/venv/bin/gunicorn", "config.wsgi:application", "-c", "gunicorn.conf.py"]
4. Compliance Einordnung (Deutsch)¶
BSI IT-Grundschutz Compliance¶
| Standard | Kriterium / Inhalt | Wie im Projekt adressiert |
|---|---|---|
| BSI IT-Grundschutz | SYS.1.6.A6 (B): Verwendung sicherer Images | Es werden ausschließlich verifizierte Basis-Images aus der offiziellen, herstellerbetriebenen SUSE-Registry genutzt, deren Ersteller eindeutig identifizierbar ist. |
| BSI IT-Grundschutz | SYS.1.6.A12 (S): Verteilung sicherer Images | Dieses Architektur-Dokument begründet dediziert, warum registry.suse.com als vertrauenswürdige Quelle klassifiziert wurde und wie die Integrität gewahrt bleibt. |
| BSI IT-Grundschutz | SYS.1.6.A17 (S): Ausführung von Containern ohne Privilegien | Durch den Einsatz der micro-Variante enthält das Produktions-Image keinerlei administrative Systemwerkzeuge, was das Risiko einer Privilegieneskalation minimiert. Der User wird auf 65532 gesetzt und hat damit keine privilegierten Rechte. |
| BSI IT-Grundschutz | SYS.1.6.A11 (S): Nur ein Dienst pro Container | Das Image ist strikt als Applikations-Container konzipiert. Da jegliche Shells fehlen, kann der Container technisch nur die definierte Django-Anwendung ausführen. |
CIS Docker & Kubernetes Benchmark Compliance¶
| Standard | Kriterium / Inhalt | Wie im Projekt adressiert |
|---|---|---|
| CIS Docker Benchmark | Sektion 4.1: Ensure that a user for the container has been created | Das finale Runtime-Image wechselt über die Direktive USER 65532:65532 explizit auf einen unprivilegierten Standard-User, statt als Root zu laufen. |
| CIS Docker Benchmark | Sektion 4.2: Ensure that containers use only trusted base images | Die Nutzung von SUSE BCI garantiert eine geschlossene Lieferkette mit kommerziellen Patches innerhalb von 72 Stunden nach Upstream-Bekanntgabe. |
| CIS Docker Benchmark | Sektion 4.3: Ensure that unnecessary packages are not installed in the container | Die finale micro-Stufe eliminiert sämtliche für den Betrieb redundanten Pakete, Compiler, Shells (bash) und Paketmanager (zypper). |
| CIS Kubernetes Benchmark | Sektion 5.2.7: Minimize the admission of root containers | Da das Dockerfile den Non-Root-User 65532 fest vorschreibt, erfüllt der resultierende Pod nativ die Restricted-Vorgaben der K8s Pod Security Standards. |