Files
honeyDueAPI/deploy-k3s/manifests/kratos/configmap.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

209 lines
6.7 KiB
YAML

# Ory Kratos configuration for honeyDue.
#
# Secrets are NOT in this ConfigMap. The DSN, cookie/cipher secrets, SMTP URI
# and OIDC client secrets are injected as environment variables from the
# kratos-secrets Secret (see kratos.yaml). Kratos is configured natively via
# env vars, so this is the idiomatic split — only non-secret config here.
#
# OPERATOR: replace the GOOGLE_OAUTH_CLIENT_ID / APPLE_* client-id placeholders
# below with the real (non-secret) OAuth client identifiers once the Apple and
# Google OAuth apps exist. The matching secrets go in kratos-secrets.
apiVersion: v1
kind: ConfigMap
metadata:
name: kratos-config
namespace: honeydue
labels:
app.kubernetes.io/name: kratos
app.kubernetes.io/part-of: honeydue
data:
kratos.yml: |
# version must track the Kratos image tag — confirm against the deployed
# Kratos release (Ory uses CalVer, e.g. v26.x). See kratos/README.md.
version: v1.3.0
serve:
public:
base_url: https://auth.myhoneydue.com/
cors:
enabled: true
allowed_origins:
- https://myhoneydue.com
- https://app.myhoneydue.com
- https://admin.myhoneydue.com
allowed_methods: [GET, POST, PUT, PATCH, DELETE, OPTIONS]
allowed_headers: [Authorization, Content-Type, X-Session-Token, Cookie]
exposed_headers: [Content-Type, Set-Cookie]
# Required: the web clients call Kratos browser flows with
# credentials (the ory_kratos_session cookie). Safe here because
# allowed_origins is an explicit list, never a wildcard.
allow_credentials: true
admin:
base_url: http://kratos.honeydue.svc.cluster.local:4434/
selfservice:
default_browser_return_url: https://app.myhoneydue.com/
allowed_return_urls:
- https://app.myhoneydue.com
- https://myhoneydue.com
- honeydue://callback
methods:
password:
enabled: true
code: # email one-time codes (verify/recover)
enabled: true
oidc:
enabled: true
config:
providers:
# index 0 — Google. client_secret is injected via env var
# SELFSERVICE_METHODS_OIDC_CONFIG_PROVIDERS_0_CLIENT_SECRET.
- id: google
provider: google
client_id: GOOGLE_OAUTH_CLIENT_ID
mapper_url: file:///etc/kratos/oidc.google.jsonnet
scope: [openid, email, profile]
# index 1 — Apple. apple_private_key is injected via env var
# SELFSERVICE_METHODS_OIDC_CONFIG_PROVIDERS_1_APPLE_PRIVATE_KEY.
- id: apple
provider: apple
client_id: APPLE_SERVICES_ID
apple_team_id: APPLE_TEAM_ID
apple_private_key_id: APPLE_PRIVATE_KEY_ID
mapper_url: file:///etc/kratos/oidc.apple.jsonnet
scope: [openid, email, name]
flows:
error:
ui_url: https://app.myhoneydue.com/auth/error
login:
ui_url: https://app.myhoneydue.com/auth/login
lifespan: 10m
registration:
ui_url: https://app.myhoneydue.com/auth/registration
lifespan: 10m
after:
password:
hooks:
- hook: session # auto-login after registration
oidc:
hooks:
- hook: session
verification:
enabled: true
ui_url: https://app.myhoneydue.com/auth/verification
use: code
after:
default_browser_return_url: https://app.myhoneydue.com/
recovery:
enabled: true
ui_url: https://app.myhoneydue.com/auth/recovery
use: code
settings:
ui_url: https://app.myhoneydue.com/auth/settings
privileged_session_max_age: 15m
logout:
after:
default_browser_return_url: https://app.myhoneydue.com/
log:
level: info
format: json
leak_sensitive_values: false
ciphers:
algorithm: xchacha20-poly1305
hashers:
algorithm: bcrypt
bcrypt:
cost: 12
identity:
default_schema_id: honeydue
schemas:
- id: honeydue
url: file:///etc/kratos/identity.schema.json
courier:
smtp:
from_address: noreply@myhoneydue.com
from_name: honeyDue
# connection_uri is injected via env COURIER_SMTP_CONNECTION_URI
session:
lifespan: 720h # 30-day sessions (mobile)
cookie:
domain: myhoneydue.com
same_site: Lax
identity.schema.json: |
{
"$id": "https://honeydue.app/identity.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "honeyDue user",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"title": "Email",
"minLength": 3,
"maxLength": 320,
"ory.sh/kratos": {
"credentials": {
"password": { "identifier": true },
"code": { "identifier": true, "via": "email" },
"totp": { "account_name": true }
},
"verification": { "via": "email" },
"recovery": { "via": "email" }
}
},
"name": {
"type": "object",
"title": "Name",
"properties": {
"first": { "type": "string", "title": "First name", "maxLength": 100 },
"last": { "type": "string", "title": "Last name", "maxLength": 100 }
}
}
},
"required": ["email"],
"additionalProperties": false
}
}
}
oidc.google.jsonnet: |
// Maps Google OIDC claims onto the honeyDue identity schema.
local claims = std.extVar('claims');
{
identity: {
traits: {
email: claims.email,
[if 'given_name' in claims || 'family_name' in claims then 'name']: {
first: if 'given_name' in claims then claims.given_name else '',
last: if 'family_name' in claims then claims.family_name else '',
},
},
},
}
oidc.apple.jsonnet: |
// Maps Apple OIDC claims onto the honeyDue identity schema. Apple only
// returns the name on the very first authorization and not in the ID
// token claims, so only email is mapped here.
local claims = std.extVar('claims');
{
identity: {
traits: {
email: claims.email,
},
},
}