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
0315dd4044
commit
c32acc70e6
53 changed files with 534 additions and 1714 deletions
|
|
@ -93,11 +93,7 @@ module "ingress" {
|
||||||
namespace = "actualbudget"
|
namespace = "actualbudget"
|
||||||
name = "budget-${var.name}"
|
name = "budget-${var.name}"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
extra_annotations = {
|
rybbit_site_id = "3e6b6b68088a"
|
||||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "0",
|
|
||||||
"nginx.ingress.kubernetes.io/client-max-body-size" : "0"
|
|
||||||
}
|
|
||||||
rybbit_site_id = "3e6b6b68088a"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,4 @@ module "ingress" {
|
||||||
name = "affine"
|
name = "affine"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
max_body_size = "500m"
|
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
|
namespace = kubernetes_namespace.audiobookshelf.metadata[0].name
|
||||||
name = "audiobookshelf"
|
name = "audiobookshelf"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
extra_annotations = {
|
rybbit_site_id = "b38fda4285df"
|
||||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "0",
|
|
||||||
"nginx.ingress.kubernetes.io/client-max-body-size" : "0"
|
|
||||||
}
|
|
||||||
rybbit_site_id = "b38fda4285df"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,13 @@ resource "kubernetes_ingress_v1" "authentik" {
|
||||||
name = "authentik"
|
name = "authentik"
|
||||||
namespace = kubernetes_namespace.authentik.metadata[0].name
|
namespace = kubernetes_namespace.authentik.metadata[0].name
|
||||||
annotations = {
|
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 {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["authentik.viktorbarzin.me"]
|
hosts = ["authentik.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
|
||||||
|
|
@ -113,26 +113,13 @@ resource "kubernetes_ingress_v1" "blog" {
|
||||||
name = "blog-ingress"
|
name = "blog-ingress"
|
||||||
namespace = kubernetes_namespace.website.metadata[0].name
|
namespace = kubernetes_namespace.website.metadata[0].name
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,website-rybbit-analytics@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/configuration-snippet" = <<-EOT
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
# 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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["viktorbarzin.me"]
|
hosts = ["viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
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"
|
name = "calibre"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
extra_annotations = {
|
extra_annotations = {
|
||||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "5000m"
|
|
||||||
|
|
||||||
"gethomepage.dev/enabled" = "true"
|
"gethomepage.dev/enabled" = "true"
|
||||||
"gethomepage.dev/description" = "Book library"
|
"gethomepage.dev/description" = "Book library"
|
||||||
# gethomepage.dev/group: Media
|
# gethomepage.dev/group: Media
|
||||||
|
|
@ -239,10 +237,8 @@ module "ingress" {
|
||||||
# gethomepage.dev/weight: 10 # optional
|
# gethomepage.dev/weight: 10 # optional
|
||||||
# gethomepage.dev/instance: "public" # optional
|
# gethomepage.dev/instance: "public" # optional
|
||||||
}
|
}
|
||||||
rybbit_site_id = "17a5c7fbb077"
|
rybbit_site_id = "17a5c7fbb077"
|
||||||
additional_configuration_snippet = <<-EOF
|
custom_content_security_policy = "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://rybbit.viktorbarzin.me"
|
||||||
more_set_headers "Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval' https://rybbit.viktorbarzin.me";
|
|
||||||
EOF
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Stacks - Anna's Archive Download Manager
|
# Stacks - Anna's Archive Download Manager
|
||||||
|
|
|
||||||
|
|
@ -181,25 +181,13 @@ resource "kubernetes_service" "crowdsec-web" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module "ingress" {
|
module "ingress" {
|
||||||
source = "../ingress_factory"
|
source = "../ingress_factory"
|
||||||
namespace = kubernetes_namespace.crowdsec.metadata[0].name
|
namespace = kubernetes_namespace.crowdsec.metadata[0].name
|
||||||
name = "crowdsec-web"
|
name = "crowdsec-web"
|
||||||
protected = true
|
protected = true
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
extra_annotations = {
|
exclude_crowdsec = true
|
||||||
# "crowdsec.io/bouncer-mode" : "bypass"
|
rybbit_site_id = "d09137795ccc"
|
||||||
"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"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# CronJob to import public blocklists into CrowdSec
|
# CronJob to import public blocklists into CrowdSec
|
||||||
|
|
|
||||||
|
|
@ -323,16 +323,5 @@ module "ingress" {
|
||||||
namespace = kubernetes_namespace.dawarich.metadata[0].name
|
namespace = kubernetes_namespace.dawarich.metadata[0].name
|
||||||
name = "dawarich"
|
name = "dawarich"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
extra_annotations = {
|
rybbit_site_id = "0abfd409f2fb"
|
||||||
"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"
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -432,18 +432,14 @@ resource "kubernetes_service" "phpmyadmin" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module "ingress" {
|
module "ingress" {
|
||||||
source = "../ingress_factory"
|
source = "../ingress_factory"
|
||||||
namespace = kubernetes_namespace.dbaas.metadata[0].name
|
namespace = kubernetes_namespace.dbaas.metadata[0].name
|
||||||
name = "pma"
|
name = "pma"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
protected = true
|
protected = true
|
||||||
extra_annotations = {
|
extra_annotations = {}
|
||||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "500m"
|
rybbit_site_id = "942c76b8bd4d"
|
||||||
}
|
custom_content_security_policy = "script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval' https://rybbit.viktorbarzin.me"
|
||||||
rybbit_site_id = "942c76b8bd4d"
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -859,10 +855,7 @@ module "ingress-pgadmin" {
|
||||||
name = "pgadmin"
|
name = "pgadmin"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
protected = true
|
protected = true
|
||||||
extra_annotations = {
|
rybbit_site_id = "7cef78e30485"
|
||||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "50m"
|
|
||||||
}
|
|
||||||
rybbit_site_id = "7cef78e30485"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,11 +103,13 @@ resource "kubernetes_ingress_v1" "discount-bandit" {
|
||||||
name = "discount-bandit"
|
name = "discount-bandit"
|
||||||
namespace = kubernetes_namespace.discount-bandit.metadata[0].name
|
namespace = kubernetes_namespace.discount-bandit.metadata[0].name
|
||||||
annotations = {
|
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 {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["discount.viktorbarzin.me"]
|
hosts = ["discount.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
|
||||||
|
|
@ -405,6 +405,5 @@ module "audiblez-web-ingress" {
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
protected = true
|
protected = true
|
||||||
max_body_size = "500m" # Allow large EPUB uploads
|
max_body_size = "500m" # Allow large EPUB uploads
|
||||||
proxy_timeout = 3600 # Long timeout for conversions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,4 @@ module "ingress" {
|
||||||
name = "draw"
|
name = "draw"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
protected = true
|
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
|
namespace = kubernetes_namespace.f1-stream.metadata[0].name
|
||||||
name = "f1"
|
name = "f1"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
extra_annotations = {
|
rybbit_site_id = "7e69786f66d5"
|
||||||
"nginx.ingress.kubernetes.io/force-ssl-redirect" : "false"
|
|
||||||
"nginx.ingress.kubernetes.io/ssl-redirect" : "false"
|
|
||||||
}
|
|
||||||
rybbit_site_id = "7e69786f66d5"
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -252,16 +252,13 @@ resource "kubernetes_ingress_v1" "finance_app" {
|
||||||
name = "finance-app"
|
name = "finance-app"
|
||||||
namespace = kubernetes_namespace.finance_app.metadata[0].name
|
namespace = kubernetes_namespace.finance_app.metadata[0].name
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||||
#"nginx.ingress.kubernetes.io/auth-url"= "https://oauth-provider/auth"
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
#"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"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["finance.viktorbarzin.me"]
|
hosts = ["finance.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,4 @@ module "ingress" {
|
||||||
namespace = kubernetes_namespace.forgejo.metadata[0].name
|
namespace = kubernetes_namespace.forgejo.metadata[0].name
|
||||||
name = "forgejo"
|
name = "forgejo"
|
||||||
tls_secret_name = var.tls_secret_name
|
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"
|
name = "frigate"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
protected = true
|
protected = true
|
||||||
extra_annotations = {
|
rybbit_site_id = "0d4044069ff5"
|
||||||
"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"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module "ingress-internal" {
|
module "ingress-internal" {
|
||||||
|
|
@ -222,17 +209,4 @@ module "ingress-internal" {
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
allow_local_access_only = true
|
allow_local_access_only = true
|
||||||
ssl_redirect = false
|
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
|
namespace = kubernetes_namespace.hackmd.metadata[0].name
|
||||||
name = "hackmd"
|
name = "hackmd"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
extra_annotations = {
|
|
||||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "20000m"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -189,14 +189,13 @@ resource "kubernetes_ingress_v1" "headscale" {
|
||||||
namespace = kubernetes_namespace.headscale.metadata[0].name
|
namespace = kubernetes_namespace.headscale.metadata[0].name
|
||||||
annotations = {
|
annotations = {
|
||||||
// DO NOT ADD CLIENT TLS AUTH as this breaks vpn auth
|
// DO NOT ADD CLIENT TLS AUTH as this breaks vpn auth
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/ssl-redirect" = false # Disable SSL redirection for this Ingress
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
"nginx.org/websocket-services" = "headscale"
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["headscale.viktorbarzin.me"]
|
hosts = ["headscale.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
|
||||||
|
|
@ -206,14 +206,14 @@ resource "kubernetes_ingress_v1" "home-assistant-ui" {
|
||||||
name = "home-assistant-ui-ingress"
|
name = "home-assistant-ui-ingress"
|
||||||
namespace = kubernetes_namespace.home_assistant.metadata[0].name
|
namespace = kubernetes_namespace.home_assistant.metadata[0].name
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/force-ssl-redirect" = "true"
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
"nginx.ingress.kubernetes.io/auth-tls-verify-client" = "on"
|
"traefik.ingress.kubernetes.io/router.tls.options" = "traefik-mtls@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/auth-tls-secret" = var.client_certificate_secret_name
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["home-assistant.viktorbarzin.me"]
|
hosts = ["home-assistant.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ ingress:
|
||||||
gethomepage.dev/description: "A modern, secure, highly customizable application dashboard."
|
gethomepage.dev/description: "A modern, secure, highly customizable application dashboard."
|
||||||
gethomepage.dev/group: "A New Group"
|
gethomepage.dev/group: "A New Group"
|
||||||
gethomepage.dev/icon: "homepage.png"
|
gethomepage.dev/icon: "homepage.png"
|
||||||
ingressClassName: "nginx"
|
ingressClassName: "traefik"
|
||||||
hosts:
|
hosts:
|
||||||
- host: &host "home.viktorbarzin.me"
|
- host: &host "home.viktorbarzin.me"
|
||||||
paths:
|
paths:
|
||||||
|
|
|
||||||
|
|
@ -460,66 +460,8 @@ resource "kubernetes_ingress_v1" "ingress" {
|
||||||
namespace = kubernetes_namespace.immich.metadata[0].name
|
namespace = kubernetes_namespace.immich.metadata[0].name
|
||||||
name = "immich"
|
name = "immich"
|
||||||
annotations = {
|
annotations = {
|
||||||
# NOTE: when changing - test video playback from mobile and web!
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-immich-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,immich-rybbit-analytics@kubernetescrd"
|
||||||
# Easy to break!
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
|
|
||||||
"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"
|
|
||||||
|
|
||||||
|
|
||||||
"gethomepage.dev/enabled" = "true"
|
"gethomepage.dev/enabled" = "true"
|
||||||
"gethomepage.dev/description" = "Photos library"
|
"gethomepage.dev/description" = "Photos library"
|
||||||
|
|
@ -533,6 +475,7 @@ resource "kubernetes_ingress_v1" "ingress" {
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["immich.viktorbarzin.me"]
|
hosts = ["immich.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
@ -724,3 +667,25 @@ resource "kubernetes_cron_job_v1" "postgresql-backup" {
|
||||||
# protected = true
|
# 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"
|
name = "jellyfin"
|
||||||
namespace = kubernetes_namespace.jellyfin.metadata[0].name
|
namespace = kubernetes_namespace.jellyfin.metadata[0].name
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "5000m"
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["jellyfin.viktorbarzin.me"]
|
hosts = ["jellyfin.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
|
||||||
|
|
@ -110,14 +110,14 @@ resource "kubernetes_ingress_v1" "kafka-ui" {
|
||||||
name = "kafka-ui-ingress"
|
name = "kafka-ui-ingress"
|
||||||
namespace = kubernetes_namespace.kafka.metadata[0].name
|
namespace = kubernetes_namespace.kafka.metadata[0].name
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/force-ssl-redirect" = "true"
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
"nginx.ingress.kubernetes.io/auth-tls-verify-client" = "on"
|
"traefik.ingress.kubernetes.io/router.tls.options" = "traefik-mtls@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/auth-tls-secret" = var.client_certificate_secret_name
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["kafka.viktorbarzin.me"]
|
hosts = ["kafka.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,10 @@ persistence:
|
||||||
existingClaim: "grafana-pvc"
|
existingClaim: "grafana-pvc"
|
||||||
ingress:
|
ingress:
|
||||||
enabled: "true"
|
enabled: "true"
|
||||||
|
ingressClassName: "traefik"
|
||||||
annotations:
|
annotations:
|
||||||
kubernetes.io/ingress.class: nginx
|
traefik.ingress.kubernetes.io/router.middlewares: "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,traefik-authentik-forward-auth@kubernetescrd"
|
||||||
# nginx.ingress.kubernetes.io/auth-url: "https://oauth2.viktorbarzin.me/oauth2/auth"
|
traefik.ingress.kubernetes.io/router.entrypoints: "websecure"
|
||||||
# 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;"
|
|
||||||
tls:
|
tls:
|
||||||
- secretName: "tls-secret"
|
- secretName: "tls-secret"
|
||||||
hosts:
|
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" {
|
resource "kubernetes_ingress_v1" "status" {
|
||||||
metadata {
|
metadata {
|
||||||
name = "hetrix-redirect-ingress"
|
name = "hetrix-redirect-ingress"
|
||||||
namespace = kubernetes_namespace.monitoring.metadata[0].name
|
namespace = kubernetes_namespace.monitoring.metadata[0].name
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "monitoring-status-redirect@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/permanent-redirect" = "https://hetrixtools.com/r/38981b548b5d38b052aca8d01285a3f3/"
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["status.viktorbarzin.me"]
|
hosts = ["status.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
@ -99,7 +118,7 @@ resource "kubernetes_ingress_v1" "status" {
|
||||||
service {
|
service {
|
||||||
name = "not-used"
|
name = "not-used"
|
||||||
port {
|
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" {
|
resource "kubernetes_ingress_v1" "status_yotovski" {
|
||||||
metadata {
|
metadata {
|
||||||
name = "hetrix-yotovski-redirect-ingress"
|
name = "hetrix-yotovski-redirect-ingress"
|
||||||
namespace = kubernetes_namespace.monitoring.metadata[0].name
|
namespace = kubernetes_namespace.monitoring.metadata[0].name
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "monitoring-yotovski-redirect@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/permanent-redirect" = "https://hetrixtools.com/r/2ba9d7a5e017794db0fd91f0115a8b3b/"
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["yotovski-status.viktorbarzin.me"]
|
hosts = ["yotovski-status.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
@ -131,7 +169,7 @@ resource "kubernetes_ingress_v1" "status_yotovski" {
|
||||||
path = "/"
|
path = "/"
|
||||||
backend {
|
backend {
|
||||||
service {
|
service {
|
||||||
name = "not-used" # redirected by annotation
|
name = "not-used" # redirected by middleware
|
||||||
port {
|
port {
|
||||||
number = 80
|
number = 80
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,19 +11,10 @@ alertmanager:
|
||||||
baseURL: "https://alertmanager.viktorbarzin.me"
|
baseURL: "https://alertmanager.viktorbarzin.me"
|
||||||
ingress:
|
ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
ingressClassName: "traefik"
|
||||||
annotations:
|
annotations:
|
||||||
kubernetes.io/ingress.class: nginx
|
traefik.ingress.kubernetes.io/router.middlewares: "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,traefik-authentik-forward-auth@kubernetescrd"
|
||||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
traefik.ingress.kubernetes.io/router.entrypoints: "websecure"
|
||||||
# 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;"
|
|
||||||
tls:
|
tls:
|
||||||
- secretName: "tls-secret"
|
- secretName: "tls-secret"
|
||||||
hosts:
|
hosts:
|
||||||
|
|
@ -100,19 +91,10 @@ server:
|
||||||
mountPath: /data/wal # Standard path for the chart
|
mountPath: /data/wal # Standard path for the chart
|
||||||
ingress:
|
ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
ingressClassName: "traefik"
|
||||||
annotations:
|
annotations:
|
||||||
kubernetes.io/ingress.class: nginx
|
traefik.ingress.kubernetes.io/router.middlewares: "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,traefik-authentik-forward-auth@kubernetescrd"
|
||||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
traefik.ingress.kubernetes.io/router.entrypoints: "websecure"
|
||||||
# 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;"
|
|
||||||
|
|
||||||
gethomepage.dev/enabled: "true"
|
gethomepage.dev/enabled: "true"
|
||||||
gethomepage.dev/description: "Prometheus"
|
gethomepage.dev/description: "Prometheus"
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,4 @@ module "ingress" {
|
||||||
namespace = kubernetes_namespace.n8n.metadata[0].name
|
namespace = kubernetes_namespace.n8n.metadata[0].name
|
||||||
name = "n8n"
|
name = "n8n"
|
||||||
tls_secret_name = var.tls_secret_name
|
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"
|
name = "nextcloud"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
port = 8080
|
port = 8080
|
||||||
extra_annotations = {
|
rybbit_site_id = "5a3bfe59a3fe"
|
||||||
"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"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module "whiteboard_ingress" {
|
module "whiteboard_ingress" {
|
||||||
|
|
@ -169,18 +163,6 @@ module "whiteboard_ingress" {
|
||||||
name = "whiteboard"
|
name = "whiteboard"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
port = 80
|
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" {
|
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"
|
name = "oauth2"
|
||||||
namespace = "oauth2"
|
namespace = "oauth2"
|
||||||
annotations = {
|
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 {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["oauth2.viktorbarzin.me"]
|
hosts = ["oauth2.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
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
|
allow_local_access_only = true # Restricts to 10.0.0.0/8, 192.168.1.0/24
|
||||||
ssl_redirect = false
|
ssl_redirect = false
|
||||||
port = 11434
|
port = 11434
|
||||||
proxy_timeout = 300 # Longer timeout for model inference
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Web UI
|
# Web UI
|
||||||
|
|
|
||||||
|
|
@ -83,11 +83,13 @@ resource "kubernetes_ingress_v1" "openid_help_page" {
|
||||||
name = "openid-help-page"
|
name = "openid-help-page"
|
||||||
namespace = "openid-help-page"
|
namespace = "openid-help-page"
|
||||||
annotations = {
|
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 {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["kubectl.viktorbarzin.me"]
|
hosts = ["kubectl.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
|
||||||
|
|
@ -140,8 +140,22 @@ module "ingress" {
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
port = 443
|
port = 443
|
||||||
extra_annotations = {
|
extra_annotations = {
|
||||||
"nginx.ingress.kubernetes.io/auth-type" = "basic" # support only basic auth; can't use authentik
|
"traefik.ingress.kubernetes.io/router.middlewares" = "owntracks-basic-auth@kubernetescrd,traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/auth-secret" = kubernetes_secret.basic_auth.metadata[0].name
|
}
|
||||||
"nginx.ingress.kubernetes.io/auth-realm" = "Authentication Required"
|
}
|
||||||
|
|
||||||
|
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
|
tls_secret_name = var.tls_secret_name
|
||||||
port = 80
|
port = 80
|
||||||
extra_annotations = {
|
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/enabled" = "true"
|
||||||
"gethomepage.dev/description" = "Document library"
|
"gethomepage.dev/description" = "Document library"
|
||||||
# gethomepage.dev/group: Media
|
# gethomepage.dev/group: Media
|
||||||
|
|
|
||||||
|
|
@ -169,13 +169,14 @@ resource "kubernetes_ingress_v1" "pihole" {
|
||||||
name = "pihole-ingress"
|
name = "pihole-ingress"
|
||||||
namespace = kubernetes_namespace.pihole.metadata[0].name
|
namespace = kubernetes_namespace.pihole.metadata[0].name
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/auth-tls-verify-client" = "on"
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
"nginx.ingress.kubernetes.io/auth-tls-secret" = "default/ca-secret"
|
"traefik.ingress.kubernetes.io/router.tls.options" = "traefik-mtls@kubernetescrd"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["pihole.viktorbarzin.me"]
|
hosts = ["pihole.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
|
||||||
|
|
@ -89,9 +89,5 @@ module "ingress" {
|
||||||
name = "plotting-book"
|
name = "plotting-book"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
|
|
||||||
additional_configuration_snippet = <<-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"
|
||||||
# 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
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,13 +89,11 @@ resource "kubernetes_service" "privatebin" {
|
||||||
}
|
}
|
||||||
|
|
||||||
module "ingress" {
|
module "ingress" {
|
||||||
source = "../ingress_factory"
|
source = "../ingress_factory"
|
||||||
namespace = kubernetes_namespace.privatebin.metadata[0].name
|
namespace = kubernetes_namespace.privatebin.metadata[0].name
|
||||||
name = "privatebin"
|
name = "privatebin"
|
||||||
host = "pb"
|
host = "pb"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
rybbit_site_id = "3ae810b0476d"
|
rybbit_site_id = "3ae810b0476d"
|
||||||
additional_configuration_snippet = <<-EOF
|
custom_content_security_policy = "script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval' https://rybbit.viktorbarzin.me"
|
||||||
more_set_headers "Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval' https://rybbit.viktorbarzin.me";
|
|
||||||
EOF
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -211,38 +211,13 @@ resource "kubernetes_ingress_v1" "proxied-ingress" {
|
||||||
name = "realestate-crawler"
|
name = "realestate-crawler"
|
||||||
namespace = kubernetes_namespace.realestate-crawler.metadata[0].name
|
namespace = kubernetes_namespace.realestate-crawler.metadata[0].name
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,realestate-crawler-rybbit-analytics@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/backend-protocol" = "http"
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
|
|
||||||
# "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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["wrongmove.viktorbarzin.me"]
|
hosts = ["wrongmove.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
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
|
type = string
|
||||||
default = "50m"
|
default = "50m"
|
||||||
}
|
}
|
||||||
variable "use_proxy_protocol" {
|
|
||||||
type = bool
|
|
||||||
default = true
|
|
||||||
}
|
|
||||||
variable "proxy_timeout" {
|
|
||||||
type = number
|
|
||||||
default = 60
|
|
||||||
}
|
|
||||||
variable "extra_annotations" {
|
variable "extra_annotations" {
|
||||||
default = {}
|
default = {}
|
||||||
}
|
}
|
||||||
|
|
@ -37,8 +29,8 @@ variable "rybbit_site_id" {
|
||||||
default = null
|
default = null
|
||||||
type = string
|
type = string
|
||||||
}
|
}
|
||||||
variable "additional_configuration_snippet" {
|
variable "custom_content_security_policy" {
|
||||||
default = ""
|
default = null
|
||||||
type = string
|
type = string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,94 +62,87 @@ resource "kubernetes_ingress_v1" "proxied-ingress" {
|
||||||
name = var.name
|
name = var.name
|
||||||
namespace = var.namespace
|
namespace = var.namespace
|
||||||
annotations = merge({
|
annotations = merge({
|
||||||
"nginx.ingress.kubernetes.io/backend-protocol" = "${var.backend_protocol}"
|
"traefik.ingress.kubernetes.io/router.middlewares" = join(",", compact([
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik-rate-limit@kubernetescrd",
|
||||||
# "nginx.ingress.kubernetes.io/auth-url" : var.protected ? "https://oauth2.viktorbarzin.me/oauth2/auth" : null
|
var.custom_content_security_policy == null ? "traefik-csp-headers@kubernetescrd" : null,
|
||||||
# "nginx.ingress.kubernetes.io/auth-signin" : var.protected ? "https://oauth2.viktorbarzin.me/oauth2/start?rd=/redirect/$http_host$escaped_request_uri" : null
|
"traefik-crowdsec@kubernetescrd",
|
||||||
# Do not do hairpinning
|
var.protected ? "traefik-authentik-forward-auth@kubernetescrd" : null,
|
||||||
# "nginx.ingress.kubernetes.io/auth-url" : var.protected ? "http://oauth2.oauth2.svc.cluster.local/oauth2/auth" : null
|
var.rybbit_site_id != null ? "${var.namespace}-rybbit-analytics-${var.name}@kubernetescrd" : 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
|
var.custom_content_security_policy != null ? "${var.namespace}-custom-csp-${var.name}@kubernetescrd" : 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
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
# "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
|
}, var.extra_annotations)
|
||||||
# "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
|
|
||||||
}
|
}
|
||||||
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 {
|
spec {
|
||||||
path = path.value
|
ingress_class_name = "traefik"
|
||||||
backend {
|
tls {
|
||||||
service {
|
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
|
content {
|
||||||
port {
|
path = path.value
|
||||||
number = var.port
|
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/
|
# https://idrac.viktorbarzin.me/
|
||||||
module "idrac" {
|
module "idrac" {
|
||||||
source = "./factory"
|
source = "./factory"
|
||||||
name = "idrac"
|
name = "idrac"
|
||||||
external_name = "idrac.viktorbarzin.lan"
|
external_name = "idrac.viktorbarzin.lan"
|
||||||
port = 443
|
port = 443
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
backend_protocol = "HTTPS"
|
backend_protocol = "HTTPS"
|
||||||
extra_annotations = {
|
extra_annotations = {}
|
||||||
# authentik causes 413; we don't need the header below
|
depends_on = [kubernetes_namespace.reverse-proxy]
|
||||||
"nginx.ingress.kubernetes.io/auth-response-headers" : null
|
|
||||||
}
|
|
||||||
depends_on = [kubernetes_namespace.reverse-proxy]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Can either listen on https or http; can't do both :/
|
# Can either listen on https or http; can't do both :/
|
||||||
# TODO: Not working yet
|
# TODO: Not working yet
|
||||||
module "tp-link-gateway" {
|
module "tp-link-gateway" {
|
||||||
source = "./factory"
|
source = "./factory"
|
||||||
name = "gw"
|
name = "gw"
|
||||||
external_name = "gw.viktorbarzin.lan"
|
external_name = "gw.viktorbarzin.lan"
|
||||||
port = 443
|
port = 443
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
backend_protocol = "HTTPS"
|
backend_protocol = "HTTPS"
|
||||||
depends_on = [kubernetes_namespace.reverse-proxy]
|
depends_on = [kubernetes_namespace.reverse-proxy]
|
||||||
protected = true
|
protected = true
|
||||||
extra_annotations = {
|
extra_annotations = {}
|
||||||
# authentik causes 413; we don't need the header below
|
|
||||||
"nginx.ingress.kubernetes.io/auth-response-headers" : null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# https://truenas.viktorbarzin.me/
|
# https://truenas.viktorbarzin.me/
|
||||||
|
|
|
||||||
|
|
@ -293,35 +293,13 @@ resource "kubernetes_ingress_v1" "rybbit" {
|
||||||
namespace = kubernetes_namespace.rybbit.metadata[0].name
|
namespace = kubernetes_namespace.rybbit.metadata[0].name
|
||||||
|
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,rybbit-rybbit-analytics@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/use-regex" = "true"
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
# 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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
ingress_class_name = "nginx"
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["rybbit.viktorbarzin.me"]
|
hosts = ["rybbit.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
@ -332,7 +310,8 @@ resource "kubernetes_ingress_v1" "rybbit" {
|
||||||
http {
|
http {
|
||||||
# API backend
|
# API backend
|
||||||
path {
|
path {
|
||||||
path = "/api(/|$)(.*)"
|
path = "/api"
|
||||||
|
path_type = "Prefix"
|
||||||
backend {
|
backend {
|
||||||
service {
|
service {
|
||||||
name = "rybbit"
|
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"
|
name = "send"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
port = 1443
|
port = 1443
|
||||||
extra_annotations = {
|
rybbit_site_id = "c1b8f8aa831b"
|
||||||
"nginx.ingress.kubernetes.io/client-max-body-size" : "0"
|
|
||||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "0",
|
|
||||||
}
|
|
||||||
rybbit_site_id = "c1b8f8aa831b"
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,4 @@ module "ingress" {
|
||||||
name = "qbittorrent"
|
name = "qbittorrent"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
protected = true
|
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"
|
name = "readarr"
|
||||||
namespace = "readarr"
|
namespace = "readarr"
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd,traefik-authentik-forward-auth@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/auth-url" : "https://oauth2.viktorbarzin.me/oauth2/auth"
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
"nginx.ingress.kubernetes.io/auth-signin" : "https://oauth2.viktorbarzin.me/oauth2/start?rd=/redirect/$http_host$escaped_request_uri"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["readarr.viktorbarzin.me"]
|
hosts = ["readarr.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
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
|
namespace = kubernetes_namespace.tuya-bridge.metadata[0].name
|
||||||
name = "tuya-bridge"
|
name = "tuya-bridge"
|
||||||
tls_secret_name = var.tls_secret_name
|
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
|
tls_secret_name = var.tls_secret_name
|
||||||
service_name = "uptime-kuma"
|
service_name = "uptime-kuma"
|
||||||
extra_annotations = {
|
extra_annotations = {
|
||||||
"nginx.org/websocket-services" = "uptime-kuma"
|
"gethomepage.dev/enabled" = "true"
|
||||||
"gethomepage.dev/enabled" = "true"
|
"gethomepage.dev/description" = "Uptime monitor"
|
||||||
"gethomepage.dev/description" = "Uptime monitor"
|
|
||||||
# gethomepage.dev/group: Media
|
# gethomepage.dev/group: Media
|
||||||
"gethomepage.dev/icon" : "uptime-kuma.png"
|
"gethomepage.dev/icon" : "uptime-kuma.png"
|
||||||
"gethomepage.dev/name" = "Uptime Kuma"
|
"gethomepage.dev/name" = "Uptime Kuma"
|
||||||
|
|
|
||||||
|
|
@ -173,19 +173,12 @@ resource "kubernetes_service" "shlink" {
|
||||||
}
|
}
|
||||||
|
|
||||||
module "ingress" {
|
module "ingress" {
|
||||||
source = "../ingress_factory"
|
source = "../ingress_factory"
|
||||||
namespace = kubernetes_namespace.shlink.metadata[0].name
|
namespace = kubernetes_namespace.shlink.metadata[0].name
|
||||||
name = "url"
|
name = "url"
|
||||||
service_name = "shlink"
|
service_name = "shlink"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
extra_annotations = {
|
extra_annotations = {}
|
||||||
"nginx.ingress.kubernetes.io/configuration-snippet" : <<-EOF
|
|
||||||
more_set_headers "Host: $host";
|
|
||||||
more_set_headers "X-Real-IP: $remote_addr";
|
|
||||||
more_set_headers "X-Forwarded-For: $proxy_add_x_forwarded_for";
|
|
||||||
more_set_headers "X-Forwarded-Proto: $scheme";
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -200,11 +200,13 @@ resource "kubernetes_ingress_v1" "vikunja" {
|
||||||
name = "vikunja"
|
name = "vikunja"
|
||||||
namespace = kubernetes_namespace.vikunja.metadata[0].name
|
namespace = kubernetes_namespace.vikunja.metadata[0].name
|
||||||
annotations = {
|
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 {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["todo.viktorbarzin.me"]
|
hosts = ["todo.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
|
||||||
|
|
@ -194,11 +194,13 @@ resource "kubernetes_ingress_v1" "webhook_handler" {
|
||||||
name = "webhook-handler-ingress"
|
name = "webhook-handler-ingress"
|
||||||
namespace = kubernetes_namespace.webhook-handler.metadata[0].name
|
namespace = kubernetes_namespace.webhook-handler.metadata[0].name
|
||||||
annotations = {
|
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 {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["webhook.viktorbarzin.me"]
|
hosts = ["webhook.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
|
||||||
|
|
@ -188,14 +188,13 @@ resource "kubernetes_ingress_v1" "ingress" {
|
||||||
namespace = kubernetes_namespace.xray.metadata[0].name
|
namespace = kubernetes_namespace.xray.metadata[0].name
|
||||||
name = "xray"
|
name = "xray"
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/backend-protocol" = "HTTP"
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
"nginx.org/websocket-services" : "xray"
|
|
||||||
"nginx.ingress.kubernetes.io/enable-access-log" = "false"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["xray-ws.viktorbarzin.me"]
|
hosts = ["xray-ws.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
@ -224,15 +223,14 @@ resource "kubernetes_ingress_v1" "ingress-grpc" {
|
||||||
namespace = kubernetes_namespace.xray.metadata[0].name
|
namespace = kubernetes_namespace.xray.metadata[0].name
|
||||||
name = "xray-grpc"
|
name = "xray-grpc"
|
||||||
annotations = {
|
annotations = {
|
||||||
"kubernetes.io/ingress.class" = "nginx"
|
"traefik.ingress.kubernetes.io/router.middlewares" = "traefik-rate-limit@kubernetescrd,traefik-csp-headers@kubernetescrd,traefik-crowdsec@kubernetescrd"
|
||||||
"nginx.ingress.kubernetes.io/enable-access-log" = "false"
|
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
|
||||||
"nginx.ingress.kubernetes.io/backend-protocol" = "GRPC"
|
"traefik.ingress.kubernetes.io/service.serversscheme" = "h2c"
|
||||||
"nginx.ingress.kubernetes.io/proxy-read-timeout" = "3600"
|
|
||||||
"nginx.ingress.kubernetes.io/proxy-send-timeout" = "3600"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["xray-grpc.viktorbarzin.me"]
|
hosts = ["xray-grpc.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
@ -262,11 +260,13 @@ resource "kubernetes_ingress_v1" "ingress-vless" {
|
||||||
namespace = kubernetes_namespace.xray.metadata[0].name
|
namespace = kubernetes_namespace.xray.metadata[0].name
|
||||||
name = "xray-vless"
|
name = "xray-vless"
|
||||||
annotations = {
|
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 {
|
spec {
|
||||||
|
ingress_class_name = "traefik"
|
||||||
tls {
|
tls {
|
||||||
hosts = ["xray-vless.viktorbarzin.me"]
|
hosts = ["xray-vless.viktorbarzin.me"]
|
||||||
secret_name = var.tls_secret_name
|
secret_name = var.tls_secret_name
|
||||||
|
|
|
||||||
|
|
@ -126,10 +126,6 @@ module "ingress" {
|
||||||
name = "ytdlp"
|
name = "ytdlp"
|
||||||
tls_secret_name = var.tls_secret_name
|
tls_secret_name = var.tls_secret_name
|
||||||
host = "yt"
|
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
|
tls_secret_name = var.tls_secret_name
|
||||||
host = "yt-highlights"
|
host = "yt-highlights"
|
||||||
protected = true
|
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