diff --git a/charts/library/common-test/tests/ingress/nginx_test.yaml b/charts/library/common-test/tests/ingress/nginx_test.yaml
new file mode 100644
index 00000000000..fffa0486e18
--- /dev/null
+++ b/charts/library/common-test/tests/ingress/nginx_test.yaml
@@ -0,0 +1,252 @@
+suite: ingress - nginx metadata test
+templates:
+ - common.yaml
+chart:
+ appVersion: &appVer v9.9.9
+release:
+ name: test-release-name
+ namespace: test-release-namespace
+tests:
+ - it: should pass with ingress created with ipWhiteList annotations from nginx
+ set:
+ service: &service
+ my-service:
+ enabled: true
+ primary: true
+ ports:
+ main:
+ enabled: true
+ primary: true
+ port: 80
+ ingress:
+ my-ingress:
+ enabled: true
+ primary: true
+ hosts: &hosts
+ - host: test-host
+ paths:
+ - path: /test-path
+ integrations:
+ nginx:
+ enabled: true
+ ipWhitelist:
+ - 10.0.0.0/8
+ - 192.168.0.0/16
+ asserts:
+ - documentIndex: &ingressDoc 1
+ isKind:
+ of: Ingress
+ - documentIndex: *ingressDoc
+ equal:
+ path: metadata.name
+ value: test-release-name-common-test
+ - documentIndex: *ingressDoc
+ isSubset:
+ path: metadata.annotations
+ content:
+ nginx.ingress.kubernetes.io/whitelist-source-range: 10.0.0.0/8,192.168.0.0/16
+
+ - it: should pass with ingress created with themePark annotations from nginx
+ set:
+ service: *service
+ ingress:
+ my-ingress:
+ enabled: true
+ primary: true
+ hosts: *hosts
+ integrations:
+ nginx:
+ enabled: true
+ themePark:
+ enabled: true
+ css: https://example.com/theme.css
+ asserts:
+ - documentIndex: &ingressDoc 1
+ isKind:
+ of: Ingress
+ - documentIndex: *ingressDoc
+ equal:
+ path: metadata.name
+ value: test-release-name-common-test
+ - documentIndex: *ingressDoc
+ isSubset:
+ path: metadata.annotations
+ content:
+ nginx.ingress.kubernetes.io/configuration-snippet: |-
+ proxy_set_header Accept-Encoding "";
+ sub_filter
+ ''
+ '
+ ';
+ sub_filter_once on;
+
+ - it: should pass with ingress created with authentik annotations from nginx
+ set:
+ service: *service
+ ingress:
+ my-ingress:
+ enabled: true
+ primary: true
+ hosts: *hosts
+ integrations:
+ nginx:
+ enabled: true
+ auth:
+ type: authentik
+ internalHost: internal.host
+ externalHost: external.host
+ asserts:
+ - documentIndex: &ingressDoc 1
+ isKind:
+ of: Ingress
+ - documentIndex: *ingressDoc
+ equal:
+ path: metadata.name
+ value: test-release-name-common-test
+ - documentIndex: *ingressDoc
+ isSubset:
+ path: metadata.annotations
+ content:
+ nginx.ingress.kubernetes.io/auth-method: GET
+ nginx.ingress.kubernetes.io/auth-response-headers: Set-Cookie,X-authentik-username,X-authentik-groups,X-authentik-entitlements,X-authentik-email,X-authentik-name,X-authentik-uid
+ nginx.ingress.kubernetes.io/auth-signin: https://external.host/outpost.goauthentik.io/start?rd=$scheme://$http_host$escaped_request_uri
+ nginx.ingress.kubernetes.io/auth-snippet: proxy_set_header X-Forwarded-Host $http_host;
+ nginx.ingress.kubernetes.io/auth-url: http://internal.host/outpost.goauthentik.io/auth/nginx
+ nginx.ingress.kubernetes.io/backend-protocol: HTTPS
+ nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
+
+ - it: should pass with ingress created with authelia annotations from nginx
+ set:
+ service: *service
+ ingress:
+ my-ingress:
+ enabled: true
+ primary: true
+ hosts: *hosts
+ integrations:
+ nginx:
+ enabled: true
+ auth:
+ type: authelia
+ internalHost: internal.host
+ externalHost: external.host
+ asserts:
+ - documentIndex: &ingressDoc 1
+ isKind:
+ of: Ingress
+ - documentIndex: *ingressDoc
+ equal:
+ path: metadata.name
+ value: test-release-name-common-test
+ - documentIndex: *ingressDoc
+ isSubset:
+ path: metadata.annotations
+ content:
+ nginx.ingress.kubernetes.io/auth-method: GET
+ nginx.ingress.kubernetes.io/auth-signin: https://external.host?rm=$request_method
+ nginx.ingress.kubernetes.io/auth-url: http://internal.host/api/verify
+
+ # Failures
+
+ - it: should fail with ipWhitelist not a slice
+ set:
+ service: *service
+ ingress:
+ my-ingress1:
+ enabled: true
+ primary: true
+ integrations:
+ nginx:
+ enabled: true
+ ipWhitelist: "not a slice"
+ hosts: *hosts
+ asserts:
+ - failedTemplate:
+ errorMessage: Ingress - Expected [integrations.nginx.ipWhitelist] to be a [slice], but got [string]
+
+ - it: should fail with auth.type not a valid type
+ set:
+ service: *service
+ ingress:
+ my-ingress1:
+ enabled: true
+ primary: true
+ integrations:
+ nginx:
+ enabled: true
+ auth:
+ type: "invalid"
+ hosts: *hosts
+ asserts:
+ - failedTemplate:
+ errorMessage: Ingress - Expected [integrations.nginx.auth.type] to be one of [authentik, authelia], but got [invalid]
+
+ - it: should fail with auth.type set to authentik but no auth.internalHost
+ set:
+ service: *service
+ ingress:
+ my-ingress1:
+ enabled: true
+ primary: true
+ integrations:
+ nginx:
+ enabled: true
+ auth:
+ type: authentik
+ hosts: *hosts
+ asserts:
+ - failedTemplate:
+ errorMessage: Ingress - Expected [integrations.nginx.auth.internalHost] and [integrations.nginx.auth.externalHost] to be set
+
+ - it: should fail with auth.type set to authentik but no auth.externalHost
+ set:
+ service: *service
+ ingress:
+ my-ingress1:
+ enabled: true
+ primary: true
+ integrations:
+ nginx:
+ enabled: true
+ auth:
+ type: authentik
+ internalHost: internal.host
+ hosts: *hosts
+ asserts:
+ - failedTemplate:
+ errorMessage: Ingress - Expected [integrations.nginx.auth.internalHost] and [integrations.nginx.auth.externalHost] to be set
+
+ - it: should fail with auth.type set to authelia but no auth.internalHost
+ set:
+ service: *service
+ ingress:
+ my-ingress1:
+ enabled: true
+ primary: true
+ integrations:
+ nginx:
+ enabled: true
+ auth:
+ type: authelia
+ hosts: *hosts
+ asserts:
+ - failedTemplate:
+ errorMessage: Ingress - Expected [integrations.nginx.auth.internalHost] and [integrations.nginx.auth.externalHost] to be set
+
+ - it: should fail with auth.type set to authelia but no auth.externalHost
+ set:
+ service: *service
+ ingress:
+ my-ingress1:
+ enabled: true
+ primary: true
+ integrations:
+ nginx:
+ enabled: true
+ auth:
+ type: authelia
+ internalHost: internal.host
+ hosts: *hosts
+ asserts:
+ - failedTemplate:
+ errorMessage: Ingress - Expected [integrations.nginx.auth.internalHost] and [integrations.nginx.auth.externalHost] to be set
diff --git a/charts/library/common/Chart.yaml b/charts/library/common/Chart.yaml
index 99c7c19a02b..3acc7116e1d 100644
--- a/charts/library/common/Chart.yaml
+++ b/charts/library/common/Chart.yaml
@@ -48,4 +48,4 @@ sources:
- https://hub.docker.com/_/
- https://hub.docker.com/r/mikefarah/yq
type: library
-version: 28.3.0
+version: 28.4.0
diff --git a/charts/library/common/templates/class/_ingress.tpl b/charts/library/common/templates/class/_ingress.tpl
index 1b5969395f2..14c730eeb68 100644
--- a/charts/library/common/templates/class/_ingress.tpl
+++ b/charts/library/common/templates/class/_ingress.tpl
@@ -49,6 +49,7 @@ objectData: The object data to be used to render the Ingress.
{{- include "tc.v1.common.lib.ingress.integration.certManager" (dict "rootCtx" $rootCtx "objectData" $objectData) -}}
{{- include "tc.v1.common.lib.ingress.integration.traefik" (dict "rootCtx" $rootCtx "objectData" $objectData) -}}
+ {{- include "tc.v1.common.lib.ingress.integration.nginx" (dict "rootCtx" $rootCtx "objectData" $objectData) -}}
{{- if ne $ingressClassName "tc-stopped" -}}{{/* If is stopped, dont render homepage annotations */}}
{{- include "tc.v1.common.lib.ingress.integration.homepage" (dict "rootCtx" $rootCtx "objectData" $objectData) -}}
{{- end }}
diff --git a/charts/library/common/templates/lib/ingress/integrations/_nginx.tpl b/charts/library/common/templates/lib/ingress/integrations/_nginx.tpl
new file mode 100644
index 00000000000..8c53b1b713b
--- /dev/null
+++ b/charts/library/common/templates/lib/ingress/integrations/_nginx.tpl
@@ -0,0 +1,32 @@
+{{- define "tc.v1.common.lib.ingress.integration.nginx" -}}
+ {{- $objectData := .objectData -}}
+ {{- $rootCtx := .rootCtx -}}
+
+ {{- $nginx := $objectData.integrations.nginx -}}
+
+ {{- if $nginx.enabled -}}
+
+ {{/* ipWhiteList */}}
+ {{- if $nginx.ipWhitelist -}}
+ {{- include "tc.v1.common.lib.ingress.integration.nginx.ipWhitelist" (dict "objectData" $objectData "whiteList" $nginx.ipWhitelist) -}}
+ {{- end -}}
+
+ {{/* themePark */}}
+ {{- if and $nginx.themePark $nginx.themePark.enabled -}}
+ {{- include "tc.v1.common.lib.ingress.integration.nginx.themePark" (dict "objectData" $objectData "themePark" $nginx.themePark) -}}
+ {{- end -}}
+
+ {{/* Auth */}}
+ {{- $validAuthTypes := (list "authentik" "authelia") -}}
+ {{- if and $nginx.auth $nginx.auth.type -}}
+ {{- if eq $nginx.auth.type "authentik" -}}
+ {{- include "tc.v1.common.lib.ingress.integration.nginx.auth.authentik" (dict "objectData" $objectData "auth" $nginx.auth) -}}
+ {{- else if eq $nginx.auth.type "authelia" -}}
+ {{- include "tc.v1.common.lib.ingress.integration.nginx.auth.authelia" (dict "objectData" $objectData "auth" $nginx.auth) -}}
+ {{- else -}}
+ {{- fail (printf "Ingress - Expected [integrations.nginx.auth.type] to be one of [%s], but got [%s]" (join ", " $validAuthTypes) $nginx.auth.type) -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- end -}}
+{{- end -}}
diff --git a/charts/library/common/templates/lib/ingress/integrations/nginx/_auth.tpl b/charts/library/common/templates/lib/ingress/integrations/nginx/_auth.tpl
new file mode 100644
index 00000000000..626bf772603
--- /dev/null
+++ b/charts/library/common/templates/lib/ingress/integrations/nginx/_auth.tpl
@@ -0,0 +1,54 @@
+{{- define "tc.v1.common.lib.ingress.integration.nginx.auth.authentik" -}}
+ {{- $objectData := .objectData -}}
+ {{- $auth := .auth -}}
+
+ {{- if and $auth.respondHeaders (not (kindIs "slice" $auth.responseHeaders)) -}}
+ {{- fail (printf "Ingress - Expected [integrations.nginx.auth.responseHeaders] to be a [slice], but got [%s]" (kindOf $auth.responseHeaders)) -}}
+ {{- end -}}
+
+ {{- $respHeaders := ($auth.responseHeaders | default (list
+ "Set-Cookie"
+ "X-authentik-username"
+ "X-authentik-groups"
+ "X-authentik-entitlements"
+ "X-authentik-email"
+ "X-authentik-name"
+ "X-authentik-uid"
+ )) -}}
+
+ {{- if or (not $auth.internalHost) (not $auth.externalHost) -}}
+ {{- fail "Ingress - Expected [integrations.nginx.auth.internalHost] and [integrations.nginx.auth.externalHost] to be set" -}}
+ {{- end -}}
+
+ {{- $_ := set $objectData.annotations "nginx.ingress.kubernetes.io/auth-method" "GET" -}}
+ {{- $_ := set $objectData.annotations "nginx.ingress.kubernetes.io/auth-response-headers" (join "," $respHeaders) -}}
+ {{- $_ := set $objectData.annotations "nginx.ingress.kubernetes.io/auth-snippet" "proxy_set_header X-Forwarded-Host $http_host;" -}}
+ {{- $_ := set $objectData.annotations "nginx.ingress.kubernetes.io/backend-protocol" "HTTPS" -}}
+ {{- $_ := set $objectData.annotations "nginx.ingress.kubernetes.io/force-ssl-redirect" "true" -}}
+ {{- $_ := set $objectData.annotations "nginx.ingress.kubernetes.io/auth-url" (printf "http://%s/outpost.goauthentik.io/auth/nginx" $auth.internalHost) -}}
+ {{- $_ := set $objectData.annotations "nginx.ingress.kubernetes.io/auth-signin" (printf "https://%s/outpost.goauthentik.io/start?rd=$scheme://$http_host$escaped_request_uri" $auth.externalHost) -}}
+{{- end -}}
+
+{{- define "tc.v1.common.lib.ingress.integration.nginx.auth.authelia" -}}
+ {{- $objectData := .objectData -}}
+ {{- $auth := .auth -}}
+
+ {{- if and $auth.respondHeaders (not (kindIs "slice" $auth.responseHeaders)) -}}
+ {{- fail (printf "Ingress - Expected [integrations.nginx.auth.responseHeaders] to be a [slice], but got [%s]" (kindOf $auth.responseHeaders)) -}}
+ {{- end -}}
+
+ {{- $respHeaders := ($auth.responseHeaders | default (list
+ "Remote-User"
+ "Remote-Name"
+ "Remote-Groups"
+ "Remote-Email"
+ )) -}}
+
+ {{- if or (not $auth.internalHost) (not $auth.externalHost) -}}
+ {{- fail "Ingress - Expected [integrations.nginx.auth.internalHost] and [integrations.nginx.auth.externalHost] to be set" -}}
+ {{- end -}}
+
+ {{- $_ := set $objectData.annotations "nginx.ingress.kubernetes.io/auth-method" "GET" -}}
+ {{- $_ := set $objectData.annotations "nginx.ingress.kubernetes.io/auth-url" (printf "http://%s/api/verify" $auth.internalHost) -}}
+ {{- $_ := set $objectData.annotations "nginx.ingress.kubernetes.io/auth-signin" (printf "https://%s?rm=$request_method" $auth.externalHost) -}}
+{{- end -}}
diff --git a/charts/library/common/templates/lib/ingress/integrations/nginx/_ipWhiteList.tpl b/charts/library/common/templates/lib/ingress/integrations/nginx/_ipWhiteList.tpl
new file mode 100644
index 00000000000..f7e958b8f9e
--- /dev/null
+++ b/charts/library/common/templates/lib/ingress/integrations/nginx/_ipWhiteList.tpl
@@ -0,0 +1,12 @@
+{{- define "tc.v1.common.lib.ingress.integration.nginx.ipWhitelist" -}}
+ {{- $objectData := .objectData -}}
+ {{- $whiteList := .whiteList -}}
+
+ {{- if not (kindIs "slice" $whiteList) -}}
+ {{- fail (printf "Ingress - Expected [integrations.nginx.ipWhitelist] to be a [slice], but got [%s]" (kindOf $whiteList)) -}}
+ {{- end -}}
+
+ {{- if $whiteList -}}
+ {{- $_ := set $objectData.annotations "nginx.ingress.kubernetes.io/whitelist-source-range" (join "," $whiteList) -}}
+ {{- end -}}
+{{- end -}}
diff --git a/charts/library/common/templates/lib/ingress/integrations/nginx/_themePark.tpl b/charts/library/common/templates/lib/ingress/integrations/nginx/_themePark.tpl
new file mode 100644
index 00000000000..81e4e7f2c06
--- /dev/null
+++ b/charts/library/common/templates/lib/ingress/integrations/nginx/_themePark.tpl
@@ -0,0 +1,18 @@
+{{- define "tc.v1.common.lib.ingress.integration.nginx.themePark" -}}
+ {{- $objectData := .objectData -}}
+ {{- $theme := .themePark -}}
+ {{- if and $theme $theme.enabled (not (kindIs "string" $theme.css)) -}}
+ {{- fail (printf "Ingress - Expected [integrations.nginx.themepark.css] to be a [string], but got [%s]" (kindOf $theme.css)) -}}
+ {{- end -}}
+
+ {{- $snippet := (list
+ "proxy_set_header Accept-Encoding \"\";"
+ "sub_filter"
+ "''"
+ (printf "'" $theme.css)
+ "';"
+ "sub_filter_once on;"
+ ) -}}
+
+ {{- $_ := set $objectData.annotations "nginx.ingress.kubernetes.io/configuration-snippet" (join "\n" $snippet) -}}
+{{- end -}}
diff --git a/charts/library/common/values.yaml b/charts/library/common/values.yaml
index fe9762e7645..1ede6196d31 100644
--- a/charts/library/common/values.yaml
+++ b/charts/library/common/values.yaml
@@ -665,6 +665,21 @@ ingress:
# # Optional, by default will try to
# # "lookup" the namespace based on the name
# namespace: ""
+ nginx:
+ enabled: false
+ themepark:
+ enabled: false
+ css: ""
+ ipWhitelist: []
+ auth:
+ # empty to disable, options: "authentik" or "authelia"
+ type: ""
+ # Internal Domain name + port to reach the auth provider, excluding http(s)
+ internalHost: ""
+ # External (ingress) Domain name to reach the auth provider, excluding http(s)
+ externalHost: ""
+ # Optional: override default response headers
+ responseHeaders: []
homepage:
enabled: false
# Default: chart name
diff --git a/cspell.config.yaml b/cspell.config.yaml
index 176cfac3d58..56fb268e25e 100644
--- a/cspell.config.yaml
+++ b/cspell.config.yaml
@@ -333,6 +333,7 @@ words:
- statping
- steamcommunica
- steammasterser
+ - stylesheet
- subchart
- sublist
- subquestion