feat(authentik): Gmail login + OIDC providers for the FuzeInfra admin plane - #454
Merged
Conversation
Contributor
Automated code review (gate-code-review)Credit balance is too low Report-only — this check never blocks merge. |
izzywdev
marked this pull request as draft
July 29, 2026 16:33
auto-merge was automatically disabled
July 29, 2026 16:33
Pull request was converted to draft
izzywdev
marked this pull request as ready for review
July 29, 2026 16:56
… plane Makes Authentik usable as the single sign-on for FuzeInfra's admin UIs, so each service stops carrying its own local password. Google sign-in was wired but unreachable. source-google.yaml creates the source and sets its flows, but the login button is rendered from the `sources` M2M on the identification stage — creating a source does not add it there. The new source-google-binding.yaml adds it, keeping authentik-built-in in the list so username/password (the akadmin break-glass) survives. Google-federated users also had nowhere to land: with link_by_email, an email that matches no existing user enrolls as an ordinary account. Since the infra admin's Google address is not the akadmin bootstrap address, signing in with Google produced a powerless second account. groups-fuzeinfra-admins.yaml pre-creates the user in a superuser group so the first Google sign-in links straight into it. provider-oidc-fuzeinfra-admin.yaml adds four OIDC providers — Cloudflare Access (which fronts every *.prod admin tile, including services with no SSO of their own), Grafana, ArgoCD and Kafka UI. All entries live in ONE blueprint so nothing depends on a cross-blueprint !Find, per the concurrent-apply race documented in provider-oidc-mendys-platform.yaml. A dedicated `groups` scope is defined because Grafana and ArgoCD request it by name for role mapping. Also adds the checksum/blueprints annotation the chart never had. Blueprints are discovered at startup, so editing the ConfigMap alone changed nothing and edits sat unapplied — the reason blueprint changes appeared to "fail silently" in prod and had to be pushed through prod-authentik-ops by hand. Client secrets are optional secretKeyRefs and are not minted here. Note the 2024.x runner honours client_secret only at creation time, so the values must be sealed BEFORE the providers are first created. Consumer side: izzywdev/FuzeInfra Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session-Id: 0e31d346-0be5-451a-9c99-c579ce8d4aa6
izzywdev
force-pushed
the
feat/authentik-infra-sso
branch
from
July 29, 2026 16:57
8c3b874 to
edfc0fd
Compare
Contributor
Automated code review (gate-code-review)Credit balance is too low Report-only — this check never blocks merge. |
izzywdev
added a commit
that referenced
this pull request
Jul 29, 2026
… invalidation_flow (#456) * fix(authentik): FuzeInfra OIDC providers were never created — missing invalidation_flow All four providers added in #454 (cloudflare-access, grafana, argocd, kafka-ui) silently failed to apply. invalidation_flow is a REQUIRED field on oauth2provider in Authentik 2024.12, and omitting it fails validation. The failure mode is quiet and misleading. Every provider entry is skipped, the Applications are created with no provider bound, and the only symptom is a 404 from /application/o/<slug>/.well-known/openid-configuration. Meanwhile the other blueprints from the same PR applied fine — the Google sign-in button is live on the login page — so it looked like the blueprints had run when they only half had. Confirmed against prod: /application/o/fuzefront/ and /application/o/mendys-platform/ both return 200 (their blueprints set invalidation_flow); grafana, argocd, kafka-ui and cloudflare-access all returned 404. Referencing default-provider-invalidation-flow is safe despite this file's inline-everything rule: it ships in Authentik's own system blueprints, applied at startup before any custom blueprint, so it is not exposed to the concurrent apply race that rule exists to avoid. Documented in the header so it does not get tidied away again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session-Id: 0e31d346-0be5-451a-9c99-c579ce8d4aa6 * secrets(prod): seal the four FuzeInfra admin-plane OIDC client secrets Adds CF_ACCESS_CLIENT_SECRET, GRAFANA_CLIENT_SECRET, ARGOCD_CLIENT_SECRET and KAFKA_UI_CLIENT_SECRET to fuzefront-secrets, merged in alongside the existing 15 keys. These MUST land in the same change as the provider fix. The Authentik 2024.x blueprint runner honours client_secret only at creation time, so if the providers are created while these keys are absent they are stamped with an empty secret and sealing afterwards does not update them — recovery would mean deleting the provider entries and re-applying. Values are 96-char hex, generated with no trailing newline: seal-secret.sh base64s a KEY=@file value verbatim, so a trailing newline would be sealed INTO the secret while `gh secret set` strips it, silently desynchronising the two sides of the handshake. The consumer halves of the same four values are sealed in izzywdev/FuzeInfra#470. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session-Id: 0e31d346-0be5-451a-9c99-c579ce8d4aa6 * chore(semgrep): exclude SealedSecret manifests from generic-secret detection detected-generic-secret fires on the base64 blobs in spec.encryptedData, which are ciphertext by construction — encrypted against the cluster's published public cert, decryptable only by the in-cluster controller's private key. Being safe to commit is the whole point of Sealed Secrets. It also re-fires on the entire file whenever a diff touches any key, so every routine credential rotation would turn the check red for a false positive. That is a check people learn to ignore, which is worse than no check. Scoped to deploy/contabo/sealed/ only, and the rationale notes the trade-off: a plaintext v1/Secret accidentally committed to THAT directory would no longer be caught by this rule, so it must stay sealed-manifests-only. Detection is unchanged everywhere else. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session-Id: 0e31d346-0be5-451a-9c99-c579ce8d4aa6 --------- Co-authored-by: fuzeone-bot[bot] <fuzeone-bot[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
izzywdev
pushed a commit
that referenced
this pull request
Jul 29, 2026
Resolves the sealed-secret conflict. master (#454/#456, the Authentik OIDC work) rewrote deploy/contabo/sealed/fuzefront-secrets.yaml from JSON to YAML and added four keys — ARGOCD_CLIENT_SECRET, CF_ACCESS_CLIENT_SECRET, GRAFANA_CLIENT_SECRET, KAFKA_UI_CLIENT_SECRET — while this branch had added LITELLM_MASTER_KEY to the old JSON form. Git saw the whole file as rewritten and could not merge it. Resolution: took master's YAML file wholesale (it is the newer canonical format and carries the four new keys), then re-inserted LITELLM_MASTER_KEY in its alphabetical position with the byte-identical ciphertext FuzeInfra sealed for fuzefront/fuzefront-secrets. Verified afterwards: 20 keys, none of the 15 pre-existing ones lost, LITELLM_MASTER_KEY value intact, target still fuzefront/fuzefront-secrets. values-prod.yaml auto-merged cleanly — my edits (chatService.enabled: true, the secret.litellmMasterKey gate, deletion of the orphaned litellm: block) sit alongside master's image-tag bumps to fcf2390 with no overlap. Worth noting: billing-service's tag is now fcf2390 rather than the stale 6135e6b it had been frozen at since 2026-06-30, which confirms the missing bump anchor added in #442 is doing its job.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Makes Authentik usable as the single sign-on for FuzeInfra's admin UIs, and fixes the two reasons Google sign-in has never actually worked.
This is the IdP half and must merge first. Consumer half: izzywdev/FuzeInfra#470.
Google sign-in was wired but unreachable
source-google.yamlcreates the Google OAuth source, setsenabled: true, and configures its flows. But the login button is rendered from thesourcesM2M on the identification stage, and creating a source does not add it there. So the source existed, was enabled, and no user could ever reach it — the comment in that file (# Show a "Sign in with Google" button on the login page) describes an outcome the config does not produce.source-google-binding.yamladds it todefault-authentication-identification.authentik-built-inis kept in the list — the field is a replace, not an append, and dropping it would remove username/password login entirely and strand theakadminbootstrap account.Google users had nowhere to land
With
user_matching_mode: link_by_email, an email matching an existing user links into that account; an unmatched email enrolls a fresh, unprivileged one. The infra admin's Google address is not theakadminbootstrap address (admin@fuzefront.com), so signing in with Google would have produced a powerless second account.groups-fuzeinfra-admins.yamlpre-creates the user in a superuser group, so the first Google sign-in links straight into it. No post-login clickops, and a rebuild from scratch reproduces it. The user has no password, so the account is Google-only.Four OIDC providers for the FuzeInfra admin plane
provider-oidc-fuzeinfra-admin.yamladds Cloudflare Access (which fronts every*.prodadmin tile, including services with no SSO of their own), Grafana, ArgoCD and Kafka UI.All entries live in one blueprint so nothing depends on a cross-blueprint
!Find— per the concurrent-apply race documented inprovider-oidc-mendys-platform.yaml. Entries within a blueprint apply in order, so the shared flow and scope mappings are safe to reference.A dedicated
groupsscope is defined, not just groups-inside-profile: Grafana'srole_attribute_pathand ArgoCD'spolicy.csvboth requestgroupsby name, and without a scope of that name the claim never arrives and every user silently lands on the lowest role.Blueprint changes never rolled the pods
Neither Deployment had a
checksum/blueprintsannotation, even thoughauthentik/ops.py:8states the deployments "roll on blueprint changes via a checksum annotation". Blueprints are discovered at startup, so editing the ConfigMap changed nothing and edits sat unapplied — which is whyprod-authentik-ops.ymldescribes the file-based runner as failing "silently" and exists as a manualworkflow_dispatchescape hatch.Both Deployments now carry the annotation. This is a precondition for everything else in this PR actually applying.
Client secrets
Four optional
secretKeyRefs (CF_ACCESS_CLIENT_SECRET,GRAFANA_CLIENT_SECRET,ARGOCD_CLIENT_SECRET,KAFKA_UI_CLIENT_SECRET) onfuzefront-secrets. Not minted in this PR — seedeploy/sealed-secrets/authentik-oidc-secrets.yaml.templatein FuzeInfra for the sealing runbook.client_secretonly at creation time; if a provider is created while the key is absent it is stamped with an empty secret, and sealing the value later does not update it. Recovery is deleting the provider entry and re-applying.Verified
helm templatewithvalues-prod.yaml: all three blueprints land in the ConfigMap, all four env vars appear on both server and worker, and thechecksum/blueprintsannotation matches across both pod templates.Not verified: nothing applied to the cluster; no live Authentik API call made.
Noticed in passing, not fixed here
MENDYS_DATASETS_CLIENT_SECRETis absent from the prod SealedSecret, so that provider was created with an empty client secret (silent — thesecretKeyRefisoptional).authentik.smtp.hostunset invalues-prod.yaml), so the blueprinted enrollment-verification and recovery email stages cannot deliver.docs/AUTHENTICATION_SETUP.mdandREADME.md:95still describe Authentik as docker-compose + clickops, which has been wrong since the blueprints landed.🤖 Generated with Claude Code