Challenges - Reverse Proxy & TLS

Manuelle Proxy-Konfiguration, Security-Entscheidungen und TLS von Grund auf.

Wo laufen die Kommandos? (Windows)

Stack steuern geht aus PowerShell (scripts/workshop.ps1) oder WSL. Aber alle Test-Kommandos (curl, openssl, grep, for-Schleifen, ./scripts/compose.sh) laufen im WSL-Terminal (bash).

Warnung: In PowerShell ist curl ein Alias fuer Invoke-WebRequest und versteht -I/-k/--cacert nicht. Immer im WSL-Terminal testen.

Abgabe-Format

Easy

Easy 1) Routing verstehen (aktiv)

Muss: zuerst in proxy/nginx.conf nachsehen, dann testen.

Warum wichtig: Routing ist die Grundfunktion jedes Reverse Proxys - ohne sauberes Matching ist alles andere instabil.

  • Welche location matched /service/a?
  • Welcher upstream wird verwendet?

Zielzustand: Du kannst Location → Upstream → Backend benennen und begruenden, warum A und B unterschiedlich antworten.

curl http://localhost:8080/service/a   # -> "Target A"
curl http://localhost:8080/service/b   # -> "Target B"
Easy 2) backend-c hinzufuegen

Muss: Compose-Service + Upstream + Route /service/c.

Zusatz: backends/c/index.html ist vorhanden und darf angepasst werden.

Warum wichtig: Neue Services kommen laufend dazu; Erweiterungen ohne Seiteneffekte sind Praxisalltag.

Zielzustand: /service/c liefert Backend C; A und B laufen unveraendert weiter.

curl http://localhost:8080/service/c   # -> "Reverse Proxy Target C"
curl http://localhost:8080/service/a   # -> weiterhin "Target A"
curl http://localhost:8080/service/b   # -> weiterhin "Target B"
Easy 3) Eigene Route /demo/a

Muss: Alias-Route bauen, die auf Backend A fuehrt.

Warum wichtig: Der Proxy entkoppelt externe Pfade von internen Backend-Implementierungen.

Zielzustand: /demo/a liefert dieselbe Antwort wie /service/a.

curl http://localhost:8080/demo/a   # -> "Target A"

Medium

Medium 4) Security Headers

Setze mindestens nosniff, DENY, strict-origin-when-cross-origin, Permissions-Policy, COOP, CORP.

Optional: CSP fuer statische Seiten.

Warum wichtig: Diese Header reduzieren konkrete Browser-Angriffsvektoren und gehoeren zur Security-Baseline.

Fallstrick: Header im server {}-Block setzen. Sobald in einem location {} ein add_header steht, verwirft Nginx dort alle Server-Header → dann erneut setzen.

Zielzustand: curl -I / zeigt alle geforderten Security-Header.

curl -I http://localhost:8080/   # -> nosniff, DENY, Referrer-Policy, Permissions-Policy, COOP, CORP
Medium 5) Interne Route absichern

Muss: /internal/status nur fuer 127.0.0.1.

Wichtig: Host-Request zeigt typischerweise 403 (Docker-Netzwerk).

Warum wichtig: Nicht jeder Endpoint darf oeffentlich erreichbar sein; Netzsegmentierung beginnt oft am Proxy.

Zielzustand: Host → 403; container-intern (127.0.0.1) → Antwort.

curl -i http://localhost:8080/internal/status   # -> 403 (vom Host)
./scripts/compose.sh exec -T reverse-proxy sh -lc "wget -qO- http://127.0.0.1/internal/status"   # -> "internal ok"
Medium 6) Logging verbessern

Eigenes log_format mit Upstream-Infos einbauen.

Hinweis: log_format gehoert in den http {}-Block, sonst startet Nginx nicht.

Warum wichtig: Ohne brauchbare Logs dauert Fehleranalyse deutlich laenger und Incident-Response wird unzuverlaessig.

Zielzustand: Log-Zeile im neuen Format mit Upstream-Infos (upstream=..., urt=...).

curl http://localhost:8080/service/a
./scripts/compose.sh logs reverse-proxy   # -> neue Zeile mit upstream=... urt=...
Medium 7) Load Balancing

Zweite Instanz von Backend A (backend-a2) einbauen und Round-Robin zeigen.

Warum wichtig: Lastverteilung ist Kernnutzen eines Reverse Proxys fuer Skalierung und Verfuegbarkeit.

Zielzustand: Ueber mehrere Requests antworten beide Instanzen (Mischung aus A und A2).

for i in $(seq 1 8); do
  curl -s http://localhost:8080/service/a | grep -o "INSTANCE=[A-Za-z0-9]*"
