From 0acb1b6b814eb29c30b50cf52769ad0419f49a93 Mon Sep 17 00:00:00 2001 From: Thomas Stallinger Date: Mon, 31 Aug 2026 09:56:15 +0200 Subject: [PATCH] feat(golden-images): unauthentifizierte Hosting-Route fuer Golden Images Analog zur bestehenden /installers/fedora-workstation/ks.cfg-Route: GET /golden-images/{filename} liefert eine Datei aus data/golden-images/ (Env-Override TUXFLOTTE_GOLDEN_IMAGES_DIR), ohne Auth-Token - das Zielgeraet hat beim Laden des Golden Image in backend_launch() noch keins. Kein personalisierter Inhalt (anders als die ISO-Build-Downloads), deshalb bewusst keine Authentifizierung noetig. Path-Traversal ueber den Dateinamen wird per Path(...).name-Vergleich abgelehnt (400). Vorbereitung fuer ADR-0024 Phase 3 (backends/mint-image/backend.sh GOLDEN_IMAGE_URL zeigt als naechstes hierher). Co-Authored-By: Claude Sonnet 5 --- app.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/app.py b/app.py index 19990a3..fd86e38 100644 --- a/app.py +++ b/app.py @@ -15,7 +15,7 @@ from uuid import UUID, uuid4 import psycopg from psycopg.types.json import Jsonb -from fastapi import FastAPI, Header, Request +from fastapi import FastAPI, Header, HTTPException, Request from pydantic import BaseModel from fastapi.responses import FileResponse @@ -54,6 +54,12 @@ MINT_ISO_PATH = str(Path(os.environ.get("TUXFLOTTE_MINT_ISO_PATH", "data/upstrea # zum Subprocess-cwd (TUXFLOTTE_INSTALLER_DIR) interpretiert, nicht relativ # zum eigenen Arbeitsverzeichnis. ISO_BUILD_OUTPUT_DIR = Path(os.environ.get("TUXFLOTTE_ISO_BUILD_OUTPUT_DIR", "data/iso-builds")).resolve() +# Golden Images (ADR-0024): bewusst unauthentifiziert, analog zu +# /installers/fedora-workstation/ks.cfg - werden von backend_launch() +# per curl geladen, bevor das Zielgeraet irgendein Token besitzt. Kein +# personalisierter/kundenspezifischer Inhalt (anders als ISO-Builds oben), +# nur ein generisches Basis-Root-Dateisystem pro Distribution. +GOLDEN_IMAGES_DIR = Path(os.environ.get("TUXFLOTTE_GOLDEN_IMAGES_DIR", "data/golden-images")).resolve() ISO_BUILD_TIMEOUT_SECONDS = 1800 # ISO-Ablauf nach 7 Tagen (Migration 0021): ergaenzt die bestehende # "neuer Build ersetzt alten"-Aufraeumung um eine reine Zeitdimension. @@ -2577,6 +2583,22 @@ def get_fedora_kickstart(): ) +@app.get("/golden-images/{filename}") +def get_golden_image(filename: str): + # Path-Traversal-Schutz: Path(...).name kappt jeden "../"-Anteil, der + # Vergleich mit dem Original-Parameter erkennt den Versuch und lehnt ihn + # ab, statt ihn still auf einen anderen Dateinamen umzubiegen. + safe_name = Path(filename).name + if safe_name != filename: + raise HTTPException(status_code=400, detail="invalid_filename") + + file_path = GOLDEN_IMAGES_DIR / safe_name + if not file_path.is_file(): + raise HTTPException(status_code=404, detail="not_found") + + return FileResponse(file_path, media_type="application/zstd") + + @app.post("/api/v1/agent/bootstrap") def agent_bootstrap(payload: AgentBootstrapRequest): agent_secret = secrets.token_urlsafe(32)