Skip to content

Permission tiers

A kubelatch permission is always the combination of a subject, a cluster, a tier and a scope. Here you see what each tier allows, where it can be granted, what it requires and, above all, what it can't guarantee.

The six tiers

Tier What it allows Scope Requires PSA
viewer Read access to what Kubernetes' view role includes: pods, pods/log, workloads, services, configmaps… without secrets. With * scope, also read access to nodes, namespaces, persistentvolumes, storageclasses and CRDs. namespace or * No
developer Everything in viewer plus creating, modifying and deleting deployments, statefulsets, daemonsets, replicasets, jobs, cronjobs, pods, configmaps, services, persistentvolumeclaims, ingresses and horizontalpodautoscalers. namespace Yes
debugger Adds: exec, attach and port-forward on pods, ephemeral containers, and reading pods and logs. namespace Yes
secrets-reader Adds: read access (get, list, watch) to secrets. namespace No
admin Kubernetes' admin role in the namespace. namespace Yes
cluster-admin Kubernetes' cluster-admin role across the whole cluster. Expiry required, 8 h maximum. * No

A subject can have several permissions on the same cluster. It's common to combine them: developer on apps plus debugger on apps for someone who needs to get into their pods.

What developer leaves out, and why

developer is not Kubernetes' edit role. edit includes secrets, pods/exec and serviceaccounts/token, which are exactly what a day-to-day working permission shouldn't grant without thinking about it. developer does not have:

  • secrets, serviceaccounts or serviceaccounts/token;
  • the exec, attach, portforward, proxy and ephemeralcontainers subresources of pods;
  • roles, rolebindings, resourcequotas or limitranges.

Those capabilities are split into separate tiers (debugger, secrets-reader, admin) so granting them is an explicit, audited decision.

The namespace is the boundary

Kubernetes says so in its own documentation: the boundaries within a namespace are weak. kubelatch can't change that, and it's worth understanding before granting anything.

Whoever can create pods in a namespace can mount any Secret in that namespace and use any ServiceAccount in that namespace, with its permissions. So:

  • Whoever has developer on a namespace reaches its Secrets and its ServiceAccounts, even though the tier doesn't include secrets. All it takes is deploying a pod that mounts them.
  • secrets-reader and debugger are conveniences, not boundaries. They save you from deploying a pod to read a Secret or to inspect another one, but they don't protect anything developer doesn't already reach.
  • ServiceAccount tokens obtained from a pod don't go through kubelatch. Whatever is done with them ends up in the cluster's native audit log, not kubelatch's. So it's worth keeping that native audit log active with the provider.

The practical consequence: grant developer, debugger and admin only on namespaces whose contents that person may see and touch. Whatever you want kept separate between teams, separate into different namespaces.

Pod Security Admission

Without Pod Security Admission, whoever can create pods can create a privileged one that mounts the node's disk, and from the node reaches the whole cluster. An ephemeral container added with debugger can do the same.

That's why developer, debugger and admin require the namespace to have the pod-security.kubernetes.io/enforce label set to baseline or restricted. kubelatch checks this when granting the permission, by reading the namespace on the cluster.

KUBELATCH_REQUIRE_PSA=false disables the check, and Permisos (Permissions) warns about it in the header. It only makes sense if another tool (OPA, Kyverno) enforces the same thing.

Protected namespaces

kube-system, kube-public, kube-node-lease and kubelatch-system don't accept permissions of any tier. KUBELATCH_PROTECTED_NAMESPACES adds others to the list. Whatever needs doing there is done with native admin access, outside kubelatch.

Allowed scopes

  • * (the whole cluster) is only allowed with viewer and cluster-admin.
  • cluster-admin is only allowed with *.
  • All other tiers can only be granted on a namespace, which must exist on that cluster at the moment of granting.

viewer with * also sees the logs of every namespace, and logs can contain secrets. Grant it knowing that.

cluster-admin as audited emergency access

cluster-admin gives full control of the cluster. kubelatch treats it as emergency access: it requires an expiry date and doesn't allow more than 8 h. Who granted it and to whom is recorded, and every request made with it ends up in the audit log. It's the preferred route for an urgent intervention while kubelatch is running.

How it's materialized on the cluster

The reconciler translates active permissions into standard RBAC on each cluster:

Scope Object it creates Points to Binding subject
Namespace RoleBinding kubelatch-<tier> in that namespace ClusterRole for the tier Group kubelatch:ns:<namespace>:<tier>
* ClusterRoleBinding kubelatch-<tier>-cluster ClusterRole for the tier Group kubelatch:cluster:<tier>

Bindings never name people: they name groups. The proxy uses impersonation to act as each person with the groups from their active permissions, and the API server applies the bindings for those groups (see The journey of a request).

viewer, developer, debugger and secrets-reader are their own aggregated ClusterRoles (kubelatch-<tier>): their rules come from a base ClusterRole (kubelatch-<tier>-base) and from any other ClusterRole with the label kubelatch.io/aggregate-to-<tier>: "true". viewer also collects everything labeled for the standard view role, and developer collects everything from viewer. So adding a CRD to a tier just means creating a small ClusterRole with that label, without touching kubelatch. admin and cluster-admin point directly to the Kubernetes roles of the same name.

A binding exists as long as at least one enabled subject has an active permission with that tier and that scope. The reconciler creates it when granted, deletes it when it's no longer needed, and removes expired permissions' bindings in its periodic pass. The proxy stops sending an expired permission's group instantly, without waiting for that pass.

Optional hardening

A namespace admin can manually create a RoleBinding to kubelatch-developer. It doesn't grant access through kubelatch, because the proxy only impersonates whoever has active permissions, but it's confusing. deploy/k8s/hardening/vap-kubelatch-bindings.yaml is a ValidatingAdmissionPolicy that reserves those bindings for the reconciler. See Security model.