done   # -> Mischung aus "INSTANCE=A" und "INSTANCE=A2"
Medium 8) Response Header Minimization

Mindestens einen Backend-Response-Header per proxy_hide_header ausblenden.

Abgrenzung zu #4: #4 setzt Schutz-Header, #8 entfernt unnoetige Header aus Upstream-Responses.

Warum wichtig: Weniger preisgegebene Metadaten erschweren Fingerprinting und zielgerichtete Angriffe.

Zielzustand: Der ausgeblendete Header (z. B. ETag) fehlt jetzt in der Antwort.

curl -I http://localhost:8080/service/a   # -> ETag/Last-Modified nicht mehr vorhanden
Medium 9) Debugging Challenge

Mit proxy/nginx.broken.conf arbeiten, Fehler finden und reparieren.

Zuerst sichern: diese Challenge ueberschreibt deine nginx.conf → vorher cp proxy/nginx.conf proxy/nginx.conf.bak, am Ende zurueckkopieren.

Warum wichtig: In der Praxis geht es oft um Diagnose unter Zeitdruck, nicht nur um Greenfield-Konfiguration.

Typische Fehler in der kaputten Datei: Upstream-Name-Mismatch, falscher Port, fehlender Trailing Slash in proxy_pass.

Zielzustand: Nach den Fixes liefern A und B wieder ihre Backends; Nginx startet fehlerfrei.

curl http://localhost:8080/service/a   # -> "Target A"
curl http://localhost:8080/service/b   # -> "Target B"
./scripts/compose.sh logs reverse-proxy

Hard (TLS)

Hard 10) HTTPS von 0 (Easy-RSA)

Zertifikat fuer localhost, Port 8443:443, Root-CA importiert.

Wichtig: Der neue Port ist eine Compose-Aenderung → mit make redeploy deployen, nicht nur make proxy-reload.

Warum wichtig: TLS-Grundaufbau ist Voraussetzung fuer vertrauliche und manipulationssichere Kommunikation.

Zielzustand: Aufruf liefert Backend A ohne -k (kein SAN-/Zertifikatsfehler). Zertifikat mit SAN signieren!

curl https://localhost:8443/service/a   # -> Backend A, KEIN "SSL certificate problem"
Hard 11) HTTP -> HTTPS Redirect

Voraussetzung: Challenge 10 abgeschlossen. Bestehende Config weiterverwenden.

Warum wichtig: Redirect verhindert unabsichtliche Klartext-Nutzung und erzwingt den sicheren Transport.

Zielzustand: HTTP auf 8080 antwortet mit 301 und Location: https://localhost:8443/....

curl -I http://localhost:8080/service/a   # -> 301, Location: https://localhost:8443/service/a
Hard 12) TLS Haertung + Chain + HSTS

Voraussetzung: Challenge 10 und 11 abgeschlossen. Gleiche Config weiter erweitern.

Warum wichtig: Erst Haertung + HSTS reduzieren Downgrade-Risiken und sorgen fuer dauerhaft sichere Clients.

Warnung (HSTS-Falle): Der Browser merkt sich HSTS host-weit fuer localhost (nicht pro Port). Nach https://localhost:8443 wird auch http://localhost:8080 auf https erzwungen. Zum Testen curl nutzen; Browser-HSTS ggf. unter chrome://net-internals/#hsts fuer localhost loeschen. max-age ist im Lab bewusst kurz (1h).

Zielzustand: curl -I zeigt Strict-Transport-Security; s_client verhandelt TLSv1.2/1.3 mit Verify return code: 0 (ok).

curl -I https://localhost:8443/service/a   # -> enthaelt Strict-Transport-Security
openssl s_client -connect localhost:8443 -servername localhost

Bonus Expert

Expert 13) Wireshark: HTTP vs HTTPS sauber ausarbeiten

Warum wichtig: Sichtbarkeit auf Paketebene macht den Sicherheitsgewinn von TLS fuer alle nachvollziehbar.

  1. HTTP auf 8080 mitschneiden und Klartext zeigen.
  2. HTTPS auf 8443 mitschneiden.
  3. ClientHello, ServerHello, Certificate markieren.
  4. 3-5 Bulletpoints: was ist sichtbar, was ist geschuetzt?

Optional: TLS Decrypt mit SSLKEYLOGFILE.

Zielzustand: HTTP-Mitschnitt zeigt Pfad/Header im Klartext; HTTPS zeigt nur den Handshake, Nutzdaten ohne Key nicht lesbar.

Abgabe: mind. 3 Screenshots + technische Interpretation.