Files
SnarfCode/scripts/setup_tier3_authentik_forwardauth.py

155 lines
6.1 KiB
Python

"""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()