Skip to main content
By the end of this page a group of people can operate the project you built for them and nothing else, and you have confirmed that from their side rather than from yours. This is the last station in this sequence, and it is what turns everything before it into someone else’s to run.

What this changes on your cluster

Nothing. IAM lives entirely in Celum’s database — policies, groups, memberships. No cluster object is created, and revoking access is a database change, not a cluster change.

Before you start

  • DATABASE_URL on the backend. IAM is stored there, and without it there is nothing to store policies in.
  • IAM_ENABLED=true. This is the one that catches people out: with it unset the middleware evaluates and logs but allows everything. A carefully scoped policy on a deployment with IAM disabled grants full access, silently.
  • Permissions iam:CreatePolicy, iam:CreateGroup, iam:AttachGroupPolicy, iam:AddGroupMember — all scoped iam:*.

The shape of it

Pick or write a policy → put it on a group → map the group to a claim → verify as the user. The last step is the only one that tells you the truth.

Step 1 — Start from a managed policy if one fits

Six ship with the product and cover most of what people need: Note the split between the third and fourth: reading the platform and downloading credentials for it are deliberately different grants, so “read-only access” does not quietly include handing out a working kubeconfig.
Managed policies are immutable. Update and delete both refuse to touch them. Copy one into a policy of your own if you need a variant — editing in place is not offered, on purpose.
IAM → Policies.
The Policies page listing the six managed policies K8sGateAdmin, K8sGateClusterDeleteBypass, K8sGateDeleteApprover, K8sGateOperator, K8sGateSensitiveRead and K8sGateViewer, each marked Managed, with IAM enforcement shown as Enforcing

IAM → Policies on a new installation: the six managed policies

Step 2 — Write the resource, and count the segments

A statement pairs an action with one or more KRNs. The grammar has one rule that causes nearly every “my policy does nothing” report:
A KRN matches on an exact segment count unless it ends in *. krn:celum:supervisor:prod:cluster:* matches clusters on prod — it does not match krn:celum:supervisor:prod:cluster:web:helm-release:x, which has more segments. Matching compares segment by segment and a different count simply returns false, with no error anywhere.A policy written one segment short of the resource it meant to cover denies everyone and says nothing.
Useful shapes:
Evaluation is AWS-shaped and worth stating once: default deny → an explicit Deny wins immediately → otherwise an Allow grants → otherwise denied. A Deny anywhere in any attached policy ends the question.

Step 3 — Create the group and map it to a claim

A group is how people reach a policy. It carries either an OIDC claim value or an explicit member list.
IAM → Groups → attach policies, add members.
The Groups page with one group, Administrators, mapped to the OIDC group celum-admins, with one policy attached and an edit and a delete action

IAM → Groups: each group shows the claim value it matches

The claim the group matches against depends on how the backend is configured — security-group ids by default, or App Role values when the deployment maps roles instead. Whichever it is, the value in the group must match the token exactly; there is no normalisation.
Attaching a policy, adding a member and updating the group are three separate permissions. An identity holding only one of them can complete part of a change and have the rest silently dropped — so grant the set, or expect partial results.

Verify — as the user, not as yourself

This is the step that matters, and the product provides it because reading your own policy document proves nothing about how it evaluates.
IAM → My Profile shows the signed-in user their own effective permissions and groups.
My Profile showing the signed-in user, the OIDC groups from the token (authentik Admins and celum-admins, the second highlighted as matched), and the matched IAM group Administrators via oidc

IAM → My Profile: the claim values in the token, and the IAM groups they matched

Have someone from the team sign in and read it. Two failures show up here and nowhere else: a claim value that does not match, and a KRN with the wrong segment count. Both look like a correct policy from the authoring side. Then have them do the actual thing — create a VM in their project, publish it. A permission that evaluates correctly and still refuses the real request usually means the route is authorised against a resource shape the policy did not anticipate.

If you need to undo it

Remove the member, detach the policy, or delete the group — iam:RemoveGroupMember, iam:DetachGroupPolicy, iam:DeleteGroup. Access ends at the next evaluation; nothing on any cluster changes. Deleting a policy that groups still reference removes the grant from all of them at once. Detaching from one group is the narrower action, and usually the one you meant.

What commonly goes wrong

Next

Permissions model

How a request becomes an action and a KRN, and why an unmapped route is denied.

Permissions reference

Every action Celum defines, with the KRN each is checked against.

Authentication & IAM

The sign-in half — OIDC, sessions, and claim mapping.

Projects

The boundary most delegations are scoped to.