Add two-tier RBAC: permission/role groups, access policies, hierarchical group claim #7

Merged
benvin merged 2 commits from benvin/rbac-groups into main 2026-07-19 02:13:29 +10:00
Owner

Why

Establishes a user → role → [permissions] model to manage app access and roles from Authentik, per the akR-/akP- convention.

What it adds

  • Permission groups akP-<app>-<access> (config/permissions/): atomic units, each names the application it grants access to. 6 groups (grafana/argocd/rancher × admin/user).
  • Role groups akR-<role> (config/roles/): what you assign users to; each nests permission groups via parents. akR-global-admin → all *-admin; akR-standard-user → all *-user. (Separate authentik_group resource so roles can reference permission ids without the self-reference error.)
  • Access policy bindings: gate each app to its permission groups. Authentik ORs bindings and propagates membership child→parent, so role members are covered.
  • Hierarchical groups scope mapping: walks user.ak_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 existing apps are unaffected until they opt in.

How membership works

Assign a user to one role (e.g. akR-global-admin) → they inherit every permission it nests → access to every app + the mapped admin/user role.

Validation

tofu validate passes (all resource types/attributes confirmed against the provider). Live plan will run in CI.

⚠️ Rollout / lockout note

The policy bindings gate all three apps on apply — only members of the akP groups (incl. via roles) can SSO in. The groups are created empty, so add yourself to akR-global-admin in the Authentik UI right after apply (each app still has its local-admin fallback, so this is recoverable, not a hard lockout).

Required follow-ups (roles don't fully take effect until these)

For inherited roles to reach each app, each app must request the groups scope and key its RBAC off the akP-* names:

  • argocd-apps: argocd-cm requestedScopes add groups; argocd-rbac-cm map akP-argocd-admin→role:admin (replaces argocd-admins).
  • argocd-apps (grafana): add groups scope; role_attribute_pathakP-grafana-admin.
  • terraform-rancher: role bindings on the akP-rancher-* principals.
  • Later: remove the now-obsolete argocd-admins group.
## Why Establishes a **user → role → [permissions]** model to manage app access and roles from Authentik, per the akR-/akP- convention. ## What it adds - **Permission groups** `akP-<app>-<access>` (`config/permissions/`): atomic units, each names the application it grants access to. 6 groups (grafana/argocd/rancher × admin/user). - **Role groups** `akR-<role>` (`config/roles/`): what you assign users to; each nests permission groups via `parents`. `akR-global-admin` → all `*-admin`; `akR-standard-user` → all `*-user`. (Separate `authentik_group` resource so roles can reference permission ids without the self-reference error.) - **Access policy bindings**: gate each app to its permission groups. Authentik ORs bindings and propagates membership child→parent, so role members are covered. - **Hierarchical `groups` scope mapping**: walks `user.ak_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 existing apps are unaffected until they opt in. ## How membership works Assign a user to **one** role (e.g. `akR-global-admin`) → they inherit every permission it nests → access to every app + the mapped admin/user role. ## Validation `tofu validate` passes (all resource types/attributes confirmed against the provider). Live `plan` will run in CI. ## ⚠️ Rollout / lockout note The policy bindings **gate all three apps on apply** — only members of the akP groups (incl. via roles) can SSO in. The groups are created empty, so **add yourself to `akR-global-admin` in the Authentik UI right after apply** (each app still has its local-admin fallback, so this is recoverable, not a hard lockout). ## Required follow-ups (roles don't fully take effect until these) For inherited roles to reach each app, each app must request the `groups` scope and key its RBAC off the `akP-*` names: - **argocd-apps**: argocd-cm `requestedScopes` add `groups`; argocd-rbac-cm map `akP-argocd-admin`→role:admin (replaces `argocd-admins`). - **argocd-apps (grafana)**: add `groups` scope; `role_attribute_path` → `akP-grafana-admin`. - **terraform-rancher**: role bindings on the `akP-rancher-*` principals. - Later: remove the now-obsolete `argocd-admins` group.
unkinben added 1 commit 2026-07-18 16:11:58 +10:00
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
1dab2ecc6f
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`.
unkinben added 1 commit 2026-07-18 16:19:36 +10:00
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
805ea48a36
- 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.
unkinben force-pushed benvin/rbac-groups from bc6b88418d to 805ea48a36 2026-07-18 16:19:36 +10:00 Compare
benvin merged commit 14ad52b835 into main 2026-07-19 02:13:29 +10:00
benvin deleted branch benvin/rbac-groups 2026-07-19 02:13:29 +10:00
Sign in to join this conversation.