The apiserver's live OIDC config still pointed at
https://authentik.riotpiao.com/application/o/kubernetes/. Authentik now runs
zero pods, so that issuer cannot be discovered and every attempt to login with
a token instead of a client certificate fails. The template itself carried no
OIDC block at all, so a render would have removed the stale config rather than
replace it.
Add the ZITADEL issuer, the `kubernetes` client id, and the groups/username
claims. Three details had to be verified against a real token first:
1. The issuer is https://zitadel.riotpiao.com with no trailing slash and no
/application/o/<app>/ suffix. That suffix belonged to the Authentik scheme;
the apiserver compares `iss` by exact string equality.
2. ZITADEL does NOT put profile/email claims in the id_token by default, so
`oidc-username-claim: email` resolved to nothing. idTokenUserinfoAssertion is
now enabled on the `kubernetes` application.
3. ZITADEL asserts roles as a nested urn claim the apiserver cannot read. The
`groupsClaim` action (created alongside this change) mirrors the bare role
names into a flat `groups` claim.
Verified with a full PKCE authorization-code flow against this client: the
id_token carries iss=https://zitadel.riotpiao.com, email, preferred_username and
groups=[homelab-admins, ...]. With oidc-groups-prefix=oidc: that maps to the
existing ClusterRoleBinding homelab-admin-oidc, which grants cluster-admin.
The issuer hostname is pinned in extraHostEntries because the apiserver's static
pod resolves through the node's DNS, not cluster CoreDNS; the ingress
LoadBalancer serves the publicly-trusted Let's Encrypt wildcard certificate.
Client-certificate auth is unchanged, so a wrong value degrades OIDC logins
without locking anyone out.
The live cluster has no Authentik workload, no DNS record and no tunnel route,
but two declarations still pointed at it.
controlplane.tftpl still set kube-apiserver oidc-issuer-url to
https://authentik.riotpiao.com/application/o/kubernetes/ and pinned that hostname
in extraHostEntries. The live API server carries zero OIDC arguments, so the
template and reality had diverged: the next machine-config render would have
re-added an issuer that does not resolve.
management-service exported KMSVC_AUTHENTIK_ISSUER_URL and
KMSVC_AUTHENTIK_AUDIENCE, both empty. Rename them to KMSVC_ZITADEL_* so the names
describe the identity provider that actually exists.
The CoreDNS Corefile kept one rewrite for authentik.riotpiao.com. The Terraform
source file no longer contains it, so the live ConfigMap was stale; that line is
removed live and the next render converges without it.
Adds permissions claim + per-service admin groups in Authentik, scoped
Role/RoleBinding per service, public PKCE kubernetes OAuth2 client, and
kube-apiserver OIDC extraArgs. Also fixes paperless OIDC signup permissions
via adapter override and adds CoreDNS rewrite for authentik.riotpiao.com.
Fixes controlplane.tftpl's install.wipe:true (should be false, live CPs already run false) and syncs coredns Corefile back to what's actually deployed (drops an unrolled-out, stale Kong-era rewrite).
Adds optional cloudflare_talos_sans (machine.certSANs, talos API :50000) and
cloudflare_apiserver_sans (cluster.apiServer.certSANs, kube-apiserver :6443) per
control-plane node. cp-1 gets cp1.homelab + cp1-talos.homelab; cp-2/cp-3 get
their cpN-talos.homelab. Values set in gitignored tfvars.
Consolidate three separate Forgejo Actions (argocd-sync, security-scan, validate-k8s) into single cluster-ci workflow for cleaner CI/CD pipeline with proper job sequencing and reduced auth overhead.
Add Terraform configuration for Talos cluster machine configs:
- Provider setup for Talos
- Centralized variables for CP and worker configs
- Template-based config generation for controlplane.yaml and worker-*.yaml
- Sensitive data separated in terraform.tfvars (gitignored)
- Local state tracking for infrastructure