diff --git a/modules/create-vm/main.tf b/modules/create-vm/main.tf index b4f0e6c6..5f3edd5e 100644 --- a/modules/create-vm/main.tf +++ b/modules/create-vm/main.tf @@ -192,9 +192,9 @@ resource "proxmox_vm_qemu" "cloudinit-vm" { for_each = var.disk_slot == "scsi0" ? [1] : [] content { disk { - storage = "local-lvm" - size = var.vm_disk_size - discard = true # Enable TRIM passthrough to LVM thin pool — reduces CoW overhead + storage = "local-lvm" + size = var.vm_disk_size + discard = true # Enable TRIM passthrough to LVM thin pool — reduces CoW overhead } } } @@ -202,9 +202,9 @@ resource "proxmox_vm_qemu" "cloudinit-vm" { for_each = var.disk_slot == "scsi1" ? [1] : [] content { disk { - storage = "local-lvm" - size = var.vm_disk_size - discard = true + storage = "local-lvm" + size = var.vm_disk_size + discard = true } } } diff --git a/modules/kubernetes/ingress_factory/main.tf b/modules/kubernetes/ingress_factory/main.tf index 1975658e..a66f5a47 100644 --- a/modules/kubernetes/ingress_factory/main.tf +++ b/modules/kubernetes/ingress_factory/main.tf @@ -31,9 +31,28 @@ variable "tls_secret_name" {} variable "backend_protocol" { default = "HTTP" } -variable "protected" { - type = bool - default = false +variable "auth" { + type = string + default = "required" + description = <<-EOT + Authentik auth posture for this ingress: + * "required" (default): standard Authentik forward-auth — login required. + Catches the legacy `protected = true` semantics. + * "public": public-tier — auto-bind anonymous requests to the `guest` + Authentik user (no UI prompt), audited but not gated. Logged-in + users keep their real identity in X-authentik-username. + * "none": no Authentik forward-auth middleware at all. Use for + Anubis-fronted content sites, native-client APIs (Git, /v2/, WebDAV), + webhook receivers, and the Authentik outpost itself. Anti-AI + headers are auto-enabled when auth = "none" unless overridden. + + Defaulting to "required" enforces "every ingress must have an explicit + auth decision recorded by Authentik" — accidental omission fails closed. + EOT + validation { + condition = contains(["required", "public", "none"], var.auth) + error_message = "auth must be one of: required, public, none." + } } variable "ingress_path" { type = list(string) @@ -142,8 +161,19 @@ variable "homepage_enabled" { } locals { - effective_host = var.full_host != null ? var.full_host : "${var.host != null ? var.host : var.name}.${var.root_domain}" - effective_anti_ai = var.anti_ai_scraping != null ? var.anti_ai_scraping : !var.protected + effective_host = var.full_host != null ? var.full_host : "${var.host != null ? var.host : var.name}.${var.root_domain}" + # Anti-AI default: ON only when no Authentik auth is in front of the ingress + # (i.e. auth = "none" — public Anubis-fronted content sites, etc.). When + # Authentik gates the request (required/public), the auth flow already + # discourages bots, so anti-AI noise is redundant. + effective_anti_ai = var.anti_ai_scraping != null ? var.anti_ai_scraping : (var.auth == "none") + + # Auth middleware selection. "none" attaches no Authentik middleware at all. + auth_middleware = ( + var.auth == "required" ? "traefik-authentik-forward-auth@kubernetescrd" : + var.auth == "public" ? "traefik-authentik-forward-auth-public@kubernetescrd" : + null + ) # External monitor enabled by default when the ingress has a public DNS # record (either CF-proxied or direct A/AAAA). Explicit bool overrides. @@ -254,7 +284,7 @@ resource "kubernetes_ingress_v1" "proxied-ingress" { var.exclude_crowdsec ? null : "traefik-crowdsec@kubernetescrd", local.effective_anti_ai ? "traefik-ai-bot-block@kubernetescrd" : null, local.effective_anti_ai ? "traefik-anti-ai-headers@kubernetescrd" : null, - var.protected ? "traefik-authentik-forward-auth@kubernetescrd" : null, + local.auth_middleware, var.allow_local_access_only ? "traefik-local-only@kubernetescrd" : null, var.custom_content_security_policy != null ? "${var.namespace}-custom-csp-${var.name}@kubernetescrd" : null, var.max_body_size != null ? "${var.namespace}-buffering-${var.name}@kubernetescrd" : null, diff --git a/stacks/_template/main.tf.example b/stacks/_template/main.tf.example index 6f52337a..f8397a36 100644 --- a/stacks/_template/main.tf.example +++ b/stacks/_template/main.tf.example @@ -87,5 +87,5 @@ module "ingress" { name = "" tls_secret_name = var.tls_secret_name dns_type = "proxied" # "proxied" (Cloudflare CDN), "non-proxied" (direct A/AAAA), or "none" - protected = false # Set true to require Authentik login + auth = "required" # "required" (Authentik login), "public" (anonymous bound to guest), or "none" (no auth) } diff --git a/stacks/actualbudget/factory/main.tf b/stacks/actualbudget/factory/main.tf index af80e962..bd5728cb 100644 --- a/stacks/actualbudget/factory/main.tf +++ b/stacks/actualbudget/factory/main.tf @@ -149,6 +149,7 @@ resource "kubernetes_service" "actualbudget" { module "ingress" { source = "../../../modules/kubernetes/ingress_factory" + auth = "required" namespace = "actualbudget" name = "budget-${var.name}" tls_secret_name = var.tls_secret_name diff --git a/stacks/affine/main.tf b/stacks/affine/main.tf index a80381ce..60c76cf9 100644 --- a/stacks/affine/main.tf +++ b/stacks/affine/main.tf @@ -352,6 +352,7 @@ resource "kubernetes_service" "affine" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "non-proxied" namespace = kubernetes_namespace.affine.metadata[0].name name = "affine" diff --git a/stacks/authentik/guest.tf b/stacks/authentik/guest.tf index f2430ae1..dd57e6cf 100644 --- a/stacks/authentik/guest.tf +++ b/stacks/authentik/guest.tf @@ -101,8 +101,8 @@ resource "authentik_flow_stage_binding" "public_login" { # request.context, so the expression policy's mutation would no-op. With # evaluate_on_plan=false + re_evaluate_policies=true, the policy fires # right before the stage runs, when flow_plan is fully populated. - evaluate_on_plan = false - re_evaluate_policies = true + evaluate_on_plan = false + re_evaluate_policies = true } resource "authentik_policy_binding" "set_guest_before_login" { @@ -198,7 +198,10 @@ resource "authentik_outpost" "public" { # `Provider for Public` external_host points here, so all redirect_uris in # the OAuth flow resolve to this hostname. module "ingress_public_outpost" { - source = "../../modules/kubernetes/ingress_factory" + 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" namespace = "authentik" name = "public-outpost" host = "public-auth" diff --git a/stacks/authentik/modules/authentik/main.tf b/stacks/authentik/modules/authentik/main.tf index 19a0ffc9..3ab9c6d3 100644 --- a/stacks/authentik/modules/authentik/main.tf +++ b/stacks/authentik/modules/authentik/main.tf @@ -70,8 +70,11 @@ resource "helm_release" "authentik" { module "ingress" { - source = "../../../../modules/kubernetes/ingress_factory" - dns_type = "proxied" + 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" + dns_type = "proxied" namespace = kubernetes_namespace.authentik.metadata[0].name name = "authentik" service_name = "goauthentik-server" @@ -91,7 +94,10 @@ module "ingress" { } module "ingress-outpost" { - source = "../../../../modules/kubernetes/ingress_factory" + 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" namespace = kubernetes_namespace.authentik.metadata[0].name name = "authentik-outpost" host = "authentik" diff --git a/stacks/beads-server/main.tf b/stacks/beads-server/main.tf index 006b9db6..e24cdcde 100644 --- a/stacks/beads-server/main.tf +++ b/stacks/beads-server/main.tf @@ -416,7 +416,7 @@ module "ingress" { namespace = kubernetes_namespace.beads.metadata[0].name name = "dolt-workbench" tls_secret_name = var.tls_secret_name - protected = false + auth = "none" exclude_crowdsec = true extra_annotations = { "gethomepage.dev/enabled" = "true" @@ -566,7 +566,7 @@ resource "kubernetes_deployment" "beadboard" { } container { - name = "beadboard" + name = "beadboard" # Phase 3 cutover 2026-05-07 — Forgejo registry consolidation. image = "forgejo.viktorbarzin.me/viktor/beadboard:${var.beadboard_image_tag}" @@ -677,7 +677,7 @@ module "beadboard_ingress" { namespace = kubernetes_namespace.beads.metadata[0].name name = "beadboard" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" exclude_crowdsec = true extra_annotations = { "gethomepage.dev/enabled" = "true" diff --git a/stacks/blog/main.tf b/stacks/blog/main.tf index d074441f..daa646a0 100644 --- a/stacks/blog/main.tf +++ b/stacks/blog/main.tf @@ -124,15 +124,16 @@ module "anubis" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "none" # Anubis-fronted; PoW challenge gates bots, no Authentik namespace = kubernetes_namespace.website.metadata[0].name name = "blog" service_name = module.anubis.service_name port = module.anubis.service_port extra_middlewares = ["traefik-x402@kubernetescrd"] - full_host = "viktorbarzin.me" - dns_type = "proxied" - tls_secret_name = var.tls_secret_name - anti_ai_scraping = false # Anubis is the gatekeeper now — drop the redundant ai-bot-block forwardAuth. + full_host = "viktorbarzin.me" + dns_type = "proxied" + tls_secret_name = var.tls_secret_name + anti_ai_scraping = false # Anubis is the gatekeeper now — drop the redundant ai-bot-block forwardAuth. extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Blog" @@ -145,12 +146,13 @@ module "ingress" { module "ingress-www" { source = "../../modules/kubernetes/ingress_factory" + auth = "none" # Anubis-fronted; PoW challenge gates bots, no Authentik namespace = kubernetes_namespace.website.metadata[0].name name = "blog-www" service_name = module.anubis.service_name port = module.anubis.service_port extra_middlewares = ["traefik-x402@kubernetescrd"] - full_host = "www.viktorbarzin.me" - tls_secret_name = var.tls_secret_name - anti_ai_scraping = false + full_host = "www.viktorbarzin.me" + tls_secret_name = var.tls_secret_name + anti_ai_scraping = false } diff --git a/stacks/changedetection/main.tf b/stacks/changedetection/main.tf index af56a320..a7f2ef59 100644 --- a/stacks/changedetection/main.tf +++ b/stacks/changedetection/main.tf @@ -218,7 +218,7 @@ module "ingress" { namespace = kubernetes_namespace.changedetection.metadata[0].name name = "changedetection" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Changedetection" diff --git a/stacks/chrome-service/main.tf b/stacks/chrome-service/main.tf index 13ab49ee..dc7a5d80 100644 --- a/stacks/chrome-service/main.tf +++ b/stacks/chrome-service/main.tf @@ -354,7 +354,7 @@ module "ingress" { namespace = kubernetes_namespace.chrome_service.metadata[0].name name = "chrome" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" # noVNC defaults to /vnc.html — auto-redirect / there. ingress_path = ["/"] extra_annotations = { diff --git a/stacks/city-guesser/main.tf b/stacks/city-guesser/main.tf index afcd9938..d717c97e 100644 --- a/stacks/city-guesser/main.tf +++ b/stacks/city-guesser/main.tf @@ -99,7 +99,7 @@ module "ingress" { namespace = "city-guesser" name = "city-guesser" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "City Guesser" diff --git a/stacks/claude-memory/main.tf b/stacks/claude-memory/main.tf index 1224d496..ecce701b 100644 --- a/stacks/claude-memory/main.tf +++ b/stacks/claude-memory/main.tf @@ -274,7 +274,10 @@ resource "kubernetes_service" "claude-memory" { } module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + 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" dns_type = "proxied" namespace = kubernetes_namespace.claude-memory.metadata[0].name name = "claude-memory" diff --git a/stacks/crowdsec/modules/crowdsec/main.tf b/stacks/crowdsec/modules/crowdsec/main.tf index ca7b1998..2099dc9c 100644 --- a/stacks/crowdsec/modules/crowdsec/main.tf +++ b/stacks/crowdsec/modules/crowdsec/main.tf @@ -282,7 +282,7 @@ module "ingress" { dns_type = "proxied" namespace = kubernetes_namespace.crowdsec.metadata[0].name name = "crowdsec-web" - protected = true + auth = "required" tls_secret_name = var.tls_secret_name exclude_crowdsec = true } diff --git a/stacks/cyberchef/main.tf b/stacks/cyberchef/main.tf index 6b4e71ae..c15a5307 100644 --- a/stacks/cyberchef/main.tf +++ b/stacks/cyberchef/main.tf @@ -113,14 +113,15 @@ module "anubis" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "none" # Anubis-fronted; PoW challenge gates bots, no Authentik dns_type = "proxied" namespace = kubernetes_namespace.cyberchef.metadata[0].name name = "cc" service_name = module.anubis.service_name port = module.anubis.service_port extra_middlewares = ["traefik-x402@kubernetescrd"] - tls_secret_name = var.tls_secret_name - anti_ai_scraping = false + tls_secret_name = var.tls_secret_name + anti_ai_scraping = false extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "CyberChef" diff --git a/stacks/dashy/main.tf b/stacks/dashy/main.tf index f773d64f..77ce1f5a 100644 --- a/stacks/dashy/main.tf +++ b/stacks/dashy/main.tf @@ -132,5 +132,5 @@ module "ingress" { namespace = kubernetes_namespace.dashy.metadata[0].name name = "dashy" tls_secret_name = var.tls_secret_name - protected = true # hidden as we use homepage now + auth = "required" # hidden as we use homepage now } diff --git a/stacks/dawarich/main.tf b/stacks/dawarich/main.tf index 392b9d82..b98878b1 100644 --- a/stacks/dawarich/main.tf +++ b/stacks/dawarich/main.tf @@ -432,7 +432,12 @@ resource "kubernetes_service" "dawarich" { # } # } module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + source = "../../modules/kubernetes/ingress_factory" + # owntracks bridge hook posts to /api/v1/owntracks/points?api_key=... from + # 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" dns_type = "proxied" namespace = kubernetes_namespace.dawarich.metadata[0].name name = "dawarich" diff --git a/stacks/dbaas/modules/dbaas/main.tf b/stacks/dbaas/modules/dbaas/main.tf index bbb4723e..dbd9530c 100644 --- a/stacks/dbaas/modules/dbaas/main.tf +++ b/stacks/dbaas/modules/dbaas/main.tf @@ -791,7 +791,7 @@ module "ingress" { namespace = kubernetes_namespace.dbaas.metadata[0].name name = "pma" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = {} } @@ -1461,7 +1461,7 @@ module "ingress-pgadmin" { namespace = kubernetes_namespace.dbaas.metadata[0].name name = "pgadmin" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" } diff --git a/stacks/ebook2audiobook/main.tf b/stacks/ebook2audiobook/main.tf index 8492991f..7b4f27e8 100644 --- a/stacks/ebook2audiobook/main.tf +++ b/stacks/ebook2audiobook/main.tf @@ -254,7 +254,7 @@ module "ingress" { namespace = kubernetes_namespace.ebook2audiobook.metadata[0].name name = "ebook2audiobook" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Ebook2Audiobook" @@ -445,7 +445,7 @@ module "audiblez-web-ingress" { host = "audiblez" dns_type = "non-proxied" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" max_body_size = "500m" # Allow large EPUB uploads extra_annotations = { "gethomepage.dev/enabled" = "true" diff --git a/stacks/ebooks/main.tf b/stacks/ebooks/main.tf index c6978a05..a616e845 100644 --- a/stacks/ebooks/main.tf +++ b/stacks/ebooks/main.tf @@ -378,6 +378,7 @@ resource "kubernetes_service" "calibre" { module "calibre_ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.ebooks.metadata[0].name name = "calibre" @@ -502,7 +503,7 @@ module "stacks_ingress" { name = "stacks" service_name = "annas-archive-stacks" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "false" } @@ -647,6 +648,7 @@ resource "kubernetes_service" "audiobookshelf" { module "audiobookshelf_ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "non-proxied" namespace = kubernetes_namespace.ebooks.metadata[0].name name = "audiobookshelf" @@ -921,7 +923,7 @@ module "book_search_ingress" { namespace = kubernetes_namespace.ebooks.metadata[0].name name = "book-search" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Book Search" @@ -940,6 +942,6 @@ module "book_search_api_ingress" { host = "book-search" service_name = "book-search" tls_secret_name = var.tls_secret_name - protected = false + auth = "none" ingress_path = ["/api/download-url", "/api/download-status", "/api/send-to-kindle", "/shortcut"] } diff --git a/stacks/echo/main.tf b/stacks/echo/main.tf index 7c31e2f1..5610d3be 100644 --- a/stacks/echo/main.tf +++ b/stacks/echo/main.tf @@ -102,6 +102,7 @@ resource "kubernetes_service" "echo" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.echo.metadata[0].name name = "echo" diff --git a/stacks/excalidraw/main.tf b/stacks/excalidraw/main.tf index c7b1f013..5e0e52bf 100644 --- a/stacks/excalidraw/main.tf +++ b/stacks/excalidraw/main.tf @@ -149,7 +149,7 @@ module "ingress" { namespace = kubernetes_namespace.excalidraw.metadata[0].name name = "draw" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Excalidraw" diff --git a/stacks/f1-stream/main.tf b/stacks/f1-stream/main.tf index 42063108..8dab1205 100644 --- a/stacks/f1-stream/main.tf +++ b/stacks/f1-stream/main.tf @@ -237,10 +237,10 @@ module "tls_secret" { # (which load before any user has a chance to solve PoW), CHALLENGE # everything else — the HTML pages. module "anubis" { - source = "../../modules/kubernetes/anubis_instance" - name = "f1" - namespace = kubernetes_namespace.f1-stream.metadata[0].name - target_url = "http://${kubernetes_service.f1-stream.metadata[0].name}.${kubernetes_namespace.f1-stream.metadata[0].name}.svc.cluster.local" + source = "../../modules/kubernetes/anubis_instance" + name = "f1" + namespace = kubernetes_namespace.f1-stream.metadata[0].name + target_url = "http://${kubernetes_service.f1-stream.metadata[0].name}.${kubernetes_namespace.f1-stream.metadata[0].name}.svc.cluster.local" policy_yaml = <<-EOT bots: - import: (data)/bots/_deny-pathological.yaml @@ -275,6 +275,7 @@ module "anubis" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "none" # Anubis-fronted; PoW challenge gates bots, no Authentik dns_type = "non-proxied" namespace = kubernetes_namespace.f1-stream.metadata[0].name name = "f1" diff --git a/stacks/fire-planner/main.tf b/stacks/fire-planner/main.tf index c0b1f831..9cd80219 100644 --- a/stacks/fire-planner/main.tf +++ b/stacks/fire-planner/main.tf @@ -432,7 +432,7 @@ module "ingress" { name = "fire-planner" port = 8080 tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "FIRE Planner" @@ -459,7 +459,7 @@ module "ingress_api" { port = 8080 ingress_path = ["/api/"] tls_secret_name = var.tls_secret_name - protected = false + auth = "public" } # Plan-time read of the ESO-created K8s Secret for Grafana datasource diff --git a/stacks/foolery/main.tf b/stacks/foolery/main.tf index f54ec8ed..5ce47294 100644 --- a/stacks/foolery/main.tf +++ b/stacks/foolery/main.tf @@ -65,7 +65,7 @@ module "ingress" { namespace = kubernetes_namespace.foolery.metadata[0].name name = "foolery" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Foolery" diff --git a/stacks/forgejo/main.tf b/stacks/forgejo/main.tf index 54c60685..e7ddbc08 100644 --- a/stacks/forgejo/main.tf +++ b/stacks/forgejo/main.tf @@ -194,7 +194,11 @@ resource "kubernetes_service" "forgejo" { } } module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + source = "../../modules/kubernetes/ingress_factory" + # 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" dns_type = "non-proxied" namespace = kubernetes_namespace.forgejo.metadata[0].name name = "forgejo" diff --git a/stacks/freedify/factory/main.tf b/stacks/freedify/factory/main.tf index e2158d4c..172dfb1f 100755 --- a/stacks/freedify/factory/main.tf +++ b/stacks/freedify/factory/main.tf @@ -225,7 +225,7 @@ module "ingress" { name = "music-${var.name}" tls_secret_name = var.tls_secret_name dns_type = "non-proxied" - protected = var.protected + auth = var.protected ? "required" : "none" extra_annotations = var.extra_annotations } @@ -235,9 +235,9 @@ resource "kubernetes_ingress_v1" "stream-noauth" { name = "music-${var.name}-stream" namespace = "freedify" annotations = { - "traefik.ingress.kubernetes.io/router.middlewares" = "traefik-retry@kubernetescrd,traefik-rate-limit@kubernetescrd" - "traefik.ingress.kubernetes.io/router.entrypoints" = "websecure" - "traefik.ingress.kubernetes.io/router.priority" = "100" + "traefik.ingress.kubernetes.io/router.middlewares" = "traefik-retry@kubernetescrd,traefik-rate-limit@kubernetescrd" + "traefik.ingress.kubernetes.io/router.entrypoints" = "websecure" + "traefik.ingress.kubernetes.io/router.priority" = "100" } } spec { diff --git a/stacks/freedify/main.tf b/stacks/freedify/main.tf index 0c37bab8..81e19489 100644 --- a/stacks/freedify/main.tf +++ b/stacks/freedify/main.tf @@ -98,14 +98,14 @@ module "viktor" { # https://music-emo.viktorbarzin.me/ module "emo" { - source = "./factory" - name = "emo" - tag = "latest" - tls_secret_name = var.tls_secret_name - depends_on = [kubernetes_namespace.freedify] - tier = local.tiers.aux - protected = true - genius_token = lookup(local.credentials["emo"], "genius_token", null) + source = "./factory" + name = "emo" + tag = "latest" + tls_secret_name = var.tls_secret_name + depends_on = [kubernetes_namespace.freedify] + tier = local.tiers.aux + protected = true + genius_token = lookup(local.credentials["emo"], "genius_token", null) gemini_api_key = lookup(local.credentials["emo"], "gemini_api_key", null) navidrome_scan_url = data.kubernetes_secret.eso_secrets.data["navidrome_scan_url"] ha_sofia_url = lookup(data.kubernetes_secret.eso_secrets.data, "ha_sofia_url", "") diff --git a/stacks/freshrss/main.tf b/stacks/freshrss/main.tf index dca27cd7..5c7cfdca 100644 --- a/stacks/freshrss/main.tf +++ b/stacks/freshrss/main.tf @@ -215,6 +215,7 @@ resource "kubernetes_service" "freshrss" { } module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = "freshrss" name = "rss" diff --git a/stacks/frigate/main.tf b/stacks/frigate/main.tf index 489daa63..f0b4cfb7 100644 --- a/stacks/frigate/main.tf +++ b/stacks/frigate/main.tf @@ -288,7 +288,7 @@ module "ingress" { namespace = kubernetes_namespace.frigate.metadata[0].name name = "frigate" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Frigate" @@ -303,6 +303,7 @@ module "ingress" { module "ingress-internal" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" namespace = kubernetes_namespace.frigate.metadata[0].name name = "frigate-lan" host = "frigate-lan" diff --git a/stacks/grampsweb/main.tf b/stacks/grampsweb/main.tf index 874d3b81..47447132 100644 --- a/stacks/grampsweb/main.tf +++ b/stacks/grampsweb/main.tf @@ -360,7 +360,7 @@ module "ingress" { service_name = "grampsweb" tls_secret_name = var.tls_secret_name max_body_size = "500m" - protected = true + auth = "required" external_monitor = false extra_annotations = { "gethomepage.dev/enabled" = "true" diff --git a/stacks/hackmd/main.tf b/stacks/hackmd/main.tf index 2eb31cdd..4d6d07ca 100644 --- a/stacks/hackmd/main.tf +++ b/stacks/hackmd/main.tf @@ -191,6 +191,7 @@ resource "kubernetes_service" "hackmd" { } module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.hackmd.metadata[0].name name = "hackmd" diff --git a/stacks/headscale/main.tf b/stacks/headscale/main.tf index 8fd0c3e3..865f1daf 100644 --- a/stacks/headscale/main.tf +++ b/stacks/headscale/main.tf @@ -11,14 +11,14 @@ locals { } module "headscale" { - source = "./modules/headscale" - tls_secret_name = var.tls_secret_name - nfs_server = var.nfs_server - headscale_config = data.vault_kv_secret_v2.secrets.data["headscale_config"] - headscale_acl = data.vault_kv_secret_v2.secrets.data["headscale_acl"] - headscale_derp_map = data.vault_kv_secret_v2.secrets.data["headscale_derp_map"] - homepage_token = try(local.homepage_credentials["headscale"]["api_key"], "") - tier = local.tiers.core - ui_cookie_secret = data.vault_kv_secret_v2.secrets.data["headscale_ui_cookie_secret"] - ui_api_key = data.vault_kv_secret_v2.secrets.data["headscale_ui_api_key"] + source = "./modules/headscale" + tls_secret_name = var.tls_secret_name + nfs_server = var.nfs_server + headscale_config = data.vault_kv_secret_v2.secrets.data["headscale_config"] + headscale_acl = data.vault_kv_secret_v2.secrets.data["headscale_acl"] + headscale_derp_map = data.vault_kv_secret_v2.secrets.data["headscale_derp_map"] + homepage_token = try(local.homepage_credentials["headscale"]["api_key"], "") + tier = local.tiers.core + ui_cookie_secret = data.vault_kv_secret_v2.secrets.data["headscale_ui_cookie_secret"] + ui_api_key = data.vault_kv_secret_v2.secrets.data["headscale_ui_api_key"] } diff --git a/stacks/headscale/modules/headscale/main.tf b/stacks/headscale/modules/headscale/main.tf index a628085d..d60a5766 100644 --- a/stacks/headscale/modules/headscale/main.tf +++ b/stacks/headscale/modules/headscale/main.tf @@ -298,7 +298,13 @@ resource "kubernetes_service" "headscale" { } module "ingress" { - source = "../../../../modules/kubernetes/ingress_factory" + source = "../../../../modules/kubernetes/ingress_factory" + # Headscale is the Tailscale control plane — native Tailscale clients + # register, exchange keys, and pull DERP maps from headscale.viktorbarzin.me. + # 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" dns_type = "non-proxied" namespace = kubernetes_namespace.headscale.metadata[0].name name = "headscale" @@ -354,6 +360,7 @@ resource "kubernetes_manifest" "derp_ingress_route" { module "ingress-ui" { source = "../../../../modules/kubernetes/ingress_factory" + auth = "required" namespace = kubernetes_namespace.headscale.metadata[0].name name = "headscale-ui" host = "headscale" diff --git a/stacks/health/main.tf b/stacks/health/main.tf index 494236f3..c98f922f 100644 --- a/stacks/health/main.tf +++ b/stacks/health/main.tf @@ -174,6 +174,7 @@ resource "kubernetes_service" "health" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "non-proxied" namespace = kubernetes_namespace.health.metadata[0].name name = "health" diff --git a/stacks/hermes-agent/main.tf b/stacks/hermes-agent/main.tf index 0881932f..b64d4734 100644 --- a/stacks/hermes-agent/main.tf +++ b/stacks/hermes-agent/main.tf @@ -111,9 +111,9 @@ resource "kubernetes_config_map" "hermes_config" { # Context compression compression = { - enabled = true - threshold = 0.50 - target_ratio = 0.20 + enabled = true + threshold = 0.50 + target_ratio = 0.20 protect_last_n = 20 } @@ -411,7 +411,7 @@ module "ingress" { namespace = kubernetes_namespace.hermes_agent.metadata[0].name name = "hermes-agent" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Hermes Agent" diff --git a/stacks/homepage/main.tf b/stacks/homepage/main.tf index d4c84c68..2dfe07f7 100644 --- a/stacks/homepage/main.tf +++ b/stacks/homepage/main.tf @@ -146,6 +146,7 @@ module "anubis" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "none" # Anubis-fronted; PoW challenge gates bots, no Authentik namespace = kubernetes_namespace.homepage.metadata[0].name name = "homepage" host = "home" @@ -153,8 +154,8 @@ module "ingress" { service_name = module.anubis.service_name port = module.anubis.service_port extra_middlewares = ["traefik-x402@kubernetescrd"] - tls_secret_name = var.tls_secret_name - anti_ai_scraping = false + tls_secret_name = var.tls_secret_name + anti_ai_scraping = false extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Homepage" diff --git a/stacks/immich/frame.tf b/stacks/immich/frame.tf index acd5fdbe..07bd65e9 100644 --- a/stacks/immich/frame.tf +++ b/stacks/immich/frame.tf @@ -123,7 +123,11 @@ resource "kubernetes_service" "immich-frame" { } module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + source = "../../modules/kubernetes/ingress_factory" + # 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" dns_type = "proxied" namespace = "immich" name = "highlights-immich" diff --git a/stacks/immich/main.tf b/stacks/immich/main.tf index 0555b653..8f105fa0 100644 --- a/stacks/immich/main.tf +++ b/stacks/immich/main.tf @@ -731,6 +731,7 @@ resource "kubernetes_service" "immich-machine-learning" { module "ingress-immich" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "non-proxied" namespace = kubernetes_namespace.immich.metadata[0].name name = "immich" @@ -954,5 +955,5 @@ resource "kubernetes_cron_job_v1" "postgresql-backup" { # namespace = kubernetes_namespace.immich.metadata[0].name # name = "immich-powertools" # tls_secret_name = var.tls_secret_name -# protected = true +# auth = "required" # } diff --git a/stacks/insta2spotify/main.tf b/stacks/insta2spotify/main.tf index 88ba7e2e..d671cbf0 100644 --- a/stacks/insta2spotify/main.tf +++ b/stacks/insta2spotify/main.tf @@ -236,7 +236,7 @@ module "ingress" { namespace = kubernetes_namespace.insta2spotify.metadata[0].name name = "insta2spotify" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" max_body_size = "50m" extra_annotations = { "gethomepage.dev/enabled" = "true" @@ -256,7 +256,7 @@ module "ingress_api" { host = "insta2spotify" service_name = "insta2spotify" tls_secret_name = var.tls_secret_name - protected = false + auth = "public" ingress_path = ["/api/identify", "/api/auth", "/api/health", "/api/history"] max_body_size = "50m" } diff --git a/stacks/jsoncrack/main.tf b/stacks/jsoncrack/main.tf index c53c6bbc..d31d89bf 100644 --- a/stacks/jsoncrack/main.tf +++ b/stacks/jsoncrack/main.tf @@ -93,14 +93,15 @@ module "anubis" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "none" # Anubis-fronted; PoW challenge gates bots, no Authentik dns_type = "proxied" namespace = kubernetes_namespace.jsoncrack.metadata[0].name name = "json" service_name = module.anubis.service_name port = module.anubis.service_port extra_middlewares = ["traefik-x402@kubernetescrd"] - tls_secret_name = var.tls_secret_name - anti_ai_scraping = false + tls_secret_name = var.tls_secret_name + anti_ai_scraping = false extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "JSON Crack" diff --git a/stacks/k8s-dashboard/main.tf b/stacks/k8s-dashboard/main.tf index bdb82f75..f6759f6a 100644 --- a/stacks/k8s-dashboard/main.tf +++ b/stacks/k8s-dashboard/main.tf @@ -96,7 +96,7 @@ module "ingress" { host = "k8s" dns_type = "proxied" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" backend_protocol = "HTTPS" port = 443 extra_annotations = { diff --git a/stacks/k8s-portal/modules/k8s-portal/main.tf b/stacks/k8s-portal/modules/k8s-portal/main.tf index 741fb443..44ae778d 100644 --- a/stacks/k8s-portal/modules/k8s-portal/main.tf +++ b/stacks/k8s-portal/modules/k8s-portal/main.tf @@ -148,7 +148,7 @@ module "ingress" { namespace = kubernetes_namespace.k8s_portal.metadata[0].name name = "k8s-portal" tls_secret_name = var.tls_secret_name - protected = true # Require Authentik login + auth = "required" # Require Authentik login extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "K8s Portal" @@ -168,5 +168,5 @@ module "ingress_setup_script" { service_name = "k8s-portal" ingress_path = ["/setup/script", "/agent"] tls_secret_name = var.tls_secret_name - protected = false + auth = "public" } diff --git a/stacks/kms/main.tf b/stacks/kms/main.tf index 2408f523..8e6594b6 100644 --- a/stacks/kms/main.tf +++ b/stacks/kms/main.tf @@ -112,14 +112,15 @@ module "anubis" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "none" # Anubis-fronted; PoW challenge gates bots, no Authentik dns_type = "non-proxied" namespace = kubernetes_namespace.kms.metadata[0].name name = "kms" service_name = module.anubis.service_name port = module.anubis.service_port extra_middlewares = ["traefik-x402@kubernetescrd"] - tls_secret_name = var.tls_secret_name - anti_ai_scraping = false + tls_secret_name = var.tls_secret_name + anti_ai_scraping = false extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "KMS" diff --git a/stacks/linkwarden/main.tf b/stacks/linkwarden/main.tf index c4fe89e0..eb9e834a 100644 --- a/stacks/linkwarden/main.tf +++ b/stacks/linkwarden/main.tf @@ -229,6 +229,7 @@ resource "kubernetes_service" "linkwarden" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.linkwarden.metadata[0].name name = "linkwarden" diff --git a/stacks/mailserver/modules/mailserver/roundcubemail.tf b/stacks/mailserver/modules/mailserver/roundcubemail.tf index d1e4c623..eb76ada1 100644 --- a/stacks/mailserver/modules/mailserver/roundcubemail.tf +++ b/stacks/mailserver/modules/mailserver/roundcubemail.tf @@ -267,7 +267,7 @@ module "ingress" { name = "mail" service_name = "roundcubemail" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Roundcube Mail" diff --git a/stacks/matrix/main.tf b/stacks/matrix/main.tf index 79a23f4c..2c4f2048 100644 --- a/stacks/matrix/main.tf +++ b/stacks/matrix/main.tf @@ -224,7 +224,12 @@ resource "kubernetes_service" "matrix" { } module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + source = "../../modules/kubernetes/ingress_factory" + # Matrix homeserver — both client-server (/_matrix/client) and + # 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" dns_type = "proxied" namespace = kubernetes_namespace.matrix.metadata[0].name name = "matrix" diff --git a/stacks/meshcentral/main.tf b/stacks/meshcentral/main.tf index 7103a64c..520fff1b 100644 --- a/stacks/meshcentral/main.tf +++ b/stacks/meshcentral/main.tf @@ -271,7 +271,7 @@ module "ingress" { name = "meshcentral" tls_secret_name = var.tls_secret_name port = 80 - protected = true + auth = "required" anti_ai_scraping = false extra_annotations = { "gethomepage.dev/enabled" = "true" diff --git a/stacks/monitoring/modules/monitoring/idrac.tf b/stacks/monitoring/modules/monitoring/idrac.tf index 5112457a..bff50ec2 100644 --- a/stacks/monitoring/modules/monitoring/idrac.tf +++ b/stacks/monitoring/modules/monitoring/idrac.tf @@ -125,6 +125,7 @@ resource "kubernetes_service" "idrac-redfish-exporter" { module "idrac-redfish-exporter-ingress" { source = "../../../../modules/kubernetes/ingress_factory" + auth = "required" namespace = kubernetes_namespace.monitoring.metadata[0].name name = "idrac-redfish-exporter" root_domain = "viktorbarzin.lan" diff --git a/stacks/monitoring/modules/monitoring/prometheus_chart_values.tpl b/stacks/monitoring/modules/monitoring/prometheus_chart_values.tpl index f1619033..6d9a20a6 100755 --- a/stacks/monitoring/modules/monitoring/prometheus_chart_values.tpl +++ b/stacks/monitoring/modules/monitoring/prometheus_chart_values.tpl @@ -1874,6 +1874,35 @@ serverFiles: severity: warning annotations: summary: "ResourceQuota {{ $labels.namespace }}/{{ $labels.resourcequota }} {{ $labels.resource }} at {{ $value | printf \"%.1f\" }} — workloads may fail to reschedule" + # K8sVersionSkew: kubelet on any node disagrees with the apiserver's gitVersion. + # Catches a half-done kubeadm rollout — e.g. master at 1.34.5 but a worker + # still on 1.34.2 after the agent aborted mid-flight. Distinct gitVersion + # count >1 across kubernetes-nodes + kubernetes-apiservers means skew exists. + # 30m for: gives a normal rolling upgrade (master + 4 workers + 10-min soaks + # ≈ 60-90 min) room to be in mid-progress without firing during a healthy + # run — but only because Prometheus only counts a node post-restart, and the + # agent's soak between workers exceeds 10min anyway. + - alert: K8sVersionSkew + expr: count(count by (git_version) (kubernetes_build_info{job=~"kubernetes-nodes|kubernetes-apiservers"})) > 1 + for: 30m + labels: + severity: warning + annotations: + summary: "Kubelet/apiserver gitVersion skew detected — possible half-done k8s upgrade. Inspect: kubectl get nodes -o jsonpath='{.items[*].status.nodeInfo.kubeletVersion}'" + # EtcdPreUpgradeSnapshotMissing: the k8s-version-upgrade agent pushes + # k8s_upgrade_in_flight=1 when it starts, and k8s_upgrade_snapshot_taken=1 + # after the etcdctl snapshot is verified. If we see in_flight=1 with no + # corresponding snapshot_taken=1 after 10 min, the agent has skipped or + # failed the snapshot — that's a critical safety hole. + - alert: EtcdPreUpgradeSnapshotMissing + expr: | + k8s_upgrade_in_flight == 1 + unless on() k8s_upgrade_snapshot_taken == 1 + for: 10m + labels: + severity: critical + annotations: + summary: "K8s upgrade is in flight but no etcd snapshot was recorded — pipeline pre-flight failed silently" - name: "Traefik Ingress" rules: - alert: TraefikDown diff --git a/stacks/monitoring/modules/monitoring/snmp_exporter.tf b/stacks/monitoring/modules/monitoring/snmp_exporter.tf index 232b1c28..e38fab1b 100644 --- a/stacks/monitoring/modules/monitoring/snmp_exporter.tf +++ b/stacks/monitoring/modules/monitoring/snmp_exporter.tf @@ -124,6 +124,7 @@ resource "kubernetes_service" "snmp-exporter" { module "snmp-exporter-ingress" { source = "../../../../modules/kubernetes/ingress_factory" + auth = "required" namespace = kubernetes_namespace.monitoring.metadata[0].name name = "snmp-exporter" root_domain = "viktorbarzin.lan" diff --git a/stacks/n8n/main.tf b/stacks/n8n/main.tf index 020a59fe..567448d3 100644 --- a/stacks/n8n/main.tf +++ b/stacks/n8n/main.tf @@ -386,7 +386,11 @@ resource "kubernetes_service" "n8n" { } } module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + source = "../../modules/kubernetes/ingress_factory" + # 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" dns_type = "proxied" namespace = kubernetes_namespace.n8n.metadata[0].name name = "n8n" diff --git a/stacks/navidrome/main.tf b/stacks/navidrome/main.tf index 9e170e0c..68dd81e9 100644 --- a/stacks/navidrome/main.tf +++ b/stacks/navidrome/main.tf @@ -229,6 +229,7 @@ resource "kubernetes_service" "navidrome" { } module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.navidrome.metadata[0].name name = "navidrome" diff --git a/stacks/netbox/main.tf b/stacks/netbox/main.tf index b95f9e49..f03181c2 100644 --- a/stacks/netbox/main.tf +++ b/stacks/netbox/main.tf @@ -232,7 +232,7 @@ module "ingress" { namespace = kubernetes_namespace.netbox.metadata[0].name name = "netbox" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Netbox" diff --git a/stacks/networking-toolbox/main.tf b/stacks/networking-toolbox/main.tf index 720db4b4..2b64484b 100644 --- a/stacks/networking-toolbox/main.tf +++ b/stacks/networking-toolbox/main.tf @@ -103,7 +103,7 @@ module "ingress" { namespace = kubernetes_namespace.networking-toolbox.metadata[0].name name = "networking-toolbox" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Networking Toolbox" diff --git a/stacks/nextcloud/main.tf b/stacks/nextcloud/main.tf index d737fa5c..ef4e5295 100644 --- a/stacks/nextcloud/main.tf +++ b/stacks/nextcloud/main.tf @@ -219,7 +219,11 @@ module "nfs_nextcloud_backup_host" { } module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + source = "../../modules/kubernetes/ingress_factory" + # 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" dns_type = "proxied" namespace = kubernetes_namespace.nextcloud.metadata[0].name name = "nextcloud" diff --git a/stacks/novelapp/main.tf b/stacks/novelapp/main.tf index 6dab8e35..9aab9144 100644 --- a/stacks/novelapp/main.tf +++ b/stacks/novelapp/main.tf @@ -217,6 +217,7 @@ resource "kubernetes_service" "novelapp" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "non-proxied" namespace = kubernetes_namespace.novelapp.metadata[0].name name = "novelapp" diff --git a/stacks/ntfy/main.tf b/stacks/ntfy/main.tf index e69c3bd3..19e63f22 100644 --- a/stacks/ntfy/main.tf +++ b/stacks/ntfy/main.tf @@ -188,7 +188,11 @@ resource "kubernetes_service" "ntfy" { } module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + source = "../../modules/kubernetes/ingress_factory" + # 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" dns_type = "proxied" namespace = kubernetes_namespace.ntfy.metadata[0].name name = "ntfy" diff --git a/stacks/nvidia/modules/nvidia/main.tf b/stacks/nvidia/modules/nvidia/main.tf index 720f6daf..58400a57 100644 --- a/stacks/nvidia/modules/nvidia/main.tf +++ b/stacks/nvidia/modules/nvidia/main.tf @@ -218,6 +218,7 @@ resource "kubernetes_service" "nvidia-exporter" { module "ingress" { source = "../../../../modules/kubernetes/ingress_factory" + auth = "required" namespace = kubernetes_namespace.nvidia.metadata[0].name name = "nvidia-exporter" root_domain = "viktorbarzin.lan" diff --git a/stacks/onlyoffice/main.tf b/stacks/onlyoffice/main.tf index a81bbed9..d3466f98 100644 --- a/stacks/onlyoffice/main.tf +++ b/stacks/onlyoffice/main.tf @@ -250,6 +250,7 @@ resource "kubernetes_service" "onlyoffice" { } module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.onlyoffice.metadata[0].name name = "onlyoffice" diff --git a/stacks/openclaw/main.tf b/stacks/openclaw/main.tf index 2ecd3b79..23edd09a 100644 --- a/stacks/openclaw/main.tf +++ b/stacks/openclaw/main.tf @@ -404,8 +404,8 @@ resource "kubernetes_deployment" "openclaw" { # this the previously-baked kubeconfig retains a SA token bound to a # long-dead pod and kubectl returns "must be logged in to the server". init_container { - name = "setup-kubeconfig" - image = "busybox:1.37" + name = "setup-kubeconfig" + image = "busybox:1.37" command = ["sh", "-c", <<-EOT cat > /home/node/.openclaw/kubeconfig <<'KUBECONFIG_EOF' apiVersion: v1 @@ -444,8 +444,8 @@ resource "kubernetes_deployment" "openclaw" { # Main container: OpenClaw container { - name = "openclaw" - image = "ghcr.io/openclaw/openclaw:2026.5.4" + name = "openclaw" + image = "ghcr.io/openclaw/openclaw:2026.5.4" # Doctor --fix auto-promotes the highest-tier codex model (gpt-5-pro) after # auth-profile-based model discovery; pin gpt-5.4-mini back to default after it. command = ["sh", "-c", "node openclaw.mjs doctor --fix 2>/dev/null; node openclaw.mjs models set openai-codex/gpt-5.4-mini 2>/dev/null; exec node openclaw.mjs gateway --allow-unconfigured --bind lan"] @@ -752,7 +752,7 @@ module "ingress" { name = "openclaw" tls_secret_name = var.tls_secret_name port = 80 - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "OpenClaw" @@ -952,6 +952,7 @@ resource "kubernetes_service" "task_webhook" { module "task_webhook_ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" namespace = kubernetes_namespace.openclaw.metadata[0].name name = "task-webhook" tls_secret_name = var.tls_secret_name @@ -1275,5 +1276,5 @@ module "openlobster_ingress" { tls_secret_name = var.tls_secret_name host = "openlobster" port = 80 - protected = true + auth = "required" } diff --git a/stacks/paperless-ngx/main.tf b/stacks/paperless-ngx/main.tf index 4bafe6ce..f012093a 100644 --- a/stacks/paperless-ngx/main.tf +++ b/stacks/paperless-ngx/main.tf @@ -254,6 +254,7 @@ resource "kubernetes_service" "paperless-ngx" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" namespace = kubernetes_namespace.paperless-ngx.metadata[0].name name = "paperless-ngx" service_name = "paperless-ngx" diff --git a/stacks/phpipam/main.tf b/stacks/phpipam/main.tf index 9fce6c14..b1453c7b 100644 --- a/stacks/phpipam/main.tf +++ b/stacks/phpipam/main.tf @@ -234,7 +234,7 @@ module "ingress" { namespace = kubernetes_namespace.phpipam.metadata[0].name name = "phpipam" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "phpIPAM" diff --git a/stacks/plotting-book/main.tf b/stacks/plotting-book/main.tf index 07d116f2..198deaaa 100644 --- a/stacks/plotting-book/main.tf +++ b/stacks/plotting-book/main.tf @@ -198,6 +198,7 @@ resource "kubernetes_service" "plotting-book" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "non-proxied" namespace = kubernetes_namespace.plotting-book.metadata[0].name name = "plotting-book" diff --git a/stacks/poison-fountain/main.tf b/stacks/poison-fountain/main.tf index 870a1675..677d2663 100644 --- a/stacks/poison-fountain/main.tf +++ b/stacks/poison-fountain/main.tf @@ -210,6 +210,7 @@ resource "kubernetes_service" "poison_fountain" { # Deliberately NO rate limiting, NO CrowdSec, NO anti-AI (we WANT scrapers here) module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" namespace = kubernetes_namespace.poison_fountain.metadata[0].name name = "poison-fountain" host = "poison" diff --git a/stacks/postiz/modules/postiz/main.tf b/stacks/postiz/modules/postiz/main.tf index 77971332..96de0918 100644 --- a/stacks/postiz/modules/postiz/main.tf +++ b/stacks/postiz/modules/postiz/main.tf @@ -136,19 +136,19 @@ resource "helm_release" "postiz" { # Non-secret env. Note: BACKEND_INTERNAL_URL stays in-pod (Postiz convention). env = { - MAIN_URL = "https://postiz.viktorbarzin.me" - FRONTEND_URL = "https://postiz.viktorbarzin.me" - NEXT_PUBLIC_BACKEND_URL = "https://postiz.viktorbarzin.me/api" - BACKEND_INTERNAL_URL = "http://localhost:3000" - STORAGE_PROVIDER = "local" - UPLOAD_DIRECTORY = "/uploads" - NEXT_PUBLIC_UPLOAD_DIRECTORY = "/uploads" + MAIN_URL = "https://postiz.viktorbarzin.me" + FRONTEND_URL = "https://postiz.viktorbarzin.me" + NEXT_PUBLIC_BACKEND_URL = "https://postiz.viktorbarzin.me/api" + BACKEND_INTERNAL_URL = "http://localhost:3000" + STORAGE_PROVIDER = "local" + UPLOAD_DIRECTORY = "/uploads" + NEXT_PUBLIC_UPLOAD_DIRECTORY = "/uploads" # Disabled — admin user already created; sign-in only. - DISABLE_REGISTRATION = "true" - IS_GENERAL = "true" - NX_ADD_PLUGINS = "false" + DISABLE_REGISTRATION = "true" + IS_GENERAL = "true" + NX_ADD_PLUGINS = "false" # Postiz uses Temporal for cron/scheduling — bring our own; Helm chart doesn't. - TEMPORAL_ADDRESS = "temporal:7233" + TEMPORAL_ADDRESS = "temporal:7233" } # Postiz reads DATABASE_URL/REDIS_URL from this Secret. The chart does @@ -159,13 +159,13 @@ resource "helm_release" "postiz" { # postiz-redis-password) — both Services are ClusterIP, only routable # from inside the postiz namespace, so the well-known creds are safe. secrets = { - DATABASE_URL = "postgresql://postiz:postiz-password@postiz-postgresql:5432/postiz" - REDIS_URL = "redis://default:postiz-redis-password@postiz-redis-master:6379" - JWT_SECRET = "" + DATABASE_URL = "postgresql://postiz:postiz-password@postiz-postgresql:5432/postiz" + REDIS_URL = "redis://default:postiz-redis-password@postiz-redis-master:6379" + JWT_SECRET = "" # IG-via-Facebook OAuth (Postiz Instagram-Business integration). Empty # placeholder; ESO patches the real values from Vault below. - FACEBOOK_APP_ID = "" - FACEBOOK_APP_SECRET = "" + FACEBOOK_APP_ID = "" + FACEBOOK_APP_SECRET = "" # IG standalone (Postiz Instagram-Login integration). Uses the modern # `instagram_business_*` scopes — does not require the FB Login dance. INSTAGRAM_APP_ID = "" @@ -247,7 +247,7 @@ module "ingress_uploads_public" { host = var.host service_name = "postiz" port = 80 - protected = false + auth = "none" ingress_path = ["/uploads"] tls_secret_name = var.tls_secret_name } @@ -260,7 +260,7 @@ module "ingress" { host = var.host service_name = "postiz" port = 80 - protected = true # Authentik forward-auth on the UI / API path + auth = "required" # Authentik forward-auth on the UI / API path ingress_path = ["/"] tls_secret_name = var.tls_secret_name extra_annotations = { @@ -473,7 +473,7 @@ resource "kubernetes_cron_job_v1" "postgres_backup" { spec { restart_policy = "OnFailure" container { - name = "backup" + name = "backup" # Same image/pattern as dbaas/postgresql-backup: official postgres # client tools + apt-installed curl for the Pushgateway push. The # bitnamilegacy/postgresql variant is stripped (no curl/wget/python), diff --git a/stacks/priority-pass/main.tf b/stacks/priority-pass/main.tf index d02aa651..4f1e7ca9 100644 --- a/stacks/priority-pass/main.tf +++ b/stacks/priority-pass/main.tf @@ -171,6 +171,6 @@ module "ingress" { namespace = "priority-pass" name = "priority-pass" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" max_body_size = "10m" } diff --git a/stacks/privatebin/main.tf b/stacks/privatebin/main.tf index 3d0b14d6..c40a3963 100644 --- a/stacks/privatebin/main.tf +++ b/stacks/privatebin/main.tf @@ -138,7 +138,11 @@ resource "kubernetes_service" "privatebin" { # the default `anti_ai_scraping` middleware is sufficient protection. module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + source = "../../modules/kubernetes/ingress_factory" + # 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" namespace = kubernetes_namespace.privatebin.metadata[0].name name = "privatebin" host = "pb" diff --git a/stacks/real-estate-crawler/main.tf b/stacks/real-estate-crawler/main.tf index b5e0b79a..269da93a 100644 --- a/stacks/real-estate-crawler/main.tf +++ b/stacks/real-estate-crawler/main.tf @@ -341,14 +341,15 @@ module "anubis" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "none" # Anubis-fronted; PoW challenge gates bots, no Authentik dns_type = "proxied" namespace = kubernetes_namespace.realestate-crawler.metadata[0].name name = "wrongmove" service_name = module.anubis.service_name port = module.anubis.service_port extra_middlewares = ["traefik-x402@kubernetescrd"] - anti_ai_scraping = false - tls_secret_name = var.tls_secret_name + anti_ai_scraping = false + tls_secret_name = var.tls_secret_name extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Wrongmove" @@ -360,7 +361,11 @@ module "ingress" { } module "ingress-api" { - source = "../../modules/kubernetes/ingress_factory" + source = "../../modules/kubernetes/ingress_factory" + # Wrongmove's public UI is Anubis-fronted (auth=none on the / path); this + # /api ingress serves XHRs from that public UI. Forward-auth here would + # break the UI. + auth = "none" dns_type = "proxied" namespace = kubernetes_namespace.realestate-crawler.metadata[0].name name = "wrongmove-api" diff --git a/stacks/resume/main.tf b/stacks/resume/main.tf index ddf82227..5c94b642 100644 --- a/stacks/resume/main.tf +++ b/stacks/resume/main.tf @@ -354,6 +354,7 @@ resource "kubernetes_service" "resume" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.resume.metadata[0].name name = "resume" diff --git a/stacks/rybbit/main.tf b/stacks/rybbit/main.tf index f386a338..f3922955 100644 --- a/stacks/rybbit/main.tf +++ b/stacks/rybbit/main.tf @@ -563,6 +563,7 @@ resource "kubernetes_service" "rybbit-client" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.rybbit.metadata[0].name name = "rybbit" @@ -579,7 +580,11 @@ module "ingress" { } module "ingress-api" { - source = "../../modules/kubernetes/ingress_factory" + source = "../../modules/kubernetes/ingress_factory" + # 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" dns_type = "proxied" namespace = kubernetes_namespace.rybbit.metadata[0].name name = "rybbit-api" diff --git a/stacks/send/main.tf b/stacks/send/main.tf index fc333246..117acff9 100644 --- a/stacks/send/main.tf +++ b/stacks/send/main.tf @@ -165,7 +165,10 @@ resource "kubernetes_service" "send" { } } module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + 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" dns_type = "non-proxied" namespace = kubernetes_namespace.send.metadata[0].name name = "send" diff --git a/stacks/servarr/aiostreams/main.tf b/stacks/servarr/aiostreams/main.tf index 4ef69adc..7d702cb5 100644 --- a/stacks/servarr/aiostreams/main.tf +++ b/stacks/servarr/aiostreams/main.tf @@ -138,11 +138,12 @@ resource "kubernetes_service" "aiostreams" { module "ingress" { source = "../../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.aiostreams.metadata[0].name name = "aiostreams" tls_secret_name = var.tls_secret_name - # protected = true + # auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "AIOStreams" diff --git a/stacks/servarr/flaresolverr/main.tf b/stacks/servarr/flaresolverr/main.tf index 2538fafe..0c28d2b7 100644 --- a/stacks/servarr/flaresolverr/main.tf +++ b/stacks/servarr/flaresolverr/main.tf @@ -80,7 +80,7 @@ module "ingress" { namespace = "servarr" name = "flaresolverr" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "FlareSolverr" diff --git a/stacks/servarr/lidarr/main.tf b/stacks/servarr/lidarr/main.tf index c2dfa465..5776b153 100644 --- a/stacks/servarr/lidarr/main.tf +++ b/stacks/servarr/lidarr/main.tf @@ -170,7 +170,7 @@ module "ingress" { namespace = "servarr" name = "lidarr" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" # extra_annotations = { # "nginx.ingress.kubernetes.io/proxy-body-size" : "1G" // allow uploading .torrent files # } @@ -183,5 +183,5 @@ module "ingress-deemix" { namespace = "servarr" name = "deemix" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" } diff --git a/stacks/servarr/listenarr/main.tf b/stacks/servarr/listenarr/main.tf index e30d42d0..1f27165e 100644 --- a/stacks/servarr/listenarr/main.tf +++ b/stacks/servarr/listenarr/main.tf @@ -132,7 +132,7 @@ module "ingress" { namespace = "servarr" name = "listenarr" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Listenarr" diff --git a/stacks/servarr/prowlarr/main.tf b/stacks/servarr/prowlarr/main.tf index fd8a94bd..1099cab9 100644 --- a/stacks/servarr/prowlarr/main.tf +++ b/stacks/servarr/prowlarr/main.tf @@ -160,7 +160,7 @@ module "ingress" { namespace = "servarr" name = "prowlarr" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Prowlarr" diff --git a/stacks/servarr/qbittorrent/main.tf b/stacks/servarr/qbittorrent/main.tf index 11f97418..eadc4f14 100644 --- a/stacks/servarr/qbittorrent/main.tf +++ b/stacks/servarr/qbittorrent/main.tf @@ -407,7 +407,7 @@ module "ingress" { namespace = "servarr" name = "qbittorrent" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "qBittorrent" diff --git a/stacks/servarr/readarr/main.tf b/stacks/servarr/readarr/main.tf index 8af766b0..5bada503 100644 --- a/stacks/servarr/readarr/main.tf +++ b/stacks/servarr/readarr/main.tf @@ -147,5 +147,5 @@ module "ingress" { name = "readarr" port = 8787 tls_secret_name = var.tls_secret_name - protected = true + auth = "required" } diff --git a/stacks/servarr/soulseek/main.tf b/stacks/servarr/soulseek/main.tf index e402a218..0572c53a 100644 --- a/stacks/servarr/soulseek/main.tf +++ b/stacks/servarr/soulseek/main.tf @@ -113,5 +113,5 @@ module "ingress" { namespace = "servarr" name = "soulseek" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" } diff --git a/stacks/speedtest/main.tf b/stacks/speedtest/main.tf index c94f1fab..714dae04 100644 --- a/stacks/speedtest/main.tf +++ b/stacks/speedtest/main.tf @@ -236,7 +236,7 @@ module "ingress" { namespace = kubernetes_namespace.speedtest.metadata[0].name name = "speedtest" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Speedtest" diff --git a/stacks/stirling-pdf/main.tf b/stacks/stirling-pdf/main.tf index fd8ff151..ad5dcd7e 100644 --- a/stacks/stirling-pdf/main.tf +++ b/stacks/stirling-pdf/main.tf @@ -132,6 +132,7 @@ resource "kubernetes_service" "stirling-pdf" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.stirling-pdf.metadata[0].name name = "stirling-pdf" diff --git a/stacks/tandoor/main.tf b/stacks/tandoor/main.tf index cd9a6126..f71a8d10 100644 --- a/stacks/tandoor/main.tf +++ b/stacks/tandoor/main.tf @@ -252,6 +252,7 @@ resource "kubernetes_service" "tandoor" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.tandoor.metadata[0].name name = "tandoor" diff --git a/stacks/technitium/modules/technitium/main.tf b/stacks/technitium/modules/technitium/main.tf index 7f5e4463..46afccb2 100644 --- a/stacks/technitium/modules/technitium/main.tf +++ b/stacks/technitium/modules/technitium/main.tf @@ -329,6 +329,7 @@ resource "kubernetes_service" "technitium_dns_internal" { module "ingress" { source = "../../../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.technitium.metadata[0].name name = "technitium" diff --git a/stacks/terminal/main.tf b/stacks/terminal/main.tf index c3d894b2..53f5b9ad 100644 --- a/stacks/terminal/main.tf +++ b/stacks/terminal/main.tf @@ -65,7 +65,7 @@ module "ingress" { namespace = kubernetes_namespace.terminal.metadata[0].name name = "terminal" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Terminal" @@ -206,7 +206,7 @@ module "ingress_ro" { namespace = kubernetes_namespace.terminal.metadata[0].name name = "terminal-ro" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Terminal (Read-Only)" diff --git a/stacks/tor-proxy/main.tf b/stacks/tor-proxy/main.tf index 407fba33..392f912f 100644 --- a/stacks/tor-proxy/main.tf +++ b/stacks/tor-proxy/main.tf @@ -300,7 +300,7 @@ module "torrserver_ingress" { name = "torrserver" tls_secret_name = var.tls_secret_name port = "8090" - protected = true + auth = "required" external_monitor = false extra_annotations = { "gethomepage.dev/enabled" = "true" diff --git a/stacks/trading-bot/main.tf b/stacks/trading-bot/main.tf index 3f941b0e..ff35f6c9 100644 --- a/stacks/trading-bot/main.tf +++ b/stacks/trading-bot/main.tf @@ -617,7 +617,7 @@ module "ingress" { name = "trading" service_name = "trading-bot-frontend" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Trading Bot" diff --git a/stacks/traefik/modules/traefik/main.tf b/stacks/traefik/modules/traefik/main.tf index c386ca7e..c4e9bb0e 100644 --- a/stacks/traefik/modules/traefik/main.tf +++ b/stacks/traefik/modules/traefik/main.tf @@ -291,7 +291,7 @@ module "ingress" { host = "traefik" port = 8080 tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Traefik" diff --git a/stacks/travel_blog/main.tf b/stacks/travel_blog/main.tf index 01fbbb15..b427ad9b 100644 --- a/stacks/travel_blog/main.tf +++ b/stacks/travel_blog/main.tf @@ -111,13 +111,14 @@ module "anubis" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "none" # Anubis-fronted; PoW challenge gates bots, no Authentik namespace = kubernetes_namespace.travel-blog.metadata[0].name name = "travel" tls_secret_name = var.tls_secret_name service_name = module.anubis.service_name port = module.anubis.service_port extra_middlewares = ["traefik-x402@kubernetescrd"] - anti_ai_scraping = false + anti_ai_scraping = false extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Travel Blog" diff --git a/stacks/tuya-bridge/main.tf b/stacks/tuya-bridge/main.tf index 574ed95d..a6733369 100644 --- a/stacks/tuya-bridge/main.tf +++ b/stacks/tuya-bridge/main.tf @@ -180,6 +180,7 @@ resource "kubernetes_service" "tuya-bridge" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.tuya-bridge.metadata[0].name name = "tuya-bridge" diff --git a/stacks/uptime-kuma/modules/uptime-kuma/main.tf b/stacks/uptime-kuma/modules/uptime-kuma/main.tf index 3572c2ce..2b0b6f0e 100644 --- a/stacks/uptime-kuma/modules/uptime-kuma/main.tf +++ b/stacks/uptime-kuma/modules/uptime-kuma/main.tf @@ -182,6 +182,7 @@ resource "kubernetes_service" "uptime-kuma" { } module "ingress" { source = "../../../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.uptime-kuma.metadata[0].name name = "uptime" diff --git a/stacks/url/main.tf b/stacks/url/main.tf index 979b0aaa..58a127ba 100644 --- a/stacks/url/main.tf +++ b/stacks/url/main.tf @@ -288,6 +288,7 @@ resource "kubernetes_service" "shlink" { module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" dns_type = "proxied" namespace = kubernetes_namespace.shlink.metadata[0].name name = "url" @@ -438,7 +439,7 @@ module "ingress-web" { name = "shlink" service_name = "shlink-web" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "false" "gethomepage.dev/name" = "Shlink Web" diff --git a/stacks/vault/main.tf b/stacks/vault/main.tf index 0e84859a..e09e1532 100644 --- a/stacks/vault/main.tf +++ b/stacks/vault/main.tf @@ -228,7 +228,12 @@ resource "vault_identity_group_alias" "admins" { } module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + source = "../../modules/kubernetes/ingress_factory" + # Vault has its own auth (OIDC, K8s, tokens). External CLI clients, + # `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" dns_type = "proxied" namespace = kubernetes_namespace.vault.metadata[0].name name = "vault" diff --git a/stacks/vaultwarden/modules/vaultwarden/main.tf b/stacks/vaultwarden/modules/vaultwarden/main.tf index b3d24983..e5fc2af1 100644 --- a/stacks/vaultwarden/modules/vaultwarden/main.tf +++ b/stacks/vaultwarden/modules/vaultwarden/main.tf @@ -196,7 +196,12 @@ resource "kubernetes_service" "vaultwarden" { } module "ingress" { - source = "../../../../modules/kubernetes/ingress_factory" + source = "../../../../modules/kubernetes/ingress_factory" + # Bitwarden-compatible API — mobile app, browser extension, desktop app, and + # 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" dns_type = "proxied" namespace = kubernetes_namespace.vaultwarden.metadata[0].name name = "vaultwarden" diff --git a/stacks/vpa/modules/vpa/main.tf b/stacks/vpa/modules/vpa/main.tf index 71b2261b..6f1e7ff3 100644 --- a/stacks/vpa/modules/vpa/main.tf +++ b/stacks/vpa/modules/vpa/main.tf @@ -111,7 +111,7 @@ module "ingress" { service_name = "goldilocks-dashboard" port = 80 tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Goldilocks" diff --git a/stacks/wealthfolio/main.tf b/stacks/wealthfolio/main.tf index 3c1ea23f..ce687138 100644 --- a/stacks/wealthfolio/main.tf +++ b/stacks/wealthfolio/main.tf @@ -481,7 +481,7 @@ module "ingress" { namespace = kubernetes_namespace.wealthfolio.metadata[0].name name = "wealthfolio" tls_secret_name = var.tls_secret_name - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Wealthfolio" @@ -514,7 +514,7 @@ resource "kubernetes_cron_job_v1" "wealthfolio_sync" { name = "registry-credentials" } container { - name = "sync" + name = "sync" # Phase 4 of forgejo-registry-consolidation 2026-05-07 + # post-cutover wealthfolio-sync rebuild: image is now # produced by /home/wizard/code/broker-sync (Forgejo diff --git a/stacks/webhook_handler/main.tf b/stacks/webhook_handler/main.tf index 09996294..2be2ae9c 100644 --- a/stacks/webhook_handler/main.tf +++ b/stacks/webhook_handler/main.tf @@ -259,7 +259,10 @@ resource "kubernetes_service" "webhook_handler" { } module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + 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" namespace = kubernetes_namespace.webhook-handler.metadata[0].name name = "webhook-handler" host = "webhook" diff --git a/stacks/woodpecker/main.tf b/stacks/woodpecker/main.tf index a27741c8..51de9e98 100644 --- a/stacks/woodpecker/main.tf +++ b/stacks/woodpecker/main.tf @@ -351,7 +351,11 @@ resource "kubernetes_cron_job_v1" "vault_secret_sync" { } module "ingress" { - source = "../../modules/kubernetes/ingress_factory" + source = "../../modules/kubernetes/ingress_factory" + # 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" dns_type = "non-proxied" namespace = kubernetes_namespace.woodpecker.metadata[0].name name = "ci" diff --git a/stacks/xray/modules/xray/main.tf b/stacks/xray/modules/xray/main.tf index 358f3c58..8541d977 100644 --- a/stacks/xray/modules/xray/main.tf +++ b/stacks/xray/modules/xray/main.tf @@ -217,7 +217,9 @@ resource "kubernetes_service" "xray-reality" { } module "ingress_ws" { - source = "../../../../modules/kubernetes/ingress_factory" + source = "../../../../modules/kubernetes/ingress_factory" + # VPN protocol (WebSocket transport) — native xray clients, not browsers. + auth = "none" dns_type = "proxied" namespace = kubernetes_namespace.xray.metadata[0].name name = "xray-ws" @@ -228,7 +230,9 @@ module "ingress_ws" { } module "ingress_grpc" { - source = "../../../../modules/kubernetes/ingress_factory" + source = "../../../../modules/kubernetes/ingress_factory" + # VPN protocol (gRPC transport) — native xray clients, not browsers. + auth = "none" dns_type = "proxied" namespace = kubernetes_namespace.xray.metadata[0].name name = "xray-grpc" @@ -243,7 +247,9 @@ module "ingress_grpc" { } module "ingress_vless" { - source = "../../../../modules/kubernetes/ingress_factory" + source = "../../../../modules/kubernetes/ingress_factory" + # VPN protocol (VLESS) — native xray clients, not browsers. + auth = "none" dns_type = "proxied" namespace = kubernetes_namespace.xray.metadata[0].name name = "xray-vless" diff --git a/stacks/ytdlp/main.tf b/stacks/ytdlp/main.tf index d8dcfcc6..a74508da 100644 --- a/stacks/ytdlp/main.tf +++ b/stacks/ytdlp/main.tf @@ -176,6 +176,7 @@ resource "kubernetes_service" "ytdlp" { } module "ingress" { source = "../../modules/kubernetes/ingress_factory" + auth = "required" namespace = kubernetes_namespace.ytdlp.metadata[0].name name = "ytdlp" tls_secret_name = var.tls_secret_name @@ -355,7 +356,7 @@ module "highlights_ingress" { name = "yt-highlights" tls_secret_name = var.tls_secret_name host = "yt-highlights" - protected = true + auth = "required" extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "YT Highlights"