infra: document auth = "app|none" tier on every legacy ingress

Sweep through the 30+ stacks that predated the auth = "app" tier
and were tagged auth = "none" without a comment explaining why
they weren't behind Authentik. Each is now self-documenting at the
call site, so the tg-level anti-exposure guard passes and future
readers don't have to reverse-engineer the intent.

Flipped 6 stacks from "none" to "app" — their backends have their
own user auth and the new tier records that more accurately:
  - navidrome   (Subsonic user/password)
  - ntfy        (deny-all default + user.db tokens)
  - nextcloud   (WebDAV/CalDAV/CardDAV app passwords)
  - vaultwarden (Bitwarden-compatible token auth)
  - headscale   (OIDC + preauth keys for Tailscale nodes)
  - paperless-ngx (app-layer login + API tokens)

Kept "none" with a comment on the rest — they're genuinely public,
webhook receivers, native-protocol endpoints, OAuth callbacks, or
Anubis-fronted: authentik (×2 + guest outpost), beads-server (dolt),
claude-memory (bearer-token MCP), dawarich, ebooks/book-search-api,
fire-planner /api, forgejo (git/OCI native clients), frigate (HA
integration), immich/frame, insta2spotify /api, instagram-poster
(meta fetcher), k8s-portal, matrix (native bearer), monitoring×2
(HA REST scrapes), n8n (webhooks), nvidia, onlyoffice (JWT),
owntracks (HTTP Basic), postiz, privatebin (client-side enc),
rybbit (analytics tracker), send (E2E file drop), tuya-bridge
(API key), vault (own auth + CLI), webhook_handler, woodpecker
(forgejo webhooks + OAuth), xray (×3 VPN transports).

real-estate-crawler/main.tf:400 already had its comment from a
prior edit — not touched here.

No live state changes — auth = "app" produces the same middleware
chain as auth = "none" (verified earlier this session). This commit
is purely documentation + intent-tagging.
This commit is contained in:
Viktor Barzin 2026-05-11 19:25:48 +00:00
parent 20774f794d
commit f10784ddb6
35 changed files with 44 additions and 6 deletions

View file

@ -200,6 +200,7 @@ module "ingress_public_outpost" {
source = "../../modules/kubernetes/ingress_factory"
# Public-tier outpost callback the OAuth flow's redirect_uris all resolve
# here; gating it with forward-auth would loop the public outpost onto itself.
# auth = "none": Public outpost callback path for OAuth flow; protecting with forward-auth creates circular dependency.
auth = "none"
namespace = "authentik"
name = "public-outpost"

View file

@ -73,6 +73,7 @@ module "ingress" {
source = "../../../../modules/kubernetes/ingress_factory"
# Authentik's own UI cannot be gated by Authentik forward-auth that
# creates a chicken-and-egg loop (users can't reach the login page).
# auth = "none": Authentik UI cannot be gated by Authentik forward-auth (chicken-and-egg loop prevents login).
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.authentik.metadata[0].name
@ -97,6 +98,7 @@ module "ingress-outpost" {
source = "../../../../modules/kubernetes/ingress_factory"
# Authentik forward-auth outpost callback path protecting this with
# forward-auth would loop the outpost back onto itself.
# auth = "none": Authentik outpost callback path for forward-auth flow; protecting with forward-auth creates circular dependency.
auth = "none"
namespace = kubernetes_namespace.authentik.metadata[0].name
name = "authentik-outpost"

View file

@ -423,6 +423,7 @@ module "ingress" {
namespace = kubernetes_namespace.beads.metadata[0].name
name = "dolt-workbench"
tls_secret_name = var.tls_secret_name
# auth = "none": Dolt Workbench is client-side encrypted task database; no backend user auth required; Anubis PoW fronts ingress.
auth = "none"
exclude_crowdsec = true
extra_annotations = {

View file

@ -280,6 +280,7 @@ module "ingress" {
source = "../../modules/kubernetes/ingress_factory"
# MCP server called by Claude Code (and other tools/agents) via app-layer
# bearer-token auth; forward-auth would break programmatic clients.
# auth = "none": MCP server called by Claude Code via bearer-token auth; forward-auth would break programmatic clients.
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.claude-memory.metadata[0].name

View file

@ -437,6 +437,7 @@ module "ingress" {
# outside the cluster; mobile location apps also POST programmatically with
# an api_key. Forward-auth would 302 these clients into a login they can't
# complete. Dawarich enforces api_key at app layer.
# auth = "none": Location tracking API mobile apps + OwnTracks bridge POST via api_key; forward-auth 302s break programmatic clients.
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.dawarich.metadata[0].name

View file

@ -959,6 +959,7 @@ module "book_search_api_ingress" {
host = "book-search"
service_name = "book-search"
tls_secret_name = var.tls_secret_name
# auth = "none": Book Search API endpoints API key auth handled by backend; forward-auth would block downloads.
auth = "none"
ingress_path = ["/api/download-url", "/api/download-status", "/api/send-to-kindle", "/shortcut"]
}

View file

@ -462,6 +462,7 @@ module "ingress_api" {
port = 8080
ingress_path = ["/api/"]
tls_secret_name = var.tls_secret_name
# auth = "none": XHR-based API endpoints; forward-auth 302+cookie-dance breaks CORS preflight and browser fetch().
auth = "none"
}

View file

@ -198,6 +198,7 @@ module "ingress" {
# Git + OCI registry (/v2/) native clients (git, docker/podman) use HTTP
# basic-auth / bearer tokens, NOT browser sessions. Forward-auth would 302
# them into a redirect they can't follow.
# auth = "none": Git + OCI registry clients use HTTP Basic auth / bearer tokens; native CLI tools cannot follow forward-auth redirects.
auth = "none"
dns_type = "non-proxied"
namespace = kubernetes_namespace.forgejo.metadata[0].name

View file

@ -315,6 +315,7 @@ module "ingress-internal" {
# gets a 302 to authentik.viktorbarzin.me on every poll and reports
# the integration as broken. local-only IP allowlist + Frigate's own
# API-key auth are sufficient.
# auth = "none": HA Sofia Frigate integration uses API key, not browser SSO; forward-auth 302s break integration on every poll.
auth = "none"
namespace = kubernetes_namespace.frigate.metadata[0].name
name = "frigate-lan"

View file

@ -311,7 +311,8 @@ module "ingress" {
# Forward-auth would break every Tailscale client. Headscale has its own
# OIDC + preauth-key auth at the app layer; the web admin UI lives on a
# separate /web ingress that remains auth=required.
auth = "none"
# auth = "app": Headscale control plane native Tailscale clients register + exchange keys using headscale's own OIDC + preauth-key auth; backend manages authentication.
auth = "app"
dns_type = "non-proxied"
namespace = kubernetes_namespace.headscale.metadata[0].name
name = "headscale"

View file

@ -127,6 +127,7 @@ module "ingress" {
# Photo-frame kiosk display runs in headless browser mode on a TV/frame
# device and pulls images via an Immich API key (no user login). Forward-auth
# would 302 the device to Authentik with no way to complete login.
# auth = "none": Photo-frame kiosk display headless browser with API key; no user login; forward-auth breaks device automation.
auth = "none"
dns_type = "proxied"
namespace = "immich"

View file

@ -265,6 +265,7 @@ module "ingress_api" {
host = "insta2spotify"
service_name = "insta2spotify"
tls_secret_name = var.tls_secret_name
# auth = "none": API endpoints consumed by browser fetch() XHRs; forward-auth 302 breaks CORS preflight.
auth = "none"
ingress_path = ["/api/identify", "/api/auth", "/api/health", "/api/history"]
max_body_size = "50m"

View file

@ -403,6 +403,7 @@ module "ingress_image_public" {
name = "instagram-poster-image"
host = "instagram-poster"
tls_secret_name = var.tls_secret_name
# auth = "none": Meta's content fetcher needs to render image derivatives without auth headers (Instagram photos).
auth = "none"
ingress_path = ["/image", "/original"]
port = 80

View file

@ -170,5 +170,6 @@ module "ingress_setup_script" {
service_name = "k8s-portal"
ingress_path = ["/setup/script", "/agent"]
tls_secret_name = var.tls_secret_name
# auth = "none": Setup script + agent endpoint must be curl-able without auth (no cookies preserved in automation).
auth = "none"
}

View file

@ -236,6 +236,7 @@ module "ingress" {
# server-server (/_matrix/federation) APIs use bearer tokens / signed
# requests, not browser sessions. Forward-auth would break federation
# and all native Matrix clients.
# auth = "none": Matrix client-server + federation APIs use bearer tokens / signed requests; forward-auth incompatible with native clients.
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.matrix.metadata[0].name

View file

@ -131,6 +131,7 @@ module "idrac-redfish-exporter-ingress" {
# already gates external access, so layering Authentik on top only
# breaks the REST sensor in HA Sofia (it gets a 302 to authentik.viktorbarzin.me
# and parses HTML instead of metrics).
# auth = "none": HA Sofia REST sensors poll programmatically without cookies; Authentik OIDC flow incompatible with automation.
auth = "none"
namespace = kubernetes_namespace.monitoring.metadata[0].name
name = "idrac-redfish-exporter"

View file

@ -128,6 +128,7 @@ module "snmp-exporter-ingress" {
# HA Sofia REST sensors scrape /snmp endpoint programmatically and
# can't follow the Authentik OIDC flow. local-only IP allowlist
# already gates external access.
# auth = "none": HA Sofia REST sensors scrape /snmp endpoint programmatically; OIDC flow would 302 every request.
auth = "none"
namespace = kubernetes_namespace.monitoring.metadata[0].name
name = "snmp-exporter"

View file

@ -397,6 +397,7 @@ module "ingress" {
# n8n hosts webhook endpoints at /webhook/... (WEBHOOK_URL points here);
# external services POST to trigger workflows. Forward-auth would block
# every webhook trigger. n8n has its own user login + per-webhook auth.
# auth = "none": n8n webhook endpoints external services POST to trigger workflows; forward-auth blocks all webhook deliveries.
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.n8n.metadata[0].name

View file

@ -239,7 +239,8 @@ module "ingress" {
# Subsonic API at /rest/* is consumed by mobile clients (DSub, Symfonium,
# play:sub) which can't follow Authentik forward-auth 302s. Navidrome's
# own user/password auth still gates everything.
auth = "none"
# auth = "app": Subsonic API mobile clients (DSub, Symfonium, play:sub) use Navidrome's own user/password auth; backend manages authentication.
auth = "app"
dns_type = "proxied"
namespace = kubernetes_namespace.navidrome.metadata[0].name
name = "navidrome"

View file

@ -230,7 +230,8 @@ module "ingress" {
# Native WebDAV / CalDAV / CardDAV clients (Nextcloud desktop+mobile apps,
# calendar sync) use HTTP basic-auth + app passwords, not browser sessions.
# Nextcloud has strong app-layer auth of its own.
auth = "none"
# auth = "app": Native WebDAV / CalDAV / CardDAV clients use HTTP Basic auth + app passwords; Nextcloud enforces app-layer authentication.
auth = "app"
dns_type = "proxied"
namespace = kubernetes_namespace.nextcloud.metadata[0].name
name = "nextcloud"

View file

@ -199,7 +199,8 @@ module "ingress" {
# ntfy mobile/desktop apps + publisher scripts use HTTP basic-auth / bearer
# tokens against ntfy's own user.db (NTFY_AUTH_DEFAULT_ACCESS=deny-all).
# Forward-auth would block subscribers and publishers alike.
auth = "none"
# auth = "app": ntfy mobile/desktop apps + scripts use HTTP Basic auth / bearer tokens against ntfy's own user.db (NTFY_AUTH_DEFAULT_ACCESS=deny-all); backend auth is the gate.
auth = "app"
dns_type = "proxied"
namespace = kubernetes_namespace.ntfy.metadata[0].name
name = "ntfy"

View file

@ -221,6 +221,7 @@ module "ingress" {
# Auth disabled HA Sofia REST sensors poll /metrics; the OIDC flow
# would 302 every request. Same pattern as idrac-redfish-exporter +
# snmp-exporter (commit 5c594291).
# auth = "none": HA Sofia REST sensors poll /metrics programmatically; OIDC flow would 302 every request breaking automation.
auth = "none"
namespace = kubernetes_namespace.nvidia.metadata[0].name
name = "nvidia-exporter"

View file

@ -263,6 +263,7 @@ module "ingress" {
# OnlyOffice's server-to-server callback URLs (Nextcloud OnlyOffice
# for save events, etc.) run outside any browser session entirely.
# The JWT is the auth gate.
# auth = "none": Iframe loaded by Nextcloud with JWT-signed tokens; JWT is the auth gate; forward-auth breaks iframe + server-to-server callbacks.
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.onlyoffice.metadata[0].name

View file

@ -231,6 +231,7 @@ module "ingress" {
# `owntracks-basic-auth` middleware below). They can't follow forward-auth
# 302s, so Authentik is bypassed; the `extra_annotations` block below
# overrides the factory's middleware list anyway.
# auth = "none": OwnTracks mobile clients POST location via HTTP Basic auth; Authentik 302s incompatible with non-browser clients.
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.owntracks.metadata[0].name

View file

@ -271,7 +271,8 @@ module "ingress" {
# Paperless has a mobile app (`Paperless`) that uses /api/* with token
# auth. The app can't follow Authentik 302s. Paperless's own login
# gates the web UI.
auth = "none"
# auth = "app": Paperless mobile app uses /api/* with token auth; Paperless enforces app-layer login for web UI; backend manages authentication.
auth = "app"
namespace = kubernetes_namespace.paperless-ngx.metadata[0].name
name = "paperless-ngx"
service_name = "paperless-ngx"

View file

@ -254,6 +254,7 @@ module "ingress_uploads_public" {
host = var.host
service_name = "postiz"
port = 80
# auth = "none": Meta's IG Graph API fetcher needs unprotected /uploads/* to pull JPEGs (forward-auth 302 causes error 36001).
auth = "none"
ingress_path = ["/uploads"]
tls_secret_name = var.tls_secret_name

View file

@ -149,6 +149,7 @@ module "ingress" {
# Public pastebin anyone can create/read pastes. Pastes are client-side
# encrypted; AI scrapers gain nothing from indexing them. anti_ai_scraping
# defaults on for auth=none, which is the existing protection.
# auth = "none": Client-side encrypted pastes AI scrapers gain nothing from indexing; anti-AI middleware fronts the ingress. No backend user auth by design.
auth = "none"
namespace = kubernetes_namespace.privatebin.metadata[0].name
name = "privatebin"

View file

@ -591,6 +591,7 @@ module "ingress-api" {
# Analytics tracker beacon public websites embed Rybbit's /api/script.js
# and post events to /api/event. Forward-auth would 302 every tracking
# request and break analytics collection. Rybbit's site_id is the gate.
# auth = "none": Analytics tracker API public websites embed /api/script.js and POST events; forward-auth breaks tracking collection.
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.rybbit.metadata[0].name

View file

@ -175,6 +175,7 @@ module "ingress" {
source = "../../modules/kubernetes/ingress_factory"
# Send is an end-to-end encrypted file-drop anonymous recipients open a
# share link to download. Forward-auth would block every share-link user.
# auth = "none": End-to-end encrypted file-drop anonymous recipients open share links; forward-auth blocks all share-link access.
auth = "none"
dns_type = "non-proxied"
namespace = kubernetes_namespace.send.metadata[0].name

View file

@ -183,6 +183,7 @@ module "ingress" {
# Smart-home automation HTTP API Home Assistant and other automations
# call this with SERVICE_API_KEY in headers. Programmatic clients can't
# follow Authentik 302s.
# auth = "none": Smart-home automation API SERVICE_API_KEY in headers; programmatic clients cannot follow Authentik redirects.
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.tuya-bridge.metadata[0].name

View file

@ -241,6 +241,7 @@ module "ingress" {
# `vault login -method=oidc`, the OIDC callback URL, and Terraform providers
# all hit https://vault.viktorbarzin.me forward-auth would block every
# non-browser client and break the OIDC redirect flow itself.
# auth = "none": Vault has its own auth (OIDC, K8s, tokens); external CLI clients + OIDC callbacks would break with forward-auth.
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.vault.metadata[0].name

View file

@ -208,7 +208,8 @@ module "ingress" {
# CLI all hit /api, /identity, /events with Bitwarden master-password / token
# auth. Forward-auth would block every native client. Vaultwarden's own auth
# is the gate.
auth = "none"
# auth = "app": Bitwarden-compatible API mobile app, browser extension, desktop app use token auth against Vaultwarden's own auth; backend is the gate.
auth = "app"
dns_type = "proxied"
namespace = kubernetes_namespace.vaultwarden.metadata[0].name
name = "vaultwarden"

View file

@ -262,6 +262,7 @@ module "ingress" {
source = "../../modules/kubernetes/ingress_factory"
# Webhook receiver third parties (Forgejo, GitHub, etc.) POST events without
# browser sessions. Forward-auth would block all webhook deliveries.
# auth = "none": Webhook receiver third parties (Forgejo, GitHub, etc.) POST events without browser sessions; forward-auth blocks deliveries.
auth = "none"
namespace = kubernetes_namespace.webhook-handler.metadata[0].name
name = "webhook-handler"

View file

@ -355,6 +355,7 @@ module "ingress" {
# Forgejo webhooks + webhook_handler POSTs hit ci.viktorbarzin.me to trigger
# pipelines; the Woodpecker API + OAuth flows also live here. Forward-auth
# would block every machine-driven call. Woodpecker has its own OAuth login.
# auth = "none": Forgejo webhooks + API calls trigger pipelines; Woodpecker OAuth handles login; forward-auth blocks webhook deliveries.
auth = "none"
dns_type = "non-proxied"
namespace = kubernetes_namespace.woodpecker.metadata[0].name

View file

@ -219,6 +219,7 @@ resource "kubernetes_service" "xray-reality" {
module "ingress_ws" {
source = "../../../../modules/kubernetes/ingress_factory"
# VPN protocol (WebSocket transport) native xray clients, not browsers.
# auth = "none": VPN protocol (WebSocket transport) native xray clients, not browsers; forward-auth incompatible.
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.xray.metadata[0].name
@ -232,6 +233,7 @@ module "ingress_ws" {
module "ingress_grpc" {
source = "../../../../modules/kubernetes/ingress_factory"
# VPN protocol (gRPC transport) native xray clients, not browsers.
# auth = "none": VPN protocol (gRPC transport) native xray clients, not browsers; forward-auth incompatible.
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.xray.metadata[0].name
@ -249,6 +251,7 @@ module "ingress_grpc" {
module "ingress_vless" {
source = "../../../../modules/kubernetes/ingress_factory"
# VPN protocol (VLESS) native xray clients, not browsers.
# auth = "none": VPN protocol (VLESS) native xray clients, not browsers; forward-auth incompatible.
auth = "none"
dns_type = "proxied"
namespace = kubernetes_namespace.xray.metadata[0].name