Skip to main content

Per-role Kubernetes Access (kube_spec)

By default, anyone with pc kube access to a cluster gets the cluster-wide read tier (and exec if their role grants kubernetes:execute). A role's kube_spec narrows that down — confining a role to specific namespaces, resources, and verbs, with allow/deny rules. This is how you give one team read-only access to acme-* namespaces while another gets exec into globex-*.

kube_spec is enforced at the in-cluster agent: an out-of-scope request gets a Kubernetes 403 Forbidden before it reaches the apiserver (and an exec/attach is denied before any stream opens). Deny always wins.

Authoring a kube_spec in the role editor

Open Settings → Roles, edit a role, and go to the Resources tab:

  1. Click + Add Resource Access → Kubernetes Access. A collapsible Kubernetes Access block appears (alongside Server Access, if present).
  2. Fill in the Allow (green) and, optionally, Deny (red) sections.
  3. Save. (System roles are read-only here; edit a custom role instead.)

Each side (Allow / Deny) has these fields:

FieldMeaning
Kubernetes groupsThe impersonation tier(s) — a multi-select dropdown of the operator allowlist (PROXIMA_KUBE_ALLOWED_GROUPS, default proxima:kube-readonly / proxima:kube-exec). Verbs are ultimately governed by k8s RBAC via these groups. A custom group appears in the dropdown once an operator adds it.
Kubernetes usersTrait templates for the impersonated audit identity (e.g. {{.email}}). Usually leave empty — the caller's email is used by default.
NamespacesGlobs the caller may act in (acme-*, default, *). Empty ⇒ no namespaced access. A request with no namespace (cluster-wide kubectl get pods -A) requires *.
Cluster labelsRestrict this rule to clusters whose synthesized labels match (env=prod, region=…). Empty ⇒ all clusters the caller can reach.
Resource rulesPer {kind, namespace, verbs}: e.g. allow pods get/list/watch but not secrets. kind is free text (CRDs allowed); verbs are a checkbox set (* = all). When empty, resources are governed by the groups (k8s RBAC) only — the v1 behavior.

YAML mode. The role editor's </> toggle shows the raw role, including kube_spec, if you prefer to edit it as JSON.

Allow vs Deny

The effective access is (union of all allow rules) − (union of all deny rules). Deny always overrides allowallow: { namespaces: ["*"] } with deny: { namespaces: ["kube-system"] } grants every namespace except kube-system. A request must match an allow rule and no deny rule.

The v1 default (no kube_spec)

A role with no kube_spec keeps the original behavior: the read/exec tier (per kubernetes:read / kubernetes:execute) across all namespaces. So you can roll out kube_spec role-by-role without a flag day — unscoped roles are unaffected.

Custom impersonation groups

The Allow/Deny Kubernetes groups field is limited to the operator-configured allowlist. To use a group beyond proxima:kube-readonly / proxima:kube-exec, an operator must add it in two places (a closed allowlist on both ends):

  1. The agent Helm chart value kubeAccess.impersonateGroups (drives the impersonate ClusterRole's resourceNames — the hard backstop on which groups the agent may ever assert).
  2. The backend env PROXIMA_KUBE_ALLOWED_GROUPS (the role-authoring validation allowlist).

If a group is missing from either, it can't be used: the role editor rejects it, or the apiserver 403s the impersonation.

Example

# Acme Engineer — read + exec within acme-* namespaces, never secrets.
kube_spec:
allow:
kubernetes_groups: ["proxima:kube-readonly", "proxima:kube-exec"]
namespaces: ["acme-*"]
deny:
kubernetes_resources:
- kind: secrets
verbs: ["*"]

See also: Overview · Security Model.