Skip to content

Spec: End-to-End Managed Auth (Dex + Authentik + Kubernetes RBAC) #9

@bdchatham

Description

@bdchatham

Spec: End-to-End Managed Auth (Dex + Authentik + Kubernetes RBAC)

Goal

Provide an AWS-IAM-like authorization experience for Aphex-managed Kubernetes clusters, where:

  1. Humans authenticate via Authentik SSO through Dex (OIDC).
  2. Dex issues OIDC tokens containing org/team group claims.
  3. Kubernetes API server validates tokens and derives user + groups.
  4. Kubernetes RBAC enforces access to namespaces via RoleBindings.
  5. Platform defines reusable “managed policies” as ClusterRoles.
  6. When the platform creates namespaces for an org/team, it automatically “attaches” those managed policies via RoleBindings.

This ensures users can only view and modify resources owned by their org, enforced natively by Kubernetes.


Architecture Summary

Control Plane Components

  • Authentik: Source of truth for users, org/team membership, groups.
  • Dex: OIDC broker/issuer for Kubernetes; forwards Authentik identity + groups.
  • Kubernetes API Server: Authenticates JWT tokens (OIDC) and authorizes requests via RBAC.
  • Aphex Controllers: Create namespaces + enroll RBAC bindings automatically.

Identity and Authorization Model

A. Human Identity (SSO)

Humans authenticate using Authentik, brokered by Dex.

Dex issues a JWT containing:

  • sub (user identifier)
  • email (optional)
  • groups (critical for RBAC mapping)

Example token claim:

{
  "email": "user@example.com",
  "groups": [
    "aphex:org:foo",
    "aphex:org:bar"
  ]
}

B. Org Group Naming Convention

All org membership must be represented as Kubernetes group strings:

  • aphex:org:<orgName>

Example:

  • aphex:org:foo
  • aphex:org:archon

Authentik is the source of truth for these groups.

Dex must forward them into the issued token.


Managed Policies (RBAC Permission Bundles)

ClusterRoles (Managed Policies)

Platform defines reusable permission sets as ClusterRoles:

  • aphex-org-view
  • aphex-org-edit
  • aphex-org-admin (optional)

These ClusterRoles define verbs/resources, but grant no access until bound.

This is equivalent to AWS “managed IAM policies.”


Namespace Ownership Model

Namespace Label Contract

All namespaces created/managed by Aphex must include:

  • aphex.io/org=<orgName>
  • aphex.io/managed=true

This applies to:

  • Org namespaces (org-<orgName>)
  • Pipeline namespaces (<pipelineName> or pipe-<pipelineName>)

This label is the platform’s ownership contract.


Policy Attachment (RoleBindings)

RoleBindings Per Namespace

When a namespace is created for org <orgName>, the platform must ensure:

  • RoleBinding aphex-org-edit exists in that namespace
  • It binds group aphex:org:<orgName> to ClusterRole aphex-org-edit

Example:

kind: RoleBinding
metadata:
  name: aphex-org-edit
  namespace: <namespace>
subjects:
- kind: Group
  name: aphex:org:<orgName>
roleRef:
  kind: ClusterRole
  name: aphex-org-edit
  apiGroup: rbac.authorization.k8s.io

This is equivalent to “attaching a managed IAM policy to a principal,” but scoped to a namespace.


Namespace Enrollment Automation

Requirement: Automatic Enrollment

When new namespaces are created dynamically, RBAC must be attached automatically.

Two supported implementation options:

Option A: Controllers stamp RBAC on namespace creation

When RepoBinding controller creates the pipeline namespace:

  • add org label
  • create RoleBindings

Option B: Dedicated Namespace Enrollment Controller (preferred)

A small controller watches Namespaces with:

  • aphex.io/managed=true
  • aphex.io/org present

Then it ensures RoleBindings exist.

This guarantees any Aphex-created namespace becomes accessible to the owning org immediately.


End-to-End Request Flow

1. User authenticates

  • User runs kubectl
  • kubectl triggers OIDC login against Dex
  • Dex redirects to Authentik
  • Authentik authenticates the user (SSO/MFA/etc)

2. Dex issues JWT token

Dex issues an OIDC token containing:

  • identity claims
  • group membership claims (groups)

3. User calls Kubernetes API

kubectl calls kube-apiserver with:

Authorization: Bearer <jwt>

4. kube-apiserver authenticates

API server verifies:

  • JWT signature
  • issuer = Dex
  • audience = kubernetes

Then it derives:

  • username
  • groups (from groups claim)

5. kube-apiserver authorizes via RBAC

RBAC checks if any RoleBinding exists in the namespace that matches:

  • user
  • or one of the user’s groups

If user is in group aphex:org:foo, and the namespace has RoleBinding binding that group to ClusterRole aphex-org-edit, the request is allowed.

Otherwise:

  • request is rejected as Forbidden
  • or resources are not visible (e.g. kubectl get pods -A only returns allowed namespaces)

Workload Identity (ServiceAccounts)

Workloads do not use Dex/Authentik.

Workloads authenticate via Kubernetes-native ServiceAccount tokens.

  • Pod runs as ServiceAccount pipeline-runner
  • RoleBinding grants SA permissions in namespace
  • API server validates SA token and applies RBAC

Humans and workloads share the same RBAC engine, but have different identity issuers.


Controller Permissions

Controllers responsible for namespace creation/enrollment require cluster-level privileges:

  • create/update namespaces
  • create/update RoleBindings in namespaces
  • read ClusterRoles

Humans should never require ClusterRoleBindings.


Acceptance Criteria

  1. User in Authentik org group aphex:org:foo can access:

    • kubectl get pods -n org-foo
    • kubectl get pods -n <foo pipeline namespace>
  2. User cannot access namespaces of other orgs:

    • kubectl get pods -n org-bar → Forbidden
  3. Creating a new pipeline namespace automatically grants access to the owning org without manual RBAC updates.

  4. kubectl get pods -A only returns resources from namespaces the user is authorized for.

  5. Platform RBAC permissions are defined once as ClusterRoles and reused everywhere via RoleBindings.


Key Invariants

  • Authentik is the source of truth for org membership.
  • Dex is the issuer of tokens Kubernetes trusts.
  • Kubernetes API server is the enforcement point.
  • Namespace is the security boundary.
  • ClusterRoles are “managed policies.”
  • RoleBindings are “policy attachments.”
  • Aphex controllers are responsible for enrolling namespaces into RBAC automatically.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions