atlas-iac/services/hermes/oauth2-proxy.yaml

352 lines
12 KiB
YAML

# 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: ConfigMap
metadata:
name: hermes-chat-oauth-templates
namespace: hermes
data:
error.html: |
{{define "error.html"}}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>{{.StatusCode}} {{.Title}}</title>
{{if or (eq .StatusCode 500) (eq .Message "Login Failed: Unable to find a valid CSRF token. Please try again.")}}<meta http-equiv="refresh" content="0;url={{.ProxyPrefix}}/sign_in?rd=/">{{end}}
<style>
body{margin:0;min-height:100vh;display:grid;place-items:center;background:#f5f5f5;color:#333;font:16px/1.5 system-ui,sans-serif}
main{width:min(560px,calc(100% - 40px));box-sizing:border-box;padding:36px;border:1px solid #ddd;border-radius:14px;background:#fff;text-align:center;box-shadow:0 12px 45px #0002}
h1{font-size:3rem;margin:.2rem}.detail{color:#666}a{display:inline-block;margin-top:18px;padding:10px 16px;border-radius:8px;background:#00bfa5;color:#fff;text-decoration:none}
</style>
</head>
<body>
<main>
{{if or (eq .StatusCode 500) (eq .Message "Login Failed: Unable to find a valid CSRF token. Please try again.")}}
<h1>Signing you back in…</h1>
<p class="detail">The previous one-time login callback expired or was already used. Hermes is starting a fresh sign-in automatically.</p>
<a href="{{.ProxyPrefix}}/sign_in?rd=/">Continue now</a>
{{else}}
<h1>{{.StatusCode}} {{.Title}}</h1>
{{if .Message}}<p class="detail">{{.Message}}</p>{{end}}
<a href="{{.ProxyPrefix}}/sign_in?rd=/">Sign in again</a>
{{end}}
</main>
</body>
</html>
{{end}}
---
apiVersion: v1
kind: Service
metadata:
name: oauth2-proxy-hermes-agent
namespace: hermes
spec:
selector:
app: oauth2-proxy-hermes-agent
ports:
- {name: http, port: 80, targetPort: 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-agent
namespace: hermes
labels:
app: oauth2-proxy-hermes-agent
spec:
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
app: oauth2-proxy-hermes-agent
template:
metadata:
labels:
app: oauth2-proxy-hermes-agent
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-pre-populate-only: "true"
vault.hashicorp.com/role: hermes-agent
vault.hashicorp.com/agent-inject-secret-oidc-config: kv/data/atlas/hermes/agent-oidc
vault.hashicorp.com/agent-inject-template-oidc-config: |
{{- with secret "kv/data/atlas/hermes/agent-oidc" -}}
client_id = "{{ .Data.data.client_id }}"
client_secret = "{{ .Data.data.client_secret }}"
cookie_secret = "{{ .Data.data.cookie_secret }}"
{{- end -}}
spec:
serviceAccountName: hermes-agent
automountServiceAccountToken: true
containers:
- name: oauth2-proxy
image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0@sha256:dcb6ff8dd21bf3058f6a22c6fa385fa5b897a9cd3914c88a2cc2bb0a85f8065d
imagePullPolicy: IfNotPresent
args:
- --provider=oidc
- --config=/vault/secrets/oidc-config
- --redirect-url=https://agent.hermes.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_agent
- --cookie-path=/
- --cookie-secure=true
- --cookie-samesite=lax
- --cookie-refresh=1h
- --cookie-expire=8h
- --upstream=http://hermes-agent.hermes.svc.cluster.local:7681
- --http-address=0.0.0.0:4180
- --skip-provider-button=true
- --reverse-proxy=true
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-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.6.0@sha256:dcb6ff8dd21bf3058f6a22c6fa385fa5b897a9cd3914c88a2cc2bb0a85f8065d
imagePullPolicy: IfNotPresent
args:
- --provider=oidc
- --config=/vault/secrets/oidc-config
- --redirect-url=https://triage.hermes.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-refresh=1h
- --cookie-expire=8h
- --upstream=http://hermes-triage.hermes.svc.cluster.local:8787
- --http-address=0.0.0.0:4180
- --skip-provider-button=true
- --reverse-proxy=true
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: "20260809-expired-callback-recovery"
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.6.0@sha256:dcb6ff8dd21bf3058f6a22c6fa385fa5b897a9cd3914c88a2cc2bb0a85f8065d
imagePullPolicy: IfNotPresent
args:
- --provider=oidc
- --config=/vault/secrets/oidc-config
- --redirect-url=https://chat.hermes.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-refresh=1h
- --cookie-expire=8h
- --custom-templates-dir=/etc/oauth2-proxy/templates
- '--skip-auth-route=GET=^/sw[.]js([?].*)?$'
- --upstream=http://hermes-chat-router.hermes.svc.cluster.local:8080
- --http-address=0.0.0.0:4180
- --skip-provider-button=true
- --reverse-proxy=true
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}