From b420f1d4bf222784d69f8d660feee7a89a2e829b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Tue, 4 Nov 2025 23:20:34 +0100 Subject: [PATCH] feat: add comprehensive Traefik security hardening MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added security enhancements to Traefik reverse proxy: **TLS Security:** - Minimum TLS 1.2 enforced - Strong cipher suites (ECDHE, AES-GCM, ChaCha20) - Modern curve preferences (P-521, P-384) - SNI strict mode enabled **HTTP Security Headers:** - HSTS with 1-year max-age, includeSubdomains, and preload - X-Frame-Options: SAMEORIGIN (clickjacking protection) - X-XSS-Protection enabled - X-Content-Type-Options: nosniff - Referrer-Policy: strict-origin-when-cross-origin - Permissions-Policy (disable camera, mic, geolocation, etc.) - X-Robots-Tag for SEO control **Rate Limiting Middlewares:** - General: 100 req/s average, 50 burst - API endpoints: 30 req/s average, 15 burst **Configuration:** - Enabled Traefik file provider for dynamic config - Security headers applied globally to web-secure entrypoint - Dynamic config in proxy/dynamic/security.yaml - Auto-reloads on config changes All HTTPS traffic now benefits from enhanced security headers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- proxy/compose.yaml | 8 +++-- proxy/dynamic/security.yaml | 61 +++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 proxy/dynamic/security.yaml diff --git a/proxy/compose.yaml b/proxy/compose.yaml index 573c917..856abdd 100644 --- a/proxy/compose.yaml +++ b/proxy/compose.yaml @@ -22,8 +22,8 @@ services: - '--providers.docker.network=${NETWORK_NAME}' # File Provider for dynamic configuration - # - '--providers.file.directory=/etc/traefik/dynamic' - # - '--providers.file.watch=true' + - '--providers.file.directory=/etc/traefik/dynamic' + - '--providers.file.watch=true' # Entrypoints - '--entrypoints.web.address=:${PROXY_PORT_HTTP:-80}' @@ -34,6 +34,10 @@ services: - '--entrypoints.web.http.redirections.entryPoint.scheme=https' - '--entrypoints.web.http.redirections.entryPoint.permanent=true' + # TLS Security Options + - '--entrypoints.web-secure.http.tls.options=default@file' + - '--entrypoints.web-secure.http.middlewares=security-headers@file' + # Let's Encrypt - '--certificatesresolvers.resolver.acme.tlschallenge=true' - '--certificatesresolvers.resolver.acme.email=${ADMIN_EMAIL}' diff --git a/proxy/dynamic/security.yaml b/proxy/dynamic/security.yaml new file mode 100644 index 0000000..b6f925b --- /dev/null +++ b/proxy/dynamic/security.yaml @@ -0,0 +1,61 @@ +tls: + options: + default: + minVersion: VersionTLS12 + cipherSuites: + - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 + - TLS_AES_128_GCM_SHA256 + - TLS_AES_256_GCM_SHA384 + - TLS_CHACHA20_POLY1305_SHA256 + curvePreferences: + - CurveP521 + - CurveP384 + sniStrict: true + +http: + middlewares: + # Security Headers Middleware + security-headers: + headers: + # HSTS (HTTP Strict Transport Security) + stsSeconds: 31536000 + stsIncludeSubdomains: true + stsPreload: true + + # Force HTTPS + forceSTSHeader: true + + # Clickjacking protection + customFrameOptionsValue: "SAMEORIGIN" + + # XSS Protection + browserXssFilter: true + + # Content Type sniffing protection + contentTypeNosniff: true + + # Referrer Policy + referrerPolicy: "strict-origin-when-cross-origin" + + # Permissions Policy (formerly Feature Policy) + customResponseHeaders: + X-Robots-Tag: "none,noarchive,nosnippet,notranslate,noimageindex" + Permissions-Policy: "camera=(), microphone=(), geolocation=(), payment=(), usb=(), magnetometer=(), accelerometer=(), gyroscope=()" + X-Content-Type-Options: "nosniff" + X-Frame-Options: "SAMEORIGIN" + + # Rate Limiting Middleware (optional, can be applied per service) + rate-limit: + rateLimit: + average: 100 + burst: 50 + period: 1s + + # Rate Limiting for API endpoints (stricter) + api-rate-limit: + rateLimit: + average: 30 + burst: 15 + period: 1s