Commit Graph

41 Commits

Author SHA1 Message Date
benvin ecfdf69d52 Merge pull request 'Add Gitea OAuth2/OIDC provider' (#13) from benvin/gitea-oidc into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #13
2026-07-30 21:09:05 +10:00
unkinben 0ba2785eb5 Add Gitea OAuth2/OIDC provider + application
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Register the k8s Gitea forge as an Authentik OIDC app so it can use SSO at
cutover. Redirect URIs cover both the temporary git2 validation host and the
final git.unkin.net host so login works across the migration.

- add config/providers_oauth2/gitea.yaml (confidential OAuth2 provider + app,
  client_secret read from kv/kubernetes/namespace/gitea/default/oauth-credentials)

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-29 22:01:58 +10:00
benvin a5a2f467a4 Merge pull request 'Set OAuth2 grant_types so authorization_code login works' (#12) from benvin/oauth2-grant-types into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #12
2026-07-28 22:38:57 +10:00
unkinben 2b39450ae2 Set OAuth2 grant_types so authorization_code login works
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
## Why

All Authentik OIDC logins (ArgoCD, Grafana, Rancher, LiteLLM, NetBox) fail
with `invalid_request` / "The request is otherwise malformed". Authentik
2026.5 added an explicit `grant_types` allow-list to the OAuth2 provider
(model default = empty list). Our module never set it, so every provider has
`grant_types = []`, and `authorize.py` rejects the authorization_code grant
(`if self.grant_type not in self.provider.grant_types`) before any user auth.

## Change

- modules/authentik: add a `grant_types` field to the `providers_oauth2`
  variable, defaulting to `["authorization_code", "refresh_token"]` (the
  standard confidential web-app set), and wire it into
  `authentik_provider_oauth2`.

## Plan

`0 to add, 5 to change, 0 to destroy` — each existing oauth2 provider's
`grant_types` goes `[] -> ["authorization_code", "refresh_token"]`; no other
attributes change. Baseline plan (pre-change) was clean (no netbox/state drift).

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-28 22:09:06 +10:00
benvin 21ef853a7c Merge pull request 'Add NetBox OAuth2/OIDC provider + application' (#11) from benvin/netbox-oidc into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #11
2026-07-28 18:06:26 +10:00
unkinben e8d0457f00 ci: re-run after authentik api recovery
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
The plan step failed on transient authentik API 500s while refreshing
unrelated existing applications; the API is healthy again (200).

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-28 17:48:03 +10:00
unkinben 7d0b8416a7 Re-trigger CI after seeding netbox oauth-credentials in Vault
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline failed
The plan step reads the netbox client_secret from Vault at plan time; it now
exists at kv/kubernetes/namespace/netbox/default/oauth-credentials.

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-28 16:49:42 +10:00
unkinben 8fa4192cc6 Add NetBox OAuth2/OIDC provider + application
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline failed
NetBox is being deployed to k8s (argocd-apps) with Authentik SSO via
python-social-auth's OpenIdConnectAuth backend. Add the confidential OAuth2
provider/application (client_id netbox, openid/email/profile scopes, strict
redirect to /oauth/complete/oidc/); the client_secret is read from Vault at
kubernetes/namespace/netbox/default/oauth-credentials (the terraform-authentik
runner policy already covers namespace/+/default/oauth-credentials).

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-28 16:44:52 +10:00
benvin 90e0ff1f6a Merge pull request 'Add Ceph dashboard SAML provider' (#9) from benvin/ceph-saml into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #9
2026-07-24 22:41:52 +10:00
benvin bd2ead5855 Merge branch 'main' into benvin/ceph-saml
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
2026-07-24 22:16:29 +10:00
benvin 70c1d4f6ba Merge pull request 'Add LiteLLM RBAC: akP-litellm groups + role claim mapping' (#10) from benvin/litellm-rbac into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #10
2026-07-19 22:00:59 +10:00
unkinben 7610627168 Add LiteLLM RBAC: akP-litellm groups + role claim mapping
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Bring LiteLLM into the two-tier RBAC and map groups to LiteLLM roles.

- akP-litellm-admin / akP-litellm-user permission groups (bound to the litellm
  app for access); added to akR-global-admin / akR-standard-user roles.
- Generic per-provider role_mappings: emit an app role claim computed from
  effective (hierarchical) group membership. LiteLLM: emits `litellm_role`
  (proxy_admin for akP-litellm-admin, internal_user for akP-litellm-user, else
  internal_user_view_only); LiteLLM reads it via GENERIC_USER_ROLE_ATTRIBUTE.

Validated: plan 5 to add, 3 to change; generated role expression renders correctly.
2026-07-19 18:42:36 +10:00
benvin a7ef454fba Merge pull request 'Add LiteLLM OAuth2/OIDC provider' (#8) from benvin/litellm-oidc into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #8
2026-07-19 18:27:12 +10:00
unkinben 9c5937776e Add Ceph dashboard SAML provider
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline failed
Ceph dashboard SSO is SAML 2.0 (no native OIDC), so onboard it via an Authentik
SAML provider + application. Also resolve SAML authorization/invalidation flows
by slug and the signing keypair by name (mirrors the oauth2 handling), since the
SAML path had not been exercised before.

- config/providers_saml/ceph.yaml: SP entity id/ACS derived from the dashboard
  base URL (audience .../auth/saml2/metadata, acs .../auth/saml2, HTTP-POST),
  signed with the built-in self-signed keypair.

Ceph side (separate, Puppet): ceph dashboard sso setup saml2
  https://dashboard.ceph.unkin.net <authentik-idp-metadata-url>

Validated with `terragrunt plan`: 2 to add (provider + application).
2026-07-19 02:22:23 +10:00
unkinben 9098c7dcfc Add LiteLLM OAuth2/OIDC provider
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
SSO for LiteLLM (litellm.k8s.syd1.au.unkin.net) via Authentik generic OIDC.
Confidential OAuth2 provider + application, openid/email/profile scopes,
/sso/callback redirect. client_secret read from Vault at
kv/kubernetes/namespace/litellm/default/oauth-credentials (seeded).
2026-07-19 02:19:19 +10:00
benvin 14ad52b835 Merge pull request 'Add two-tier RBAC: permission/role groups, access policies, hierarchical group claim' (#7) from benvin/rbac-groups into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #7
2026-07-19 02:13:28 +10:00
unkinben 805ea48a36 Derive group name from filename; use distinct ak_groups claim
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
- Permission/role group name now comes from the config filename (the map key),
  dropping the redundant `name` field from each YAML and the object types.
- The hierarchical mapping emits an `ak_groups` claim (scope `ak_groups`) instead
  of `groups`, so it never collides with the direct-groups the default profile
  mapping already emits under `groups` (Authentik overrides same-key claims in an
  unpredictable order). Apps request the `ak_groups` scope and read that claim.
2026-07-18 16:19:34 +10:00
unkinben 1dab2ecc6f Add two-tier RBAC: permission/role groups, access policies, group claim
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
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`.
2026-07-18 16:11:39 +10:00
benvin 55ba291531 Merge pull request 'Add Rancher OAuth2/OIDC provider' (#6) from benvin/rancher-oidc into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #6
2026-07-16 22:23:34 +10:00
unkinben 58e17d5ae8 Add Rancher OAuth2/OIDC provider
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Extends Authentik SSO to Rancher (rancher.k8s.syd1.au.unkin.net) so cluster
access uses Authentik identity and groups.

- Add config/providers_oauth2/rancher.yaml: confidential OAuth2 provider +
  application (slug rancher), openid/email/profile scopes, /verify-auth
  redirect (Rancher's OIDC callback). client_secret read from Vault at
  kv/kubernetes/namespace/cattle-system/default/oauth-credentials.
2026-07-15 20:59:38 +10:00
benvin 4dadd1f4ab Merge pull request 'Add ArgoCD OAuth2/OIDC provider' (#3) from benvin/argocd-oidc into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #3
2026-07-12 23:04:47 +10:00
benvin a6dca8eb96 Merge branch 'main' into benvin/argocd-oidc
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
2026-07-12 23:02:21 +10:00
benvin 3af322dff3 Merge pull request 'Fix perpetual redirect_uri drift on oauth2 providers' (#5) from benvin/fix-redirect-uri-type into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #5
2026-07-12 23:02:09 +10:00
unkinben c62fdb574a Add argocd-admins group
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Declaratively manage the group that argocd-rbac-cm maps to role:admin, so
onboarding ArgoCD SSO does not require creating the group by hand in the UI.
2026-07-12 22:58:32 +10:00
unkinben 1fc0b70e1a Add ArgoCD OAuth2/OIDC provider
Extends Authentik SSO to ArgoCD so cluster operators log in with their
Authentik identity and group membership instead of the local admin account.

- Add config/providers_oauth2/argocd.yaml: confidential OAuth2 provider +
  application (slug argocd), client_id argocd, openid/email/profile scopes,
  web SSO and CLI (localhost:8085) redirect URIs. client_secret is read from
  Vault at kv/kubernetes/namespace/argocd/default/oauth-credentials, matching
  the existing Grafana pattern.
2026-07-12 22:58:32 +10:00
unkinben 5faa2f84f6 Fix perpetual redirect_uri drift on oauth2 providers
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
authentik_provider_oauth2.allowed_redirect_uris is list(map(string)) and the
API always stores a redirect_uri_type key on each entry. The module only set
matching_mode and url, so every plan showed the Grafana provider being updated
in-place (state map had 3 keys, config map had 2) and never converged.

Add redirect_uri_type to the redirect_uris object, defaulting to
"authorization". `terragrunt plan` now reports no changes.
2026-07-12 22:57:57 +10:00
benvin 58b200c512 Merge pull request 'Fix self-referential authentik_group parents' (#4) from benvin/fix-group-parents into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #4
2026-07-12 22:55:47 +10:00
unkinben 7636d45f21 Fix self-referential authentik_group parents
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Adding the first managed group (argocd-admins) exposed a dormant bug: the
groups resource resolved `parents` by indexing authentik_group.this itself,
which OpenTofu rejects as a self-referential block. config/groups/ had been
empty, so `tofu plan` never hit it before.

Pass `parents` through as literal group PKs instead (the resource cannot
reference itself, so parent-by-map-key was never viable). Plan is clean:
3 to add (argocd provider, application, argocd-admins group).
2026-07-12 22:42:17 +10:00
benvin 9e75f39a06 Merge pull request 'Initial scaffold' (#1) from benvin/initial-scaffold into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #1
2026-07-06 23:52:04 +10:00
benvin 11a25fdca0 Merge pull request 'authentik: add Grafana OAuth2/OIDC provider' (#2) from benvin/grafana-oidc into benvin/initial-scaffold
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Reviewed-on: #2
2026-07-06 23:50:13 +10:00
unkinben 0b1b67fbd5 ci: re-run after vault #82 applied (token + oauth read policy live)
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
2026-07-06 23:44:04 +10:00
unkinben 93742883a5 fix: skip_child_token on vault provider
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was canceled
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.
2026-07-06 23:43:16 +10:00
unkinben d96d36a079 makefile: source TF_VAR_authentik_token from vault (kv/service/terraform/authentik)
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline failed
The authentik provider needs a token but nothing supplied it, so plan
failed with 'No value for required variable authentik_token'. Source it
from Vault in vault_env like the consul creds, from the dedicated
terraform-service path kv/service/terraform/authentik (field: token),
overridable via AUTHENTIK_TOKEN_KV_* vars.
2026-07-06 23:32:21 +10:00
unkinben 41cc0fce8b ci: re-run plan on fixed head (duplicate required_providers resolved)
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline failed
2026-07-06 23:17:37 +10:00
unkinben d1aef45d1d fix: drop duplicate required_providers from generated backend.tf
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was canceled
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.
2026-07-06 23:12:43 +10:00
unkinben 3d7131032f ci: re-run plan after terraform-vault kv policy applied
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline failed
2026-07-06 23:08:03 +10:00
unkinben 97be93a9ff authentik: add Grafana OAuth2/OIDC provider + application
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline failed
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.
2026-07-06 22:06:48 +10:00
unkinben 00a122135e Use identity.k8s.syd1.au.unkin.net as provider endpoint
ci/woodpecker/pr/plan Pipeline failed
ci/woodpecker/pr/pre-commit Pipeline was successful
2026-06-28 12:11:47 +10:00
unkinben 8aa2273dcf Fix provider schema for goauthentik/authentik 2026.5.0
ci/woodpecker/pr/plan Pipeline failed
ci/woodpecker/pr/pre-commit Pipeline was successful
- group: parent → parents (list)
- saml/oauth2: add required invalidation_flow
- oauth2: remove redirect_uris (use allowed_redirect_uris via config)
- ldap: replace authorization_flow/search_group with bind_flow/unbind_flow
- Add versions.tf with required_providers block
- Remove service_connection from outpost (auto-discovered)
2026-06-28 12:04:19 +10:00
unkinben 4042760a16 Initial scaffold
ci/woodpecker/pr/plan Pipeline failed
ci/woodpecker/pr/pre-commit Pipeline failed
- 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
2026-06-28 11:55:26 +10:00
gitadmin 2d87c83ab9 Initial commit 2026-06-28 01:00:14 +10:00