This page gives you good practices for planning your role-based access control (RBAC) policies. To learn how to implement RBAC in Google Kubernetes Engine (GKE), refer to Configure role-based access control.
RBAC is a core security feature in Kubernetes that lets you create fine-grained permissions to manage what actions users and workloads can perform on resources in your clusters. As a platform administrator, you create RBAC roles and bind those roles to subjects, which are authenticated users such as service accounts or Google Groups.
Before you begin
Ensure that you're familiar with the following concepts:
For a checklist of this guidance, see Checklist summary.
How RBAC works
RBAC supports the following types of roles and bindings:
- ClusterRole: a set of permissions that can be applied to any namespace, or to the entire cluster.
- Role: a set of permissions that is limited to a single namespace.
- ClusterRoleBinding: bind a
ClusterRole
to a user or a group for all namespaces in the cluster. - RoleBinding: bind a
Role
or aClusterRole
to a user or a group within a specific namespace.
You define permissions as rules
in a Role
or a ClusterRole
. Each rules
field in a role consists of an API group, the API resources within that API
group, and the verbs (actions) allowed on those resources. Optionally, you
can scope verbs to named instances of API resources by using the resourceNames
field. For an example, see
Restrict access to specific resource instances.
After defining a role, you use a RoleBinding
or a ClusterRoleBinding
to bind
the role to a subject. Choose the type of binding based on whether you want to
grant permissions in a single namespace or in multiple namespaces.
RBAC role design
Use the principle of least privilege
When assigning permissions in an RBAC role, use the principle of least privilege and grant the minimum permissions needed to perform a task. Using the principle of least privilege reduces the potential for privilege escalation if your cluster is compromised, and reduces the likelihood that excessive access results in a security incident.
When designing your roles, carefully consider common privilege escalation risks,
such as escalate
or bind
verbs, create
access for PersistentVolumes, or
create
access for Certificate Signing Requests. For a list of risks, refer to
Kubernetes RBAC - privilege escalation risks.
Avoid default roles and groups
Kubernetes creates a set of default ClusterRoles and ClusterRoleBindings that
you can use for API discovery and to enable managed component functionality. The
permissions granted by these default roles might be extensive depending on the
role. Kubernetes also
has a set of default users and user groups, identified by the system:
prefix.
By default, Kubernetes and GKE automatically bind these roles to
the default groups and to various subjects. For a full list of the default roles
and bindings that Kubernetes creates, refer to
Default roles and role bindings.
The following table describes some default roles, users, and groups. We recommend that you avoid interacting with these roles, users, and groups unless you've carefully evaluated them, because interacting with these resources can have unintended consequences to your cluster's security posture.
Name | Type | Description |
---|---|---|
cluster-admin |
ClusterRole | Grants a subject permission to do anything on any resource in the cluster. |
system:anonymous |
User | Kubernetes assigns this user to API server requests that have no authentication information provided. Binding a role to this user gives any unauthenticated user the permissions granted by that role. |
system:unauthenticated |
Group | Kubernetes assigns this group to API server requests that have no authentication information provided. Binding a role to this group gives any unauthenticated user the permissions granted by that role. |
system:authenticated |
Group | GKE assigns this group to API server requests made
by any user who is signed in with a Google Account, including all
Gmail accounts. In practice, this isn't
meaningfully different from Binding a role to this group gives any user with a Google Account, including all Gmail accounts, the permissions granted by that role. |
system:masters |
Group | Kubernetes assigns the Adding your own subjects to this group gives those subjects access to do anything to any resource in your cluster. |
If possible, avoid creating bindings that involve the default users, roles, and groups. This can have unintended consequences to your cluster's security posture. For example:
- Binding the default
cluster-admin
ClusterRole to thesystem:unauthenticated
group gives any unauthenticated users access to all resources in the cluster (including Secrets). These highly-privileged bindings are actively targeted by attacks such as mass malware campaigns. - Binding a custom Role to the
system:unauthenticated
group gives unauthenticated users the permissions granted by that Role.
When possible, use the following guidelines:
- Don't add your own subjects to the
system:masters
group. - Don't bind the
system:unauthenticated
group to any RBAC roles. - Don't bind the
system:authenticated
group to any RBAC roles. - Don't bind the
system:anonymous
user to any RBAC roles. - Don't bind the
cluster-admin
ClusterRole to your own subjects or to any of the default users and groups. If your application requires many permissions, determine the exact permissions required and create a specific role for that purpose. - Evaluate the permissions granted by other default roles before binding subjects.
- Evaluate the roles bound to default groups before modifying the members of those groups.
Prevent usage of default groups
You can use the gcloud CLI to disable non-default RBAC bindings in a
cluster that reference the system:unauthenticated
and system:authenticated
groups or the system:anonymous
user. Use one or both of the following flags
when you create a new GKE cluster or update an existing cluster.
Using these flags doesn't disable the default Kubernetes bindings that reference
these groups. These flags require GKE version 1.30.1-gke.1283000
or later.
--no-enable-insecure-binding-system-authenticated
: Disable non-default bindings that referencesystem:authenticated
.--no-enable-insecure-binding-system-unauthenticated
: Disable non-default bindings that referencesystem:unauthenticated
andsystem:anonymous
.
Detect and remove usage of default roles and groups
To check whether your clusters reference these users and groups in RBAC bindings, enable the standard tier of Kubernetes security posture scanning for your clusters or fleet so that GKE can show you results in the security posture dashboard in the Google Cloud console. For instructions, see Enable workload configuration auditing.
The following sections show you how to find the specific RoleBindings or ClusterRoleBindings that reference default users and groups, and how to delete those resources.
ClusterRoleBindings
List the names of any ClusterRoleBindings with the subject
system:anonymous
,system:unauthenticated
, orsystem:authenticated
:kubectl get clusterrolebindings -o json \ | jq -r '["Name"], ["-----"], (.items[] | select((.subjects | length) > 0) | select(any(.subjects[]; .name == "system:anonymous" or .name == "system:unauthenticated" or .name == "system:authenticated")) | [.metadata.namespace, .metadata.name]) | @tsv'
The output should list only the following ClusterRoleBindings:
Name ---- "system:basic-user" "system:discovery" "system:public-info-viewer"
If the output contains additional non-default bindings, do the following for each additional binding. If your output doesn't contain non-default bindings, skip the following steps.
List the permissions of the role associated with the binding:
kubectl get clusterrolebinding CLUSTER_ROLE_BINDING_NAME -o json \ | jq ' .roleRef.name +" " + .roleRef.kind' \ | sed -e 's/"//g' \ | xargs -l bash -c 'kubectl get $1 $0 -o yaml'
Replace
CLUSTER_ROLE_BINDING_NAME
with the name of the non-default ClusterRoleBinding.The output is similar to the following:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: ... rules: - apiGroups: - "" resources: - secrets verbs: - get - watch - list
If you determine that the permissions in the output are safe to grant to the default users or groups, no further action is required. If you determine that the permissions granted by the binding are unsafe, proceed to the next step.
Delete an unsafe binding from your cluster:
kubectl delete clusterrolebinding CLUSTER_ROLE_BINDING_NAME
Replace
CLUSTER_ROLE_BINDING_NAME
with the name of the ClusterRoleBinding to delete.
RoleBindings
List the namespace and name of any RoleBindings with the subject
system:anonymous
,system:unauthenticated
, orsystem:authenticated
:kubectl get rolebindings -A -o json \ | jq -r '["Namespace", "Name"], ["---------", "-----"], (.items[] | select((.subjects | length) > 0) | select(any(.subjects[]; .name == "system:anonymous" or .name == "system:unauthenticated" or .name == "system:authenticated")) | [.metadata.namespace, .metadata.name]) | @tsv'
If your cluster is configured correctly, the output should be blank. If the output contains any non-default bindings, do the following steps for each additional binding. If your output is blank, skip the following steps.
If you only know the name of the RoleBinding then you can use the following command to find matching rolebindings across all namespaces:
kubectl get rolebindings -A -o json \ | jq -r '["Namespace", "Name"], ["---------", "-----"], (.items[] | select((.subjects | length) > 0) | select(.metadata.name == "ROLE_BINDING_NAME") | [.metadata.namespace, .metadata.name]) | @tsv'
Replace
ROLE_BINDING_NAME
with the name of the non-default RoleBinding.List the permissions of the Role associated with the binding:
kubectl get rolebinding ROLE_BINDING_NAME --namespace ROLE_BINDING_NAMESPACE -o json \ | jq ' .roleRef.name +" " + .roleRef.kind' \ | sed -e 's/"//g' \ | xargs -l bash -c 'kubectl get $1 $0 -o yaml --namespace ROLE_BINDING_NAMESPACE'
Replace the following:
ROLE_BINDING_NAME
: the name of the non-default RoleBinding.ROLE_BINDING_NAMESPACE
: the namespace of the non-default RoleBinding.
The output is similar to the following:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: ... rules: - apiGroups: - "" resources: - secrets verbs: - get - watch - list
If you determine that the permissions in the output are safe to grant to the default users or groups, no further action is required. If you determine that the permissions granted by the binding are unsafe, proceed to the next step.
Delete an unsafe binding from your cluster:
kubectl delete rolebinding ROLE_BINDING_NAME --namespace ROLE_BINDING_NAMESPACE
Replace the following:
ROLE_BINDING_NAME
: the name of the RoleBinding to delete.ROLE_BINDING_NAMESPACE
: the namespace of the RoleBinding to delete.
Scope permissions to the namespace level
Use bindings and roles as follows, depending on the needs of your workload or user:
- To grant access to resources in one namespace, use a
Role
with aRoleBinding
. - To grant access to resources in more than one namespace, use a
ClusterRole
with aRoleBinding
for each namespace. - To grant access to resources in every namespace, use a
ClusterRole
with aClusterRoleBinding
.
Grant permissions in as few namespaces as possible.
Don't use wildcards
The *
character is a wildcard that applies to everything. Avoid using
wildcards in your rules. Explicitly specify API groups, resources, and verbs in
RBAC rules. For example, specifying *
in the verbs
field would grant get
,
list
, watch
, patch
, update
, deletecollection
, and delete
permissions
on the resources. The following table shows examples of avoiding wildcards in
your rules:
Recommended | Not recommended |
---|---|
- rules: apiGroups: ["apps","extensions"] resources: ["deployments"] verbs: ["get","list","watch"] Grants |
- rules: apiGroups: ["*"] resources: ["deployments"] verbs: ["get","list","watch"] Grants the verbs to |
- rules: apiGroups: ["apps", "extensions"] resources: ["deployments"] verbs: ["get", "list", "watch"] Grants only |
- rules: apiGroups: ["apps", "extensions"] resources: ["deployments"] verbs: ["*"] Grants all verbs, including |
Use separate rules to grant least-privilege access to specific resources
When planning your rules, try the following high-level steps for a more efficient least-privilege rule design in each role:
- Draft separate RBAC rules for each verb on each resource that a subject needs to access.
- After drafting the rules, analyze the rules to check whether multiple rules
have the same
verbs
list. Combine those rules into a single rule. - Keep all the remaining rules separate from each other.
This approach results in a more organized rule design, where rules that grant the same verbs to multiple resources are combined, and rules that grant different verbs to resources are separate.
For example, if your workload needs get permissions for the deployments
resource, but needs list
and watch
on the daemonsets
resources, you should
use separate rules when creating a role. When you bind the RBAC role to your
workload, it won't be able to use watch
on deployments
.
As another example, if your workload needs get
and watch
on both the pods
resource and the daemonsets
resource, you can combine those into a single
rule, because the workload needs the same verbs on both resources.
In the following table, both rule designs work, but the split rules more granularly restrict resource access based on your needs:
Recommended | Not recommended |
---|---|
- rules: apiGroups: ["apps"] resources: ["deployments"] verbs: ["get"] - rules: apiGroups: ["apps"] resources: ["daemonsets"] verbs: ["list", "watch"] Grants |
- rules: apiGroups: ["apps"] resources: ["deployments", "daemonsets"] verbs: ["get","list","watch"] Grants the verbs to both Deployments and DaemonSets. A subject
who might not require |
- rules: apiGroups: ["apps"] resources: ["daemonsets", "deployments"] verbs: ["list", "watch"] Combines two rules because the subject needs the same verbs for
both the |
- rules: apiGroups: ["apps"] resources: ["daemonsets"] verbs: ["list", "watch"] - rules: apiGroups: ["apps"] resources: ["deployments"] verbs: ["list", "watch"] These split rules would have the same result as the combined rule, but would create unnecessary clutter in your role manifest |
Restrict access to specific resource instances
RBAC lets you use the resourceNames
field in your rules to restrict access to
a specific named instance of a resource. For example, if you're writing an RBAC
role that needs to update
the seccomp-high
ConfigMap and nothing else, you
can use resourceNames
to specify only that ConfigMap. Use resourceNames
whenever possible.
Recommended | Not recommended |
---|---|
- rules: apiGroups: [""] resources: ["configmaps"] resourceNames: ["seccomp-high"] verbs: ["update"] Restricts the subject to only update the |
- rules: apiGroups: [""] resources: ["configmaps"] verbs: ["update"] The subject can update the |
- rules: apiGroups: [""] resources: ["configmaps"] verbs: ["list"] - rules: apiGroups: [""] resources: ["configmaps"] resourceNames: ["seccomp-high"] verbs: ["update"] Grants |
- rules: apiGroups: [""] resources: ["configmaps"] verbs: ["update", "list"] Grants |
Don't let service accounts modify RBAC resources
Do not bind Role
or ClusterRole
resources that have bind
, escalate
,
create
, update
, or patch
permissions on the rbac.authorization.k8s.io
API group to service accounts in any namespace. escalate
and bind
in
particular can let an attacker bypass the
escalation prevention mechanisms built into RBAC.
Kubernetes service accounts
Create a Kubernetes service account for each workload
Create a separate Kubernetes service account for each workload. Bind a
least-privilege Role
or ClusterRole
to that service account.
Don't use the default service account
Kubernetes creates a service account named default
in every namespace. The
default
service account is automatically assigned to Pods that don't
explicitly specify a service account in the manifest. Avoid binding a Role
or
ClusterRole
to the default
service account. Kubernetes might assign the default
service account to a Pod that doesn't need the access granted in those roles.
Don't automatically mount service account tokens
The automountServiceAccountToken
field in the Pod specification tells
Kubernetes to inject a credential token for a Kubernetes service account into
the Pod. The Pod can use this token to make authenticated requests to the
Kubernetes API server. The default value for this field is true
.
In all GKE versions, set automountServiceAccountToken=false
in
the Pod specification if your Pods don't need to communicate with the API
server.
Prefer ephemeral tokens over Secret-based tokens
By default, the kubelet process on the node retrieves a short-lived,
automatically rotating service account token for each Pod. The kubelet mounts
this token on the Pod as a
projected volume
unless you set the automountServiceAccountToken
field to false
in the Pod
specification. Any calls to the Kubernetes API from the Pod use this token to
authenticate to the API server.
If you're manually retrieving service account tokens, avoid using Kubernetes
Secrets to store the token. Secret-based service account tokens are legacy
credentials that don't expire and aren't rotated automatically. If you need
credentials for service accounts, use the
TokenRequest
API
to obtain short-lived tokens that are automatically rotated.
Continuously review RBAC permissions
Review your RBAC roles and access regularly to identify potential escalation
pathways and redundant rules. For example, consider a situation where you don't
delete a RoleBinding
that binds a Role
with special privileges to a deleted
user. If an attacker creates a user account in that namespace with the same name
as the deleted user, they'd be bound to that Role
and would inherit the same
access. Periodic reviews minimize this risk.
Checklist summary
What's next
- Read the GKE hardening advice.
- Read Kubernetes RBAC good practices.
- Explore our other best practices.
- View sample manifests for common cluster roles