cluster:Delete and a KRN like krn:vks:supervisor:<supervisor>:cluster:<cluster> — and those two are checked against the policies attached to your groups. This page explains that reduction and the matching rules behind it. For setting OIDC up, see Authentication & IAM; for the full action list, see Permissions reference.
From request to decision
1
Skip list
A small set of routes never reaches IAM at all: the health check, the four
/auth/* endpoints, and everything under /api/iam/me/ (your own permissions, groups, and API tokens — self-service by definition). The MCP endpoint under /mcp is also skipped here because it authorizes per tool on re-dispatch.2
Route lookup
The request’s method and path are matched against the route map, whose keys are chi-style patterns such as
GET /api/supervisors/{name}/summary. A {placeholder} segment matches any single segment; the number of segments must match exactly.3
KRN resolution
The matched entry carries a KRN template. Placeholders are filled from the path —
{name} from the supervisor segment, {cluster} from the cluster segment, and so on. {?supervisor} is filled from the ?supervisor query parameter instead.4
Evaluation
The action and the resolved KRN are checked against every statement in every policy attached to your groups.
Unmapped routes
If no entry in the route map matches, the request is denied outright whenIAM_ENABLED=true. The response names the reason:
IAM_ENABLED=false, the same request is logged and allowed.
Actions
An action isservice:Verb — cluster:List, vm:Start, iam:CreatePolicy. Policy statements match them three ways:
There is no partial-verb wildcard:
cluster:Get* is not a pattern, it is a literal that will never match.
KRNs
A KRN is colon-separated segments after the fixedkrn:vks: prefix, alternating type and identifier:
Matching rules
A trailing * matches everything remaining
A trailing * matches everything remaining
krn:vks:supervisor:* matches krn:vks:supervisor:prod and krn:vks:supervisor:prod:cluster:web. A trailing wildcard is not “one more segment” — it is “the rest of the KRN, however deep”.This is the rule most likely to surprise you. A statement meant to grant supervisor-level reads also covers every cluster, VM, gateway, and pool beneath that supervisor.A * in the middle matches exactly one segment
A * in the middle matches exactly one segment
krn:vks:supervisor:*:cluster:* matches any cluster on any supervisor. The first * consumes exactly the supervisor name.Segment counts must otherwise match
Segment counts must otherwise match
Without a trailing wildcard, a pattern only matches a KRN with the same number of segments.
krn:vks:supervisor:prod does not match krn:vks:supervisor:prod:cluster:web — grant the cluster resource explicitly, or use a trailing wildcard.Prefix wildcards work inside a segment
Prefix wildcards work inside a segment
prod-* matches prod-cluster-1. So krn:vks:supervisor:*:cluster:prod-* scopes a policy to clusters whose names start with prod-, on any supervisor.Policy documents
effect of exactly Allow or Deny, at least one action, and at least one resource.
Evaluation order
1
Start denied
With nothing matching, the answer is no.
2
Any matching Deny ends it
The first statement that matches both the action and the resource with
effect: Deny returns denied immediately — no later Allow can override it, regardless of which policy or group it came from.3
Otherwise, a matching Allow wins
If any statement matched with
effect: Allow and nothing denied, the request proceeds.Deny in one attached policy will override a narrow Allow in another. That is the intended way to carve exceptions out of K8sGateAdmin-shaped grants.
Where your policies come from
Your effective policy set is the union of the policies attached to every group you belong to. You belong to a group when either is true:- The group’s mapped OIDC group value exactly equals one of the values in your token’s claim (
groupsorroles, perOIDC_MAPPING_SOURCE). - Your email is on the group’s manual member list.
Group and policy data is cached and refreshed on a 30-second loop. An IAM change can take up to half a minute to take effect for an already-signed-in user. Changes to the user’s own claims require a fresh sign-in, since groups come from the token.
Enforcement modes
Set
IAM_DEBUG=true to log each check with the resolved action, KRN, and the statement that matched. It is the fastest way to answer “why was this denied” — the log names whether it was an explicit deny or the default deny, and how many policies were in play.
Audit trail
The resolved action and KRN are attached to the request before the handler runs, so the audit log records what was attempted in the same vocabulary policies are written in. Mutating requests are recorded with user, action, resource, status, and duration, and are browsable at/audit-logs with the audit-log:List permission.
Related
Permissions reference
Every action, grouped by service, with its KRN shape.
Authentication & IAM
OIDC setup, built-in policies, and the first-admin bootstrap.
Supervisors & clusters
Why supervisor names appear inside KRNs.
Environment variables
IAM_ENABLED, IAM_DEBUG, and the OIDC claim settings.