# services/hermes/oauth2-proxy.yaml apiVersion: v1 kind: ConfigMap metadata: name: hermes-owner-allowlist namespace: hermes data: allowed-emails: | brad@bstein.dev --- apiVersion: v1 kind: Service metadata: name: oauth2-proxy-hermes-agent namespace: hermes spec: selector: app: hermes-agent # The agent dashboard and terminal must stay reachable while the # cli-lane-runner readiness probe holds the shared pod NotReady. publishNotReadyAddresses: true ports: - {name: http, port: 80, targetPort: auth-http} --- apiVersion: v1 kind: Service metadata: name: oauth2-proxy-hermes-triage namespace: hermes spec: selector: app: oauth2-proxy-hermes-triage ports: - {name: http, port: 80, targetPort: http} --- apiVersion: v1 kind: Service metadata: name: oauth2-proxy-hermes-chat namespace: hermes spec: selector: app: oauth2-proxy-hermes-chat ports: - {name: http, port: 80, targetPort: http} --- apiVersion: apps/v1 kind: Deployment metadata: name: oauth2-proxy-hermes-triage namespace: hermes labels: app: oauth2-proxy-hermes-triage spec: replicas: 1 revisionHistoryLimit: 2 selector: matchLabels: app: oauth2-proxy-hermes-triage template: metadata: labels: app: oauth2-proxy-hermes-triage annotations: vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/agent-pre-populate-only: "true" vault.hashicorp.com/role: hermes vault.hashicorp.com/agent-inject-secret-oidc-config: kv/data/atlas/hermes/triage-oidc vault.hashicorp.com/agent-inject-template-oidc-config: | {{- with secret "kv/data/atlas/hermes/triage-oidc" -}} client_id = "{{ .Data.data.client_id }}" client_secret = "{{ .Data.data.client_secret }}" cookie_secret = "{{ .Data.data.cookie_secret }}" {{- end -}} spec: serviceAccountName: hermes-vault automountServiceAccountToken: true containers: - name: oauth2-proxy image: quay.io/oauth2-proxy/oauth2-proxy:v7.15.3@sha256:10a1165743a192e1940b4708fb9647027185ce11a681a1c5519b442ff7f1f561 imagePullPolicy: IfNotPresent args: - --provider=oidc - --config=/vault/secrets/oidc-config - --redirect-url=https://triage.bstein.dev/oauth2/callback - --oidc-issuer-url=https://sso.bstein.dev/realms/atlas - --user-id-claim=sub - --code-challenge-method=S256 - --scope=openid profile email - --email-domain=* - --authenticated-emails-file=/etc/oauth2-proxy/allowed-emails - --set-xauthrequest=true - --pass-user-headers=true - --pass-basic-auth=false - --proxy-websockets=true - --cookie-name=__Host-hermes_triage - --cookie-path=/ - --cookie-secure=true - --cookie-samesite=lax - --cookie-csrf-expire=10m - --cookie-csrf-per-request=true - --cookie-csrf-per-request-limit=8 - --cookie-refresh=19m - --cookie-expire=168h - --session-store-type=redis - --redis-connection-url=redis://hermes-oauth-sessions.hermes.svc.cluster.local:6379/2 - --api-route=^/api/ - --api-route=^/health$ - --upstream=http://hermes-triage.hermes.svc.cluster.local:8787 - --http-address=0.0.0.0:4180 - --skip-provider-button=true - --reverse-proxy=true - --trusted-proxy-ip=10.42.0.0/16 ports: - {name: http, containerPort: 4180} readinessProbe: httpGet: {path: /ping, port: http} initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: httpGet: {path: /ping, port: http} initialDelaySeconds: 20 periodSeconds: 20 securityContext: allowPrivilegeEscalation: false capabilities: drop: [ALL] readOnlyRootFilesystem: true runAsNonRoot: true seccompProfile: type: RuntimeDefault resources: requests: {cpu: 25m, memory: 64Mi} limits: {cpu: 250m, memory: 256Mi} volumeMounts: - {name: allowlist, mountPath: /etc/oauth2-proxy, readOnly: true} - {name: tmp, mountPath: /tmp} volumes: - name: allowlist configMap: name: hermes-owner-allowlist - name: tmp emptyDir: {sizeLimit: 64Mi} --- apiVersion: apps/v1 kind: Deployment metadata: name: oauth2-proxy-hermes-chat namespace: hermes labels: app: oauth2-proxy-hermes-chat spec: replicas: 1 revisionHistoryLimit: 2 selector: matchLabels: app: oauth2-proxy-hermes-chat template: metadata: labels: app: oauth2-proxy-hermes-chat annotations: ai.bstein.dev/config-rev: "20260811-redis-sessions" vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/agent-pre-populate-only: "true" vault.hashicorp.com/role: hermes-chat vault.hashicorp.com/agent-inject-secret-oidc-config: kv/data/atlas/hermes/chat-oidc vault.hashicorp.com/agent-inject-template-oidc-config: | {{- with secret "kv/data/atlas/hermes/chat-oidc" -}} client_id = "{{ .Data.data.client_id }}" client_secret = "{{ .Data.data.client_secret }}" cookie_secret = "{{ .Data.data.cookie_secret }}" {{- end -}} spec: serviceAccountName: hermes-chat automountServiceAccountToken: true containers: - name: oauth2-proxy image: quay.io/oauth2-proxy/oauth2-proxy:v7.15.3@sha256:10a1165743a192e1940b4708fb9647027185ce11a681a1c5519b442ff7f1f561 imagePullPolicy: IfNotPresent args: - --provider=oidc - --config=/vault/secrets/oidc-config - --redirect-url=https://chat.bstein.dev/oauth2/callback - --oidc-issuer-url=https://sso.bstein.dev/realms/atlas - --user-id-claim=sub - --code-challenge-method=S256 - --scope=openid profile email - --email-domain=* - --set-xauthrequest=true - --pass-user-headers=true - --pass-basic-auth=false - --proxy-websockets=true - --cookie-name=__Host-hermes_chat - --cookie-path=/ - --cookie-secure=true - --cookie-samesite=lax - --cookie-csrf-expire=10m - --cookie-csrf-per-request=true - --cookie-csrf-per-request-limit=8 - --cookie-refresh=19m - --cookie-expire=168h - --session-store-type=redis - --redis-connection-url=redis://hermes-oauth-sessions.hermes.svc.cluster.local:6379/1 - --custom-templates-dir=/etc/oauth2-proxy/templates - '--skip-auth-route=GET=^/sw[.]js([?].*)?$' - '--skip-auth-route=GET=^/healthz$' - --api-route=^/api/ - --api-route=^/health$ - --upstream=http://hermes-chat-router.hermes.svc.cluster.local:8080 - --http-address=0.0.0.0:4180 - --skip-provider-button=true - --reverse-proxy=true - --trusted-proxy-ip=10.42.0.0/16 ports: - {name: http, containerPort: 4180} readinessProbe: httpGet: {path: /ping, port: http} initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: httpGet: {path: /ping, port: http} initialDelaySeconds: 20 periodSeconds: 20 securityContext: allowPrivilegeEscalation: false capabilities: drop: [ALL] readOnlyRootFilesystem: true runAsNonRoot: true seccompProfile: type: RuntimeDefault resources: requests: {cpu: 25m, memory: 64Mi} limits: {cpu: 250m, memory: 256Mi} volumeMounts: - {name: templates, mountPath: /etc/oauth2-proxy/templates, readOnly: true} - {name: tmp, mountPath: /tmp} volumes: - name: templates configMap: name: hermes-chat-oauth-templates - name: tmp emptyDir: {sizeLimit: 64Mi}