# Experiment B-7 — oauth2-proxy, to measure how replicas share a cookie secret # and what happens when it is rotated (Q1, unknown 7). # # This is a different shape of problem from the BFF. The BFF keeps state on the # server, so the question was "which store". oauth2-proxy keeps no server state # at all: the whole session rides in a cookie that is signed and encrypted with # --cookie-secret. So there is nothing to share and nothing to lose on restart — # instead, every replica must hold the *same* secret, and changing it invalidates # every cookie at once. # # kubectl apply -f deploy/lab/k8s/b7-oauth2-proxy.yaml # # app2.hyeonworks.com is borrowed from Grafana for the duration of this # experiment; the certificate only covers auth / app1 / app2, so a fourth name # is not available. Grafana's Ingress is restored afterwards. apiVersion: v1 kind: Secret metadata: name: oauth2-proxy-secrets namespace: keycloak-lab type: Opaque stringData: # oauth2-proxy requires exactly 16, 24 or 32 bytes. This is the value whose # rotation the experiment is about. COOKIE_SECRET_A: "lab-cookie-secret-aaaaaaaaaaaaaa" COOKIE_SECRET_B: "lab-cookie-secret-bbbbbbbbbbbbbb" CLIENT_SECRET: proxy-lab-secret --- apiVersion: apps/v1 kind: Deployment metadata: name: oauth2-proxy namespace: keycloak-lab spec: # Two replicas is the point: Q1 asks how they share the secret. replicas: 2 selector: matchLabels: { app: oauth2-proxy } template: metadata: labels: { app: oauth2-proxy } spec: # See B-1: Kubernetes injects _PORT as a tcp:// URL and it # collides with ordinary configuration names. enableServiceLinks: false topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: { app: oauth2-proxy } containers: - name: oauth2-proxy image: quay.io/oauth2-proxy/oauth2-proxy:v7.7.1 args: - --provider=oidc - --oidc-issuer-url=https://auth.hyeonworks.com/realms/keycloak-patterns - --client-id=oauth2-proxy - --redirect-url=https://app2.hyeonworks.com/oauth2/callback - --email-domain=* - --http-address=0.0.0.0:4180 # The upstream is the same echo app the B-4 header experiment used, # so what the proxy forwards can be read straight off the response. - --upstream=http://echo.header-lab.svc:8081 # ★ 이 옵션을 켜면 세션(=쿠키)에 access token 이 들어간다. # 그러면 Set-Cookie 가 커져 프록시 앞단에서 502 가 났다. # B-4 에서 본 헤더 크기 절벽이 이번에는 응답 쪽에서 나타난 것이다. # - --pass-authorization-header=true - --set-xauthrequest=true - --reverse-proxy=true - --cookie-secure=true # One hour, matching the value Q1 records for the current setup. - --cookie-expire=1h - --skip-provider-button=true # ★ 쿠키에 세션 전체를 담으면 Set-Cookie 가 커지고, 그 응답이 # 앞단 nginx 의 proxy_buffer 를 넘겨 502 가 났다(측정됨). # Redis 로 옮기면 쿠키에는 티켓만 남는다 — 그리고 그 순간 # "replica 가 secret 을 공유해야 한다"는 문제의 성격도 바뀐다. - --session-store-type=redis - --redis-connection-url=redis://redis.keycloak-lab.svc:6379 env: - name: OAUTH2_PROXY_CLIENT_SECRET valueFrom: secretKeyRef: { name: oauth2-proxy-secrets, key: CLIENT_SECRET } # Which of the two secrets is in use is switched here. Both replicas # read the same key, which is exactly the sharing Q1 asks about. - name: OAUTH2_PROXY_COOKIE_SECRET valueFrom: secretKeyRef: { name: oauth2-proxy-secrets, key: COOKIE_SECRET_A } ports: - containerPort: 4180 name: http readinessProbe: httpGet: { path: /ping, port: http } initialDelaySeconds: 5 resources: requests: { memory: 32Mi, cpu: 20m } limits: { memory: 128Mi } --- apiVersion: v1 kind: Service metadata: name: oauth2-proxy namespace: keycloak-lab spec: selector: { app: oauth2-proxy } ports: - port: 4180 targetPort: http --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: oauth2-proxy namespace: keycloak-lab spec: ingressClassName: traefik rules: - host: app2.hyeonworks.com http: paths: - path: / pathType: Prefix backend: service: name: oauth2-proxy port: number: 4180