security: harden traefik auth flow — fix header spoofing, TLS leak, DERP rate-limit

- Auth-proxy fallback now sets ALL X-authentik-* headers (username, uid,
  email, name, groups) to prevent client-supplied header spoofing when
  Authentik is down. Previously only username was set, allowing a malicious
  client to inject fake X-authentik-groups.
- Catch-all IngressRoute restricted to *.viktorbarzin.me only. Non-matching
  domains no longer get the wildcard cert served (TLS info leak).
- Added rate-limit and CrowdSec middleware to catch-all IngressRoute.
- Added rate-limit middleware to Headscale DERP IngressRoute.
- Rotated auth-proxy basicAuth credentials (bcrypt cost 5 → 12, admin → emergency-admin).
- Created Authentik brute-force reputation policy (threshold -5, IP+username).
This commit is contained in:
Viktor Barzin 2026-04-05 20:01:06 +03:00
parent 3d02036a18
commit 0e3c0fb503
3 changed files with 50 additions and 8 deletions

View file

@ -324,11 +324,17 @@ resource "kubernetes_manifest" "derp_ingress_route" {
name = kubernetes_service.headscale.metadata[0].name
port = 8080
}]
# Only retry middleware no CrowdSec, rate limit, anti-AI, error pages
middlewares = [{
name = "retry"
namespace = "traefik"
}]
# Minimal middleware retry + rate-limit. No CrowdSec/anti-AI (DERP is a relay protocol)
middlewares = [
{
name = "retry"
namespace = "traefik"
},
{
name = "rate-limit"
namespace = "traefik"
},
]
}]
tls = {
secretName = var.tls_secret_name

View file

@ -158,7 +158,9 @@ resource "kubernetes_manifest" "tlsstore_default" {
depends_on = [helm_release.traefik, module.tls_secret]
}
# Catch-all IngressRoute serves 404 for unknown hosts (lowest priority)
# Catch-all IngressRoute serves 404 for unmatched *.viktorbarzin.me hosts (lowest priority)
# Only matches *.viktorbarzin.me non-viktorbarzin.me domains get TLS rejection (no matching router)
# This prevents leaking the wildcard cert to attackers who point arbitrary domains at our IP
resource "kubernetes_manifest" "ingressroute_catchall" {
manifest = {
apiVersion = "traefik.io/v1alpha1"
@ -170,9 +172,13 @@ resource "kubernetes_manifest" "ingressroute_catchall" {
spec = {
entryPoints = ["websecure"]
routes = [{
match = "HostRegexp(`.+`)"
match = "HostRegexp(`^(.+\\.)?viktorbarzin\\.me$`)"
kind = "Rule"
priority = 1
middlewares = [
{ name = "rate-limit", namespace = kubernetes_namespace.traefik.metadata[0].name },
{ name = "crowdsec", namespace = kubernetes_namespace.traefik.metadata[0].name },
]
services = [{
name = "error-pages"
namespace = kubernetes_namespace.traefik.metadata[0].name

View file

@ -494,9 +494,17 @@ resource "kubernetes_config_map" "auth_proxy_config" {
location @fallback_auth {
auth_basic "Emergency Access";
auth_basic_user_file /etc/nginx/htpasswd;
# Set ALL X-authentik-* headers to prevent client-supplied header spoofing.
# Without this, a client could inject fake X-authentik-groups and backends
# that trust these headers would grant elevated access.
add_header X-authentik-username $remote_user always;
add_header X-authentik-uid "" always;
add_header X-authentik-email "" always;
add_header X-authentik-name "" always;
add_header X-authentik-groups "" always;
add_header X-Auth-Fallback "true" always;
return 200;
root /usr/share/nginx/fallback;
try_files /ok =403;
}
location /outpost.goauthentik.io/ {
@ -518,6 +526,17 @@ resource "kubernetes_config_map" "auth_proxy_config" {
}
}
resource "kubernetes_config_map" "auth_proxy_fallback" {
metadata {
name = "auth-proxy-fallback"
namespace = kubernetes_namespace.traefik.metadata[0].name
}
data = {
"ok" = "authenticated"
}
}
resource "kubernetes_deployment" "auth_proxy" {
metadata {
name = "auth-proxy"
@ -577,6 +596,11 @@ resource "kubernetes_deployment" "auth_proxy" {
sub_path = "htpasswd"
read_only = true
}
volume_mount {
name = "fallback"
mount_path = "/usr/share/nginx/fallback"
read_only = true
}
liveness_probe {
http_get {
@ -618,6 +642,12 @@ resource "kubernetes_deployment" "auth_proxy" {
secret_name = kubernetes_secret.auth_proxy_htpasswd.metadata[0].name
}
}
volume {
name = "fallback"
config_map {
name = kubernetes_config_map.auth_proxy_fallback.metadata[0].name
}
}
}
}
}