The Authentik API token used by estate automation was created by hand in the
UI and pasted into Vault, so it was undocumented, unauditable and impossible
to rotate reproducibly. Model it as config instead.
Add a service_accounts config kind, discovered from config/service_accounts/
like the other kinds. Each entry creates a service_account user, an RBAC role
carrying its global permissions, its API tokens, and (optionally) a kv-v2
write publishing each token key.
Add sa-agent-api granting view_outpost, view_token and view_token_key, with a
non-expiring api token agent-api-token published to kv/service/authentik/agent-api-token.
Keep local/default terragrunt runs pointed at the real public URL;
set the goauthentik#954 ClusterIP workaround via TF_VAR_authentik_url
in the CI environment blocks instead of as a terragrunt input.
Parameterise the authentik provider url as var.authentik_url (default:
the environment's public URL) and override it for
identity.k8s.syd1.au.unkin.net to
http://authentik-server.authentik.svc.cluster.local. Combined with
sessionAffinity: ClientIP on the Service, in-cluster CI runs pin to a
single server replica, eliminating the cross-replica read-back race
(goauthentik/terraform-provider-authentik#954).
Introduce a user -> role -> [permissions] model for app access and roles,
managed declaratively.
- Permission groups (akP-<app>-<access>) under config/permissions/: atomic units,
each names the application it grants access to.
- Role groups (akR-<role>) under config/roles/: what users are assigned to;
each nests permission groups via parents (akR-global-admin -> all *-admin,
akR-standard-user -> all *-user). Split into a separate authentik_group
resource so roles can reference permission ids without self-reference.
- Policy bindings gate each application to its permission groups (and, via
child->parent membership propagation, the roles that nest them).
- Hierarchical `groups` scope mapping: walks user groups up through .parents so
the OIDC claim includes inherited permission groups (works around
goauthentik/authentik#15579). Inert until a provider requests the `groups`
scope, so no behaviour change to existing apps until they opt in.
Validated with `tofu validate`.
The CI VAULT_TOKEN (short-lived k8s-auth role token) can't create child
tokens, so the vault provider failed with 'failed to create limited child
token: permission denied'. Use the token directly.
The module's versions.tf and the root.hcl-generated backend.tf both
declared required_providers, which OpenTofu rejects ("A module may have
only one required providers configuration"), so terragrunt init/plan
failed. Keep them in the module's versions.tf (authentik + vault) and
generate only the backend + provider blocks.
Adds an OIDC provider + application so the in-cluster Grafana
(grafana.k8s.syd1.au.unkin.net) can authenticate users against Authentik.
Extends the oauth2 module so provider config stays declarative and
secret-free:
- Resolve authorization/invalidation flows by slug (data.authentik_flow)
and scope mappings by managed identifier
(data.authentik_property_mapping_provider_scope).
- Read client_secret from Vault kv-v2 (data.vault_kv_secret_v2) instead of
committing it; adds the hashicorp/vault provider (auth via VAULT_ADDR/
VAULT_TOKEN from the Makefile).
- Support allowed_redirect_uris on the oauth2 provider.
config/providers_oauth2/grafana.yaml wires client_id `grafana`, the
openid/email/profile scopes, the login/generic_oauth redirect URI, and
points client_secret at kv/kubernetes/namespace/grafana/default/oauth-credentials.
- Terraform module for groups, SAML/OAuth2/LDAP providers, applications, and LDAP outposts
- Data-driven YAML config with Terragrunt config loader
- Environment: identity.unkin.net with Consul backend
- Provider: goauthentik/authentik 2026.5.0
- Woodpecker CI pipelines (pre-commit, plan, apply)
- Makefile with Vault AppRole and K8s auth support