From 53dc9d9f405e5181669ff212b044c9968b577634 Mon Sep 17 00:00:00 2001 From: Trong Huu Nguyen Date: Wed, 21 May 2025 10:37:49 +0200 Subject: [PATCH] charts: add wonderwall-forward-auth Co-Authored-By: Thomas Siegfried Krampl --- .github/workflows/deploy.yml | 52 ++++++++--- .gitignore | 1 + charts/wonderwall-forward-auth/.helmignore | 23 +++++ charts/wonderwall-forward-auth/Chart.lock | 6 ++ charts/wonderwall-forward-auth/Chart.yaml | 9 ++ charts/wonderwall-forward-auth/Feature.yaml | 35 ++++++++ .../templates/_helpers.tpl | 62 +++++++++++++ .../templates/deployment.yaml | 89 +++++++++++++++++++ .../templates/horizontalpodautoscaler.yaml | 21 +++++ .../templates/ingress.yaml | 23 +++++ .../templates/networkpolicy.yaml | 21 +++++ .../templates/poddisruptionbudget.yaml | 12 +++ .../templates/secret.yaml | 32 +++++++ .../templates/service.yaml | 16 ++++ charts/wonderwall-forward-auth/values.yaml | 47 ++++++++++ 15 files changed, 438 insertions(+), 11 deletions(-) create mode 100644 charts/wonderwall-forward-auth/.helmignore create mode 100644 charts/wonderwall-forward-auth/Chart.lock create mode 100644 charts/wonderwall-forward-auth/Chart.yaml create mode 100644 charts/wonderwall-forward-auth/Feature.yaml create mode 100644 charts/wonderwall-forward-auth/templates/_helpers.tpl create mode 100644 charts/wonderwall-forward-auth/templates/deployment.yaml create mode 100644 charts/wonderwall-forward-auth/templates/horizontalpodautoscaler.yaml create mode 100644 charts/wonderwall-forward-auth/templates/ingress.yaml create mode 100644 charts/wonderwall-forward-auth/templates/networkpolicy.yaml create mode 100644 charts/wonderwall-forward-auth/templates/poddisruptionbudget.yaml create mode 100644 charts/wonderwall-forward-auth/templates/secret.yaml create mode 100644 charts/wonderwall-forward-auth/templates/service.yaml create mode 100644 charts/wonderwall-forward-auth/values.yaml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 896f0b9..376d840 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -33,7 +33,7 @@ jobs: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 - name: Install cosign - uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # ratchet:sigstore/cosign-installer@main + uses: sigstore/cosign-installer@e9a05e6d32d7ed22b5656cd874ef31af58d05bfa # ratchet:sigstore/cosign-installer@main with: cosign-release: 'v2.2.3' - name: Verify runner image @@ -48,6 +48,36 @@ jobs: push: true push_ghcr: true workload_identity_provider: ${{ secrets.NAIS_IO_WORKLOAD_IDENTITY_PROVIDER }} + outputs: + version: ${{ steps.build_push_sign.outputs.version }} + charts: + needs: build + name: Build and push chart + if: github.ref == 'refs/heads/master' + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + strategy: + fail-fast: false + matrix: + chart: ["wonderwall", "wonderwall-forward-auth"] + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 + - id: "auth" + name: "Authenticate to Google Cloud" + uses: "google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f" # ratchet:google-github-actions/auth@v2 + with: + workload_identity_provider: ${{ secrets.NAIS_IO_WORKLOAD_IDENTITY_PROVIDER }} + service_account: "gh-wonderwall@nais-io.iam.gserviceaccount.com" + token_format: "access_token" + - name: "Login to registry" + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # ratchet:docker/login-action@v3 + with: + registry: "${{ env.GOOGLE_REGISTRY }}/nais-io/nais/feature" + username: "oauth2accesstoken" + password: "${{ steps.auth.outputs.access_token }}" - uses: azure/setup-helm@b9e51907a09c216f16ebe8536097933489208112 # ratchet:azure/setup-helm@v4 name: 'Setup Helm' with: @@ -55,16 +85,16 @@ jobs: - name: Package chart id: package_chart env: - CHART_PATH: ./charts/wonderwall + CHART_PATH: ./charts/${{ matrix.chart }} run: | - base_version="$(yq '.version' < "${{ env.CHART_PATH }}/Chart.yaml")" - chart_version="${base_version}-${{ steps.build_push_sign.outputs.version }}" + base_version="1.0.0" + chart_version="${base_version}-${{ needs.build.outputs.version }}" yq eval \ '.version="'"$chart_version"'"' \ "${{ env.CHART_PATH }}/Chart.yaml" --inplace yq eval \ - '.image.tag="${{ steps.build_push_sign.outputs.version }}"' \ + '.image.tag="${{ needs.build.outputs.version }}"' \ "${{ env.CHART_PATH }}/values.yaml" --inplace # helm dependency update "${{ env.CHART_PATH }}" @@ -79,10 +109,6 @@ jobs: chart="${{ steps.package_chart.outputs.archive }}" echo "Pushing: $chart" helm push "$chart" oci://${{ env.GOOGLE_REGISTRY }}/nais-io/nais/feature - outputs: - chart_name: ${{ steps.package_chart.outputs.name }} - chart_version: ${{ steps.package_chart.outputs.version }} - chart_archive: ${{ steps.package_chart.outputs.archive }} rollout: name: Rollout if: github.actor != 'dependabot[bot]' && github.ref == 'refs/heads/master' @@ -90,8 +116,12 @@ jobs: runs-on: fasit-deploy permissions: id-token: write + strategy: + fail-fast: false + matrix: + chart: ["wonderwall", "wonderwall-forward-auth"] steps: - uses: nais/fasit-deploy@v2 # ratchet:exclude with: - chart: oci://${{ env.GOOGLE_REGISTRY }}/nais-io/nais/feature/${{ needs.build.outputs.chart_name }} - version: ${{ needs.build.outputs.chart_version }} + chart: oci://${{ env.GOOGLE_REGISTRY }}/nais-io/nais/feature/${{ matrix.chart }} + version: "1.0.0-${{ needs.build.outputs.chart_version }}" diff --git a/.gitignore b/.gitignore index 9904f6e..6acb365 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ run.sh *.iml .env* *.out +*.tgz # nix stuffs /.direnv diff --git a/charts/wonderwall-forward-auth/.helmignore b/charts/wonderwall-forward-auth/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/wonderwall-forward-auth/.helmignore @@ -0,0 +1,23 @@ +# 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 +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/wonderwall-forward-auth/Chart.lock b/charts/wonderwall-forward-auth/Chart.lock new file mode 100644 index 0000000..b1dded2 --- /dev/null +++ b/charts/wonderwall-forward-auth/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: valkey + repository: https://charts.bitnami.com/bitnami + version: 3.0.7 +digest: sha256:d6621585cb66ddc9802c7a6303b20a33a5970aeaaaf57ee9b45d1cbd9f7a7b27 +generated: "2025-05-20T14:28:10.651543+02:00" diff --git a/charts/wonderwall-forward-auth/Chart.yaml b/charts/wonderwall-forward-auth/Chart.yaml new file mode 100644 index 0000000..174b192 --- /dev/null +++ b/charts/wonderwall-forward-auth/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +name: wonderwall-forward-auth +description: Forward-auth service for loadbalancer-fa +type: application +version: 1.0.0 +dependencies: + - name: valkey + version: 3.0.7 + repository: https://charts.bitnami.com/bitnami diff --git a/charts/wonderwall-forward-auth/Feature.yaml b/charts/wonderwall-forward-auth/Feature.yaml new file mode 100644 index 0000000..2a6c391 --- /dev/null +++ b/charts/wonderwall-forward-auth/Feature.yaml @@ -0,0 +1,35 @@ +environmentKinds: + - management +timeout: "1800s" +values: + openid.clientID: + required: true + computed: + template: | + {{ .Env.wonderwall_forward_auth_zitadel_client_id | quote }} + openid.clientSecret: + required: true + computed: + template: | + {{ .Env.wonderwall_forward_auth_zitadel_client_secret | quote }} + replicas.min: + config: + type: int + replicas.max: + config: + type: int + session.cookieEncryptionKey: + description: Cookie encryption key, 256 bits (e.g. 32 ASCII characters) encoded with standard base64. + computed: + template: | + {{ .Env.wonderwall_forward_auth_encryption_key | quote }} + sso.domain: + description: Domain for forward auth + computed: + template: | + {{ .Tenant.Name }}.cloud.nais.io + sso.defaultRedirectURL: + description: Default redirect URL for forward auth + computed: + template: | + {{ subdomain . "console" | quote }} diff --git a/charts/wonderwall-forward-auth/templates/_helpers.tpl b/charts/wonderwall-forward-auth/templates/_helpers.tpl new file mode 100644 index 0000000..b8614ad --- /dev/null +++ b/charts/wonderwall-forward-auth/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "wonderwall-forward-auth.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "wonderwall-forward-auth.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "wonderwall-forward-auth.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "wonderwall-forward-auth.labels" -}} +helm.sh/chart: {{ include "wonderwall-forward-auth.chart" . }} +{{ include "wonderwall-forward-auth.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "wonderwall-forward-auth.selectorLabels" -}} +app.kubernetes.io/name: {{ include "wonderwall-forward-auth.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "wonderwall-forward-auth.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "wonderwall-forward-auth.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/wonderwall-forward-auth/templates/deployment.yaml b/charts/wonderwall-forward-auth/templates/deployment.yaml new file mode 100644 index 0000000..c021ac4 --- /dev/null +++ b/charts/wonderwall-forward-auth/templates/deployment.yaml @@ -0,0 +1,89 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + reloader.stakater.com/search: "true" + labels: + {{- include "wonderwall-forward-auth.labels" . | nindent 4 }} + name: {{ include "wonderwall-forward-auth.fullname" . }} +spec: + replicas: 2 + selector: + matchLabels: + {{- include "wonderwall-forward-auth.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: {{ include "wonderwall-forward-auth.fullname" . }} + labels: + {{- include "wonderwall-forward-auth.labels" . | nindent 8 }} + {{ printf "%s-client" .Values.valkey.fullnameOverride }}: "true" + name: {{ include "wonderwall-forward-auth.fullname" . }} + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: "app.kubernetes.io/name" + operator: In + values: + - "{{ include "wonderwall-forward-auth.fullname" . }}" + topologyKey: kubernetes.io/hostname + weight: 10 + containers: + - env: + - name: WONDERWALL_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.valkey.fullnameOverride }} + key: "valkey-password" + envFrom: + - secretRef: + name: {{ include "wonderwall-forward-auth.fullname" . }} + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /oauth2/ping + port: http + name: {{ include "wonderwall-forward-auth.fullname" . }} + ports: + - containerPort: 8080 + name: http + protocol: TCP + readinessProbe: + httpGet: + path: /oauth2/ping + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsGroup: 1069 + runAsNonRoot: true + runAsUser: 1069 + seccompProfile: + type: RuntimeDefault + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /tmp + name: writable-tmp + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: + seccompProfile: + type: RuntimeDefault + terminationGracePeriodSeconds: 30 + volumes: + - emptyDir: {} + name: writable-tmp diff --git a/charts/wonderwall-forward-auth/templates/horizontalpodautoscaler.yaml b/charts/wonderwall-forward-auth/templates/horizontalpodautoscaler.yaml new file mode 100644 index 0000000..2340b83 --- /dev/null +++ b/charts/wonderwall-forward-auth/templates/horizontalpodautoscaler.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + labels: + {{- include "wonderwall-forward-auth.labels" . | nindent 4 }} + name: {{ include "wonderwall-forward-auth.fullname" . }} +spec: + minReplicas: {{ .Values.replicas.min }} + maxReplicas: {{ .Values.replicas.max }} + metrics: + - resource: + name: cpu + target: + averageUtilization: 75 + type: Utilization + type: Resource + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "wonderwall-forward-auth.fullname" . }} diff --git a/charts/wonderwall-forward-auth/templates/ingress.yaml b/charts/wonderwall-forward-auth/templates/ingress.yaml new file mode 100644 index 0000000..d21e4ee --- /dev/null +++ b/charts/wonderwall-forward-auth/templates/ingress.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/proxy-buffer-size: 16k + nginx.ingress.kubernetes.io/enable-global-auth: "false" + labels: + {{- include "wonderwall-forward-auth.labels" . | nindent 4 }} + name: {{ include "wonderwall-forward-auth.fullname" . }} +spec: + ingressClassName: {{ .Values.ingressClassName }} + rules: + - host: {{ .Values.sso.domain }} + http: + paths: + - backend: + service: + name: {{ include "wonderwall-forward-auth.fullname" . }} + port: + number: 80 + path: / + pathType: ImplementationSpecific diff --git a/charts/wonderwall-forward-auth/templates/networkpolicy.yaml b/charts/wonderwall-forward-auth/templates/networkpolicy.yaml new file mode 100644 index 0000000..8930269 --- /dev/null +++ b/charts/wonderwall-forward-auth/templates/networkpolicy.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + labels: + {{- include "wonderwall-forward-auth.labels" . | nindent 4 }} + name: {{ include "wonderwall-forward-auth.fullname" . }} +spec: + ingress: + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: nais-system + podSelector: + matchLabels: + nais.io/ingressClass: {{ .Values.ingressClassName }} + podSelector: + matchLabels: + {{- include "wonderwall-forward-auth.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress diff --git a/charts/wonderwall-forward-auth/templates/poddisruptionbudget.yaml b/charts/wonderwall-forward-auth/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..0d49aa9 --- /dev/null +++ b/charts/wonderwall-forward-auth/templates/poddisruptionbudget.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + labels: + {{- include "wonderwall-forward-auth.labels" . | nindent 4 }} + name: {{ include "wonderwall-forward-auth.fullname" . }} +spec: + {{- toYaml .Values.podDisruptionBudget | nindent 2 }} + selector: + matchLabels: + {{- include "wonderwall-forward-auth.selectorLabels" . | nindent 6 }} diff --git a/charts/wonderwall-forward-auth/templates/secret.yaml b/charts/wonderwall-forward-auth/templates/secret.yaml new file mode 100644 index 0000000..b2396fe --- /dev/null +++ b/charts/wonderwall-forward-auth/templates/secret.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: v1 +kind: Secret +type: kubernetes.io/Opaque +metadata: + name: {{ include "wonderwall-forward-auth.fullname" . }} + annotations: + reloader.stakater.com/match: "true" + labels: + {{- include "wonderwall-forward-auth.labels" . | nindent 4 }} +stringData: + WONDERWALL_BIND_ADDRESS: "0.0.0.0:8080" + WONDERWALL_COOKIE_SAME_SITE: "None" + WONDERWALL_METRICS_BIND_ADDRESS: "0.0.0.0:8081" + WONDERWALL_INGRESS: "https://{{ .Values.sso.domain }}" + WONDERWALL_SHUTDOWN_WAIT_BEFORE_PERIOD: "5s" + WONDERWALL_OPENID_PROVIDER: "openid" + WONDERWALL_OPENID_CLIENT_ID: "{{ .Values.openid.clientID | required ".Values.openid.clientID is required." }}" + WONDERWALL_OPENID_CLIENT_SECRET: "{{ .Values.openid.clientSecret | required ".Values.openid.clientSecret is required." }}" + WONDERWALL_OPENID_WELL_KNOWN_URL: "{{ .Values.openid.wellKnownURL | required ".Values.openid.wellKnownURL is required." }}" + WONDERWALL_ENCRYPTION_KEY: "{{ .Values.session.cookieEncryptionKey | required ".Values.session.cookieEncryptionKey is required." }}" + WONDERWALL_REDIS_URI: "redis://{{ .Values.valkey.fullnameOverride }}-primary:6379" + WONDERWALL_REDIS_USERNAME: "default" + WONDERWALL_SESSION_MAX_LIFETIME: "{{ .Values.session.maxLifetime | required ".Values.session.maxLifetime is required." }}" + WONDERWALL_SESSION_FORWARD_AUTH: "true" + WONDERWALL_SESSION_INACTIVITY: "{{ .Values.session.inactivity | required ".Values.session.inactivity is required." }}" + WONDERWALL_SESSION_INACTIVITY_TIMEOUT: "{{ .Values.session.inactivityTimeout | required ".Values.session.inactivityTimeout is required." }}" + WONDERWALL_SSO_DOMAIN: "{{ .Values.sso.domain | required ".Values.sso.domain is required." }}" + WONDERWALL_SSO_ENABLED: "true" + WONDERWALL_SSO_MODE: "server" + WONDERWALL_SSO_SESSION_COOKIE_NAME: "{{ .Values.session.cookieName | required ".Values.session.cookieName is required." }}" + WONDERWALL_SSO_SERVER_DEFAULT_REDIRECT_URL: "{{ .Values.sso.defaultRedirectURL | required ".Values.sso.defaultRedirectURL is required." }}" diff --git a/charts/wonderwall-forward-auth/templates/service.yaml b/charts/wonderwall-forward-auth/templates/service.yaml new file mode 100644 index 0000000..67630ac --- /dev/null +++ b/charts/wonderwall-forward-auth/templates/service.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: v1 +kind: Service +metadata: + labels: + {{- include "wonderwall-forward-auth.labels" . | nindent 4 }} + name: {{ include "wonderwall-forward-auth.fullname" . }} +spec: + type: ClusterIP + ports: + - name: http + port: 80 + protocol: TCP + targetPort: http + selector: + {{- include "wonderwall-forward-auth.selectorLabels" . | nindent 4 }} diff --git a/charts/wonderwall-forward-auth/values.yaml b/charts/wonderwall-forward-auth/values.yaml new file mode 100644 index 0000000..cc0e62d --- /dev/null +++ b/charts/wonderwall-forward-auth/values.yaml @@ -0,0 +1,47 @@ +nameOverride: "" +fullnameOverride: "" + +image: + repository: europe-north1-docker.pkg.dev/nais-io/nais/images/wonderwall + tag: latest + +resources: + limits: + cpu: "2" + memory: 512Mi + requests: + cpu: 100m + memory: 64Mi +replicas: + min: 2 + max: 4 +podDisruptionBudget: + maxUnavailable: 1 +ingressClassName: nais-ingress-fa + +openid: + clientID: + clientSecret: + wellKnownURL: https://auth.nais.io/.well-known/openid-configuration +session: + maxLifetime: 10h + # 256 bits key, in standard base64 encoding + cookieEncryptionKey: + cookieName: nais-io-forward-auth + inactivity: true + inactivityTimeout: 1h +sso: + defaultRedirectURL: + domain: + +valkey: + fullnameOverride: "wonderwall-forward-auth-valkey" + architecture: "standalone" + primary: + resourcesPreset: "medium" + persistence: + enabled: false + networkPolicy: + enabled: true + allowExternal: false + allowExternalEgress: false