Migrate all service modules from nginx-ingress to Traefik
- Remove nginx-specific ingress variables (use_proxy_protocol, proxy_timeout, additional_configuration_snippet) - Update ingress annotations to use Traefik middleware CRDs - Delete nginx-ingress module (replaced by traefik) - Add new traefik middleware.tf for shared middleware definitions - Update service modules to work with new ingress_factory interface
This commit is contained in:
parent
43cdebe791
commit
b36932f9a3
50 changed files with 516 additions and 1681 deletions
|
|
@ -93,11 +93,7 @@ module "ingress" {
|
|||
namespace = "actualbudget"
|
||||
name = "budget-${var.name}"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "0",
|
||||
"nginx.ingress.kubernetes.io/client-max-body-size" : "0"
|
||||
}
|
||||
rybbit_site_id = "3e6b6b68088a"
|
||||
rybbit_site_id = "3e6b6b68088a"
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -211,7 +211,4 @@ module "ingress" {
|
|||
name = "affine"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
max_body_size = "500m"
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "500m"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,10 +129,6 @@ module "ingress" {
|
|||
namespace = kubernetes_namespace.audiobookshelf.metadata[0].name
|
||||
name = "audiobookshelf"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "0",
|
||||
"nginx.ingress.kubernetes.io/client-max-body-size" : "0"
|
||||
}
|
||||
rybbit_site_id = "b38fda4285df"
|
||||
rybbit_site_id = "b38fda4285df"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,11 +40,13 @@ resource "kubernetes_ingress_v1" "authentik" {
|
|||
name = "authentik"
|
||||
namespace = kubernetes_namespace.authentik.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"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
|
||||
|
|
|
|||
|
|
@ -113,26 +113,13 @@ resource "kubernetes_ingress_v1" "blog" {
|
|||
name = "blog-ingress"
|
||||
namespace = kubernetes_namespace.website.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/configuration-snippet" = <<-EOT
|
||||
# Only modify HTML
|
||||
sub_filter_types text/html;
|
||||
sub_filter_once off;
|
||||
|
||||
# Disable compression so sub_filter works
|
||||
proxy_set_header Accept-Encoding "";
|
||||
|
||||
# Inject analytics before </head>
|
||||
sub_filter '</head>' '
|
||||
<script src="https://rybbit.viktorbarzin.me/api/script.js"
|
||||
data-site-id="da853a2438d0"
|
||||
defer></script>
|
||||
</head>';
|
||||
EOT
|
||||
"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
|
||||
|
|
@ -171,3 +158,25 @@ resource "kubernetes_ingress_v1" "blog" {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 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>"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,8 +224,6 @@ module "ingress" {
|
|||
name = "calibre"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "5000m"
|
||||
|
||||
"gethomepage.dev/enabled" = "true"
|
||||
"gethomepage.dev/description" = "Book library"
|
||||
# gethomepage.dev/group: Media
|
||||
|
|
@ -239,10 +237,8 @@ module "ingress" {
|
|||
# gethomepage.dev/weight: 10 # optional
|
||||
# gethomepage.dev/instance: "public" # optional
|
||||
}
|
||||
rybbit_site_id = "17a5c7fbb077"
|
||||
additional_configuration_snippet = <<-EOF
|
||||
more_set_headers "Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval' https://rybbit.viktorbarzin.me";
|
||||
EOF
|
||||
rybbit_site_id = "17a5c7fbb077"
|
||||
custom_content_security_policy = "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://rybbit.viktorbarzin.me"
|
||||
}
|
||||
|
||||
# Stacks - Anna's Archive Download Manager
|
||||
|
|
|
|||
|
|
@ -181,25 +181,13 @@ resource "kubernetes_service" "crowdsec-web" {
|
|||
}
|
||||
}
|
||||
module "ingress" {
|
||||
source = "../ingress_factory"
|
||||
namespace = kubernetes_namespace.crowdsec.metadata[0].name
|
||||
name = "crowdsec-web"
|
||||
protected = true
|
||||
tls_secret_name = var.tls_secret_name
|
||||
extra_annotations = {
|
||||
# "crowdsec.io/bouncer-mode" : "bypass"
|
||||
"nginx.ingress.kubernetes.io/server-snippet" : <<-EOF
|
||||
# --- Disable CrowdSec for this host ---
|
||||
set $crowdsec_bypass 1;
|
||||
access_by_lua_block {
|
||||
-- Skip calling CrowdSec for this server
|
||||
if ngx.var.crowdsec_bypass == "1" then
|
||||
return
|
||||
end
|
||||
}
|
||||
EOF
|
||||
}
|
||||
rybbit_site_id = "d09137795ccc"
|
||||
source = "../ingress_factory"
|
||||
namespace = kubernetes_namespace.crowdsec.metadata[0].name
|
||||
name = "crowdsec-web"
|
||||
protected = true
|
||||
tls_secret_name = var.tls_secret_name
|
||||
exclude_crowdsec = true
|
||||
rybbit_site_id = "d09137795ccc"
|
||||
}
|
||||
|
||||
# CronJob to import public blocklists into CrowdSec
|
||||
|
|
|
|||
|
|
@ -323,16 +323,5 @@ module "ingress" {
|
|||
namespace = kubernetes_namespace.dawarich.metadata[0].name
|
||||
name = "dawarich"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/limit-connections" : 100
|
||||
"nginx.ingress.kubernetes.io/limit-rps" : 50
|
||||
"nginx.ingress.kubernetes.io/limit-rpm" : 1000
|
||||
"nginx.ingress.kubernetes.io/limit-burst-multiplier" : 500
|
||||
"nginx.ingress.kubernetes.io/limit-rate-after" : 1000
|
||||
"nginx.ingress.kubernetes.io/configuration-snippet" = <<-EOF
|
||||
limit_req_status 429;
|
||||
limit_conn_status 429;
|
||||
EOF
|
||||
}
|
||||
rybbit_site_id = "0abfd409f2fb"
|
||||
rybbit_site_id = "0abfd409f2fb"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,11 +103,13 @@ resource "kubernetes_ingress_v1" "discount-bandit" {
|
|||
name = "discount-bandit"
|
||||
namespace = kubernetes_namespace.discount-bandit.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"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
|
||||
|
|
|
|||
|
|
@ -405,6 +405,5 @@ module "audiblez-web-ingress" {
|
|||
tls_secret_name = var.tls_secret_name
|
||||
protected = true
|
||||
max_body_size = "500m" # Allow large EPUB uploads
|
||||
proxy_timeout = 3600 # Long timeout for conversions
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,4 @@ module "ingress" {
|
|||
name = "draw"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
protected = true
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/auth-response-headers" = "X-authentik-username,X-authentik-email,X-authentik-name"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,9 +87,5 @@ module "ingress" {
|
|||
namespace = kubernetes_namespace.f1-stream.metadata[0].name
|
||||
name = "f1"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/force-ssl-redirect" : "false"
|
||||
"nginx.ingress.kubernetes.io/ssl-redirect" : "false"
|
||||
}
|
||||
rybbit_site_id = "7e69786f66d5"
|
||||
rybbit_site_id = "7e69786f66d5"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -252,16 +252,13 @@ resource "kubernetes_ingress_v1" "finance_app" {
|
|||
name = "finance-app"
|
||||
namespace = kubernetes_namespace.finance_app.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
#"nginx.ingress.kubernetes.io/auth-url"= "https://oauth-provider/auth"
|
||||
#"nginx.ingress.kubernetes.io/auth-signin"= "https://oauth-provider/sign_in?rd=$request_uri"
|
||||
"nginx.ingress.kubernetes.io/proxy-connect-timeout" = "600"
|
||||
"nginx.ingress.kubernetes.io/proxy-send-timeout" = "600"
|
||||
"nginx.ingress.kubernetes.io/proxy-read-timeout" = "600"
|
||||
"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 = ["finance.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
|
|
|
|||
|
|
@ -99,7 +99,4 @@ module "ingress" {
|
|||
namespace = kubernetes_namespace.forgejo.metadata[0].name
|
||||
name = "forgejo"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "20000m"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,20 +196,7 @@ module "ingress" {
|
|||
name = "frigate"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
protected = true
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "20000m"
|
||||
# Websockets
|
||||
"nginx.org/websocket-services" : "frigate"
|
||||
"nginx.ingress.kubernetes.io/proxy-set-header" : "Upgrade $http_upgrade"
|
||||
"nginx.ingress.kubernetes.io/proxy-set-header" : "Connection $connection_upgrade"
|
||||
"nginx.ingress.kubernetes.io/proxy-redirect-from" : "off"
|
||||
|
||||
"nginx.ingress.kubernetes.io/limit-rps" : 50000
|
||||
"nginx.ingress.kubernetes.io/limit-rpm" : 1000000
|
||||
"nginx.ingress.kubernetes.io/limit-burst-multiplier" : 50000
|
||||
"nginx.ingress.kubernetes.io/limit-rate-after" : 100000
|
||||
}
|
||||
rybbit_site_id = "0d4044069ff5"
|
||||
rybbit_site_id = "0d4044069ff5"
|
||||
}
|
||||
|
||||
module "ingress-internal" {
|
||||
|
|
@ -222,17 +209,4 @@ module "ingress-internal" {
|
|||
tls_secret_name = var.tls_secret_name
|
||||
allow_local_access_only = true
|
||||
ssl_redirect = false
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "20000m"
|
||||
# Websockets
|
||||
"nginx.org/websocket-services" : "frigate"
|
||||
"nginx.ingress.kubernetes.io/proxy-set-header" : "Upgrade $http_upgrade"
|
||||
"nginx.ingress.kubernetes.io/proxy-set-header" : "Connection $connection_upgrade"
|
||||
"nginx.ingress.kubernetes.io/proxy-redirect-from" : "off"
|
||||
|
||||
"nginx.ingress.kubernetes.io/limit-rps" : 50000
|
||||
"nginx.ingress.kubernetes.io/limit-rpm" : 1000000
|
||||
"nginx.ingress.kubernetes.io/limit-burst-multiplier" : 50000
|
||||
"nginx.ingress.kubernetes.io/limit-rate-after" : 100000
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,7 +150,4 @@ module "ingress" {
|
|||
namespace = kubernetes_namespace.hackmd.metadata[0].name
|
||||
name = "hackmd"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "20000m"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,14 +206,14 @@ resource "kubernetes_ingress_v1" "home-assistant-ui" {
|
|||
name = "home-assistant-ui-ingress"
|
||||
namespace = kubernetes_namespace.home_assistant.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/force-ssl-redirect" = "true"
|
||||
"nginx.ingress.kubernetes.io/auth-tls-verify-client" = "on"
|
||||
"nginx.ingress.kubernetes.io/auth-tls-secret" = var.client_certificate_secret_name
|
||||
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||
"traefik.ingress.kubernetes.io/router.tls.options" = "traefik-mtls@kubernetescrd"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
ingress_class_name = "traefik"
|
||||
tls {
|
||||
hosts = ["home-assistant.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ ingress:
|
|||
gethomepage.dev/description: "A modern, secure, highly customizable application dashboard."
|
||||
gethomepage.dev/group: "A New Group"
|
||||
gethomepage.dev/icon: "homepage.png"
|
||||
ingressClassName: "nginx"
|
||||
ingressClassName: "traefik"
|
||||
hosts:
|
||||
- host: &host "home.viktorbarzin.me"
|
||||
paths:
|
||||
|
|
|
|||
|
|
@ -460,66 +460,8 @@ resource "kubernetes_ingress_v1" "ingress" {
|
|||
namespace = kubernetes_namespace.immich.metadata[0].name
|
||||
name = "immich"
|
||||
annotations = {
|
||||
# NOTE: when changing - test video playback from mobile and web!
|
||||
# Easy to break!
|
||||
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/backend-protocol" = "HTTP"
|
||||
|
||||
# As per https://immich.app/docs/administration/reverse-proxy
|
||||
"nginx.org/websocket-services" : "immich-server"
|
||||
# Websockets
|
||||
"nginx.ingress.kubernetes.io/proxy-set-header" : "Upgrade $http_upgrade"
|
||||
"nginx.ingress.kubernetes.io/proxy-set-header" : "Connection $connection_upgrade" # this makes a difference for web!!!
|
||||
"nginx.ingress.kubernetes.io/proxy-redirect-from" : "off"
|
||||
# Timeouts
|
||||
"nginx.ingress.kubernetes.io/proxy-read-timeout" : "6000s",
|
||||
"nginx.ingress.kubernetes.io/proxy-send-timeout" : "6000s",
|
||||
|
||||
"nginx.ingress.kubernetes.io/proxy-connect-timeout" : "60s"
|
||||
|
||||
# Allow big uploads
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "0"
|
||||
"nginx.ingress.kubernetes.io/proxy-buffering" : "off"
|
||||
"nginx.ingress.kubernetes.io/proxy-request-buffering" : "off"
|
||||
"nginx.ingress.kubernetes.io/proxy-http-version" : "1.1"
|
||||
# "nginx.ingress.kubernetes.io/client-body-buffer-size" : "512m"
|
||||
# "nginx.ingress.kubernetes.io/proxy-buffers-number" : "4"
|
||||
|
||||
# More lenient DDOS protection as to not confuse with image loading
|
||||
"nginx.ingress.kubernetes.io/limit-connections" : 5000
|
||||
"nginx.ingress.kubernetes.io/limit-rps" : 100
|
||||
"nginx.ingress.kubernetes.io/limit-rpm" : 6000
|
||||
"nginx.ingress.kubernetes.io/limit-burst-multiplier" : 10
|
||||
|
||||
# good for downloading big files - https://www.pdxdev.com/nginx-content-delivery/configuring-nginx-for-large-file-transfers/
|
||||
"nginx.ingress.kubernetes.io/configuration-snippet" : <<EOF
|
||||
directio 4m;
|
||||
sendfile off;
|
||||
aio on;
|
||||
|
||||
limit_req_status 429;
|
||||
limit_conn_status 429;
|
||||
|
||||
# Rybbit Analytics
|
||||
# Only modify HTML
|
||||
sub_filter_types text/html;
|
||||
sub_filter_once off;
|
||||
|
||||
# Disable compression so sub_filter works
|
||||
proxy_set_header Accept-Encoding "";
|
||||
|
||||
# Inject analytics before </head>
|
||||
sub_filter '</head>' '
|
||||
<script src="https://rybbit.viktorbarzin.me/api/script.js"
|
||||
data-site-id="35eedb7a3d2b"
|
||||
defer></script>
|
||||
</head>';
|
||||
EOF
|
||||
|
||||
"nginx.ingress.kubernetes.io/enable-modsecurity" : "false" # this is important!!!; setting it to true enables buffering and can lead to ooms when ploading big files
|
||||
"nginx.ingress.kubernetes.io/enable-owasp-modsecurity-crs" : "false"
|
||||
|
||||
"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"
|
||||
|
|
@ -533,6 +475,7 @@ resource "kubernetes_ingress_v1" "ingress" {
|
|||
}
|
||||
|
||||
spec {
|
||||
ingress_class_name = "traefik"
|
||||
tls {
|
||||
hosts = ["immich.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
|
|
@ -724,3 +667,25 @@ 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>"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -113,12 +113,13 @@ resource "kubernetes_ingress_v1" "jellyfin" {
|
|||
name = "jellyfin"
|
||||
namespace = kubernetes_namespace.jellyfin.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "5000m"
|
||||
"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
|
||||
|
|
|
|||
|
|
@ -110,14 +110,14 @@ resource "kubernetes_ingress_v1" "kafka-ui" {
|
|||
name = "kafka-ui-ingress"
|
||||
namespace = kubernetes_namespace.kafka.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/force-ssl-redirect" = "true"
|
||||
"nginx.ingress.kubernetes.io/auth-tls-verify-client" = "on"
|
||||
"nginx.ingress.kubernetes.io/auth-tls-secret" = var.client_certificate_secret_name
|
||||
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||
"traefik.ingress.kubernetes.io/router.tls.options" = "traefik-mtls@kubernetescrd"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
ingress_class_name = "traefik"
|
||||
tls {
|
||||
hosts = ["kafka.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
|
|
|
|||
|
|
@ -6,14 +6,10 @@ persistence:
|
|||
existingClaim: "grafana-pvc"
|
||||
ingress:
|
||||
enabled: "true"
|
||||
ingressClassName: "traefik"
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
# nginx.ingress.kubernetes.io/auth-url: "https://oauth2.viktorbarzin.me/oauth2/auth"
|
||||
# nginx.ingress.kubernetes.io/auth-signin: "https://oauth2.viktorbarzin.me/oauth2/start?rd=/redirect/$http_host$escaped_request_uri"
|
||||
nginx.ingress.kubernetes.io/auth-url: "http://ak-outpost-authentik-embedded-outpost.authentik.svc.cluster.local:9000/outpost.goauthentik.io/auth/nginx"
|
||||
nginx.ingress.kubernetes.io/auth-signin: "https://authentik.viktorbarzin.me/outpost.goauthentik.io/start?rd=$scheme%3A%2F%2F$host$escaped_request_uri"
|
||||
nginx.ingress.kubernetes.io/auth-response-headers: "Set-Cookie,X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid"
|
||||
nginx.ingress.kubernetes.io/auth-snippet: "proxy_set_header X-Forwarded-Host $http_host;"
|
||||
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"
|
||||
tls:
|
||||
- secretName: "tls-secret"
|
||||
hosts:
|
||||
|
|
|
|||
|
|
@ -75,17 +75,36 @@ resource "kubernetes_cron_job_v1" "monitor_prom" {
|
|||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_manifest" "status_redirect_middleware" {
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "Middleware"
|
||||
metadata = {
|
||||
name = "status-redirect"
|
||||
namespace = kubernetes_namespace.monitoring.metadata[0].name
|
||||
}
|
||||
spec = {
|
||||
redirectRegex = {
|
||||
regex = ".*"
|
||||
replacement = "https://hetrixtools.com/r/38981b548b5d38b052aca8d01285a3f3/"
|
||||
permanent = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_ingress_v1" "status" {
|
||||
metadata {
|
||||
name = "hetrix-redirect-ingress"
|
||||
namespace = kubernetes_namespace.monitoring.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/permanent-redirect" = "https://hetrixtools.com/r/38981b548b5d38b052aca8d01285a3f3/"
|
||||
"traefik.ingress.kubernetes.io/router.middlewares" = "monitoring-status-redirect@kubernetescrd"
|
||||
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
ingress_class_name = "traefik"
|
||||
tls {
|
||||
hosts = ["status.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
|
|
@ -99,7 +118,7 @@ resource "kubernetes_ingress_v1" "status" {
|
|||
service {
|
||||
name = "not-used"
|
||||
port {
|
||||
number = 80 # redirected by annotation
|
||||
number = 80 # redirected by middleware
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -109,17 +128,36 @@ resource "kubernetes_ingress_v1" "status" {
|
|||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_manifest" "yotovski_redirect_middleware" {
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "Middleware"
|
||||
metadata = {
|
||||
name = "yotovski-redirect"
|
||||
namespace = kubernetes_namespace.monitoring.metadata[0].name
|
||||
}
|
||||
spec = {
|
||||
redirectRegex = {
|
||||
regex = ".*"
|
||||
replacement = "https://hetrixtools.com/r/2ba9d7a5e017794db0fd91f0115a8b3b/"
|
||||
permanent = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_ingress_v1" "status_yotovski" {
|
||||
metadata {
|
||||
name = "hetrix-yotovski-redirect-ingress"
|
||||
namespace = kubernetes_namespace.monitoring.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/permanent-redirect" = "https://hetrixtools.com/r/2ba9d7a5e017794db0fd91f0115a8b3b/"
|
||||
"traefik.ingress.kubernetes.io/router.middlewares" = "monitoring-yotovski-redirect@kubernetescrd"
|
||||
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
ingress_class_name = "traefik"
|
||||
tls {
|
||||
hosts = ["yotovski-status.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
|
|
@ -131,7 +169,7 @@ resource "kubernetes_ingress_v1" "status_yotovski" {
|
|||
path = "/"
|
||||
backend {
|
||||
service {
|
||||
name = "not-used" # redirected by annotation
|
||||
name = "not-used" # redirected by middleware
|
||||
port {
|
||||
number = 80
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,19 +11,10 @@ alertmanager:
|
|||
baseURL: "https://alertmanager.viktorbarzin.me"
|
||||
ingress:
|
||||
enabled: true
|
||||
ingressClassName: "traefik"
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
# Enable client certificate authentication
|
||||
# nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
|
||||
# Create the secret containing the trusted ca certificates
|
||||
# nginx.ingress.kubernetes.io/auth-tls-secret: "default/ca-secret"
|
||||
# nginx.ingress.kubernetes.io/auth-url: "https://oauth2.viktorbarzin.me/oauth2/auth"
|
||||
# nginx.ingress.kubernetes.io/auth-signin: "https://oauth2.viktorbarzin.me/oauth2/start?rd=/redirect/$http_host$escaped_request_uri"
|
||||
nginx.ingress.kubernetes.io/auth-url: "http://ak-outpost-authentik-embedded-outpost.authentik.svc.cluster.local:9000/outpost.goauthentik.io/auth/nginx"
|
||||
nginx.ingress.kubernetes.io/auth-signin: "https://authentik.viktorbarzin.me/outpost.goauthentik.io/start?rd=$scheme%3A%2F%2F$host$escaped_request_uri"
|
||||
nginx.ingress.kubernetes.io/auth-response-headers: "Set-Cookie,X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid"
|
||||
nginx.ingress.kubernetes.io/auth-snippet: "proxy_set_header X-Forwarded-Host $http_host;"
|
||||
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"
|
||||
tls:
|
||||
- secretName: "tls-secret"
|
||||
hosts:
|
||||
|
|
@ -100,19 +91,10 @@ server:
|
|||
mountPath: /data/wal # Standard path for the chart
|
||||
ingress:
|
||||
enabled: true
|
||||
ingressClassName: "traefik"
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
# Enable client certificate authentication
|
||||
# nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
|
||||
# Create the secret containing the trusted ca certificates
|
||||
# nginx.ingress.kubernetes.io/auth-tls-secret: "default/ca-secret"
|
||||
# nginx.ingress.kubernetes.io/auth-url: "https://oauth2.viktorbarzin.me/oauth2/auth"
|
||||
# nginx.ingress.kubernetes.io/auth-signin: "https://oauth2.viktorbarzin.me/oauth2/start?rd=/redirect/$http_host$escaped_request_uri"
|
||||
"nginx.ingress.kubernetes.io/auth-url": "http://ak-outpost-authentik-embedded-outpost.authentik.svc.cluster.local:9000/outpost.goauthentik.io/auth/nginx"
|
||||
"nginx.ingress.kubernetes.io/auth-signin": "https://authentik.viktorbarzin.me/outpost.goauthentik.io/start?rd=$scheme%3A%2F%2F$host$escaped_request_uri"
|
||||
"nginx.ingress.kubernetes.io/auth-response-headers": "Set-Cookie,X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid"
|
||||
"nginx.ingress.kubernetes.io/auth-snippet": "proxy_set_header X-Forwarded-Host $http_host;"
|
||||
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"
|
||||
|
||||
gethomepage.dev/enabled: "true"
|
||||
gethomepage.dev/description: "Prometheus"
|
||||
|
|
|
|||
|
|
@ -134,7 +134,4 @@ module "ingress" {
|
|||
namespace = kubernetes_namespace.n8n.metadata[0].name
|
||||
name = "n8n"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "20000m"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,13 +154,7 @@ module "ingress" {
|
|||
name = "nextcloud"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
port = 8080
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/client-max-body-size" : "0"
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "0",
|
||||
"nginx.ingress.kubernetes.io/limit-rps" : 1000 # Increased to allow webdav syncing
|
||||
"nginx.ingress.kubernetes.io/limit-rpm" : 60000
|
||||
}
|
||||
rybbit_site_id = "5a3bfe59a3fe"
|
||||
rybbit_site_id = "5a3bfe59a3fe"
|
||||
}
|
||||
|
||||
module "whiteboard_ingress" {
|
||||
|
|
@ -169,18 +163,6 @@ module "whiteboard_ingress" {
|
|||
name = "whiteboard"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
port = 80
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/client-max-body-size" : "0"
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "0",
|
||||
|
||||
# Websockets
|
||||
# "nginx.ingress.kubernetes.io/proxy-set-header" : "Upgrade $http_upgrade"
|
||||
# "nginx.ingress.kubernetes.io/proxy-set-header" : "Connection $connection_upgrade" # this makes a difference for web!!!
|
||||
|
||||
# Timeouts
|
||||
"nginx.ingress.kubernetes.io/proxy-read-timeout" : "6000s",
|
||||
"nginx.ingress.kubernetes.io/proxy-send-timeout" : "6000s",
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_config_map" "backup-script" {
|
||||
|
|
|
|||
|
|
@ -1,910 +0,0 @@
|
|||
# module "nginx-controller" {
|
||||
# source = "terraform-iaac/nginx-controller/helm"
|
||||
# namespace = "ingress-nginx-test"
|
||||
# create_namespace = true
|
||||
# atomic = true
|
||||
# ingress_class_is_default = false
|
||||
# ingress_class_name = "nginx-test"
|
||||
# }
|
||||
variable "honeypotapikey" {
|
||||
default = null
|
||||
}
|
||||
variable "crowdsec_api_key" {}
|
||||
variable "crowdsec_captcha_secret_key" {}
|
||||
variable "crowdsec_captcha_site_key" {}
|
||||
variable "tier" { type = string }
|
||||
|
||||
resource "kubernetes_namespace" "ingress_nginx" {
|
||||
metadata {
|
||||
name = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
# "istio-injection" : "enabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
resource "kubernetes_service_account" "ingress_nginx" {
|
||||
metadata {
|
||||
name = "ingress-nginx"
|
||||
namespace = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "controller"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
automount_service_account_token = true
|
||||
}
|
||||
|
||||
# Jobs create a cert and modify this secret. This is problematic as TF recreates it every time
|
||||
# Instead, on each fresh install, uncomment this, get nginx working and comment it.
|
||||
# Also rm from state: tf state rm module.kubernetes_cluster.module.nginx-ingress.kubernetes_service_account.ingress_nginx_admission
|
||||
resource "kubernetes_service_account" "ingress_nginx_admission" {
|
||||
metadata {
|
||||
name = "ingress-nginx-admission"
|
||||
namespace = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "admission-webhook"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
resource "kubernetes_role" "ingress_nginx" {
|
||||
metadata {
|
||||
name = "ingress-nginx"
|
||||
namespace = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "controller"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
rule {
|
||||
verbs = ["get"]
|
||||
api_groups = [""]
|
||||
resources = ["namespaces"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["get", "list", "watch", "update", "create", "delete"]
|
||||
api_groups = [""]
|
||||
resources = ["configmaps", "pods", "secrets", "endpoints"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["get", "list", "watch"]
|
||||
api_groups = [""]
|
||||
resources = ["services"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["get", "list", "watch"]
|
||||
api_groups = ["networking.k8s.io"]
|
||||
resources = ["ingresses"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["update"]
|
||||
api_groups = ["networking.k8s.io"]
|
||||
resources = ["ingresses/status"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["get", "list", "watch"]
|
||||
api_groups = ["networking.k8s.io"]
|
||||
resources = ["ingressclasses"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["get", "update"]
|
||||
api_groups = ["coordination.k8s.io"]
|
||||
resources = ["leases"]
|
||||
resource_names = ["ingress-nginx-leader"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["create"]
|
||||
api_groups = ["coordination.k8s.io"]
|
||||
resources = ["leases"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["create", "patch"]
|
||||
api_groups = [""]
|
||||
resources = ["events"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["list", "watch", "get"]
|
||||
api_groups = ["discovery.k8s.io"]
|
||||
resources = ["endpointslices"]
|
||||
}
|
||||
}
|
||||
resource "kubernetes_role" "ingress_nginx_admission" {
|
||||
metadata {
|
||||
name = "ingress-nginx-admission"
|
||||
namespace = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "admission-webhook"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
rule {
|
||||
verbs = ["get", "create", "patch", "update", "watch", "list"]
|
||||
api_groups = [""]
|
||||
resources = ["secrets"]
|
||||
}
|
||||
}
|
||||
resource "kubernetes_cluster_role" "ingress_nginx" {
|
||||
metadata {
|
||||
name = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
rule {
|
||||
verbs = ["list", "watch"]
|
||||
api_groups = [""]
|
||||
resources = ["configmaps", "endpoints", "nodes", "pods", "secrets", "namespaces"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["list", "watch"]
|
||||
api_groups = ["coordination.k8s.io"]
|
||||
resources = ["leases"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["get"]
|
||||
api_groups = [""]
|
||||
resources = ["nodes"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["get", "list", "watch"]
|
||||
api_groups = [""]
|
||||
resources = ["services"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["get", "list", "watch"]
|
||||
api_groups = ["networking.k8s.io"]
|
||||
resources = ["ingresses"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["create", "patch"]
|
||||
api_groups = [""]
|
||||
resources = ["events"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["update"]
|
||||
api_groups = ["networking.k8s.io"]
|
||||
resources = ["ingresses/status"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["get", "list", "watch"]
|
||||
api_groups = ["networking.k8s.io"]
|
||||
resources = ["ingressclasses"]
|
||||
}
|
||||
rule {
|
||||
verbs = ["list", "watch", "get"]
|
||||
api_groups = ["discovery.k8s.io"]
|
||||
resources = ["endpointslices"]
|
||||
}
|
||||
}
|
||||
resource "kubernetes_cluster_role" "ingress_nginx_admission" {
|
||||
metadata {
|
||||
name = "ingress-nginx-admission"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "admission-webhook"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
rule {
|
||||
verbs = ["get", "update"]
|
||||
api_groups = ["admissionregistration.k8s.io"]
|
||||
resources = ["validatingwebhookconfigurations"]
|
||||
}
|
||||
}
|
||||
resource "kubernetes_role_binding" "ingress_nginx" {
|
||||
metadata {
|
||||
name = "ingress-nginx"
|
||||
namespace = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "controller"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
subject {
|
||||
kind = "ServiceAccount"
|
||||
name = "ingress-nginx"
|
||||
namespace = "ingress-nginx"
|
||||
}
|
||||
role_ref {
|
||||
api_group = "rbac.authorization.k8s.io"
|
||||
kind = "Role"
|
||||
name = "ingress-nginx"
|
||||
}
|
||||
}
|
||||
resource "kubernetes_role_binding" "ingress_nginx_admission" {
|
||||
metadata {
|
||||
name = "ingress-nginx-admission"
|
||||
namespace = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "admission-webhook"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
subject {
|
||||
kind = "ServiceAccount"
|
||||
name = "ingress-nginx-admission"
|
||||
namespace = "ingress-nginx"
|
||||
}
|
||||
role_ref {
|
||||
api_group = "rbac.authorization.k8s.io"
|
||||
kind = "Role"
|
||||
name = "ingress-nginx-admission"
|
||||
}
|
||||
}
|
||||
resource "kubernetes_cluster_role_binding" "ingress_nginx" {
|
||||
metadata {
|
||||
name = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
subject {
|
||||
kind = "ServiceAccount"
|
||||
name = "ingress-nginx"
|
||||
namespace = "ingress-nginx"
|
||||
}
|
||||
role_ref {
|
||||
api_group = "rbac.authorization.k8s.io"
|
||||
kind = "ClusterRole"
|
||||
name = "ingress-nginx"
|
||||
}
|
||||
}
|
||||
resource "kubernetes_cluster_role_binding" "ingress_nginx_admission" {
|
||||
metadata {
|
||||
name = "ingress-nginx-admission"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "admission-webhook"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
subject {
|
||||
kind = "ServiceAccount"
|
||||
name = "ingress-nginx-admission"
|
||||
namespace = "ingress-nginx"
|
||||
}
|
||||
role_ref {
|
||||
api_group = "rbac.authorization.k8s.io"
|
||||
kind = "ClusterRole"
|
||||
name = "ingress-nginx-admission"
|
||||
}
|
||||
}
|
||||
resource "kubernetes_config_map" "ingress_nginx_controller" {
|
||||
metadata {
|
||||
name = "ingress-nginx-controller"
|
||||
namespace = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "controller"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
data = {
|
||||
use-forwarded-headers = "true"
|
||||
compute-full-forwarded-for = "true"
|
||||
enable-real-ip = "true"
|
||||
allow-snippet-annotations = true
|
||||
limit-req-status-code = 429
|
||||
limit-conn-status-code = 429
|
||||
enable-modsecurity = true
|
||||
enable-owasp-modsecurity-crs = false
|
||||
modsecurity-snippet : <<-EOT
|
||||
SecRuleEngine On
|
||||
${var.honeypotapikey != null ? format("%s %s", "SecHttpBlKey", var.honeypotapikey) : ""}
|
||||
SecAction "id:900500,\
|
||||
phase:1,\
|
||||
nolog,\
|
||||
pass,\
|
||||
t:none,\
|
||||
setvar:tx.block_search_ip=0,\
|
||||
setvar:tx.block_suspicious_ip=1,\
|
||||
setvar:tx.block_harvester_ip=1,\
|
||||
setvar:tx.block_spammer_ip=1"
|
||||
EOT
|
||||
plugins = "crowdsec"
|
||||
# plugins = ""
|
||||
lua-shared-dicts = "crowdsec_cache: 50m"
|
||||
http-snippet : <<-EOT
|
||||
proxy_cache_path /tmp/nginx-cache levels=1:2 keys_zone=static-cache:2m max_size=100m inactive=7d use_temp_path=off;
|
||||
proxy_cache_key $scheme$proxy_host$request_uri;
|
||||
proxy_cache_lock on;
|
||||
proxy_cache_use_stale updating;
|
||||
EOT
|
||||
server-snippet : <<-EOT
|
||||
lua_ssl_trusted_certificate "/etc/ssl/certs/ca-certificates.crt"; # Captcha
|
||||
#resolver local=on ipv6=off valid=600s;
|
||||
EOT
|
||||
# first own works
|
||||
# log-format-upstream : <<-EOT
|
||||
# $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_cf_connecting_ip" "$http_cf_ray" "$http_x_forwarded_for" "$host";
|
||||
# EOT
|
||||
|
||||
# ketpt do debug why it's invalid syntax lol
|
||||
# log-format-upstream : <<-EOT
|
||||
# $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_cf_connecting_ip" "$http_cf_ray" "$http_x_forwarded_for" "$host";
|
||||
# EOT
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_config_map" "udp_services" {
|
||||
metadata {
|
||||
name = "udp-services"
|
||||
namespace = "ingress-nginx"
|
||||
}
|
||||
data = {
|
||||
53 : "technitium/technitium-dns:53"
|
||||
# 8554 : "frigate/frigate:8554"
|
||||
}
|
||||
}
|
||||
resource "kubernetes_config_map" "tcp_services" {
|
||||
metadata {
|
||||
name = "tcp-services"
|
||||
namespace = "ingress-nginx"
|
||||
}
|
||||
data = {
|
||||
# 9443 : "wireguard/xray:7443" // reality
|
||||
# 8554 : "frigate/frigate:8554"
|
||||
}
|
||||
}
|
||||
resource "kubernetes_service" "ingress_nginx_controller" {
|
||||
metadata {
|
||||
name = "ingress-nginx-controller"
|
||||
namespace = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "controller"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
port {
|
||||
name = "http"
|
||||
protocol = "TCP"
|
||||
port = 80
|
||||
target_port = "http"
|
||||
}
|
||||
port {
|
||||
name = "https"
|
||||
protocol = "TCP"
|
||||
port = 443
|
||||
target_port = "https"
|
||||
}
|
||||
port {
|
||||
name = "dns"
|
||||
protocol = "UDP"
|
||||
port = 53
|
||||
target_port = "dns"
|
||||
}
|
||||
# port {
|
||||
# name = "frigate-rtsptcp"
|
||||
# port = 8554
|
||||
# protocol = "TCP"
|
||||
# }
|
||||
# port {
|
||||
# name = "frigate-rtspudp"
|
||||
# port = 8554
|
||||
# protocol = "UDP"
|
||||
# }
|
||||
# port {
|
||||
# name = "xray-reality"
|
||||
# protocol = "TCP"
|
||||
# port = 9443 # expose tcp port here
|
||||
# target_port = "9443"
|
||||
# }
|
||||
selector = {
|
||||
"app.kubernetes.io/component" = "controller"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
}
|
||||
type = "LoadBalancer"
|
||||
external_traffic_policy = "Local" // see https://metallb.universe.tf/usage/
|
||||
# ip_families = ["IPv4"]
|
||||
}
|
||||
}
|
||||
resource "kubernetes_service" "ingress_nginx_controller_admission" {
|
||||
metadata {
|
||||
name = "ingress-nginx-controller-admission"
|
||||
namespace = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "controller"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
port {
|
||||
name = "https-webhook"
|
||||
port = 443
|
||||
target_port = "webhook"
|
||||
}
|
||||
selector = {
|
||||
"app.kubernetes.io/component" = "controller"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
}
|
||||
type = "ClusterIP"
|
||||
}
|
||||
}
|
||||
resource "kubernetes_deployment" "ingress_nginx_controller" {
|
||||
metadata {
|
||||
name = "ingress-nginx-controller"
|
||||
namespace = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "controller"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
tier = var.tier
|
||||
}
|
||||
annotations = {
|
||||
"reloader.stakater.com/search" = "true"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
replicas = 3
|
||||
|
||||
selector {
|
||||
match_labels = {
|
||||
"app.kubernetes.io/component" = "controller"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
}
|
||||
}
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "controller"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
"app" = "ingress-nginx"
|
||||
}
|
||||
annotations = {
|
||||
"prometheus.io/scrape" = "true"
|
||||
"prometheus.io/port" = 10254
|
||||
|
||||
"diun.enable" = "true"
|
||||
"diun.include_tags" = "^v\\d+(?:\\.\\d+)?(?:\\.\\d+)?.*$"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
volume {
|
||||
name = "webhook-cert"
|
||||
secret {
|
||||
secret_name = "ingress-nginx-admission"
|
||||
}
|
||||
}
|
||||
# volume {
|
||||
# name = "modsecurity"
|
||||
# config_map {
|
||||
# name = "modsecurity"
|
||||
# }
|
||||
# }
|
||||
|
||||
## Crowdsec
|
||||
init_container {
|
||||
name = "init-clone-crowdsec-bouncer"
|
||||
image = "crowdsecurity/lua-bouncer-plugin"
|
||||
env {
|
||||
name = "API_URL"
|
||||
value = "http://crowdsec-service.crowdsec.svc.cluster.local:8080"
|
||||
}
|
||||
env {
|
||||
// if you can't connect with bouncer not found, regenerate api key with:
|
||||
// "cscli bouncers add nginx" on the lapi
|
||||
name = "API_KEY"
|
||||
value = var.crowdsec_api_key
|
||||
}
|
||||
env {
|
||||
name = "MODE"
|
||||
value = "stream"
|
||||
}
|
||||
env {
|
||||
name = "CAPTCHA_PROVIDER"
|
||||
value = "hcaptcha"
|
||||
}
|
||||
env {
|
||||
name = "BOUNCING_ON_TYPE"
|
||||
value = "all"
|
||||
# value = "ban"
|
||||
}
|
||||
env {
|
||||
name = "SECRET_KEY"
|
||||
value = var.crowdsec_captcha_secret_key
|
||||
}
|
||||
env {
|
||||
name = "SITE_KEY"
|
||||
value = var.crowdsec_captcha_site_key
|
||||
}
|
||||
|
||||
# env {
|
||||
# name = "DISABLE_RUN"
|
||||
# value = "true"
|
||||
# }
|
||||
env {
|
||||
name = "BAN_TEMPLATE_PATH"
|
||||
value = "/etc/nginx/lua/plugins/crowdsec/templates/ban.html"
|
||||
}
|
||||
env {
|
||||
name = "CAPTCHA_TEMPLATE_PATH"
|
||||
value = "/etc/nginx/lua/plugins/crowdsec/templates/captcha.html"
|
||||
}
|
||||
env {
|
||||
name = "BOUNCER_CONFIG"
|
||||
value = "/crowdsec/crowdsec-bouncer.conf"
|
||||
}
|
||||
# command = ["sh", "-c", "sh /docker_start.sh; mkdir -p /lua_plugins/crowdsec/; cp -r /crowdsec /lua_plugins/; chown -R 101:101 /lua_plugins/"]
|
||||
command = ["sh", "-c", "sh /docker_start.sh; mkdir -p /lua_plugins/crowdsec/; cp -R /crowdsec/* /lua_plugins/crowdsec/"]
|
||||
|
||||
volume_mount {
|
||||
name = "crowdsec"
|
||||
mount_path = "/lua_plugins"
|
||||
}
|
||||
}
|
||||
# Share bouncer config
|
||||
volume {
|
||||
name = "crowdsec"
|
||||
empty_dir {
|
||||
}
|
||||
}
|
||||
container {
|
||||
name = "controller"
|
||||
# https://github.com/kubernetes/ingress-nginx
|
||||
image = "registry.k8s.io/ingress-nginx/controller:v1.11.8"
|
||||
args = ["/nginx-ingress-controller", "--election-id=ingress-nginx-leader", "--controller-class=k8s.io/ingress-nginx", "--ingress-class=nginx", "--configmap=$(POD_NAMESPACE)/ingress-nginx-controller", "--validating-webhook=:8443", "--validating-webhook-certificate=/usr/local/certificates/cert", "--validating-webhook-key=/usr/local/certificates/key", "--udp-services-configmap", "ingress-nginx/udp-services", "--tcp-services-configmap", "ingress-nginx/tcp-services"]
|
||||
volume_mount {
|
||||
name = "crowdsec"
|
||||
mount_path = "/etc/nginx/lua/plugins/crowdsec"
|
||||
sub_path = "crowdsec"
|
||||
}
|
||||
port {
|
||||
name = "http"
|
||||
container_port = 80
|
||||
protocol = "TCP"
|
||||
}
|
||||
port {
|
||||
name = "https"
|
||||
container_port = 443
|
||||
protocol = "TCP"
|
||||
}
|
||||
port {
|
||||
name = "dns"
|
||||
container_port = 53
|
||||
protocol = "UDP"
|
||||
}
|
||||
# port {
|
||||
# name = "xray-reality"
|
||||
# container_port = 9443 # expose port here
|
||||
# protocol = "TCP"
|
||||
# }
|
||||
port {
|
||||
name = "webhook"
|
||||
container_port = 8443
|
||||
protocol = "TCP"
|
||||
}
|
||||
# port {
|
||||
# name = "frigate-rtsptcp"
|
||||
# container_port = 8554
|
||||
# protocol = "TCP"
|
||||
# }
|
||||
# port {
|
||||
# name = "frigate-rtspudp"
|
||||
# container_port = 8554
|
||||
# protocol = "UDP"
|
||||
# }
|
||||
port {
|
||||
name = "metrics"
|
||||
container_port = 10254
|
||||
protocol = "TCP"
|
||||
}
|
||||
env {
|
||||
name = "POD_NAME"
|
||||
value_from {
|
||||
field_ref {
|
||||
field_path = "metadata.name"
|
||||
}
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "POD_NAMESPACE"
|
||||
value_from {
|
||||
field_ref {
|
||||
field_path = "metadata.namespace"
|
||||
}
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "LD_PRELOAD"
|
||||
value = "/usr/local/lib/libmimalloc.so"
|
||||
}
|
||||
resources {
|
||||
requests = {
|
||||
cpu = "100m"
|
||||
memory = "90Mi"
|
||||
}
|
||||
}
|
||||
volume_mount {
|
||||
name = "webhook-cert"
|
||||
read_only = true
|
||||
mount_path = "/usr/local/certificates/"
|
||||
}
|
||||
# Not used atm
|
||||
# volume_mount {
|
||||
# name = "modsecurity"
|
||||
# read_only = true
|
||||
# mount_path = "/etc/nginx/modsecurity"
|
||||
# # sub_path = "modsecurity.conf"
|
||||
# }
|
||||
liveness_probe {
|
||||
http_get {
|
||||
path = "/healthz"
|
||||
port = "10254"
|
||||
scheme = "HTTP"
|
||||
}
|
||||
initial_delay_seconds = 10
|
||||
timeout_seconds = 1
|
||||
period_seconds = 10
|
||||
success_threshold = 1
|
||||
failure_threshold = 5
|
||||
}
|
||||
readiness_probe {
|
||||
http_get {
|
||||
path = "/healthz"
|
||||
port = "10254"
|
||||
scheme = "HTTP"
|
||||
}
|
||||
initial_delay_seconds = 10
|
||||
timeout_seconds = 1
|
||||
period_seconds = 10
|
||||
success_threshold = 1
|
||||
failure_threshold = 3
|
||||
}
|
||||
lifecycle {
|
||||
pre_stop {
|
||||
exec {
|
||||
command = ["/wait-shutdown"]
|
||||
}
|
||||
}
|
||||
}
|
||||
image_pull_policy = "IfNotPresent"
|
||||
security_context {
|
||||
capabilities {
|
||||
add = ["NET_BIND_SERVICE"]
|
||||
drop = ["ALL"]
|
||||
}
|
||||
run_as_user = 101
|
||||
allow_privilege_escalation = true
|
||||
}
|
||||
}
|
||||
termination_grace_period_seconds = 300
|
||||
dns_policy = "ClusterFirst"
|
||||
node_selector = {
|
||||
"kubernetes.io/os" = "linux"
|
||||
}
|
||||
service_account_name = "ingress-nginx"
|
||||
}
|
||||
}
|
||||
strategy {
|
||||
type = "RollingUpdate"
|
||||
rolling_update {
|
||||
max_unavailable = "1"
|
||||
max_surge = "2"
|
||||
}
|
||||
}
|
||||
|
||||
revision_history_limit = 10
|
||||
}
|
||||
}
|
||||
resource "kubernetes_job" "ingress_nginx_admission_create" {
|
||||
metadata {
|
||||
name = "ingress-nginx-admission-create"
|
||||
namespace = "ingress-nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "admission-webhook"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.8.2"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
template {
|
||||
metadata {
|
||||
name = "ingress-nginx-admission-create"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "admission-webhook"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.8.2"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
container {
|
||||
name = "create"
|
||||
image = "registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407@sha256:543c40fd093964bc9ab509d3e791f9989963021f1e9e4c9c7b6700b02bfb227b"
|
||||
args = ["create", "--host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc", "--namespace=$(POD_NAMESPACE)", "--secret-name=ingress-nginx-admission"]
|
||||
env {
|
||||
name = "POD_NAMESPACE"
|
||||
value_from {
|
||||
field_ref {
|
||||
field_path = "metadata.namespace"
|
||||
}
|
||||
}
|
||||
}
|
||||
image_pull_policy = "IfNotPresent"
|
||||
}
|
||||
restart_policy = "OnFailure"
|
||||
node_selector = {
|
||||
"kubernetes.io/os" = "linux"
|
||||
}
|
||||
service_account_name = "ingress-nginx-admission"
|
||||
security_context {
|
||||
run_as_user = 2000
|
||||
run_as_non_root = true
|
||||
fs_group = 2000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Jobs create a cert and modify this secret. This is problematic as TF recreates it every time
|
||||
# Instead, on each fresh install, uncomment this, get nginx working and comment it.
|
||||
# Also rm from state: tf state rm module.kubernetes_cluster.module.nginx-ingress.kubernetes_job.ingress_nginx_admission_patch
|
||||
# resource "kubernetes_job" "ingress_nginx_admission_patch" {
|
||||
# metadata {
|
||||
# name = "ingress-nginx-admission-patch"
|
||||
# namespace = "ingress-nginx"
|
||||
# labels = {
|
||||
# "app.kubernetes.io/component" = "admission-webhook"
|
||||
# "app.kubernetes.io/instance" = "ingress-nginx"
|
||||
# "app.kubernetes.io/name" = "ingress-nginx"
|
||||
# "app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
# "app.kubernetes.io/version" = "1.13.1"
|
||||
# }
|
||||
# }
|
||||
# spec {
|
||||
# template {
|
||||
# metadata {
|
||||
# name = "ingress-nginx-admission-patch"
|
||||
# labels = {
|
||||
# "app.kubernetes.io/component" = "admission-webhook"
|
||||
# "app.kubernetes.io/instance" = "ingress-nginx"
|
||||
# "app.kubernetes.io/name" = "ingress-nginx"
|
||||
# "app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
# "app.kubernetes.io/version" = "1.13.1"
|
||||
# }
|
||||
# }
|
||||
# spec {
|
||||
# container {
|
||||
# name = "patch"
|
||||
# image = "registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407@sha256:543c40fd093964bc9ab509d3e791f9989963021f1e9e4c9c7b6700b02bfb227b"
|
||||
# args = ["patch", "--webhook-name=ingress-nginx-admission", "--namespace=$(POD_NAMESPACE)", "--patch-mutating=false", "--secret-name=ingress-nginx-admission", "--patch-failure-policy=Fail"]
|
||||
# env {
|
||||
# name = "POD_NAMESPACE"
|
||||
# value_from {
|
||||
# field_ref {
|
||||
# field_path = "metadata.namespace"
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# image_pull_policy = "IfNotPresent"
|
||||
# }
|
||||
# restart_policy = "OnFailure"
|
||||
# node_selector = {
|
||||
# "kubernetes.io/os" = "linux"
|
||||
# }
|
||||
# service_account_name = "ingress-nginx-admission"
|
||||
# security_context {
|
||||
# run_as_user = 2000
|
||||
# run_as_non_root = true
|
||||
# fs_group = 2000
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
resource "kubernetes_ingress_class" "nginx" {
|
||||
metadata {
|
||||
name = "nginx"
|
||||
labels = {
|
||||
"app.kubernetes.io/component" = "controller"
|
||||
"app.kubernetes.io/instance" = "ingress-nginx"
|
||||
"app.kubernetes.io/name" = "ingress-nginx"
|
||||
"app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
"app.kubernetes.io/version" = "1.13.1"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
controller = "k8s.io/ingress-nginx"
|
||||
}
|
||||
}
|
||||
|
||||
# Jobs create a cert and modify this secret. This is problematic as TF recreates it every time
|
||||
# Instead, on each fresh install, uncomment this, get nginx working and comment it.
|
||||
# Also rm from state: tf state rm module.kubernetes_cluster.module.nginx-ingress.kubernetes_service_account.ingress_nginx_admission
|
||||
# resource "kubernetes_validating_webhook_configuration" "ingress_nginx_admission" {
|
||||
# metadata {
|
||||
# name = "ingress-nginx-admission"
|
||||
# labels = {
|
||||
# "app.kubernetes.io/component" = "admission-webhook"
|
||||
# "app.kubernetes.io/instance" = "ingress-nginx"
|
||||
# "app.kubernetes.io/name" = "ingress-nginx"
|
||||
# "app.kubernetes.io/part-of" = "ingress-nginx"
|
||||
# "app.kubernetes.io/version" = "1.13.1"
|
||||
# }
|
||||
# }
|
||||
# webhook {
|
||||
# name = "validate.nginx.ingress.kubernetes.io"
|
||||
# client_config {
|
||||
# service {
|
||||
# namespace = "ingress-nginx"
|
||||
# name = "ingress-nginx-controller-admission"
|
||||
# path = "/networking/v1/ingresses"
|
||||
# }
|
||||
# }
|
||||
# rule {
|
||||
# api_versions = ["v1"]
|
||||
# api_groups = ["networking.k8s.io"]
|
||||
# resources = ["ingresses"]
|
||||
# operations = ["CREATE", "UPDATE"]
|
||||
# }
|
||||
# failure_policy = "Fail"
|
||||
# match_policy = "Equivalent"
|
||||
# side_effects = "None"
|
||||
# admission_review_versions = ["v1"]
|
||||
# }
|
||||
# }
|
||||
|
||||
resource "kubernetes_config_map" "modsecurity" {
|
||||
metadata {
|
||||
name = "modsecurity"
|
||||
namespace = "ingress-nginx"
|
||||
annotations = {
|
||||
"reloader.stakater.com/match" = "true"
|
||||
}
|
||||
}
|
||||
|
||||
data = {
|
||||
"modsecurity.conf" = file("${path.module}/modsecurity.conf")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,289 +0,0 @@
|
|||
### NOT USED ATM
|
||||
|
||||
|
||||
# -- Rule engine initialization ----------------------------------------------
|
||||
|
||||
# Enable ModSecurity, attaching it to every transaction. Use detection
|
||||
# only to start with, because that minimises the chances of post-installation
|
||||
# disruption.
|
||||
#
|
||||
SecRuleEngine DetectionOnly
|
||||
|
||||
|
||||
# -- Request body handling ---------------------------------------------------
|
||||
|
||||
# Allow ModSecurity to access request bodies. If you don't, ModSecurity
|
||||
# won't be able to see any POST parameters, which opens a large security
|
||||
# hole for attackers to exploit.
|
||||
#
|
||||
SecRequestBodyAccess On
|
||||
|
||||
|
||||
# Enable XML request body parser.
|
||||
# Initiate XML Processor in case of xml content-type
|
||||
#
|
||||
SecRule REQUEST_HEADERS:Content-Type "^(?:application(?:/soap\+|/)|text/)xml" \
|
||||
"id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
|
||||
|
||||
# Enable JSON request body parser.
|
||||
# Initiate JSON Processor in case of JSON content-type; change accordingly
|
||||
# if your application does not use 'application/json'
|
||||
#
|
||||
SecRule REQUEST_HEADERS:Content-Type "^application/json" \
|
||||
"id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
|
||||
|
||||
# Sample rule to enable JSON request body parser for more subtypes.
|
||||
# Uncomment or adapt this rule if you want to engage the JSON
|
||||
# Processor for "+json" subtypes
|
||||
#
|
||||
#SecRule REQUEST_HEADERS:Content-Type "^application/[a-z0-9.-]+[+]json" \
|
||||
# "id:'200006',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
|
||||
|
||||
# Maximum request body size we will accept for buffering. If you support
|
||||
# file uploads then the value given on the first line has to be as large
|
||||
# as the largest file you are willing to accept. The second value refers
|
||||
# to the size of data, with files excluded. You want to keep that value as
|
||||
# low as practical.
|
||||
#
|
||||
SecRequestBodyLimit 13107200
|
||||
SecRequestBodyNoFilesLimit 131072
|
||||
|
||||
# What to do if the request body size is above our configured limit.
|
||||
# Keep in mind that this setting will automatically be set to ProcessPartial
|
||||
# when SecRuleEngine is set to DetectionOnly mode in order to minimize
|
||||
# disruptions when initially deploying ModSecurity.
|
||||
#
|
||||
SecRequestBodyLimitAction Reject
|
||||
|
||||
# Maximum parsing depth allowed for JSON objects. You want to keep this
|
||||
# value as low as practical.
|
||||
#
|
||||
SecRequestBodyJsonDepthLimit 512
|
||||
|
||||
# Maximum number of args allowed per request. You want to keep this
|
||||
# value as low as practical. The value should match that in rule 200007.
|
||||
SecArgumentsLimit 1000
|
||||
|
||||
# If SecArgumentsLimit has been set, you probably want to reject any
|
||||
# request body that has only been partly parsed. The value used in this
|
||||
# rule should match what was used with SecArgumentsLimit
|
||||
SecRule &ARGS "@ge 1000" \
|
||||
"id:'200007', phase:2,t:none,log,deny,status:400,msg:'Failed to fully parse request body due to large argument count',severity:2"
|
||||
|
||||
# Verify that we've correctly processed the request body.
|
||||
# As a rule of thumb, when failing to process a request body
|
||||
# you should reject the request (when deployed in blocking mode)
|
||||
# or log a high-severity alert (when deployed in detection-only mode).
|
||||
#
|
||||
SecRule REQBODY_ERROR "!@eq 0" \
|
||||
"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
|
||||
|
||||
# By default be strict with what we accept in the multipart/form-data
|
||||
# request body. If the rule below proves to be too strict for your
|
||||
# environment consider changing it to detection-only. You are encouraged
|
||||
# _not_ to remove it altogether.
|
||||
#
|
||||
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
|
||||
"id:'200003',phase:2,t:none,log,deny,status:400, \
|
||||
msg:'Multipart request body failed strict validation: \
|
||||
PE %{REQBODY_PROCESSOR_ERROR}, \
|
||||
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
|
||||
BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
|
||||
DB %{MULTIPART_DATA_BEFORE}, \
|
||||
DA %{MULTIPART_DATA_AFTER}, \
|
||||
HF %{MULTIPART_HEADER_FOLDING}, \
|
||||
LF %{MULTIPART_LF_LINE}, \
|
||||
SM %{MULTIPART_MISSING_SEMICOLON}, \
|
||||
IQ %{MULTIPART_INVALID_QUOTING}, \
|
||||
IP %{MULTIPART_INVALID_PART}, \
|
||||
IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
|
||||
FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
|
||||
|
||||
# Did we see anything that might be a boundary?
|
||||
#
|
||||
# Here is a short description about the ModSecurity Multipart parser: the
|
||||
# parser returns with value 0, if all "boundary-like" line matches with
|
||||
# the boundary string which given in MIME header. In any other cases it returns
|
||||
# with different value, eg. 1 or 2.
|
||||
#
|
||||
# The RFC 1341 descript the multipart content-type and its syntax must contains
|
||||
# only three mandatory lines (above the content):
|
||||
# * Content-Type: multipart/mixed; boundary=BOUNDARY_STRING
|
||||
# * --BOUNDARY_STRING
|
||||
# * --BOUNDARY_STRING--
|
||||
#
|
||||
# First line indicates, that this is a multipart content, second shows that
|
||||
# here starts a part of the multipart content, third shows the end of content.
|
||||
#
|
||||
# If there are any other lines, which starts with "--", then it should be
|
||||
# another boundary id - or not.
|
||||
#
|
||||
# After 3.0.3, there are two kinds of types of boundary errors: strict and permissive.
|
||||
#
|
||||
# If multipart content contains the three necessary lines with correct order, but
|
||||
# there are one or more lines with "--", then parser returns with value 2 (non-zero).
|
||||
#
|
||||
# If some of the necessary lines (usually the start or end) misses, or the order
|
||||
# is wrong, then parser returns with value 1 (also a non-zero).
|
||||
#
|
||||
# You can choose, which one is what you need. The example below contains the
|
||||
# 'strict' mode, which means if there are any lines with start of "--", then
|
||||
# ModSecurity blocked the content. But the next, commented example contains
|
||||
# the 'permissive' mode, then you check only if the necessary lines exists in
|
||||
# correct order. Whit this, you can enable to upload PEM files (eg "----BEGIN.."),
|
||||
# or other text files, which contains eg. HTTP headers.
|
||||
#
|
||||
# The difference is only the operator - in strict mode (first) the content blocked
|
||||
# in case of any non-zero value. In permissive mode (second, commented) the
|
||||
# content blocked only if the value is explicit 1. If it 0 or 2, the content will
|
||||
# allowed.
|
||||
#
|
||||
|
||||
#
|
||||
# See #1747 and #1924 for further information on the possible values for
|
||||
# MULTIPART_UNMATCHED_BOUNDARY.
|
||||
#
|
||||
SecRule MULTIPART_UNMATCHED_BOUNDARY "@eq 1" \
|
||||
"id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
|
||||
|
||||
|
||||
# PCRE Tuning
|
||||
# We want to avoid a potential RegEx DoS condition
|
||||
#
|
||||
SecPcreMatchLimit 1000
|
||||
SecPcreMatchLimitRecursion 1000
|
||||
|
||||
# Some internal errors will set flags in TX and we will need to look for these.
|
||||
# All of these are prefixed with "MSC_". The following flags currently exist:
|
||||
#
|
||||
# MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded.
|
||||
#
|
||||
SecRule TX:/^MSC_/ "!@streq 0" \
|
||||
"id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
|
||||
|
||||
|
||||
# -- Response body handling --------------------------------------------------
|
||||
|
||||
# Allow ModSecurity to access response bodies.
|
||||
# You should have this directive enabled in order to identify errors
|
||||
# and data leakage issues.
|
||||
#
|
||||
# Do keep in mind that enabling this directive does increases both
|
||||
# memory consumption and response latency.
|
||||
#
|
||||
SecResponseBodyAccess On
|
||||
|
||||
# Which response MIME types do you want to inspect? You should adjust the
|
||||
# configuration below to catch documents but avoid static files
|
||||
# (e.g., images and archives).
|
||||
#
|
||||
SecResponseBodyMimeType text/plain text/html text/xml
|
||||
|
||||
# Buffer response bodies of up to 512 KB in length.
|
||||
SecResponseBodyLimit 524288
|
||||
|
||||
# What happens when we encounter a response body larger than the configured
|
||||
# limit? By default, we process what we have and let the rest through.
|
||||
# That's somewhat less secure, but does not break any legitimate pages.
|
||||
#
|
||||
SecResponseBodyLimitAction ProcessPartial
|
||||
|
||||
|
||||
# -- Filesystem configuration ------------------------------------------------
|
||||
|
||||
# The location where ModSecurity stores temporary files (for example, when
|
||||
# it needs to handle a file upload that is larger than the configured limit).
|
||||
#
|
||||
# This default setting is chosen due to all systems have /tmp available however,
|
||||
# this is less than ideal. It is recommended that you specify a location that's private.
|
||||
#
|
||||
SecTmpDir /tmp/
|
||||
|
||||
# The location where ModSecurity will keep its persistent data. This default setting
|
||||
# is chosen due to all systems have /tmp available however, it
|
||||
# too should be updated to a place that other users can't access.
|
||||
#
|
||||
SecDataDir /tmp/
|
||||
|
||||
|
||||
# -- File uploads handling configuration -------------------------------------
|
||||
|
||||
# The location where ModSecurity stores intercepted uploaded files. This
|
||||
# location must be private to ModSecurity. You don't want other users on
|
||||
# the server to access the files, do you?
|
||||
#
|
||||
#SecUploadDir /opt/modsecurity/var/upload/
|
||||
|
||||
# By default, only keep the files that were determined to be unusual
|
||||
# in some way (by an external inspection script). For this to work you
|
||||
# will also need at least one file inspection rule.
|
||||
#
|
||||
#SecUploadKeepFiles RelevantOnly
|
||||
|
||||
# Uploaded files are by default created with permissions that do not allow
|
||||
# any other user to access them. You may need to relax that if you want to
|
||||
# interface ModSecurity to an external program (e.g., an anti-virus).
|
||||
#
|
||||
#SecUploadFileMode 0600
|
||||
|
||||
|
||||
# -- Debug log configuration -------------------------------------------------
|
||||
|
||||
# The default debug log configuration is to duplicate the error, warning
|
||||
# and notice messages from the error log.
|
||||
#
|
||||
#SecDebugLog /opt/modsecurity/var/log/debug.log
|
||||
#SecDebugLogLevel 3
|
||||
|
||||
|
||||
# -- Audit log configuration -------------------------------------------------
|
||||
|
||||
# Log the transactions that are marked by a rule, as well as those that
|
||||
# trigger a server error (determined by a 5xx or 4xx, excluding 404,
|
||||
# level response status codes).
|
||||
#
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
|
||||
|
||||
# Log everything we know about a transaction.
|
||||
SecAuditLogParts ABIJDEFHZ
|
||||
|
||||
# Use a single file for logging. This is much easier to look at, but
|
||||
# assumes that you will use the audit log only ocassionally.
|
||||
#
|
||||
SecAuditLogType Concurrent
|
||||
SecAuditLog /var/log/modsec_audit.log
|
||||
|
||||
# Specify the path for concurrent audit logging.
|
||||
#SecAuditLogStorageDir /opt/modsecurity/var/audit/
|
||||
|
||||
|
||||
# -- Miscellaneous -----------------------------------------------------------
|
||||
|
||||
# Use the most commonly used application/x-www-form-urlencoded parameter
|
||||
# separator. There's probably only one application somewhere that uses
|
||||
# something else so don't expect to change this value.
|
||||
#
|
||||
SecArgumentSeparator &
|
||||
|
||||
# Settle on version 0 (zero) cookies, as that is what most applications
|
||||
# use. Using an incorrect cookie version may open your installation to
|
||||
# evasion attacks (against the rules that examine named cookies).
|
||||
#
|
||||
SecCookieFormat 0
|
||||
|
||||
# Specify your Unicode Code Point.
|
||||
# This mapping is used by the t:urlDecodeUni transformation function
|
||||
# to properly map encoded data to your language. Properly setting
|
||||
# these directives helps to reduce false positives and negatives.
|
||||
#
|
||||
SecUnicodeMapFile unicode.mapping 20127
|
||||
|
||||
# Improve the quality of ModSecurity by sharing information about your
|
||||
# current ModSecurity version and dependencies versions.
|
||||
# The following information will be shared: ModSecurity version,
|
||||
# Web Server version, APR version, PCRE version, Lua version, Libxml2
|
||||
# version, Anonymous unique id for host.
|
||||
SecStatusEngine On
|
||||
|
||||
SecAuditLogStorageDir /var/log/audit/
|
||||
|
|
@ -215,11 +215,13 @@ resource "kubernetes_ingress_v1" "oauth" {
|
|||
name = "oauth2"
|
||||
namespace = "oauth2"
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"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
|
||||
|
|
|
|||
|
|
@ -169,7 +169,6 @@ module "ollama-api-ingress" {
|
|||
allow_local_access_only = true # Restricts to 10.0.0.0/8, 192.168.1.0/24
|
||||
ssl_redirect = false
|
||||
port = 11434
|
||||
proxy_timeout = 300 # Longer timeout for model inference
|
||||
}
|
||||
|
||||
# Web UI
|
||||
|
|
|
|||
|
|
@ -83,11 +83,13 @@ resource "kubernetes_ingress_v1" "openid_help_page" {
|
|||
name = "openid-help-page"
|
||||
namespace = "openid-help-page"
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"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
|
||||
|
|
|
|||
|
|
@ -140,8 +140,22 @@ module "ingress" {
|
|||
tls_secret_name = var.tls_secret_name
|
||||
port = 443
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/auth-type" = "basic" # support only basic auth; can't use authentik
|
||||
"nginx.ingress.kubernetes.io/auth-secret" = kubernetes_secret.basic_auth.metadata[0].name
|
||||
"nginx.ingress.kubernetes.io/auth-realm" = "Authentication Required"
|
||||
"traefik.ingress.kubernetes.io/router.middlewares" = "owntracks-basic-auth@kubernetescrd,traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_manifest" "basic_auth_middleware" {
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "Middleware"
|
||||
metadata = {
|
||||
name = "basic-auth"
|
||||
namespace = kubernetes_namespace.owntracks.metadata[0].name
|
||||
}
|
||||
spec = {
|
||||
basicAuth = {
|
||||
secret = kubernetes_secret.basic_auth.metadata[0].name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,10 +154,6 @@ module "ingress" {
|
|||
tls_secret_name = var.tls_secret_name
|
||||
port = 80
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "0"
|
||||
# see https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md#rate-limiting for all annotations
|
||||
# "nginx.ingress.kubernetes.io/limit-rpm": "5"
|
||||
|
||||
"gethomepage.dev/enabled" = "true"
|
||||
"gethomepage.dev/description" = "Document library"
|
||||
# gethomepage.dev/group: Media
|
||||
|
|
|
|||
|
|
@ -169,13 +169,14 @@ resource "kubernetes_ingress_v1" "pihole" {
|
|||
name = "pihole-ingress"
|
||||
namespace = kubernetes_namespace.pihole.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/auth-tls-verify-client" = "on"
|
||||
"nginx.ingress.kubernetes.io/auth-tls-secret" = "default/ca-secret"
|
||||
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||
"traefik.ingress.kubernetes.io/router.tls.options" = "traefik-mtls@kubernetescrd"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
ingress_class_name = "traefik"
|
||||
tls {
|
||||
hosts = ["pihole.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
|
|
|
|||
|
|
@ -89,9 +89,5 @@ module "ingress" {
|
|||
name = "plotting-book"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
|
||||
additional_configuration_snippet = <<-EOF
|
||||
# Override CSP to allow data: URIs and blob: for database/workers
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
add_header Content-Security-Policy "default-src 'self' blob: data:; img-src 'self' data: blob:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; worker-src 'self' blob:; connect-src 'self' blob:; frame-ancestors 'self' *.viktorbarzin.me viktorbarzin.me" always;
|
||||
EOF
|
||||
custom_content_security_policy = "default-src 'self' blob: data:; img-src 'self' data: blob:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; worker-src 'self' blob:; connect-src 'self' blob:; frame-ancestors 'self' *.viktorbarzin.me viktorbarzin.me"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,13 +89,11 @@ resource "kubernetes_service" "privatebin" {
|
|||
}
|
||||
|
||||
module "ingress" {
|
||||
source = "../ingress_factory"
|
||||
namespace = kubernetes_namespace.privatebin.metadata[0].name
|
||||
name = "privatebin"
|
||||
host = "pb"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
rybbit_site_id = "3ae810b0476d"
|
||||
additional_configuration_snippet = <<-EOF
|
||||
more_set_headers "Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval' https://rybbit.viktorbarzin.me";
|
||||
EOF
|
||||
source = "../ingress_factory"
|
||||
namespace = kubernetes_namespace.privatebin.metadata[0].name
|
||||
name = "privatebin"
|
||||
host = "pb"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
rybbit_site_id = "3ae810b0476d"
|
||||
custom_content_security_policy = "script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval' https://rybbit.viktorbarzin.me"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,38 +211,13 @@ resource "kubernetes_ingress_v1" "proxied-ingress" {
|
|||
name = "realestate-crawler"
|
||||
namespace = kubernetes_namespace.realestate-crawler.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/backend-protocol" = "http"
|
||||
|
||||
# "nginx.ingress.kubernetes.io/auth-url" : var.protected ? "http://ak-outpost-authentik-embedded-outpost.authentik.svc.cluster.local:9000/outpost.goauthentik.io/auth/nginx" : null
|
||||
# "nginx.ingress.kubernetes.io/auth-signin" : var.protected ? "https://authentik.viktorbarzin.me/outpost.goauthentik.io/start?rd=$scheme%3A%2F%2F$host$escaped_request_uri" : null
|
||||
# "nginx.ingress.kubernetes.io/auth-snippet" : var.protected ? "proxy_set_header X-Forwarded-Host $http_host;" : null
|
||||
|
||||
"nginx.ingress.kubernetes.io/configuration-snippet" = <<-EOF
|
||||
limit_req_status 429;
|
||||
limit_conn_status 429;
|
||||
|
||||
# Rybbit Analytics
|
||||
# Only modify HTML
|
||||
sub_filter_types text/html;
|
||||
sub_filter_once off;
|
||||
|
||||
# Disable compression so sub_filter works
|
||||
proxy_set_header Accept-Encoding "";
|
||||
|
||||
# Inject analytics before </head>
|
||||
sub_filter '</head>' '
|
||||
<script src="https://rybbit.viktorbarzin.me/api/script.js"
|
||||
data-site-id="edee05de453d"
|
||||
defer></script>
|
||||
</head>';
|
||||
EOF
|
||||
"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"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
spec {
|
||||
ingress_class_name = "traefik"
|
||||
tls {
|
||||
hosts = ["wrongmove.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
|
|
@ -473,3 +448,25 @@ 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>"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,14 +22,6 @@ variable "max_body_size" {
|
|||
type = string
|
||||
default = "50m"
|
||||
}
|
||||
variable "use_proxy_protocol" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
variable "proxy_timeout" {
|
||||
type = number
|
||||
default = 60
|
||||
}
|
||||
variable "extra_annotations" {
|
||||
default = {}
|
||||
}
|
||||
|
|
@ -37,8 +29,8 @@ variable "rybbit_site_id" {
|
|||
default = null
|
||||
type = string
|
||||
}
|
||||
variable "additional_configuration_snippet" {
|
||||
default = ""
|
||||
variable "custom_content_security_policy" {
|
||||
default = null
|
||||
type = string
|
||||
}
|
||||
|
||||
|
|
@ -70,94 +62,87 @@ resource "kubernetes_ingress_v1" "proxied-ingress" {
|
|||
name = var.name
|
||||
namespace = var.namespace
|
||||
annotations = merge({
|
||||
"nginx.ingress.kubernetes.io/backend-protocol" = "${var.backend_protocol}"
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
# "nginx.ingress.kubernetes.io/auth-url" : var.protected ? "https://oauth2.viktorbarzin.me/oauth2/auth" : null
|
||||
# "nginx.ingress.kubernetes.io/auth-signin" : var.protected ? "https://oauth2.viktorbarzin.me/oauth2/start?rd=/redirect/$http_host$escaped_request_uri" : null
|
||||
# Do not do hairpinning
|
||||
# "nginx.ingress.kubernetes.io/auth-url" : var.protected ? "http://oauth2.oauth2.svc.cluster.local/oauth2/auth" : null
|
||||
# "nginx.ingress.kubernetes.io/auth-signin" : var.protected ? "http://oauth2.oauth2.svc.cluster.local/oauth2/start?rd=/redirect/$http_host$escaped_request_uri" : null
|
||||
|
||||
"nginx.ingress.kubernetes.io/auth-url" : var.protected ? "http://ak-outpost-authentik-embedded-outpost.authentik.svc.cluster.local:9000/outpost.goauthentik.io/auth/nginx" : null
|
||||
# "nginx.ingress.kubernetes.io/auth-signin" : var.protected ? "https://authentik.viktorbarzin.me/outpost.goauthentik.io/start?rd=$scheme%3A%2F%2F$host$escaped_request_uri" : null
|
||||
# "nginx.ingress.kubernetes.io/auth-signin" : var.protected ? "https://authentik.viktorbarzin.me/outpost.goauthentik.io/start?rd=$scheme://$http_host$escaped_request_uri" : null
|
||||
"nginx.ingress.kubernetes.io/auth-signin" : var.protected ? "https://authentik.viktorbarzin.me/outpost.goauthentik.io/start?rd=$escaped_request_uri" : null
|
||||
"nginx.ingress.kubernetes.io/auth-response-headers" : var.protected ? "Set-Cookie,X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid" : null
|
||||
"nginx.ingress.kubernetes.io/auth-snippet" : var.protected ? "proxy_set_header X-Forwarded-Host $http_host;" : null
|
||||
|
||||
# # 2. Local Basic Auth Config
|
||||
# nginx.ingress.kubernetes.io/auth-type: basic
|
||||
# nginx.ingress.kubernetes.io/auth-secret: emergency-basic-auth
|
||||
# nginx.ingress.kubernetes.io/auth-realm: "Authentik Down - Use Emergency Login"
|
||||
|
||||
# # 3. The Fallback Magic
|
||||
# nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
# satisfy any;
|
||||
# allow all;
|
||||
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : var.max_body_size
|
||||
"nginx.ingress.kubernetes.io/use-proxy-protocol" : var.use_proxy_protocol
|
||||
"nginx.ingress.kubernetes.io/proxy-connect-timeout" : var.proxy_timeout
|
||||
"nginx.ingress.kubernetes.io/proxy-send-timeout" : var.proxy_timeout
|
||||
"nginx.ingress.kubernetes.io/proxy-read-timeout" : var.proxy_timeout
|
||||
|
||||
"nginx.ingress.kubernetes.io/configuration-snippet" = <<-EOF
|
||||
limit_req_status 429;
|
||||
limit_conn_status 429;
|
||||
${var.additional_configuration_snippet}
|
||||
${var.rybbit_site_id != null ? <<-JS
|
||||
# Rybbit Analytics
|
||||
# Only modify HTML
|
||||
sub_filter_types text/html;
|
||||
sub_filter_once off;
|
||||
|
||||
# Disable compression so sub_filter works
|
||||
proxy_set_header Accept-Encoding "";
|
||||
|
||||
# Inject analytics before </head>
|
||||
sub_filter '</head>' '
|
||||
<script src="https://rybbit.viktorbarzin.me/api/script.js"
|
||||
data-site-id="${var.rybbit_site_id}"
|
||||
defer></script>
|
||||
</head>';
|
||||
JS
|
||||
: ""
|
||||
}
|
||||
EOF
|
||||
|
||||
}, var.extra_annotations)
|
||||
}
|
||||
|
||||
spec {
|
||||
tls {
|
||||
hosts = ["${var.name}.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
"traefik.ingress.kubernetes.io/router.middlewares" = join(",", compact([
|
||||
"traefik-rate-limit@kubernetescrd",
|
||||
var.custom_content_security_policy == null ? "traefik-csp-headers@kubernetescrd" : null,
|
||||
"traefik-crowdsec@kubernetescrd",
|
||||
var.protected ? "traefik-authentik-forward-auth@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,
|
||||
]))
|
||||
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||
}, var.extra_annotations)
|
||||
}
|
||||
rule {
|
||||
host = "${var.name}.viktorbarzin.me"
|
||||
http {
|
||||
dynamic "path" {
|
||||
# for_each = { for pr in var.ingress_path : pr => pr }
|
||||
for_each = var.ingress_path
|
||||
|
||||
content {
|
||||
path = path.value
|
||||
backend {
|
||||
service {
|
||||
spec {
|
||||
ingress_class_name = "traefik"
|
||||
tls {
|
||||
hosts = ["${var.name}.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
}
|
||||
rule {
|
||||
host = "${var.name}.viktorbarzin.me"
|
||||
http {
|
||||
dynamic "path" {
|
||||
for_each = var.ingress_path
|
||||
|
||||
name = var.name
|
||||
port {
|
||||
number = var.port
|
||||
content {
|
||||
path = path.value
|
||||
backend {
|
||||
service {
|
||||
|
||||
name = var.name
|
||||
port {
|
||||
number = var.port
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# path {
|
||||
# # path = var.ingress_path
|
||||
# path = each.value
|
||||
# }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Rybbit analytics middleware (rewritebody plugin) - created per service when rybbit_site_id is set
|
||||
resource "kubernetes_manifest" "rybbit_analytics" {
|
||||
count = var.rybbit_site_id != null ? 1 : 0
|
||||
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "Middleware"
|
||||
metadata = {
|
||||
name = "rybbit-analytics-${var.name}"
|
||||
namespace = var.namespace
|
||||
}
|
||||
spec = {
|
||||
plugin = {
|
||||
rewritebody = {
|
||||
rewrites = [{
|
||||
regex = "</head>"
|
||||
replacement = "<script src=\"https://rybbit.viktorbarzin.me/api/script.js\" data-site-id=\"${var.rybbit_site_id}\" defer></script></head>"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Custom CSP headers middleware - created per service when custom_content_security_policy is set
|
||||
resource "kubernetes_manifest" "custom_csp" {
|
||||
count = var.custom_content_security_policy != null ? 1 : 0
|
||||
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "Middleware"
|
||||
metadata = {
|
||||
name = "custom-csp-${var.name}"
|
||||
namespace = var.namespace
|
||||
}
|
||||
spec = {
|
||||
headers = {
|
||||
contentSecurityPolicy = var.custom_content_security_policy
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,34 +76,28 @@ module "nas-files" {
|
|||
|
||||
# https://idrac.viktorbarzin.me/
|
||||
module "idrac" {
|
||||
source = "./factory"
|
||||
name = "idrac"
|
||||
external_name = "idrac.viktorbarzin.lan"
|
||||
port = 443
|
||||
tls_secret_name = var.tls_secret_name
|
||||
backend_protocol = "HTTPS"
|
||||
extra_annotations = {
|
||||
# authentik causes 413; we don't need the header below
|
||||
"nginx.ingress.kubernetes.io/auth-response-headers" : null
|
||||
}
|
||||
depends_on = [kubernetes_namespace.reverse-proxy]
|
||||
source = "./factory"
|
||||
name = "idrac"
|
||||
external_name = "idrac.viktorbarzin.lan"
|
||||
port = 443
|
||||
tls_secret_name = var.tls_secret_name
|
||||
backend_protocol = "HTTPS"
|
||||
extra_annotations = {}
|
||||
depends_on = [kubernetes_namespace.reverse-proxy]
|
||||
}
|
||||
|
||||
# Can either listen on https or http; can't do both :/
|
||||
# TODO: Not working yet
|
||||
module "tp-link-gateway" {
|
||||
source = "./factory"
|
||||
name = "gw"
|
||||
external_name = "gw.viktorbarzin.lan"
|
||||
port = 443
|
||||
tls_secret_name = var.tls_secret_name
|
||||
backend_protocol = "HTTPS"
|
||||
depends_on = [kubernetes_namespace.reverse-proxy]
|
||||
protected = true
|
||||
extra_annotations = {
|
||||
# authentik causes 413; we don't need the header below
|
||||
"nginx.ingress.kubernetes.io/auth-response-headers" : null
|
||||
}
|
||||
source = "./factory"
|
||||
name = "gw"
|
||||
external_name = "gw.viktorbarzin.lan"
|
||||
port = 443
|
||||
tls_secret_name = var.tls_secret_name
|
||||
backend_protocol = "HTTPS"
|
||||
depends_on = [kubernetes_namespace.reverse-proxy]
|
||||
protected = true
|
||||
extra_annotations = {}
|
||||
}
|
||||
|
||||
# https://truenas.viktorbarzin.me/
|
||||
|
|
|
|||
|
|
@ -293,35 +293,13 @@ resource "kubernetes_ingress_v1" "rybbit" {
|
|||
namespace = kubernetes_namespace.rybbit.metadata[0].name
|
||||
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/use-regex" = "true"
|
||||
# Optional: enable SSL redirect
|
||||
#"nginx.ingress.kubernetes.io/force-ssl-redirect" = "true"
|
||||
|
||||
"nginx.ingress.kubernetes.io/configuration-snippet" = <<-EOF
|
||||
limit_req_status 429;
|
||||
limit_conn_status 429;
|
||||
|
||||
# Rybbit Analytics
|
||||
# Only modify HTML
|
||||
sub_filter_types text/html;
|
||||
sub_filter_once off;
|
||||
|
||||
# Disable compression so sub_filter works
|
||||
proxy_set_header Accept-Encoding "";
|
||||
|
||||
# Inject analytics before </head>
|
||||
sub_filter '</head>' '
|
||||
<script src="https://rybbit.viktorbarzin.me/api/script.js"
|
||||
data-site-id="3c476801a777"
|
||||
defer></script>
|
||||
</head>';
|
||||
EOF
|
||||
"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 = "nginx"
|
||||
ingress_class_name = "traefik"
|
||||
tls {
|
||||
hosts = ["rybbit.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
|
|
@ -332,7 +310,8 @@ resource "kubernetes_ingress_v1" "rybbit" {
|
|||
http {
|
||||
# API backend
|
||||
path {
|
||||
path = "/api(/|$)(.*)"
|
||||
path = "/api"
|
||||
path_type = "Prefix"
|
||||
backend {
|
||||
service {
|
||||
name = "rybbit"
|
||||
|
|
@ -361,3 +340,25 @@ resource "kubernetes_ingress_v1" "rybbit" {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 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>"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,9 +114,5 @@ module "ingress" {
|
|||
name = "send"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
port = 1443
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/client-max-body-size" : "0"
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "0",
|
||||
}
|
||||
rybbit_site_id = "c1b8f8aa831b"
|
||||
rybbit_site_id = "c1b8f8aa831b"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,7 +140,4 @@ module "ingress" {
|
|||
name = "qbittorrent"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
protected = true
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "1G" // allow uploading .torrent files
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,13 +123,13 @@ resource "kubernetes_ingress_v1" "readarr" {
|
|||
name = "readarr"
|
||||
namespace = "readarr"
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/auth-url" : "https://oauth2.viktorbarzin.me/oauth2/auth"
|
||||
"nginx.ingress.kubernetes.io/auth-signin" : "https://oauth2.viktorbarzin.me/oauth2/start?rd=/redirect/$http_host$escaped_request_uri"
|
||||
"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
|
||||
|
|
|
|||
177
modules/kubernetes/traefik/middleware.tf
Normal file
177
modules/kubernetes/traefik/middleware.tf
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# Shared Traefik Middleware CRDs
|
||||
# These are referenced by ingress resources via annotations like:
|
||||
# "traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd"
|
||||
|
||||
# Rate limiting middleware
|
||||
resource "kubernetes_manifest" "middleware_rate_limit" {
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "Middleware"
|
||||
metadata = {
|
||||
name = "rate-limit"
|
||||
namespace = kubernetes_namespace.traefik.metadata[0].name
|
||||
}
|
||||
spec = {
|
||||
rateLimit = {
|
||||
average = 5
|
||||
burst = 250
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [helm_release.traefik]
|
||||
}
|
||||
|
||||
# Authentik forward auth middleware
|
||||
resource "kubernetes_manifest" "middleware_authentik_forward_auth" {
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "Middleware"
|
||||
metadata = {
|
||||
name = "authentik-forward-auth"
|
||||
namespace = kubernetes_namespace.traefik.metadata[0].name
|
||||
}
|
||||
spec = {
|
||||
forwardAuth = {
|
||||
address = "http://ak-outpost-authentik-embedded-outpost.authentik.svc.cluster.local:9000/outpost.goauthentik.io/auth/traefik"
|
||||
trustForwardHeader = true
|
||||
authResponseHeaders = [
|
||||
"X-authentik-username",
|
||||
"X-authentik-uid",
|
||||
"X-authentik-email",
|
||||
"X-authentik-name",
|
||||
"X-authentik-groups",
|
||||
"Set-Cookie",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [helm_release.traefik]
|
||||
}
|
||||
|
||||
# IP allowlist for local-only access
|
||||
resource "kubernetes_manifest" "middleware_local_only" {
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "Middleware"
|
||||
metadata = {
|
||||
name = "local-only"
|
||||
namespace = kubernetes_namespace.traefik.metadata[0].name
|
||||
}
|
||||
spec = {
|
||||
ipAllowList = {
|
||||
sourceRange = [
|
||||
"192.168.1.0/24",
|
||||
"10.0.0.0/8",
|
||||
"fc00::/7",
|
||||
"fe80::/10",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [helm_release.traefik]
|
||||
}
|
||||
|
||||
# HTTPS redirect middleware
|
||||
resource "kubernetes_manifest" "middleware_redirect_https" {
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "Middleware"
|
||||
metadata = {
|
||||
name = "redirect-https"
|
||||
namespace = kubernetes_namespace.traefik.metadata[0].name
|
||||
}
|
||||
spec = {
|
||||
redirectScheme = {
|
||||
scheme = "https"
|
||||
permanent = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [helm_release.traefik]
|
||||
}
|
||||
|
||||
# CSP headers middleware (default)
|
||||
resource "kubernetes_manifest" "middleware_csp_headers" {
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "Middleware"
|
||||
metadata = {
|
||||
name = "csp-headers"
|
||||
namespace = kubernetes_namespace.traefik.metadata[0].name
|
||||
}
|
||||
spec = {
|
||||
headers = {
|
||||
contentSecurityPolicy = "frame-ancestors 'self' *.viktorbarzin.me viktorbarzin.me"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [helm_release.traefik]
|
||||
}
|
||||
|
||||
# CrowdSec bouncer plugin middleware
|
||||
resource "kubernetes_manifest" "middleware_crowdsec" {
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "Middleware"
|
||||
metadata = {
|
||||
name = "crowdsec"
|
||||
namespace = kubernetes_namespace.traefik.metadata[0].name
|
||||
}
|
||||
spec = {
|
||||
plugin = {
|
||||
crowdsec-bouncer = {
|
||||
crowdsecLapiKey = var.crowdsec_api_key
|
||||
crowdsecLapiHost = "crowdsec-service.crowdsec.svc.cluster.local:8080"
|
||||
crowdsecMode = "stream"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [helm_release.traefik]
|
||||
}
|
||||
|
||||
# TLS option for mTLS (client certificate auth)
|
||||
resource "kubernetes_manifest" "tls_option_mtls" {
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "TLSOption"
|
||||
metadata = {
|
||||
name = "mtls"
|
||||
namespace = kubernetes_namespace.traefik.metadata[0].name
|
||||
}
|
||||
spec = {
|
||||
clientAuth = {
|
||||
secretNames = ["ca-secret"]
|
||||
clientAuthType = "RequireAndVerifyClientCert"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [helm_release.traefik]
|
||||
}
|
||||
|
||||
# Immich-specific rate limit (higher limits for photo uploads)
|
||||
resource "kubernetes_manifest" "middleware_immich_rate_limit" {
|
||||
manifest = {
|
||||
apiVersion = "traefik.io/v1alpha1"
|
||||
kind = "Middleware"
|
||||
metadata = {
|
||||
name = "immich-rate-limit"
|
||||
namespace = kubernetes_namespace.traefik.metadata[0].name
|
||||
}
|
||||
spec = {
|
||||
rateLimit = {
|
||||
average = 100
|
||||
burst = 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [helm_release.traefik]
|
||||
}
|
||||
|
|
@ -97,13 +97,4 @@ module "ingress" {
|
|||
namespace = kubernetes_namespace.tuya-bridge.metadata[0].name
|
||||
name = "tuya-bridge"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/server-snippet" : <<-EOF
|
||||
location /metrics {
|
||||
deny all;
|
||||
return 403;
|
||||
}
|
||||
EOF
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,9 +98,8 @@ module "ingress" {
|
|||
tls_secret_name = var.tls_secret_name
|
||||
service_name = "uptime-kuma"
|
||||
extra_annotations = {
|
||||
"nginx.org/websocket-services" = "uptime-kuma"
|
||||
"gethomepage.dev/enabled" = "true"
|
||||
"gethomepage.dev/description" = "Uptime monitor"
|
||||
"gethomepage.dev/enabled" = "true"
|
||||
"gethomepage.dev/description" = "Uptime monitor"
|
||||
# gethomepage.dev/group: Media
|
||||
"gethomepage.dev/icon" : "uptime-kuma.png"
|
||||
"gethomepage.dev/name" = "Uptime Kuma"
|
||||
|
|
|
|||
|
|
@ -200,11 +200,13 @@ resource "kubernetes_ingress_v1" "vikunja" {
|
|||
name = "vikunja"
|
||||
namespace = kubernetes_namespace.vikunja.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"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
|
||||
|
|
|
|||
|
|
@ -194,11 +194,13 @@ resource "kubernetes_ingress_v1" "webhook_handler" {
|
|||
name = "webhook-handler-ingress"
|
||||
namespace = kubernetes_namespace.webhook-handler.metadata[0].name
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"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
|
||||
|
|
|
|||
|
|
@ -188,14 +188,13 @@ resource "kubernetes_ingress_v1" "ingress" {
|
|||
namespace = kubernetes_namespace.xray.metadata[0].name
|
||||
name = "xray"
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/backend-protocol" = "HTTP"
|
||||
"nginx.org/websocket-services" : "xray"
|
||||
"nginx.ingress.kubernetes.io/enable-access-log" = "false"
|
||||
"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 = ["xray-ws.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
|
|
@ -224,15 +223,14 @@ resource "kubernetes_ingress_v1" "ingress-grpc" {
|
|||
namespace = kubernetes_namespace.xray.metadata[0].name
|
||||
name = "xray-grpc"
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"nginx.ingress.kubernetes.io/enable-access-log" = "false"
|
||||
"nginx.ingress.kubernetes.io/backend-protocol" = "GRPC"
|
||||
"nginx.ingress.kubernetes.io/proxy-read-timeout" = "3600"
|
||||
"nginx.ingress.kubernetes.io/proxy-send-timeout" = "3600"
|
||||
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||
"traefik.ingress.kubernetes.io/service.serversscheme" = "h2c"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
ingress_class_name = "traefik"
|
||||
tls {
|
||||
hosts = ["xray-grpc.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
|
|
@ -262,11 +260,13 @@ resource "kubernetes_ingress_v1" "ingress-vless" {
|
|||
namespace = kubernetes_namespace.xray.metadata[0].name
|
||||
name = "xray-vless"
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "nginx"
|
||||
"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 = ["xray-vless.viktorbarzin.me"]
|
||||
secret_name = var.tls_secret_name
|
||||
|
|
|
|||
|
|
@ -126,10 +126,6 @@ module "ingress" {
|
|||
name = "ytdlp"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
host = "yt"
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/client-max-body-size" : "0"
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "0",
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------
|
||||
|
|
@ -321,8 +317,4 @@ module "highlights_ingress" {
|
|||
tls_secret_name = var.tls_secret_name
|
||||
host = "yt-highlights"
|
||||
protected = true
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-read-timeout" : "300"
|
||||
"nginx.ingress.kubernetes.io/proxy-send-timeout" : "300"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue