Gotify has no OIDC support, so it cannot validate a ZITADEL token itself. Put oauth2-proxy in front of it and let nginx ask the proxy for every request. The Gotify REST API keeps its own client-token check. /message, /application, /client, /user, /version, /stream and /health are skipped by the proxy, so Forgejo webhooks, the harness, poimen-sender and the Android client keep working without a browser session. Only the web UI requires SSO. The /oauth2 path needs its own ingress: the auth_request annotation would otherwise also guard /oauth2/start, and the login entry point would demand a login first. The client id and secret come from project role provisioning: `zitadel-provision.py apply` now creates the `gotify` OIDC app, and the secret is SOPS-encrypted under k8s/argocd/secrets. Gotify's own login remains behind the proxy. ZITADEL decides who reaches the service, Gotify decides what that person may do inside it.
83 lines
3.1 KiB
YAML
83 lines
3.1 KiB
YAML
# oauth2-proxy in front of Gotify. Gotify has no OIDC support of its own, so it
|
|
# cannot validate a ZITADEL token. This proxy is the front door: nginx asks it
|
|
# for an auth decision on every request (auth_request), and it answers from a
|
|
# ZITADEL session cookie.
|
|
#
|
|
# The Gotify REST API keeps its own client-token auth (X-Gotify-Key) and must
|
|
# stay reachable without a browser session, or every push sender breaks:
|
|
# Forgejo webhooks, the harness, poimen-sender and the ntfy-style relays all post
|
|
# to /message. skip-auth-route leaves those paths to Gotify's own token check.
|
|
#
|
|
# Gotify's own login still exists behind the proxy. ZITADEL decides who may
|
|
# reach the service; Gotify decides what that person may do inside it.
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: gotify-oauth2-proxy
|
|
namespace: notifications
|
|
labels:
|
|
app: gotify-oauth2-proxy
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: gotify-oauth2-proxy
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: gotify-oauth2-proxy
|
|
spec:
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 65534
|
|
seccompProfile:
|
|
type: RuntimeDefault
|
|
containers:
|
|
- name: oauth2-proxy
|
|
image: quay.io/oauth2-proxy/oauth2-proxy:v7.7.1
|
|
args:
|
|
- --provider=oidc
|
|
- --oidc-issuer-url=https://zitadel.riotpiao.com
|
|
- --email-domain=*
|
|
- --upstream=static://202
|
|
- --reverse-proxy=true
|
|
- --set-xauthrequest=true
|
|
- --cookie-secure=true
|
|
- --cookie-expire=12h
|
|
- --cookie-refresh=1h
|
|
- --skip-provider-button=true
|
|
- --redirect-url=https://gotify.riotpiao.com/oauth2/callback
|
|
- --http-address=0.0.0.0:4180
|
|
# Browser paths keep SSO. API paths fall through to Gotify's own
|
|
# client-token check, so existing senders and the Android client
|
|
# keep working without a browser session.
|
|
- --skip-auth-route=^/(message|application|client|user|version|stream|health)(/.*)?$
|
|
env:
|
|
- name: OAUTH2_PROXY_CLIENT_ID
|
|
valueFrom:
|
|
secretKeyRef: {name: gotify-oauth2-proxy, key: client-id}
|
|
- name: OAUTH2_PROXY_CLIENT_SECRET
|
|
valueFrom:
|
|
secretKeyRef: {name: gotify-oauth2-proxy, key: client-secret}
|
|
- name: OAUTH2_PROXY_COOKIE_SECRET
|
|
valueFrom:
|
|
secretKeyRef: {name: gotify-oauth2-proxy, key: cookie-secret}
|
|
ports:
|
|
- name: http
|
|
containerPort: 4180
|
|
readinessProbe:
|
|
httpGet: {path: /ping, port: http}
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 10
|
|
livenessProbe:
|
|
httpGet: {path: /ping, port: http}
|
|
initialDelaySeconds: 15
|
|
periodSeconds: 20
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
capabilities:
|
|
drop: ["ALL"]
|
|
resources:
|
|
requests: {cpu: 10m, memory: 32Mi}
|
|
limits: {cpu: 200m, memory: 128Mi}
|