-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Spec: End-to-End Managed Auth (Dex + Authentik + Kubernetes RBAC)
Goal
Provide an AWS-IAM-like authorization experience for Aphex-managed Kubernetes clusters, where:
- Humans authenticate via Authentik SSO through Dex (OIDC).
- Dex issues OIDC tokens containing org/team group claims.
- Kubernetes API server validates tokens and derives user + groups.
- Kubernetes RBAC enforces access to namespaces via RoleBindings.
- Platform defines reusable “managed policies” as ClusterRoles.
- 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:fooaphex: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-viewaphex-org-editaphex-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>orpipe-<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-editexists in that namespace - It binds group
aphex:org:<orgName>to ClusterRoleaphex-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.ioThis 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=trueaphex.io/orgpresent
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
groupsclaim)
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 -Aonly 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
-
User in Authentik org group
aphex:org:foocan access:kubectl get pods -n org-fookubectl get pods -n <foo pipeline namespace>
-
User cannot access namespaces of other orgs:
kubectl get pods -n org-bar→ Forbidden
-
Creating a new pipeline namespace automatically grants access to the owning org without manual RBAC updates.
-
kubectl get pods -Aonly returns resources from namespaces the user is authorized for. -
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.