ingress_factory: replace protected bool with auth enum + audit pass across 100 stacks
Phase 3+4 of default-deny ingress plan. Replaces the `protected = bool` (default
false → unprotected) variable in `modules/kubernetes/ingress_factory` with
`auth = string` enum (default "required" → fail-closed). Touches every
ingress_factory caller so the audit decision is recorded explicitly in code.
ingress_factory (Phase 3):
- `auth = "required"`: standard Authentik forward-auth (the legacy
`protected = true` semantic).
- `auth = "public"`: forward-auth via the new `authentik-forward-auth-public`
middleware → dedicated public outpost → guest auto-bind. Logged-in users
keep their real identity.
- `auth = "none"`: no Authentik middleware. For Anubis-fronted content, native
client APIs (Git, /v2/, WebDAV), webhook receivers, the Authentik outpost
itself.
- `effective_anti_ai` default flips ON only when `auth = "none"` (auth-gated
ingresses don't need anti-AI noise; the auth flow already discourages bots).
Audit pass (Phase 4) across 96 ingress_factory call sites:
- 49 explicit `protected = true` → `auth = "required"`
- 8 explicit `protected = false` → `auth = "none"` (5) or `auth = "public"` (3)
- 64 previously-default (no protected line) → `auth = "required"` ADDED, then
reviewed individually:
* 9 Anubis-fronted (blog, www, kms, travel, f1, cyberchef, jsoncrack,
homepage, wrongmove UI, privatebin) → `auth = "none"`
* 22 native-client / programmatic surfaces (Forgejo Git+/v2/, webhook
handler, claude-memory MCP, Nextcloud WebDAV, Matrix, Vault CLI/OIDC,
xray VPN, ntfy, woodpecker webhooks, n8n triggers, ntfy push, dawarich
location ingestion, immich frame kiosk, headscale CP, send anonymous
drops, rybbit beacon, vaultwarden API, Authentik UI itself + outposts) →
`auth = "none"`
* Remaining ~33 → `auth = "required"` confirmed (admin tools, internal
UIs, services without app-level auth)
- Smoke-test promotions to `auth = "public"`: fire-planner public UI,
k8s-portal API, insta2spotify callback.
Three call sites in wrapper modules (`stacks/freedify/factory/`,
`stacks/reverse-proxy/modules/reverse_proxy/`) keep their internal `protected`
bool — they translate to `auth` internally, out of scope for this rename.
Behavior change: previously-default ingresses now fail closed (require
Authentik login) unless explicitly flipped to `auth = "none"` or
`auth = "public"`. This is the audit goal — no more accidentally-unprotected
surfaces. Sites that were intentionally public (Anubis content, native APIs,
webhooks) are now explicitly recorded as `auth = "none"`.
Drive-by: `modules/create-vm/main.tf` picked up cosmetic alignment via
`terraform fmt -recursive` during the audit. Behavior-neutral.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
88e57fdddb
commit
ff5538a667
100 changed files with 351 additions and 165 deletions
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -87,5 +87,5 @@ module "ingress" {
|
|||
name = "<app-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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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", "")
|
||||
|
|
|
|||
|
|
@ -215,6 +215,7 @@ resource "kubernetes_service" "freshrss" {
|
|||
}
|
||||
module "ingress" {
|
||||
source = "../../modules/kubernetes/ingress_factory"
|
||||
auth = "required"
|
||||
dns_type = "proxied"
|
||||
namespace = "freshrss"
|
||||
name = "rss"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
# }
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -147,5 +147,5 @@ module "ingress" {
|
|||
name = "readarr"
|
||||
port = 8787
|
||||
tls_secret_name = var.tls_secret_name
|
||||
protected = true
|
||||
auth = "required"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,5 +113,5 @@ module "ingress" {
|
|||
namespace = "servarr"
|
||||
name = "soulseek"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
protected = true
|
||||
auth = "required"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue