Metainformationen zur Seite
  •  

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
server:traefik [2025/09/25 14:50] walbaumserver:traefik [2025/09/25 15:05] (aktuell) walbaum
Zeile 708: Zeile 708:
 #      sniStrict: true #      sniStrict: true
 </codedoc> </codedoc>
 +
 +===== Traefik security headers and CSP (DRY config) =====
 +
 +Last updated: 25.09.2025
 +
 +==== High‑level design ====
 +
 +  * One baseline for security headers: security-headers-base
 +  * Small header variants you can compose: -noindex, -allowframes, -hsts-subdomains, cache-public
 +  * Separate CORS middlewares: cors-default, cors-collections
 +  * One base CSP: CSP-base (+ per‑service CSP middlewares that only add what’s different)
 +  * Chains compose the above into per‑service “one-liners” you reference from docker-compose labels.
 +
 +==== Security headers ====
 +
 +=== Baseline (security-headers-base) ===
 +
 +Sets the shared hardening and sane defaults. Highlights:
 +
 +  * addVaryHeader: true
 +  * contentTypeNosniff: true
 +  * browserXssFilter: true
 +  * referrerPolicy: same-origin
 +  * permissionsPolicy: fullscreen=(self "https://smns-bw.org"), geolocation=*, midi=(), camera=(), usb=(), magnetometer=(), accelerometer=(), vr=(), speaker=(), ambient-light-sensor=(), gyroscope=(), microphone=(), payment=()
 +  * HSTS: forceSTSHeader: true, stsSeconds: 31536000, stsPreload: false
 +  * X-Frame-Options: frameDeny: true by default (prefer CSP frame-ancestors for allowlists)
 +  * TLS/proxy awareness: sslRedirect: true; sslProxyHeaders.X-Forwarded-Proto: https
 +  * Scrub response headers (customResponseHeaders): Server: "", X-Powered-By: "", X-Robots-Tag: "index, follow"
 +  * Upstream request header: customRequestHeaders.X-Forwarded-Proto: https
 +Rationale:
 +
 +  * Default deny framing (clickjacking defense); enable per service via -allowframes and control who via CSP.
 +  * Keep includeSubdomains off by default to avoid accidental HSTS lock-in; use the variant when needed.
 +
 +==== Variants you can compose ====
 +
 +  * security-headers-noindex
 +    * Same as base, but X-Robots-Tag: "none,noarchive,nosnippet,notranslate,noimageindex"
 +  * security-headers-allowframes
 +    * Same as base, but frameDeny: false (use CSP frame-ancestors to specify who can frame)
 +  * security-headers-hsts-subdomains
 +    * Same as base, but stsIncludeSubdomains: true, stsSeconds: 63072000
 +  * cache-public
 +    * Adds Cache-Control: public to customResponseHeaders
 +
 +==== CORS middlewares ====
 +
 +  * cors-default
 +    * accessControlAllowMethods: GET, OPTIONS, PUT
 +    * accessControlAllowHeaders: "*"
 +    * accessControlMaxAge: 100
 +    * addVaryHeader: true
 +  * cors-collections
 +    * Inherits cors-default + accessControlAllowOriginList:
 +      * https://pydeepzoom.smns-bw.org
 +      * https://pictures.smns-bw.org
 +
 +==== Content Security Policy (CSP) ====
 +
 +=== Base CSP (CSP-base) ===
 +
 +Applies to most services unchanged.
 +
 +<code yaml> CSP-base: headers: contentSecurityPolicy: &CSP_BASE > default-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org; frame-ancestors 'self' *.smns-bw.org; frame-src *.smns-bw.org; base-uri 'self'; form-action 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org; </code>
 +
 +Notes:
 +
 +  * Only one CSP header is honored. Don’t stack multiple CSP middlewares in a single chain; “last header wins.”
 +  * Use Report-Only during testing by duplicating to contentSecurityPolicyReportOnly.
 +
 +==== How to add a new service ====
 +
 +  * If defaults are enough:
 +    * Use secure-global chain.
 +  * If it needs framing:
 +    * Use security-headers-allowframes in the chain and set CSP frame-ancestors to the exact allowlist.
 +  * If it needs special CORS:
 +    * Add or create a cors-<service> middleware and include it in the chain.
 +  * If it needs special CSP:
 +    * Copy CSP-base to CSP-<service> and append only the minimal deltas (new hosts/tokens).
 +  * Wire it in docker-compose:
 +    * traefik.http.routers.<name>.middlewares=secure-<name>@file
 +==== Verification (quick commands) ====
 +
 +  * Check headers:
 +    * curl -sI https://<host> | egrep -i "strict-transport-security|x-frame-options|x-content-type-options|referrer-policy|permissions-policy|x-robots-tag"
 +    * Check CSP is present (and only once):
 +    * curl -sI https://<host> | grep -i "content-security-policy"
 +  * Check CORS (preflight example):
 +    * curl -sI -X OPTIONS https://<host>/ -H "Origin: https://example.com" -H "Access-Control-Request-Method: GET"
 +  * Check robots indexing:
 +    * curl -sI https://<host>/ | grep -i x-robots-tag
 +
 +==== Operational notes ====
 +
 +  * Prefer CSP frame-ancestors over X-Frame-Options for precise embedding control.
 +  * Consider a Report-Only CSP during rollouts (duplicate middleware with contentSecurityPolicyReportOnly).
 +  * HSTS includeSubdomains is opt-in via variant to avoid unintentional hard lock-in.
 +  * If a page doesn’t render: check the browser console for CSP violations first; add only the specific host/type needed.
 +==== Appendix: Anchor usage ====
 +We used YAML anchors to stay DRY:
 +
 +  * &SEC_BASE / *SEC_BASE for baseline headers.
 +  * &CSP_BASE / *CSP_BASE for base CSP string.
 +This keeps the source config compact while allowing targeted overrides.
  
 ===== Traefik v3 Healthcheck (Docker) ===== ===== Traefik v3 Healthcheck (Docker) =====
Zeile 815: Zeile 920:
   * [[https://docs.docker.com/reference/compose-file/services/#healthcheck|Docker Compose healthcheck docs]]   * [[https://docs.docker.com/reference/compose-file/services/#healthcheck|Docker Compose healthcheck docs]]
  
-Authored for SMNS IT by Chattie and AI Programmer — [[:server:date?media=server:date|]]+Authored for SMNS IT by Chattie and AI Programmer