feat(auth): scaffold Ory Kratos identity service — phase 1 (infrastructure)
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>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
# Ory Kratos — honeyDue identity service (Phase 1: infrastructure)
|
||||
|
||||
This directory deploys [Ory Kratos](https://www.ory.sh/kratos/) into the
|
||||
`honeydue` namespace as the identity provider — replacing the hand-rolled auth
|
||||
in `internal/services/auth_service.go` etc.
|
||||
|
||||
**Phase 1 is infrastructure only.** Once deployed, Kratos runs but nothing uses
|
||||
it yet — the honeyDue Go API still does its own auth. Phase 2 (backend swap)
|
||||
and Phase 3 (KMP/web clients) follow. Migrating onto Kratos can lose all
|
||||
existing user data — honeyDue is pre-production, so no user import is done.
|
||||
|
||||
The deploy is **gated**: `03-deploy.sh` applies Kratos only when the
|
||||
`kratos-secrets` Secret exists, and `02-setup-secrets.sh` creates that Secret
|
||||
only when `config.yaml` has a `kratos:` block. Until then the existing stack
|
||||
deploys completely unaffected.
|
||||
|
||||
## Files
|
||||
|
||||
| File | What |
|
||||
|---|---|
|
||||
| `configmap.yaml` | `kratos.yml`, identity schema, Google/Apple OIDC claim mappers (no secrets) |
|
||||
| `migrate-job.yaml` | `kratos migrate sql` — schema migration, run before the Deployment |
|
||||
| `kratos.yaml` | Deployment (×2), Service, NetworkPolicies |
|
||||
| `ingress.yaml` | `auth.myhoneydue.com` → Kratos public API :4433 |
|
||||
|
||||
## Operator prerequisites (must be done before deploying)
|
||||
|
||||
1. **Kratos version** — Ory uses CalVer (`v25.x` / `v26.x`). Pick the current
|
||||
stable, then replace `REPLACE_WITH_CURRENT_STABLE_TAG` in `kratos.yaml` and
|
||||
`migrate-job.yaml` with `oryd/kratos:vXX.Y@sha256:<digest>`, and set the
|
||||
matching `version:` in `configmap.yaml`.
|
||||
|
||||
2. **Kratos database** — create a separate Neon database named `kratos` (do not
|
||||
share honeyDue's). Capture its connection string as the DSN.
|
||||
|
||||
3. **DNS** — add `auth.myhoneydue.com` in Cloudflare (proxied), pointing at the
|
||||
cluster ingress like the other honeyDue hosts. Confirm the
|
||||
`cloudflare-origin-cert` TLS secret covers `auth.myhoneydue.com`.
|
||||
|
||||
4. **Google OAuth client** — Google Cloud Console → create an OAuth 2.0 client.
|
||||
Redirect URI: `https://auth.myhoneydue.com/self-service/methods/oidc/callback/google`.
|
||||
Put the **client ID** into `configmap.yaml` (`GOOGLE_OAUTH_CLIENT_ID`); the
|
||||
**client secret** goes in `config.yaml`.
|
||||
|
||||
5. **Apple Sign In** — Apple Developer → a Services ID + a Sign in with Apple
|
||||
key. Return URL: `https://auth.myhoneydue.com/self-service/methods/oidc/callback/apple`.
|
||||
Put the **Services ID / Team ID / Key ID** into `configmap.yaml`
|
||||
(`APPLE_SERVICES_ID` / `APPLE_TEAM_ID` / `APPLE_PRIVATE_KEY_ID`); the **.p8
|
||||
private key** goes in `config.yaml`.
|
||||
|
||||
6. **`config.yaml`** — add a `kratos:` block:
|
||||
```yaml
|
||||
kratos:
|
||||
dsn: "postgres://USER:PASS@HOST/kratos?sslmode=require"
|
||||
secrets_cookie: "<openssl rand -hex 16>" # generate ONCE, keep stable
|
||||
secrets_cipher: "<openssl rand -hex 16>" # must be exactly 32 chars
|
||||
smtp_connection_uri: "smtps://USER:PASS@smtp.fastmail.com:465/"
|
||||
google_client_secret: "<from Google Cloud Console>"
|
||||
apple_private_key: |
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
...
|
||||
-----END PRIVATE KEY-----
|
||||
```
|
||||
`secrets_cookie` / `secrets_cipher` must stay stable forever — rotating them
|
||||
invalidates every session and makes encrypted data unreadable.
|
||||
|
||||
## Deploy
|
||||
|
||||
```bash
|
||||
cd honeyDueAPI-go
|
||||
export KUBECONFIG="$(pwd)/deploy-k3s/kubeconfig"
|
||||
./deploy-k3s/scripts/02-setup-secrets.sh # creates kratos-secrets from config.yaml
|
||||
./deploy-k3s/scripts/03-deploy.sh # applies kratos manifests, runs migrate, rolls
|
||||
```
|
||||
|
||||
`03-deploy.sh` applies `configmap.yaml` → runs `migrate-job.yaml` → waits →
|
||||
applies `kratos.yaml` + `ingress.yaml`.
|
||||
|
||||
## Verify
|
||||
|
||||
- `kubectl -n honeydue get pods -l app.kubernetes.io/name=kratos` — 2/2 Running
|
||||
- `kubectl -n honeydue logs job/kratos-migrate` — migration succeeded
|
||||
- `curl https://auth.myhoneydue.com/health/ready` — `{"status":"ok"}`
|
||||
- `curl https://auth.myhoneydue.com/self-service/registration/api` — returns a flow
|
||||
|
||||
## Not yet done (later phases)
|
||||
|
||||
- **Phase 2** — honeyDue Go backend: swap `middleware/auth.go` for Kratos
|
||||
session validation, drop the hand-rolled auth code, rebuild the `users`
|
||||
table keyed on the Kratos identity ID.
|
||||
- **Phase 3** — KMP mobile + Next.js web clients point at Kratos flows.
|
||||
- Admin-panel auth stays on its own JWT (out of scope).
|
||||
Reference in New Issue
Block a user