Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,18 @@ jobs:
fi
done

- name: Pre-upgrade ingress migration
run: |
# team-devoops-plain previously contained the /auth (Keycloak) path.
# It has been moved to team-devoops-open. Delete the old ingress so
# the nginx admission webhook does not reject the new one for duplicate paths.
kubectl -n "$NAMESPACE" delete ingress team-devoops-plain --ignore-not-found

- name: Helm upgrade
run: |
helm upgrade --install team-devoops infra/helm/team-devoops \
--namespace "$NAMESPACE" \
--set global.image.tag=${{ github.sha }} \
--set keycloak.hostname=https://ge83mom-devops26.stud.k8s.aet.cit.tum.de/auth \
--set forwardAuth.cookieSecret="${{ secrets.FORWARD_AUTH_COOKIE_SECRET }}" \
--rollback-on-failure --timeout 15m
2 changes: 2 additions & 0 deletions infra/helm/team-devoops/files/realm-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,12 @@
"directAccessGrantsEnabled": false,
"redirectUris": [
"https://team-devoops.uaenorth.cloudapp.azure.com/_oauth",
"https://ge83mom-devops26.stud.k8s.aet.cit.tum.de/oauth2/callback",
"http://localhost/_oauth"
],
"webOrigins": [
"https://team-devoops.uaenorth.cloudapp.azure.com",
"https://ge83mom-devops26.stud.k8s.aet.cit.tum.de",
"http://localhost"
]
}
Expand Down
81 changes: 81 additions & 0 deletions infra/helm/team-devoops/templates/forward-auth.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{{- if .Values.forwardAuth.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: oauth2-proxy
labels:
{{- include "team-devoops.labels" (dict "name" "oauth2-proxy" "root" $) | nindent 4 }}
spec:
replicas: 1
strategy:
type: RollingUpdate
selector:
matchLabels:
{{- include "team-devoops.selectorLabels" (dict "name" "oauth2-proxy") | nindent 6 }}
template:
metadata:
labels:
{{- include "team-devoops.selectorLabels" (dict "name" "oauth2-proxy") | nindent 8 }}
spec:
{{- with .Values.global.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: oauth2-proxy
image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 4180
env:
- name: OAUTH2_PROXY_PROVIDER
value: oidc
- name: OAUTH2_PROXY_OIDC_ISSUER_URL
value: {{ .Values.forwardAuth.oidcIssuerUrl | quote }}
- name: OAUTH2_PROXY_CLIENT_ID
value: {{ .Values.forwardAuth.clientId | quote }}
- name: OAUTH2_PROXY_CLIENT_SECRET
value: {{ .Values.forwardAuth.clientSecret | quote }}
- name: OAUTH2_PROXY_COOKIE_SECRET
value: {{ .Values.forwardAuth.cookieSecret | quote }}
- name: OAUTH2_PROXY_EMAIL_DOMAINS
value: "*"
- name: OAUTH2_PROXY_UPSTREAM
value: "static://202"
- name: OAUTH2_PROXY_HTTP_ADDRESS
value: "0.0.0.0:4180"
- name: OAUTH2_PROXY_REDIRECT_URL
value: {{ printf "https://%s/oauth2/callback" .Values.ingress.host | quote }}
- name: OAUTH2_PROXY_COOKIE_SECURE
value: "true"
- name: OAUTH2_PROXY_SKIP_PROVIDER_BUTTON
value: "true"
- name: OAUTH2_PROXY_INSECURE_OIDC_ALLOW_UNVERIFIED_EMAIL
value: "true"
- name: OAUTH2_PROXY_OIDC_EMAIL_CLAIM
value: "sub"
- name: OAUTH2_PROXY_COOKIE_CSRF_PER_REQUEST
value: "true"
- name: OAUTH2_PROXY_COOKIE_CSRF_EXPIRE
value: "5m"
resources:
requests:
cpu: 10m
memory: 16Mi
limits:
cpu: 50m
memory: 32Mi
---
apiVersion: v1
kind: Service
metadata:
name: oauth2-proxy
labels:
{{- include "team-devoops.labels" (dict "name" "oauth2-proxy" "root" $) | nindent 4 }}
spec:
selector:
{{- include "team-devoops.selectorLabels" (dict "name" "oauth2-proxy") | nindent 4 }}
ports:
- port: 80
targetPort: 4180
{{- end }}
66 changes: 63 additions & 3 deletions infra/helm/team-devoops/templates/ingress.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
{{- if .Values.ingress.enabled }}
{{- $host := .Values.ingress.host }}
{{- $tls := .Values.ingress.tls }}
{{- $fa := .Values.forwardAuth }}
# ---------------------------------------------------------------------------
# Stripped ingress: services whose path prefix must be removed before the
# request reaches the backend (Traefik stripPrefix parity). Uses a regex
# capture group so `/api/v1/members/foo` -> `/foo`.
# Auth-protected when forwardAuth is enabled.
# ---------------------------------------------------------------------------
apiVersion: networking.k8s.io/v1
kind: Ingress
Expand All @@ -18,6 +20,10 @@ metadata:
{{- if and $tls.enabled $tls.clusterIssuer }}
cert-manager.io/cluster-issuer: {{ $tls.clusterIssuer | quote }}
{{- end }}
{{- if $fa.enabled }}
nginx.ingress.kubernetes.io/auth-url: "http://oauth2-proxy.{{ $.Release.Namespace }}.svc.cluster.local/oauth2/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://{{ $host }}/oauth2/start?rd=$escaped_request_uri"
{{- end }}
spec:
ingressClassName: {{ .Values.ingress.className }}
{{- if $tls.enabled }}
Expand Down Expand Up @@ -46,17 +52,22 @@ spec:
---
# ---------------------------------------------------------------------------
# Plain ingress: services served at their path as-is (web-client, api-docs).
# Auth-protected when forwardAuth is enabled.
# ---------------------------------------------------------------------------
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: team-devoops-plain
labels:
{{- include "team-devoops.labels" (dict "name" "ingress-plain" "root" $) | nindent 4 }}
{{- if and $tls.enabled $tls.clusterIssuer }}
annotations:
{{- if and $tls.enabled $tls.clusterIssuer }}
cert-manager.io/cluster-issuer: {{ $tls.clusterIssuer | quote }}
{{- end }}
{{- end }}
{{- if $fa.enabled }}
nginx.ingress.kubernetes.io/auth-url: "http://oauth2-proxy.{{ $.Release.Namespace }}.svc.cluster.local/oauth2/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://{{ $host }}/oauth2/start?rd=$escaped_request_uri"
{{- end }}
spec:
ingressClassName: {{ .Values.ingress.className }}
{{- if $tls.enabled }}
Expand All @@ -72,7 +83,7 @@ spec:
http:
paths:
{{- range $name, $svc := .Values.services }}
{{- if not $svc.stripPrefix }}
{{- if and (not $svc.stripPrefix) (not $svc.open) }}
- path: {{ $svc.path }}
pathType: Prefix
backend:
Expand All @@ -82,6 +93,35 @@ spec:
number: {{ $svc.port }}
{{- end }}
{{- end }}
---
# ---------------------------------------------------------------------------
# Open ingress: Keycloak (auth provider) and the forward-auth OAuth callback
# must never be behind forward-auth to avoid redirect loops.
# ---------------------------------------------------------------------------
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: team-devoops-open
labels:
{{- include "team-devoops.labels" (dict "name" "ingress-open" "root" $) | nindent 4 }}
{{- if and $tls.enabled $tls.clusterIssuer }}
annotations:
cert-manager.io/cluster-issuer: {{ $tls.clusterIssuer | quote }}
{{- end }}
spec:
ingressClassName: {{ .Values.ingress.className }}
{{- if $tls.enabled }}
tls:
- hosts:
- {{ $host | quote }}
{{- if $tls.secretName }}
secretName: {{ $tls.secretName }}
{{- end }}
{{- end }}
rules:
- host: {{ $host | quote }}
http:
paths:
{{- if .Values.keycloak.enabled }}
- path: {{ .Values.keycloak.path }}
pathType: Prefix
Expand All @@ -91,4 +131,24 @@ spec:
port:
number: 8080
{{- end }}
{{- if $fa.enabled }}
- path: /oauth2/
pathType: Prefix
backend:
service:
name: oauth2-proxy
port:
number: 80
{{- end }}
{{- range $name, $svc := .Values.services }}
{{- if $svc.open }}
- path: {{ $svc.path }}
pathType: Prefix
backend:
service:
name: {{ $name }}
port:
number: {{ $svc.port }}
{{- end }}
{{- end }}
{{- end }}
16 changes: 16 additions & 0 deletions infra/helm/team-devoops/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,21 @@ ingress:
# Adds the cert-manager.io/cluster-issuer annotation on the ingresses.
clusterIssuer: letsencrypt-prod

# ---------------------------------------------------------------------------
# Forward-auth: deploys oauth2-proxy as an OIDC session proxy and wires all
# nginx ingresses through it via auth_request. Keycloak and /oauth2/ are
# excluded from auth to prevent redirect loops.
# ---------------------------------------------------------------------------
forwardAuth:
enabled: true
oidcIssuerUrl: "https://ge83mom-devops26.stud.k8s.aet.cit.tum.de/auth/realms/devops"
clientId: "traefik-forward-auth"
clientSecret: "traefik-forward-auth-secret"
# 32+ character random string used to sign session cookies.
# Override at deploy time: --set forwardAuth.cookieSecret="$FORWARD_AUTH_COOKIE_SECRET"
# Generate with: openssl rand -base64 32
cookieSecret: ""

# Rolling update strategy — maxSurge: 0 ensures the old pod is terminated before
# scheduling the new one, which is required to stay within the namespace CPU quota.
strategy:
Expand Down Expand Up @@ -216,6 +231,7 @@ services:
port: 8080
db: false
stripPrefix: false
open: true
resources:
requests:
cpu: 50m
Expand Down
2 changes: 2 additions & 0 deletions infra/keycloak/realm-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,12 @@
"directAccessGrantsEnabled": false,
"redirectUris": [
"https://team-devoops.uaenorth.cloudapp.azure.com/_oauth",
"https://ge83mom-devops26.stud.k8s.aet.cit.tum.de/oauth2/callback",
"http://localhost/_oauth"
],
"webOrigins": [
"https://team-devoops.uaenorth.cloudapp.azure.com",
"https://ge83mom-devops26.stud.k8s.aet.cit.tum.de",
"http://localhost"
]
}
Expand Down
Loading