diff --git a/charts/incubator/traefik-forward-auth/.helmignore b/charts/incubator/traefik-forward-auth/.helmignore new file mode 100644 index 00000000000..77ca5567b26 --- /dev/null +++ b/charts/incubator/traefik-forward-auth/.helmignore @@ -0,0 +1,30 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ +# OWNERS file for Kubernetes +OWNERS +# helm-docs templates +*.gotmpl +# docs folder +/docs +# icon +icon.png diff --git a/charts/incubator/traefik-forward-auth/Chart.yaml b/charts/incubator/traefik-forward-auth/Chart.yaml new file mode 100644 index 00000000000..cde57c01e63 --- /dev/null +++ b/charts/incubator/traefik-forward-auth/Chart.yaml @@ -0,0 +1,35 @@ +apiVersion: v2 +kubeVersion: ">=1.16.0-0" +name: traefik-forward-auth +version: 0.1.0 +appVersion: "2.2.0" +description: A minimal forward authentication service that provides OAuth/SSO login and authentication for the traefik reverse proxy/load balancer. An example for a typical setup is included in the source (docs/how-to.md). +type: application +deprecated: false +home: https://github.com/truecharts/charts/tree/master/charts/incubator/traefik-forward-auth +icon: https://raw.githubusercontent.com/truecharts/charts/master/incubator/traefik-forward-auth/icon.png?raw=true +keywords: + - traefik-forward-auth + - traefik + - forward-auth + - auth + - ingress + - middleware +sources: + - https://github.com/truecharts/charts/tree/master/charts/incubator/traefik-forward-auth + - https://github.com/thomseddon/traefik-forward-auth +dependencies: + - name: common + repository: https://library-charts.truecharts.org + version: + 11.1.2 + # condition: +maintainers: + - email: info@truecharts.org + name: TrueCharts + url: https://truecharts.org +annotations: + truecharts.org/catagories: | + - network + truecharts.org/SCALE-support: "true" + truecharts.org/grade: U diff --git a/charts/incubator/traefik-forward-auth/README.md b/charts/incubator/traefik-forward-auth/README.md new file mode 100644 index 00000000000..9b45abe7b30 --- /dev/null +++ b/charts/incubator/traefik-forward-auth/README.md @@ -0,0 +1,26 @@ +# README + +## General Info + +TrueCharts can be installed as both *normal* Helm Charts or as Apps on TrueNAS SCALE. +However only installations using the TrueNAS SCALE Apps system are supported. + +For more information about this App, please check the docs on the TrueCharts [website](https://truecharts.org/charts/stable/) + +**This chart is not maintained by the upstream project and any issues with the chart should be raised [here](https://github.com/truecharts/charts/issues/new/choose)** + +## Support + +- Please check our [quick-start guides for TrueNAS SCALE](https://truecharts.org/manual/SCALE%20Apps/Important-MUST-READ). +- See the [Website](https://truecharts.org) +- Check our [Discord](https://discord.gg/tVsPTHWTtr) +- Open a [issue](https://github.com/truecharts/charts/issues/new/choose) + +--- + +## Sponsor TrueCharts + +TrueCharts can only exist due to the incredible effort of our staff. +Please consider making a [donation](https://truecharts.org/sponsor) or contributing back to the project any way you can! + +*All Rights Reserved - The TrueCharts Project* diff --git a/charts/incubator/traefik-forward-auth/docs/how-to.md b/charts/incubator/traefik-forward-auth/docs/how-to.md new file mode 100644 index 00000000000..c6099299e06 --- /dev/null +++ b/charts/incubator/traefik-forward-auth/docs/how-to.md @@ -0,0 +1,71 @@ +# traefik-forward-auth + +This app makes it possible to have a layer of security in front of your publicly exposed apps. +It supports Google, OIDC, and generic OAuth2. +Please read the [GitHub README of the original project](https://github.com/thomseddon/traefik-forward-auth) for your +authentication options. + +Note: generally, phone apps do not support redirection during their authentication flow, so this middleware is more suitable for +protecting portals that you would access through a browser. + +## A standard setup (auth host mode) + +This method will add a middleware to the traefik instance with Google authentication which then you can apply on any apps +with either subdomain or path prefix Ingress rules. +The example domain will be `https://example.com` which should be substituted to your externally accessible domain name. + +### Setting up traefik-forward-auth + +Assuming you have set up the `Client ID for Web application` in the developer console and set the `Authorized redirect URIs` to +`https://auth.example.com/_oauth`, start installing traefik-forward-auth: + +- Set a `Secret` (it's mandatory, but can be any string of your choosing). +- Set `Auth host` to `auth.example.com`. +- Add your email to `Whitelist`. + +![auth-options](img/auth-options.png) + +- Add your root domain to `Cookie options`. + +![cookie-options](img/cookie-options.png) + +- Set the `Client ID` and `Client Secret` to the ones presented on the developer console. `Prompt` can be left empty. + +![google-options](img/google-options.png) + +- Set up Ingress for the app as `auth.example.com` as usual. +- That's it, since this is a stateless program, it doesn't need any special permissions or storage. + +### Creating the middleware on traefik + +The traefik instance has to be made aware of the forward authentication. Edit your traefik installation: + +- Go to `websecure` entrypoint and enable `Accept forwarded headers`. +- Add your default gateway (internal router IP) to `Trusted IPs` if using hairpin NAT. If you are using DNS override for your + domain name, you can probably skip this step. + +![traefik-forwarded-headers](img/traefik-forwarded-headers.png) + +- Go to `Middlewares` and add a `forward-auth` one. +- Name it (use a short one if planning to add to many apps). +- Add `https://auth.example.com/_oauth` as address. This will redirect initial requests to the traefik-forward-auth container. +- Check `trustForwardHeader`. +- Add `X-Forwarded-User` to `authResponseHeaders`. + +![traefik-middleware](img/traefik-middleware.png) + +### Applying the middleware on apps + +To actually use the forward authentication, you have to add it to either a chain or by itself to existing app Ingresses. + +![ingress-middleware](img/ingress-middleware.png) + +### Per-app whitelist + +In case you need per-app whitelists, you have two options: set up multiple instances of traefik-forward-auth (cumbersome) or +use custom rules. Consult the readme of the original project how to set them. + +### Testing + +Opening your URL should result in being redirected to Google authentication. Subsequent checks if the auth is working can be +made by opening an incognito window. diff --git a/charts/incubator/traefik-forward-auth/docs/img/auth-options.png b/charts/incubator/traefik-forward-auth/docs/img/auth-options.png new file mode 100644 index 00000000000..0b813327ae8 Binary files /dev/null and b/charts/incubator/traefik-forward-auth/docs/img/auth-options.png differ diff --git a/charts/incubator/traefik-forward-auth/docs/img/cookie-options.png b/charts/incubator/traefik-forward-auth/docs/img/cookie-options.png new file mode 100644 index 00000000000..d70890ccdee Binary files /dev/null and b/charts/incubator/traefik-forward-auth/docs/img/cookie-options.png differ diff --git a/charts/incubator/traefik-forward-auth/docs/img/google-options.png b/charts/incubator/traefik-forward-auth/docs/img/google-options.png new file mode 100644 index 00000000000..9449505707c Binary files /dev/null and b/charts/incubator/traefik-forward-auth/docs/img/google-options.png differ diff --git a/charts/incubator/traefik-forward-auth/docs/img/ingress-middleware.png b/charts/incubator/traefik-forward-auth/docs/img/ingress-middleware.png new file mode 100644 index 00000000000..aa9c2d76c7c Binary files /dev/null and b/charts/incubator/traefik-forward-auth/docs/img/ingress-middleware.png differ diff --git a/charts/incubator/traefik-forward-auth/docs/img/traefik-forwarded-headers.png b/charts/incubator/traefik-forward-auth/docs/img/traefik-forwarded-headers.png new file mode 100644 index 00000000000..4a2d1f6ba08 Binary files /dev/null and b/charts/incubator/traefik-forward-auth/docs/img/traefik-forwarded-headers.png differ diff --git a/charts/incubator/traefik-forward-auth/docs/img/traefik-middleware.png b/charts/incubator/traefik-forward-auth/docs/img/traefik-middleware.png new file mode 100644 index 00000000000..1c1929bbbb8 Binary files /dev/null and b/charts/incubator/traefik-forward-auth/docs/img/traefik-middleware.png differ diff --git a/charts/incubator/traefik-forward-auth/icon.png b/charts/incubator/traefik-forward-auth/icon.png new file mode 100644 index 00000000000..dbde507c130 Binary files /dev/null and b/charts/incubator/traefik-forward-auth/icon.png differ diff --git a/charts/incubator/traefik-forward-auth/questions.yaml b/charts/incubator/traefik-forward-auth/questions.yaml new file mode 100644 index 00000000000..05eca2b935f --- /dev/null +++ b/charts/incubator/traefik-forward-auth/questions.yaml @@ -0,0 +1,409 @@ +# Include{groups} +questions: +# Include{global} +# Include{controller} +# Include{replicas} +# Include{replica1} +# Include{controllerExpertExtraArgs} +# Include{containerConfig} +# Include{controllerExpert} + - variable: tfaAppOptions + group: App Configuration + label: Application Options + schema: + type: dict + attrs: + - variable: secret + label: Secret + description: Mandatory, can be any string. + schema: + type: string + required: true + private: true + - variable: port + label: Port + schema: + type: int + default: 4181 + - variable: logLevel + label: Log level + schema: + type: string + default: warn + enum: + - value: trace + description: Trace (most detailed) + - value: debug + description: Debug + - value: info + description: Information + - value: warn + description: Warning + - value: error + description: Error + - value: fatal + description: Fatal + - value: panic + description: Panic (least detailed) + - variable: logFormat + label: Log format + schema: + type: string + default: text + enum: + - value: text + description: Text + - value: json + description: JSON + - value: pretty + description: Pretty + - variable: tfaAuthOptions + group: App Configuration + label: Auth Options + schema: + type: dict + attrs: + - variable: authHost + label: Auth host + description: Single host to use when returning from 3rd party auth. + schema: + type: string + - variable: urlPath + label: Callback URL Path + schema: + type: string + default: "/_oauth" + - variable: defaultAction + label: Default action + schema: + type: string + default: auth + enum: + - value: auth + description: Authenticate + - value: allow + description: Allow (do not require authentication) + - variable: defaultProvider + label: Default provider + schema: + type: string + default: google + enum: + - value: google + description: Google Provider + - value: oidc + description: OIDC Provider + - value: generic-oauth + description: Generic OAuth2 Provider + - variable: domain + label: Domains + description: Only allow given email domains. + schema: + type: list + default: [] + items: + - variable: allowedDomain + label: Host + schema: + type: string + required: true + - variable: whitelist + label: Whitelist + description: Only allow given email addresses. + schema: + type: list + default: [] + items: + - variable: allowedEmail + label: Host + schema: + type: string + required: true + - variable: rules + label: Rules + description: Additional rules in rule..= format. + schema: + type: list + default: [] + items: + - variable: rule + label: Rule + schema: + type: string + required: true + - variable: logoutRedirect + label: Logout redirect + description: URL to redirect to following logout. + schema: + type: string + - variable: tfaCookieOptions + group: App Configuration + label: Cookie Options + schema: + type: dict + attrs: + - variable: cookieDomain + label: Cookie domain hosts + schema: + type: list + default: [] + items: + - variable: cookieDomainHost + label: Host + schema: + type: string + required: true + - variable: cookieName + label: Cookie name + schema: + type: string + default: "_forward_auth" + - variable: csrfCookieName + label: CSRF cookie name + schema: + type: string + default: "_forward_auth_csrf" + - variable: lifetime + label: Lifetime + description: Lifetime in seconds. + schema: + type: int + default: 43200 + - variable: insecureCookie + label: Use insecure cookies + schema: + type: boolean + default: false + - variable: tfaGoogleOptions + group: App Configuration + label: Google Provider + schema: + type: dict + attrs: + - variable: clientId + label: Client ID + schema: + type: string + private: true + - variable: clientSecret + label: Client Secret + schema: + type: string + private: true + - variable: prompt + label: Prompt + description: Space separated list of OpenID prompt options. + schema: + type: string + - variable: tfaOidcOptions + group: App Configuration + label: OIDC Provider + schema: + type: dict + attrs: + - variable: issuerUrl + label: Issuer URL + schema: + type: string + - variable: clientId + label: Client ID + schema: + type: string + private: true + - variable: clientSecret + label: Client Secret + schema: + type: string + private: true + - variable: resource + label: Resource + description: Optional resource indicator. + schema: + type: string + - variable: tfaOauthOptions + group: App Configuration + label: Generic OAuth2 Provider + schema: + type: dict + attrs: + - variable: authUrl + label: Auth/Login URL + schema: + type: string + - variable: tokenUrl + label: Token URL + schema: + type: string + - variable: userUrl + label: User URL + description: URL used to retrieve user info. + schema: + type: string + - variable: clientId + label: Client ID + schema: + type: string + private: true + - variable: clientSecret + label: Client Secret + schema: + type: string + private: true + - variable: scopes + label: Scopes + schema: + type: string + default: profile, email + - variable: tokenStyle + label: Token style + description: How token is presented when querying the User URL + schema: + type: string + default: header + enum: + - value: header + description: Header + - value: query + description: Query + - variable: resource + label: Resource + description: Optional resource indicator. + schema: + type: string +# Include{fixedEnv} +# Include{containerConfig} +# Include{serviceRoot} + - variable: main + label: "Main Service" + description: "The Primary service on which the healthcheck runs, often the webUI" + schema: + type: dict + attrs: +# Include{serviceSelector} + - variable: main + label: "Main Service Port Configuration" + schema: + type: dict + attrs: + - variable: port + label: "Port" + description: "This port exposes the container port on the service" + schema: + type: int + default: 4181 + required: true + - variable: advanced + label: "Show Advanced settings" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: enabled + label: "Enable the port" + schema: + type: boolean + default: true + - variable: protocol + label: "Port Type" + schema: + type: string + default: "HTTP" + enum: + - value: HTTP + description: "HTTP" + - value: "HTTPS" + description: "HTTPS" + - value: TCP + description: "TCP" + - value: "UDP" + description: "UDP" + - variable: nodePort + label: "Node Port (Optional)" + description: "This port gets exposed to the node. Only considered when service type is NodePort, Simple or LoadBalancer" + schema: + type: int + min: 9000 + max: 65535 + - variable: targetPort + label: "Target Port" + description: "The internal(!) port on the container the Application runs on" + schema: + type: int + default: 4181 +# Include{serviceExpertRoot} + default: false +# Include{serviceExpert} +# Include{serviceList} +# Include{ingressRoot} + - variable: main + label: "Main Ingress" + schema: + type: dict + attrs: +# Include{ingressDefault} +# Include{ingressTLS} +# Include{ingressTraefik} +# Include{ingressExpert} +# Include{ingressList} + - variable: advancedSecurity + label: "Show Advanced Security Settings" + group: "Security and Permissions" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: securityContext + label: "Security Context" + schema: + type: dict + attrs: + - variable: privileged + label: "Privileged mode" + schema: + type: boolean + default: false + - variable: readOnlyRootFilesystem + label: "ReadOnly Root Filesystem" + schema: + type: boolean + default: true + - variable: allowPrivilegeEscalation + label: "Allow Privilege Escalation" + schema: + type: boolean + default: false + - variable: runAsNonRoot + label: "runAsNonRoot" + schema: + type: boolean + default: true +# Include{securityContextAdvanced} +# Include{podSecurityContextRoot} + - variable: runAsUser + label: "runAsUser" + description: "The UserID of the user running the application" + schema: + type: int + default: 568 + - variable: runAsGroup + label: "runAsGroup" + description: "The groupID this App of the user running the application" + schema: + type: int + default: 568 + - variable: fsGroup + label: "fsGroup" + description: "The group that should own ALL storage." + schema: + type: int + default: 568 +# Include{podSecurityContextAdvanced} +# Include{resources} +# Include{advanced} +# Include{addons} +# Include{codeserver} +# Include{promtail} +# Include{netshoot} +# Include{vpn} diff --git a/charts/incubator/traefik-forward-auth/templates/_args.tpl b/charts/incubator/traefik-forward-auth/templates/_args.tpl new file mode 100644 index 00000000000..e75a8fd6f60 --- /dev/null +++ b/charts/incubator/traefik-forward-auth/templates/_args.tpl @@ -0,0 +1,34 @@ +{{- define "tfa.args" -}} +args: + - --log-level={{ .Values.tfaAppOptions.logLevel }} + - --log-format={{ .Values.tfaAppOptions.logFormat }} + {{- if .Values.tfaAuthOptions.authHost }} + - --auth-host={{ .Values.tfaAuthOptions.authHost }} + {{- end }} + {{- range .Values.tfaCookieOptions.cookieDomain }} + - --cookie-domain={{ . }} + {{- end }} + {{- if .Values.tfaCookieOptions.insecureCookie }} + - --insecure-cookie + {{- end }} + - --cookie-name={{ .Values.tfaCookieOptions.cookieName }} + - --csrf-cookie-name={{ .Values.tfaCookieOptions.csrfCookieName }} + - --default-action={{ .Values.tfaAuthOptions.defaultAction }} + - --default-provider={{ .Values.tfaAuthOptions.defaultProvider }} + {{- range .Values.tfaAuthOptions.domain }} + - --domain={{ . }} + {{- end }} + - --lifetime={{ .Values.tfaCookieOptions.lifetime }} + {{- if .Values.tfaAuthOptions.logoutRedirect }} + - --logout-redirect={{ .Values.tfaAuthOptions.logoutRedirect }} + {{- end }} + - --url-path={{ .Values.tfaAuthOptions.urlPath }} + - --secret={{ .Values.tfaAppOptions.secret }} + {{- range .Values.tfaAuthOptions.whitelist }} + - --whitelist={{ . }} + {{- end }} + - --port={{ .Values.tfaAppOptions.port }} + {{- range .Values.tfaAuthOptions.rules }} + - --{{ . }} + {{- end }} +{{- end -}} diff --git a/charts/incubator/traefik-forward-auth/templates/_secret.tpl b/charts/incubator/traefik-forward-auth/templates/_secret.tpl new file mode 100644 index 00000000000..d950139c6d8 --- /dev/null +++ b/charts/incubator/traefik-forward-auth/templates/_secret.tpl @@ -0,0 +1,57 @@ +{{/* Define the secret */}} +{{- define "tfa.secret" -}} + +{{- $googleSecretName := printf "%s-google-secret" (include "tc.common.names.fullname" .) }} +{{- $oidcSecretName := printf "%s-oidc-secret" (include "tc.common.names.fullname" .) }} +{{- $oauthSecretName := printf "%s-oauth2-secret" (include "tc.common.names.fullname" .) }} + +--- + +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ $googleSecretName }} + labels: + {{- include "tc.common.labels" . | nindent 4 }} +data: + PROVIDERS_GOOGLE_CLIENT_ID: {{ .Values.tfaGoogleOptions.clientId | trimAll "\"" | b64enc }} + PROVIDERS_GOOGLE_CLIENT_SECRET: {{ .Values.tfaGoogleOptions.clientSecret | trimAll "\"" | b64enc }} + PROVIDERS_GOOGLE_PROMPT: {{ .Values.tfaGoogleOptions.prompt | trimAll "\"" | b64enc }} + +--- + +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ $oidcSecretName }} + labels: + {{- include "tc.common.labels" . | nindent 4 }} +data: + PROVIDERS_OIDC_ISSUER_URL: {{ .Values.tfaOidcOptions.issuerUrl | trimAll "\"" | b64enc }} + PROVIDERS_OIDC_CLIENT_ID: {{ .Values.tfaOidcOptions.clientId | trimAll "\"" | b64enc }} + PROVIDERS_OIDC_CLIENT_SECRET: {{ .Values.tfaOidcOptions.clientSecret | trimAll "\"" | b64enc }} + PROVIDERS_OIDC_RESOURCE: {{ .Values.tfaOidcOptions.resource | trimAll "\"" | b64enc }} + +--- + +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ $oauthSecretName }} + labels: + {{- include "tc.common.labels" . | nindent 4 }} +data: + PROVIDERS_GENERIC_OAUTH_AUTH_URL: {{ .Values.tfaOauthOptions.authUrl | trimAll "\"" | b64enc }} + PROVIDERS_GENERIC_OAUTH_TOKEN_URL: {{ .Values.tfaOauthOptions.tokenUrl | trimAll "\"" | b64enc }} + PROVIDERS_GENERIC_OAUTH_USER_URL: {{ .Values.tfaOauthOptions.userUrl | trimAll "\"" | b64enc }} + PROVIDERS_GENERIC_OAUTH_CLIENT_ID: {{ .Values.tfaOauthOptions.clientId | trimAll "\"" | b64enc }} + PROVIDERS_GENERIC_OAUTH_CLIENT_SECRET: {{ .Values.tfaOauthOptions.clientSecret | trimAll "\"" | b64enc }} + PROVIDERS_GENERIC_OAUTH_TOKEN_STYLE: {{ .Values.tfaOauthOptions.tokenStyle | trimAll "\"" | b64enc }} + PROVIDERS_GENERIC_OAUTH_RESOURCE: {{ .Values.tfaOauthOptions.resource | trimAll "\"" | b64enc }} + +--- + +{{- end }} diff --git a/charts/incubator/traefik-forward-auth/templates/common.yaml b/charts/incubator/traefik-forward-auth/templates/common.yaml new file mode 100644 index 00000000000..dd59166b203 --- /dev/null +++ b/charts/incubator/traefik-forward-auth/templates/common.yaml @@ -0,0 +1,13 @@ +{{/* Make sure all variables are set properly */}} +{{- include "tc.common.loader.init" . }} + +{{/* Render secret */}} +{{- include "tfa.secret" . }} + +{{- $tplArgs := (include "tfa.args" . | fromYaml) }} +{{- $_ := set .Values "tplArgs" $tplArgs -}} +{{- $args := concat .Values.args .Values.tplArgs.args }} +{{- $_ := set .Values "args" $args -}} + +{{/* Render the templates */}} +{{ include "tc.common.loader.apply" . }} diff --git a/charts/incubator/traefik-forward-auth/values.yaml b/charts/incubator/traefik-forward-auth/values.yaml new file mode 100644 index 00000000000..498d6dd70e9 --- /dev/null +++ b/charts/incubator/traefik-forward-auth/values.yaml @@ -0,0 +1,62 @@ +image: + repository: tccr.io/truecharts/traefik-forward-auth + pullPolicy: IfNotPresent + tag: latest@sha256:edd7eb812cb38e59d32b5a00398b57a78506db2390cbe295f5df590a38a5d44e + +envFrom: + - secretRef: + name: '{{ include "tc.common.names.fullname" . }}-google-secret' + - secretRef: + name: '{{ include "tc.common.names.fullname" . }}-oidc-secret' + - secretRef: + name: '{{ include "tc.common.names.fullname" . }}-oauth2-secret' + +service: + main: + ports: + main: + targetPort: 4181 + port: 4181 + +tfaAppOptions: + secret: something-random + port: 4181 + logLevel: warn + logFormat: text + +tfaAuthOptions: + authHost: + urlPath: /_oauth + defaultAction: auth + defaultProvider: google + domain: [] + whitelist: [] + rules: [] + +tfaCookieOptions: + cookieDomain: [] + cookieName: _forward_auth + csrfCookieName: _forward_auth_csrf + lifetime: 43200 + insecureCookie: false + +tfaGoogleOptions: + clientId: "changeme" + clientSecret: "changeme" + prompt: "changeme" + +tfaOidcOptions: + issuerUrl: "changeme" + clientId: "changeme" + clientSecret: "changeme" + resource: "changeme" + +tfaOauthOptions: + authUrl: "changeme" + tokenUrl: "changeme" + userUrl: "changeme" + clientId: "changeme" + clientSecret: "changeme" + scopes: "changeme" + tokenStyle: header + resource: "changeme"