[ci skip] Refactor raw ingresses to use ingress_factory module

Enhance ingress_factory with full_host, extra_middlewares, and
skip_default_rate_limit variables. Fix TLS hosts bug to use
effective_host. Migrate 13 services from raw kubernetes_ingress_v1
resources to centralized ingress_factory module calls, removing
manual rybbit middleware CRDs where the factory now handles them.
This commit is contained in:
Viktor Barzin 2026-02-10 21:11:46 +00:00
parent 70376b623e
commit 6d6ec0c1e2
13 changed files with 161 additions and 582 deletions

View file

@ -35,50 +35,21 @@ resource "helm_release" "authentik" {
}
resource "kubernetes_ingress_v1" "authentik" {
metadata {
name = "authentik"
namespace = kubernetes_namespace.authentik.metadata[0].name
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
spec {
ingress_class_name = "traefik"
tls {
hosts = ["authentik.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "authentik.viktorbarzin.me"
http {
path {
path = "/outpost.goauthentik.io"
path_type = "Prefix"
backend {
service {
name = "ak-outpost-authentik-embedded-outpost"
port {
number = 9000
}
}
}
}
path {
path = "/"
path_type = "Prefix"
backend {
service {
name = "goauthentik-server"
port {
number = 80
}
}
}
}
}
}
}
module "ingress" {
source = "../ingress_factory"
namespace = kubernetes_namespace.authentik.metadata[0].name
name = "authentik"
service_name = "goauthentik-server"
tls_secret_name = var.tls_secret_name
}
module "ingress-outpost" {
source = "../ingress_factory"
namespace = kubernetes_namespace.authentik.metadata[0].name
name = "authentik-outpost"
host = "authentik"
service_name = "ak-outpost-authentik-embedded-outpost"
port = 9000
ingress_path = ["/outpost.goauthentik.io"]
tls_secret_name = var.tls_secret_name
}

View file

@ -108,75 +108,22 @@ resource "kubernetes_service" "blog" {
}
}
resource "kubernetes_ingress_v1" "blog" {
metadata {
name = "blog-ingress"
namespace = kubernetes_namespace.website.metadata[0].name
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,website-rybbit-analytics@kubernetescrd"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
spec {
ingress_class_name = "traefik"
tls {
hosts = ["viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "viktorbarzin.me"
http {
path {
path = "/"
backend {
service {
name = "blog"
port {
number = 80
}
}
}
}
}
}
rule {
host = "www.viktorbarzin.me"
http {
path {
path = "/"
backend {
service {
name = "blog"
port {
number = 80
}
}
}
}
}
}
}
module "ingress" {
source = "../ingress_factory"
namespace = kubernetes_namespace.website.metadata[0].name
name = "blog"
service_name = "blog"
full_host = "viktorbarzin.me"
tls_secret_name = var.tls_secret_name
rybbit_site_id = "da853a2438d0"
}
# Rybbit analytics middleware for blog
resource "kubernetes_manifest" "rybbit_analytics" {
manifest = {
apiVersion = "traefik.io/v1alpha1"
kind = "Middleware"
metadata = {
name = "rybbit-analytics"
namespace = kubernetes_namespace.website.metadata[0].name
}
spec = {
plugin = {
rewritebody = {
rewrites = [{
regex = "</head>"
replacement = "<script src=\"https://rybbit.viktorbarzin.me/api/script.js\" data-site-id=\"da853a2438d0\" defer></script></head>"
}]
}
}
}
}
module "ingress-www" {
source = "../ingress_factory"
namespace = kubernetes_namespace.website.metadata[0].name
name = "blog-www"
service_name = "blog"
full_host = "www.viktorbarzin.me"
tls_secret_name = var.tls_secret_name
rybbit_site_id = "da853a2438d0"
}

View file

@ -98,37 +98,10 @@ resource "kubernetes_service" "discount-bandit" {
}
}
resource "kubernetes_ingress_v1" "discount-bandit" {
metadata {
name = "discount-bandit"
namespace = kubernetes_namespace.discount-bandit.metadata[0].name
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
spec {
ingress_class_name = "traefik"
tls {
hosts = ["discount.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "discount.viktorbarzin.me"
http {
path {
path = "/"
backend {
service {
name = "discount-bandit"
port {
number = 80
}
}
}
}
}
}
}
module "ingress" {
source = "../ingress_factory"
namespace = kubernetes_namespace.discount-bandit.metadata[0].name
name = "discount-bandit"
host = "discount"
tls_secret_name = var.tls_secret_name
}

View file

@ -455,47 +455,25 @@ resource "kubernetes_service" "immich-machine-learning" {
}
}
resource "kubernetes_ingress_v1" "ingress" {
metadata {
namespace = kubernetes_namespace.immich.metadata[0].name
name = "immich"
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-immich-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,immich-rybbit-analytics@kubernetescrd"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
"gethomepage.dev/enabled" = "true"
"gethomepage.dev/description" = "Photos library"
"gethomepage.dev/icon" = "immich.png"
"gethomepage.dev/name" = "Immich"
"gethomepage.dev/widget.type" = "immich"
"gethomepage.dev/widget.url" = "https://immich.viktorbarzin.me"
"gethomepage.dev/pod-selector" = ""
"gethomepage.dev/widget.key" = var.homepage_token
}
}
spec {
ingress_class_name = "traefik"
tls {
hosts = ["immich.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "immich.viktorbarzin.me"
http {
path {
backend {
service {
name = "immich-server"
port {
number = 2283
}
}
}
}
}
}
module "ingress-immich" {
source = "../ingress_factory"
namespace = kubernetes_namespace.immich.metadata[0].name
name = "immich"
service_name = "immich-server"
port = 2283
tls_secret_name = var.tls_secret_name
rybbit_site_id = "35eedb7a3d2b"
skip_default_rate_limit = true
extra_middlewares = ["traefik-immich-rate-limit@kubernetescrd"]
extra_annotations = {
"gethomepage.dev/enabled" = "true"
"gethomepage.dev/description" = "Photos library"
"gethomepage.dev/icon" = "immich.png"
"gethomepage.dev/name" = "Immich"
"gethomepage.dev/widget.type" = "immich"
"gethomepage.dev/widget.url" = "https://immich.viktorbarzin.me"
"gethomepage.dev/pod-selector" = ""
"gethomepage.dev/widget.key" = var.homepage_token
}
}
@ -667,25 +645,3 @@ resource "kubernetes_cron_job_v1" "postgresql-backup" {
# protected = true
# }
# Rybbit analytics middleware for Immich
resource "kubernetes_manifest" "rybbit_analytics" {
manifest = {
apiVersion = "traefik.io/v1alpha1"
kind = "Middleware"
metadata = {
name = "rybbit-analytics"
namespace = kubernetes_namespace.immich.metadata[0].name
}
spec = {
plugin = {
rewritebody = {
rewrites = [{
regex = "</head>"
replacement = "<script src=\"https://rybbit.viktorbarzin.me/api/script.js\" data-site-id=\"35eedb7a3d2b\" defer></script></head>"
}]
}
}
}
}
}

View file

@ -59,6 +59,22 @@ variable "exclude_crowdsec" {
type = bool
default = false
}
variable "full_host" {
type = string
default = null
}
variable "extra_middlewares" {
type = list(string)
default = []
}
variable "skip_default_rate_limit" {
type = bool
default = false
}
locals {
effective_host = var.full_host != null ? var.full_host : "${var.host != null ? var.host : var.name}.${var.root_domain}"
}
resource "kubernetes_service" "proxied-service" {
@ -89,15 +105,15 @@ resource "kubernetes_ingress_v1" "proxied-ingress" {
name = var.name
namespace = var.namespace
annotations = merge({
"traefik.ingress.kubernetes.io/router.middlewares" = join(",", compact([
"traefik-rate-limit@kubernetescrd",
"traefik.ingress.kubernetes.io/router.middlewares" = join(",", compact(concat([
var.skip_default_rate_limit ? null : "traefik-rate-limit@kubernetescrd",
var.custom_content_security_policy == null ? "traefik-csp-headers@kubernetescrd" : null,
var.exclude_crowdsec ? null : "traefik-crowdsec@kubernetescrd",
var.protected ? "traefik-authentik-forward-auth@kubernetescrd" : null,
var.allow_local_access_only ? "traefik-local-only@kubernetescrd" : null,
var.rybbit_site_id != null ? "${var.namespace}-rybbit-analytics-${var.name}@kubernetescrd" : null,
var.custom_content_security_policy != null ? "${var.namespace}-custom-csp-${var.name}@kubernetescrd" : null,
]))
], var.extra_middlewares)))
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}, var.extra_annotations)
}
@ -105,11 +121,11 @@ resource "kubernetes_ingress_v1" "proxied-ingress" {
spec {
ingress_class_name = "traefik"
tls {
hosts = ["${var.name}.${var.root_domain}"]
hosts = [local.effective_host]
secret_name = var.tls_secret_name
}
rule {
host = "${var.host != null ? var.host : var.name}.${var.root_domain}"
host = local.effective_host
http {
dynamic "path" {
for_each = var.ingress_path
@ -132,7 +148,7 @@ resource "kubernetes_ingress_v1" "proxied-ingress" {
}
}
# Rybbit analytics middleware (rewritebody plugin) - created per service when rybbit_site_id is set
# Rybbit analytics middleware (rewrite-body plugin with content-type filtering) - created per service when rybbit_site_id is set
resource "kubernetes_manifest" "rybbit_analytics" {
count = var.rybbit_site_id != null ? 1 : 0
@ -145,11 +161,14 @@ resource "kubernetes_manifest" "rybbit_analytics" {
}
spec = {
plugin = {
rewritebody = {
rewrite-body = {
rewrites = [{
regex = "</head>"
replacement = "<script src=\"https://rybbit.viktorbarzin.me/api/script.js\" data-site-id=\"${var.rybbit_site_id}\" defer></script></head>"
}]
monitoring = {
types = ["text/html"]
}
}
}
}

View file

@ -108,38 +108,10 @@ resource "kubernetes_service" "jellyfin" {
}
}
resource "kubernetes_ingress_v1" "jellyfin" {
metadata {
name = "jellyfin"
namespace = kubernetes_namespace.jellyfin.metadata[0].name
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
spec {
ingress_class_name = "traefik"
tls {
hosts = ["jellyfin.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "jellyfin.viktorbarzin.me"
http {
path {
path = "/"
backend {
service {
name = "jellyfin"
port {
number = 80
}
}
}
}
}
}
}
module "ingress" {
source = "../ingress_factory"
namespace = kubernetes_namespace.jellyfin.metadata[0].name
name = "jellyfin"
tls_secret_name = var.tls_secret_name
}

View file

@ -210,39 +210,11 @@ resource "kubernetes_service" "oauth_proxy" {
}
}
resource "kubernetes_ingress_v1" "oauth" {
metadata {
name = "oauth2"
namespace = "oauth2"
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
spec {
ingress_class_name = "traefik"
tls {
hosts = ["oauth2.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "oauth2.viktorbarzin.me"
http {
path {
path = "/"
backend {
service {
name = "oauth2"
port {
number = 80
}
}
}
}
}
}
}
module "ingress" {
source = "../ingress_factory"
namespace = "oauth2"
name = "oauth2"
tls_secret_name = var.tls_secret_name
}

View file

@ -78,37 +78,10 @@ resource "kubernetes_service" "openid_help_page" {
}
}
resource "kubernetes_ingress_v1" "openid_help_page" {
metadata {
name = "openid-help-page"
namespace = "openid-help-page"
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
spec {
ingress_class_name = "traefik"
tls {
hosts = ["kubectl.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "kubectl.viktorbarzin.me"
http {
path {
path = "/"
backend {
service {
name = "openid-help-page"
port {
number = 80
}
}
}
}
}
}
}
module "ingress" {
source = "../ingress_factory"
namespace = "openid-help-page"
name = "openid-help-page"
host = "kubectl"
tls_secret_name = var.tls_secret_name
}

View file

@ -89,14 +89,6 @@ resource "kubernetes_service" "realestate-crawler-ui" {
}
}
}
# module "ingress" {
# source = "../ingress_factory"
# namespace = kubernetes_namespace.realestate-crawler.metadata[0].name
# name = "wrongmove"
# service_name = "realestate-crawler-ui"
# tls_secret_name = var.tls_secret_name
# protected = true
# }
resource "kubernetes_deployment" "realestate-crawler-api" {
metadata {
@ -228,60 +220,24 @@ resource "kubernetes_service" "realestate-crawler-api" {
}
}
}
# module "ingress-api" {
# source = "../ingress_factory"
# namespace = kubernetes_namespace.realestate-crawler.metadata[0].name
# name = "wrongmove-api"
# service_name = "realestate-crawler-api"
# tls_secret_name = var.tls_secret_name
# }
resource "kubernetes_ingress_v1" "proxied-ingress" {
metadata {
name = "realestate-crawler"
namespace = kubernetes_namespace.realestate-crawler.metadata[0].name
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,realestate-crawler-rybbit-analytics@kubernetescrd"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
module "ingress" {
source = "../ingress_factory"
namespace = kubernetes_namespace.realestate-crawler.metadata[0].name
name = "wrongmove"
service_name = "realestate-crawler-ui"
tls_secret_name = var.tls_secret_name
rybbit_site_id = "edee05de453d"
}
spec {
ingress_class_name = "traefik"
tls {
hosts = ["wrongmove.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "wrongmove.viktorbarzin.me"
http {
path {
path = "/"
path_type = "Prefix"
backend {
service {
name = "realestate-crawler-ui"
port {
number = 80
}
}
}
}
path {
path = "/api"
path_type = "Prefix"
backend {
service {
name = "realestate-crawler-api"
port {
number = 80
}
}
}
}
}
}
}
module "ingress-api" {
source = "../ingress_factory"
namespace = kubernetes_namespace.realestate-crawler.metadata[0].name
name = "wrongmove-api"
host = "wrongmove"
service_name = "realestate-crawler-api"
ingress_path = ["/api"]
tls_secret_name = var.tls_secret_name
}
@ -490,25 +446,3 @@ resource "kubernetes_cron_job_v1" "scrape-rightmove" {
}
}
}
# Rybbit analytics middleware for real-estate-crawler
resource "kubernetes_manifest" "rybbit_analytics" {
manifest = {
apiVersion = "traefik.io/v1alpha1"
kind = "Middleware"
metadata = {
name = "rybbit-analytics"
namespace = kubernetes_namespace.realestate-crawler.metadata[0].name
}
spec = {
plugin = {
rewritebody = {
rewrites = [{
regex = "</head>"
replacement = "<script src=\"https://rybbit.viktorbarzin.me/api/script.js\" data-site-id=\"edee05de453d\" defer></script></head>"
}]
}
}
}
}
}

View file

@ -286,79 +286,21 @@ resource "kubernetes_service" "rybbit-client" {
}
}
resource "kubernetes_ingress_v1" "rybbit" {
metadata {
name = "rybbit"
namespace = kubernetes_namespace.rybbit.metadata[0].name
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,rybbit-rybbit-analytics@kubernetescrd"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
spec {
ingress_class_name = "traefik"
tls {
hosts = ["rybbit.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "rybbit.viktorbarzin.me"
http {
# API backend
path {
path = "/api"
path_type = "Prefix"
backend {
service {
name = "rybbit"
port {
number = 80
}
}
}
}
# Frontend
path {
path = "/"
path_type = "Prefix"
backend {
service {
name = "rybbit-client"
port {
number = 80
}
}
}
}
}
}
}
module "ingress" {
source = "../ingress_factory"
namespace = kubernetes_namespace.rybbit.metadata[0].name
name = "rybbit"
service_name = "rybbit-client"
tls_secret_name = var.tls_secret_name
rybbit_site_id = "3c476801a777"
}
# Rybbit analytics middleware for self-tracking
resource "kubernetes_manifest" "rybbit_analytics" {
manifest = {
apiVersion = "traefik.io/v1alpha1"
kind = "Middleware"
metadata = {
name = "rybbit-analytics"
namespace = kubernetes_namespace.rybbit.metadata[0].name
}
spec = {
plugin = {
rewritebody = {
rewrites = [{
regex = "</head>"
replacement = "<script src=\"https://rybbit.viktorbarzin.me/api/script.js\" data-site-id=\"3c476801a777\" defer></script></head>"
}]
}
}
}
}
module "ingress-api" {
source = "../ingress_factory"
namespace = kubernetes_namespace.rybbit.metadata[0].name
name = "rybbit-api"
host = "rybbit"
service_name = "rybbit"
ingress_path = ["/api"]
tls_secret_name = var.tls_secret_name
}

View file

@ -118,37 +118,11 @@ resource "kubernetes_service" "readarr" {
}
}
resource "kubernetes_ingress_v1" "readarr" {
metadata {
name = "readarr"
namespace = "readarr"
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,traefik-authentik-forward-auth@kubernetescrd"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
spec {
ingress_class_name = "traefik"
tls {
hosts = ["readarr.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "readarr.viktorbarzin.me"
http {
path {
path = "/"
backend {
service {
name = "readarr"
port {
number = 8787
}
}
}
}
}
}
}
module "ingress" {
source = "../../ingress_factory"
namespace = "readarr"
name = "readarr"
port = 8787
tls_secret_name = var.tls_secret_name
protected = true
}

View file

@ -195,49 +195,22 @@ resource "kubernetes_service" "api" {
}
}
resource "kubernetes_ingress_v1" "vikunja" {
metadata {
name = "vikunja"
namespace = kubernetes_namespace.vikunja.metadata[0].name
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
spec {
ingress_class_name = "traefik"
tls {
hosts = ["todo.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "todo.viktorbarzin.me"
http {
path {
path = "/"
backend {
service {
name = "vikunja"
port {
number = 80
}
}
}
}
path {
path = "/api/"
backend {
service {
name = "api"
port {
number = 3456
}
}
}
}
}
}
}
module "ingress" {
source = "../ingress_factory"
namespace = kubernetes_namespace.vikunja.metadata[0].name
name = "vikunja"
host = "todo"
tls_secret_name = var.tls_secret_name
}
module "ingress-api" {
source = "../ingress_factory"
namespace = kubernetes_namespace.vikunja.metadata[0].name
name = "vikunja-api"
host = "todo"
service_name = "api"
port = 3456
ingress_path = ["/api/"]
tls_secret_name = var.tls_secret_name
}

View file

@ -189,37 +189,10 @@ resource "kubernetes_service" "webhook_handler" {
}
}
resource "kubernetes_ingress_v1" "webhook_handler" {
metadata {
name = "webhook-handler-ingress"
namespace = kubernetes_namespace.webhook-handler.metadata[0].name
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
spec {
ingress_class_name = "traefik"
tls {
hosts = ["webhook.viktorbarzin.me"]
secret_name = var.tls_secret_name
}
rule {
host = "webhook.viktorbarzin.me"
http {
path {
path = "/"
backend {
service {
name = "webhook-handler"
port {
number = 80
}
}
}
}
}
}
}
module "ingress" {
source = "../ingress_factory"
namespace = kubernetes_namespace.webhook-handler.metadata[0].name
name = "webhook-handler"
host = "webhook"
tls_secret_name = var.tls_secret_name
}