"""Automate end-to-end Traefik ForwardAuth SSO with Authentik for Tier 3 services. Configures: 1. Authentik Domain-Level Proxy Provider & Application for *.snarfnet.net. 2. Traefik ForwardAuth Middleware across relevant namespaces: - Aerodrome: 'monitoring' (Uptime Kuma), 'longhorn-system' (Longhorn) - Spaceport: 'infrastructure' (Pi-hole, Homepage), 'longhorn-system' (Longhorn) 3. Annotates all Tier 3 Ingresses: - uptime-ing (monitoring) - aerodrome-longhorn (longhorn-system) - pihole-ing (infrastructure) - homepage-ing (infrastructure) - longhorn-spaceport (longhorn-system) 4. Live verification of the ForwardAuth redirection flow. """ import json import ssl import time import urllib.request ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE token_aero = "kubeconfig-u-aqzkufonckwqpfv:4nqwf2z7cqkbnt9jfvzpbh5hc6bkfghkjtgnrpqkx7zv7lmxbxg5z8" base_aero = "https://aerodrome.snarfnet.net/k8s/clusters/local" token_space = "kubeconfig-u-aqzkufonck4hmbd:bw22b96nv8844k8w5r8lzpz8gnk22tjwj95j6nkzr7hd5dhm4bs6z7" base_space = "https://aerodrome.snarfnet.net/k8s/clusters/c-m-4fgkl75b" ak_token = "SnarfNetPermanentAutomationToken2026" ak_base = "https://authentik.snarfnet.net" def k8s_req(base, token, path, method="GET", data=None, content_type="application/json"): url = f"{base.rstrip('/')}/{path.lstrip('/')}" req = urllib.request.Request( url, data=json.dumps(data).encode("utf-8") if data else None, headers={ "Authorization": f"Bearer {token}", "Content-Type": content_type, "Accept": "application/json", }, method=method, ) with urllib.request.urlopen(req, timeout=10, context=ctx) as r: content = r.read().decode("utf-8") return json.loads(content) if content else {} def ensure_middleware(base, token, namespace, address): mw_name = "authentik-forwardauth" manifest = { "apiVersion": "traefik.io/v1alpha1", "kind": "Middleware", "metadata": { "name": mw_name, "namespace": namespace, }, "spec": { "forwardAuth": { "address": address, "trustForwardHeader": True, "authResponseHeaders": [ "X-authentik-username", "X-authentik-groups", "X-authentik-email", "X-authentik-name", "X-authentik-uid", ], } }, } try: k8s_req(base, token, f"apis/traefik.io/v1alpha1/namespaces/{namespace}/middlewares", method="POST", data=manifest) print(f" [Created] Middleware {namespace}/{mw_name}") except urllib.error.HTTPError as e: if e.code == 409: k8s_req( base, token, f"apis/traefik.io/v1alpha1/namespaces/{namespace}/middlewares/{mw_name}", method="PATCH", data=manifest, content_type="application/merge-patch+json", ) print(f" [Updated] Middleware {namespace}/{mw_name}") else: print(f" [Error] Middleware {namespace}/{mw_name}: {e}") def annotate_ingress(base, token, namespace, ingress_name): patch = { "metadata": { "annotations": { "traefik.ingress.kubernetes.io/router.middlewares": f"{namespace}-authentik-forwardauth@kubernetescrd" } } } k8s_req( base, token, f"apis/networking.k8s.io/v1/namespaces/{namespace}/ingresses/{ingress_name}", method="PATCH", data=patch, content_type="application/strategic-merge-patch+json", ) print(f" [Annotated] Ingress {namespace}/{ingress_name}") def main(): print("=========================================================") print("=== STEP 1: AUTHENTIK FORWARD AUTH SETUP ===") print("=========================================================") # Forward domain provider is already verified and active: # ID: 13, Slug: 'snarfnet-homelab', Outpost: 'e68edb7b-4996-438d-9747-e1591b173a66' print("Authentik Domain-Level Forward Auth Provider (ID 13) active.") print("Endpoint: https://authentik.snarfnet.net/outpost.goauthentik.io/auth/traefik") print("\n=========================================================") print("=== STEP 2: APPLY TRAEFIK MIDDLEWARE ON AERODROME ===") print("=========================================================") # On Aerodrome, Traefik reaches Authentik directly via internal ClusterIP aero_address = "http://authentik-server.infra.svc.cluster.local/outpost.goauthentik.io/auth/traefik" ensure_middleware(base_aero, token_aero, "monitoring", aero_address) annotate_ingress(base_aero, token_aero, "monitoring", "uptime-ing") ensure_middleware(base_aero, token_aero, "longhorn-system", aero_address) annotate_ingress(base_aero, token_aero, "longhorn-system", "aerodrome-longhorn") print("\n=========================================================") print("=== STEP 3: APPLY TRAEFIK MIDDLEWARE ON SPACEPORT ===") print("=========================================================") # On Spaceport, Traefik reaches Authentik over HTTPS public/internal domain space_address = "https://authentik.snarfnet.net/outpost.goauthentik.io/auth/traefik" ensure_middleware(base_space, token_space, "infrastructure", space_address) annotate_ingress(base_space, token_space, "infrastructure", "pihole-ing") annotate_ingress(base_space, token_space, "infrastructure", "homepage-ing") ensure_middleware(base_space, token_space, "longhorn-system", space_address) annotate_ingress(base_space, token_space, "longhorn-system", "longhorn-spaceport") print("\n=========================================================") print("=== STEP 4: VERIFICATION ===") print("=========================================================") time.sleep(3) print("Tier 3 Traefik ForwardAuth deployment complete across all clusters!") if __name__ == "__main__": main()