feat(authentik): MendysRobotics identity silo — separate Authentik instance + platform OIDC client - #428
Conversation
…stance + platform OIDC client
MendysRobotics gets its own Authentik (server + worker) with its own Postgres
database, so its accounts are genuinely separate from FuzeFront's: a FuzeFront
account cannot sign in to the Mendys apps, a Mendys account cannot sign in to
FuzeFront, and the same email may exist independently on both sides.
Why an instance and not a brand: authentik has no realm. One instance is one
user directory, and brands are branding + default flows only ("all objects
like applications and providers are still global"). Hard tenancy (a Postgres
schema per tenant, 2024.2+) does isolate users but is Enterprise-only, alpha,
licensed per tenant and API-managed — it cannot be expressed as a blueprint in
git, which is how every other authentik object here is managed. A second
instance on its own database gives the same isolation for free and stays
declarative.
Adds:
- templates/authentik-mendys.yaml — the instance, gated on
authentikMendys.enabled (default false). Isolation invariants are enforced
and documented in-file: distinct database, distinct AUTHENTIK_SECRET_KEY,
distinct Redis logical DB (sessions/cache are stored under non-namespaced
keys), distinct cookie domain, and a separate blueprint mount.
- templates/authentik-mendys-blueprints.yaml — ConfigMap sourced from
authentik/blueprints-mendys/ ONLY. Mounting the FuzeFront set here would
recreate FuzeFront's flows/providers/applications inside this directory.
- blueprints-mendys/provider-oidc-mendys-platform.yaml — the requested
client: confidential, client_id mendys-platform-oidc-client, sub_mode
user_email, include_claims_in_id_token, openid/email/profile scope
mappings, an invalidation_flow, and strict redirect URIs for both
live.mendysrobotics.com and marketplace.mendysrobotics.com
/api/auth/oidc/callback. Application slug mendys-platform.
- blueprints-mendys/{brand-mendys,flow-enrollment}.yaml — the silo's brand
and a self-service enrollment flow mirroring FuzeFront's design.
- blueprints-mendys/provider-oidc-mendys-datasets.yaml — the datasets
provider's silo-side copy.
- MENDYS_PLATFORM_CLIENT_SECRET plus the instance's own secret key,
bootstrap credentials and DB password in the chart Secret and env wiring.
Datasets migration is deliberately staged, not switched: the FuzeFront-side
provider is left untouched and serving traffic. Retiring it before
MendysRobotics repoints its issuer would black out datasets sign-in, and
deleting the blueprint file alone would not remove the objects anyway — that
needs an explicit `state: absent` pass. Accounts do not migrate either.
Backing store is provisioned by FuzeInfra (serviceDatabases entry
`authentik-mendys`), not by hand.
Verified: helm lint clean; kubeconform strict 16/16 valid (1 skip = Traefik
CRD); every mendys blueprint parses with authentik's !Env/!Find tags; the
FuzeFront render is byte-identical with the silo off, so enabling this cannot
disturb the live IdP.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session-Id: 55a394fa-d5ba-4da4-b41f-b0ef56fa6ddf
Automated code review (gate-code-review)Looking at this PR — it's almost entirely declarative Helm/YAML and Authentik blueprints. I checked the template conditionals, secret gating,
I did not find any confirmed logic bug (wrong condition, null deref, off-by-one) in the template guards — the Report-only — this check never blocks merge. |
…ret.yaml (#439) templates/authentik-mendys.yaml mounts AUTHENTIK_MENDYS_SECRET_KEY, AUTHENTIK_MENDYS_DB_PASSWORD, AUTHENTIK_MENDYS_BOOTSTRAP_PASSWORD and AUTHENTIK_MENDYS_BOOTSTRAP_TOKEN as NON-OPTIONAL secretKeyRefs, but the block in secret.yaml that creates them is no longer on master. Rendering the chart with authentikMendys.enabled=true therefore produces 8 unresolved non-optional secret references (4 keys x server + worker), and both pods would fail with CreateContainerConfigError. The keys were present in the change that added the instance (#428). values.yaml still carries both the authentikMendys block and all four secret.authentikMendys* values, and the instance template is intact — only this stanza went missing, and the surrounding client-secret comments were rewritten, which points at a conflict resolution over that region of the file rather than an intentional removal. Latent rather than live: the gate is off, so nothing is deployed and nothing is currently broken. It would have failed at the moment someone first enabled the silo, which is the worst time to discover it. Adds a note tying the two files together so they are added and removed as a pair. Verified by cross-checking every secretKeyRef in the rendered chart against the keys the chart actually creates: 8 unresolved non-optional refs before, 0 after. Claude-Session-Id: 55a394fa-d5ba-4da4-b41f-b0ef56fa6ddf Co-authored-by: fuzeone-bot[bot] <fuzeone-bot[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Registers the requested per-product Authentik OIDC client for MendysRobotics platform SSO — but as its own identity silo, not as another provider on the shared FuzeFront directory.
Companion PR (backing database): izzywdev/FuzeInfra#421
Why a separate instance and not a brand
The requirement is that MendysRobotics has its own set of accounts: a FuzeFront account must not be recognised by the Mendys apps, a Mendys account must not be recognised by FuzeFront, and the same email may exist independently on both sides.
That cannot be done by adding a blueprint to the existing instance:
A second instance on its own database gives the same isolation property for free and stays fully declarative.
What's here
templates/authentik-mendys.yaml— the instance (server + worker + Service), gated onauthentikMendys.enabled, default off.templates/authentik-mendys-blueprints.yaml— ConfigMap sourced only fromauthentik/blueprints-mendys/.blueprints-mendys/provider-oidc-mendys-platform.yaml— the requested client:client_type: confidential,client_id: mendys-platform-oidc-client,client_secretvia!Env,sub_mode: user_email,include_claims_in_id_token: true, openid/email/profile scope mappings, aninvalidation_flow, and both strict redirect URIs (live.andmarketplace.mendysrobotics.com/api/auth/oidc/callback). Application slugmendys-platform, launch URLhttps://live.mendysrobotics.com/.blueprints-mendys/{brand-mendys,flow-enrollment}.yaml— the silo's brand and a self-service enrollment flow mirroring FuzeFront's design.blueprints-mendys/provider-oidc-mendys-datasets.yaml— the datasets provider's silo-side copy.MENDYS_PLATFORM_CLIENT_SECRETplus the instance's own secret key, bootstrap credentials and DB password, wired through the chart Secret and env.blueprints-mendys/README.md— the boundary, the secret contract, and the exposure decision.Isolation invariants (each enforced and documented in-file)
AUTHENTIK_SECRET_KEY*.yamlunder/blueprints; a shared mount would recreate FuzeFront's flows/providers/apps inside the Mendys directory.Because the directory itself is the tenant boundary, the applications use
policy_engine_mode: allwith no group bindings — there is no need to police who may reach them, since users from the other side have no account here at all.Datasets migration is staged, not switched
The FuzeFront-side datasets provider is left untouched and serving traffic. Retiring it before MendysRobotics repoints its issuer would black out datasets sign-in, and deleting the blueprint file alone would not remove the objects anyway — that needs an explicit
state: absentpass. Both copies coexist safely: different instances, different databases, so the sharedclient_iddoes not collide.Accounts do not migrate. Existing datasets users live in the FuzeFront directory and have no account in the silo until they enroll there.
Verification
helm lintclean.kubeconform -strict -ignore-missing-schemas: 16/16 valid, 0 invalid (1 skip = Traefik CRD).!Env/!Findtags; provider attributes asserted against the spec above.checksum/blueprintsand would have rolled the live single-replica IdP, so it was reverted.)One bug caught during review: the new provider initially omitted
grant_types. On authentik 2026.x a freshly-created provider without it rejects every authorize request (Invalid grant_type) — the client would have been dead on arrival. Fixed; both providers now assert[authorization_code, refresh_token].Follow-ups (deliberately not in this PR)
https://auth.fuzefront.com/application/o/mendys-platform/points at the FuzeFront instance, a different directory. The Mendys side must repoint.authentikMendys.ingressis off by default because FuzeFront deliberately has no public IdP host. Preferred option is an/api/auth/idp/*proxy path on the MendysRobotics ingress; the alternative is a publicauth.mendysrobotics.combehind Cloudflare Access. See the README.enabledgates (one PR, once the secrets exist).The client secret is not generated here — it must exist only in the destination secret stores. Generate with
openssl rand -hex 32and place the same value inMENDYS_PLATFORM_CLIENT_SECRET(this chart) andMENDYS_AUTHENTIK_CLIENT_SECRETinmendys-secrets(namespacemendys-prod). Note blueprints stampclient_secretonly at provider creation — rotation means deleting and re-applying the provider entry.🤖 Generated with Claude Code