b66151ddd9
First phase of replacing the hand-rolled auth (internal/services/auth_service.go
et al.) with Ory Kratos. This commit is infrastructure only — Kratos will run
but nothing consumes it yet; the Go API still does its own auth until phase 2.
Adds deploy-k3s/manifests/kratos/:
- configmap.yaml — kratos.yml, identity schema, Google/Apple OIDC claim
mappers (no secrets in the ConfigMap)
- migrate-job.yaml — `kratos migrate sql`, run before the Deployment
- kratos.yaml — Deployment (x2), Service, NetworkPolicies
- ingress.yaml — auth.myhoneydue.com -> Kratos public API :4433
- README.md — operator prerequisites + deploy runbook
Wiring:
- 02-setup-secrets.sh creates kratos-secrets, gated on a config.yaml `kratos:`
block (DSN, cookie/cipher, SMTP URI, OIDC client secret, Apple key).
- 03-deploy.sh applies the Kratos manifests + runs the migrate Job, gated on
the kratos-secrets Secret existing.
Both gates mean the existing stack deploys completely unaffected until the
operator completes the prerequisites (Neon `kratos` DB, auth.myhoneydue.com
DNS, Apple/Google OAuth apps, Kratos image version). Pre-production, so no
user-data migration — see manifests/kratos/README.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
205 lines
6.5 KiB
YAML
205 lines
6.5 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]
|
|
allowed_headers: [Authorization, Content-Type, X-Session-Token, Cookie]
|
|
exposed_headers: [Content-Type, Set-Cookie]
|
|
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,
|
|
},
|
|
},
|
|
}
|