Files
honeyDueAPI/deploy-k3s/manifests/kratos/kratos.yaml
T
Trey t 3d3ba84df0
Backend CI / Test (push) Has been cancelled
Backend CI / Contract Tests (push) Has been cancelled
Backend CI / Lint (push) Has been cancelled
Backend CI / Secret Scanning (push) Has been cancelled
Backend CI / Build (push) Has been cancelled
fix(auth): delete the Kratos identity on account deletion
Account deletion removed all local data but left the Ory Kratos
identity intact — an orphaned identity that can still authenticate.
Close the gap:

- kratos.Client gains the admin API: NewClient(publicURL, adminURL)
  and DeleteIdentity (DELETE /admin/identities/{id}; a 404 is treated
  as success so a retry after a partial failure is idempotent).
- AuthService.DeleteAccount deletes the Kratos identity FIRST; if that
  call fails it aborts before touching local data, so the operation is
  retryable rather than partially applied.
- KRATOS_ADMIN_URL config (default http://kratos:4434) + router wiring.
- kratos NetworkPolicy split: the api pods may now reach the admin API
  :4434 (Traefik still reaches only the public API :4433).
- kratos CORS: allow_credentials + OPTIONS so the web browser flows
  (ory_kratos_session cookie) work; origins stay an explicit allowlist.
- Regression tests: identity teardown happens, and a Kratos failure
  aborts the deletion instead of orphaning local data.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 21:55:33 -05:00

208 lines
6.1 KiB
YAML

# Ory Kratos — identity service for honeyDue.
#
# Deployed only once the operator has completed the prerequisites in
# kratos/README.md (Neon `kratos` database, auth.myhoneydue.com DNS, Apple +
# Google OAuth apps, and the kratos-secrets Secret). Until then 03-deploy.sh
# skips the Kratos apply, so the existing stack is unaffected.
#
# IMAGE: oryd/kratos uses CalVer (v25.x / v26.x). The tag below is a
# fail-loud placeholder — set the current stable tag and pin a @sha256:
# digest (like redis/vmagent) before deploying. See kratos/README.md.
# The schema-migration Job is in migrate-job.yaml (run before this).
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kratos
namespace: honeydue
labels:
app.kubernetes.io/name: kratos
app.kubernetes.io/part-of: honeydue
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
selector:
matchLabels:
app.kubernetes.io/name: kratos
template:
metadata:
labels:
app.kubernetes.io/name: kratos
app.kubernetes.io/part-of: honeydue
spec:
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: kratos
image: oryd/kratos:REPLACE_WITH_CURRENT_STABLE_TAG
imagePullPolicy: IfNotPresent
args:
- serve
- --config
- /etc/kratos/kratos.yml
- --watch-courier # send verification/recovery email in-process
ports:
- name: public
containerPort: 4433
- name: admin
containerPort: 4434
env:
# Kratos is configured natively via env vars; secrets come from
# the kratos-secrets Secret rather than the ConfigMap.
- name: DSN
valueFrom: { secretKeyRef: { name: kratos-secrets, key: dsn } }
- name: SECRETS_COOKIE
valueFrom: { secretKeyRef: { name: kratos-secrets, key: secrets_cookie } }
- name: SECRETS_CIPHER
valueFrom: { secretKeyRef: { name: kratos-secrets, key: secrets_cipher } }
- name: COURIER_SMTP_CONNECTION_URI
valueFrom: { secretKeyRef: { name: kratos-secrets, key: smtp_connection_uri } }
# OIDC provider secrets — index must match the providers list
# order in configmap.yaml (0 = google, 1 = apple).
- name: SELFSERVICE_METHODS_OIDC_CONFIG_PROVIDERS_0_CLIENT_SECRET
valueFrom: { secretKeyRef: { name: kratos-secrets, key: google_client_secret } }
- name: SELFSERVICE_METHODS_OIDC_CONFIG_PROVIDERS_1_APPLE_PRIVATE_KEY
valueFrom: { secretKeyRef: { name: kratos-secrets, key: apple_private_key } }
volumeMounts:
- name: config
mountPath: /etc/kratos
readOnly: true
- name: tmp
mountPath: /tmp
readinessProbe:
httpGet:
path: /health/ready
port: 4434
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health/alive
port: 4434
initialDelaySeconds: 10
periodSeconds: 30
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: "1"
memory: 512Mi
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumes:
- name: config
configMap:
name: kratos-config
- name: tmp
emptyDir:
sizeLimit: 64Mi
---
apiVersion: v1
kind: Service
metadata:
name: kratos
namespace: honeydue
labels:
app.kubernetes.io/name: kratos
app.kubernetes.io/part-of: honeydue
spec:
selector:
app.kubernetes.io/name: kratos
ports:
- name: public
port: 4433
targetPort: 4433
- name: admin
port: 4434
targetPort: 4434
---
# Ingress to Kratos. Traefik (the auth.myhoneydue.com IngressRoute) reaches
# only the public API :4433. The honeyDue api pods reach the public API :4433
# (session whoami) AND the admin API :4434 (identity deletion on account
# close). The admin API :4434 takes no other cluster ingress.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-to-kratos
namespace: honeydue
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: kratos
policyTypes:
- Ingress
ingress:
# Traefik ingress controller -> public API only.
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- port: 4433
protocol: TCP
# honeyDue api pods -> public API (whoami) + admin API (identity deletion).
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: api
ports:
- port: 4433
protocol: TCP
- port: 4434
protocol: TCP
---
# Kratos egress: DNS, the Neon Postgres database, SMTP, and HTTPS to the
# OIDC providers (Apple/Google token + JWKS endpoints).
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress-from-kratos
namespace: honeydue
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: kratos
policyTypes:
- Egress
egress:
- to:
- namespaceSelector: {}
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
# Neon Postgres (external)
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.42.0.0/16
- 10.43.0.0/16
ports:
- port: 5432
protocol: TCP
# SMTP (Fastmail) + HTTPS to Apple/Google OIDC endpoints (external)
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.42.0.0/16
- 10.43.0.0/16
ports:
- port: 465
protocol: TCP
- port: 443
protocol: TCP