Best practices for GKE RBAC Stay organized with collections Save and categorize content based on your preferences.
This document is about good practices for planning your role-based accesscontrol (RBAC) policies in Google Kubernetes Engine (GKE) (GKE). Thisdocument assumes that you know about the following:
RBAC is a core security feature in Kubernetes that lets you create fine-grainedpermissions to manage what actions users and workloads can perform on resourcesin your clusters. You create RBACroles andbind those roles tosubjects,which are authenticated users such as service accounts or Google Groups.
This document is for Security specialists and Operators who plan andimplement RBAC policies for their organization. To learn more about common rolesand example tasks that we reference in Google Cloud content, seeCommon GKE user roles and tasks.
For a checklist of the guidance in this document, seeChecklist summary.
To learn how to implement RBAC in Google Kubernetes Engine (GKE), seeConfigure role-based access control.
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
ClusterRoleto a user or a group for allnamespaces in the cluster. - RoleBinding: bind a
Roleor aClusterRoleto a user or a groupwithin a specific namespace.
You define permissions asrules in aRole or aClusterRole. Eachrulesfield in a role consists of an API group, the API resources within that APIgroup, and the verbs (actions) allowed on those resources. Optionally, youcan scope verbs to named instances of API resources by using theresourceNamesfield. For an example, seeRestrict access to specific resource instances.
After defining a role, you use aRoleBinding or aClusterRoleBinding to bindthe role to a subject. Choose the type of binding based on whether you want togrant 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 privilegeand grant the minimum permissions needed to perform a task. Using the principleof least privilege reduces the potential for privilege escalation if yourcluster is compromised, and reduces the likelihood that excessive access resultsin a security incident.
When designing your roles, carefully consider common privilege escalation risks,such asescalate orbind verbs,create access for PersistentVolumes, orcreate access for Certificate Signing Requests. For a list of risks, refer toKubernetes RBAC - privilege escalation risks.
Avoid default roles and groups
Kubernetes creates a set of default ClusterRoles and ClusterRoleBindings thatyou can use for API discovery and to enable managed component functionality. Thepermissions granted by these default roles might be extensive depending on therole. Kubernetes alsohas a set of default users and user groups, identified by thesystem: prefix.By default, Kubernetes and GKE automatically bind these roles tothe default groups and to various subjects. For a full list of the default rolesand bindings that Kubernetes creates, refer toDefault roles and role bindings.
The following table describes some default roles, users, and groups. Werecommend that you avoid interacting with these roles, users, and groups unlessyou've carefully evaluated them, because interacting with these resources can haveunintended 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 securityposture. For example:
- Binding the default
cluster-adminClusterRole to thesystem:unauthenticatedgroup gives any unauthenticated users access to allresources in the cluster (including Secrets). These highly-privilegedbindings are actively targeted by attacks such as mass malware campaigns. - Binding a custom Role to the
system:unauthenticatedgroup givesunauthenticated users the permissions granted by that Role.
When possible, use the following guidelines:
- Don't add your own subjects to the
system:mastersgroup. - Don't bind the
system:unauthenticatedgroup to any RBAC roles. - Don't bind the
system:authenticatedgroup to any RBAC roles. - Don't bind the
system:anonymoususer to any RBAC roles. - Don't bind the
cluster-adminClusterRole to your own subjects or to any ofthe default users and groups. If your application requires manypermissions, determine the exact permissions required and create aspecific role for that purpose. - Evaluate the permissions granted by other default roles before bindingsubjects.
- Evaluate the roles bound to default groups before modifying the members ofthose groups.
Prevent usage of default groups
You can use the gcloud CLI to disable non-default RBAC bindings in acluster that reference thesystem:unauthenticated andsystem:authenticatedgroups or thesystem:anonymous user. Use one or both of the following flagswhen you create a new GKE cluster or update an existing cluster.Using these flags doesn't disable the default Kubernetes bindings that referencethese groups. These flags require GKE version 1.30.1-gke.1283000or later.
--no-enable-insecure-binding-system-authenticated: Disable non-defaultbindings that referencesystem:authenticated.--no-enable-insecure-binding-system-unauthenticated: Disable non-defaultbindings that referencesystem:unauthenticatedandsystem:anonymous.
Detect and remove usage of default roles and groups
Note: To help secure your clusters against mass malware attacks that exploitcluster-admin access misconfigurations, GKE clusters runningversion 1.28 and later won't allow you to bind thecluster-admin ClusterRoleto thesystem:anonymous user or to thesystem:unauthenticated orsystem:authenticated groups.To check whether your clusters reference these users and groups in RBACbindings, enable the standard tier of Kubernetes security posture scanning foryour clusters or fleet so that GKE can show you results in thesecurity posture dashboard in the Google Cloud console. For instructions,seeEnable workload configuration auditing.
The following sections show you how to find the specific RoleBindings orClusterRoleBindings that reference default users and groups, and how to deletethose resources.
ClusterRoleBindings
List the names of any ClusterRoleBindings with the subject
system:anonymous,system:unauthenticated, orsystem:authenticated:kubectlgetclusterrolebindings-ojson\|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 followingforeach additional binding. If your output doesn't contain non-defaultbindings, skip the following steps.
List the permissions of the role associated with the binding:
kubectlgetclusterrolebindingCLUSTER_ROLE_BINDING_NAME-ojson\|jq' .roleRef.name +" " + .roleRef.kind'\|sed-e's/"//g'\|xargs-lbash-c'kubectl get $1 $0 -o yaml'Replace
CLUSTER_ROLE_BINDING_NAMEwith the name ofthe non-default ClusterRoleBinding.The output is similar to the following:
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:...rules:- apiGroups: - "" resources: - secrets verbs: - get - watch - listIf you determine that the permissions in the output are safe to grant to thedefault users or groups, no further action is required. If you determinethat the permissions granted by the binding are unsafe, proceed to the nextstep.
Delete an unsafe binding from your cluster:
kubectldeleteclusterrolebindingCLUSTER_ROLE_BINDING_NAMEReplace
CLUSTER_ROLE_BINDING_NAMEwith the name ofthe ClusterRoleBinding to delete.
RoleBindings
List the namespace and name of any RoleBindings with the subject
system:anonymous,system:unauthenticated, orsystem:authenticated:kubectlgetrolebindings-A-ojson\|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 beblank.If the output contains any non-default bindings, do the followingsteps foreach additional binding. If your output is blank, skip thefollowing steps.
If you only know the name of the RoleBinding then you can use thefollowing command to find matching rolebindings across all namespaces:
kubectlgetrolebindings-A-ojson\|jq-r'["Namespace", "Name"], ["---------", "-----"], (.items[] | select((.subjects | length) > 0) | select(.metadata.name == "ROLE_BINDING_NAME") | [.metadata.namespace, .metadata.name]) | @tsv'Replace
ROLE_BINDING_NAMEwith the name of the non-default RoleBinding.List the permissions of the Role associated with the binding:
kubectlgetrolebindingROLE_BINDING_NAME--namespaceROLE_BINDING_NAMESPACE-ojson\|jq' .roleRef.name +" " + .roleRef.kind'\|sed-e's/"//g'\|xargs-lbash-c'kubectl get $1 $0 -o yaml --namespaceROLE_BINDING_NAMESPACE'Replace the following:
ROLE_BINDING_NAME: the name of the non-defaultRoleBinding.ROLE_BINDING_NAMESPACE: the namespace of thenon-default RoleBinding.
The output is similar to the following:
apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:...rules:- apiGroups: - "" resources: - secrets verbs: - get - watch - listIf you determine that the permissions in the output are safe to grant to thedefault users or groups, no further action is required. If you determinethat the permissions granted by the binding are unsafe, proceed to the nextstep.
Delete an unsafe binding from your cluster:
kubectldeleterolebindingROLE_BINDING_NAME--namespaceROLE_BINDING_NAMESPACEReplace the following:
ROLE_BINDING_NAME: the name of the RoleBindingto delete.ROLE_BINDING_NAMESPACE: the namespace of theRoleBinding to delete.
Scope permissions to the namespace level
Use bindings and roles as follows, depending on the needs of your workload oruser:
- To grant access to resources inone namespace, use a
Rolewith aRoleBinding. - To grant access to resources inmore than one namespace, use a
ClusterRolewith aRoleBindingfor each namespace. - To grant access to resources inevery namespace, use a
ClusterRolewith aClusterRoleBinding.
Grant permissions in as few namespaces as possible.
Don't use wildcards
The* character is awildcard that applies to everything. Avoid usingwildcards in your rules. Explicitly specify API groups, resources, and verbs inRBAC rules. For example, specifying* in theverbs field would grantget,list,watch,patch,update,deletecollection, anddelete permissionson the resources. The following table shows examples of avoiding wildcards inyour 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 moreefficient least-privilege rule design in each role:
- Draft separate RBAC rules for each verb on each resource that a subjectneeds to access.
- After drafting the rules, analyze the rules to check whether multiple ruleshave the same
verbslist. 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 grantthe same verbs to multiple resources are combined, and rules that grantdifferent verbs to resources are separate.
For example, if your workload needs get permissions for thedeploymentsresource, but needslist andwatch on thedaemonsets resources, you shoulduse separate rules when creating a role. When you bind the RBAC role to yourworkload, it won't be able to usewatch ondeployments.
As another example, if your workload needsget andwatch on both thepodsresource and thedaemonsets resource, you can combine those into a singlerule, because the workload needs the same verbs on both resources.
In the following table, both rule designs work, but the split rules moregranularly 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 theresourceNames field in your rules to restrict access toa specific named instance of a resource. For example, if you're writing an RBACrole that needs toupdate theseccomp-high ConfigMap and nothing else, youcan useresourceNames to specify only that ConfigMap. UseresourceNameswhenever possible.
resourceNames forlist andcreate verbs. For example,if you're writing a role that needs tolist all ConfigMaps in addition toupdating theseccomp-high ConfigMap, you need to split the rules.| 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 bindRole orClusterRole resources that havebind,escalate,create,update, orpatch permissions on therbac.authorization.k8s.ioAPI group to service accounts in any namespace.escalate andbind inparticular can let an attacker bypass theescalation 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 aleast-privilegeRole orClusterRole to that service account.
Don't use the default service account
Kubernetes creates a service account nameddefault in every namespace. Thedefault service account is automatically assigned to Pods that don'texplicitly specify a service account in the manifest. Avoid binding aRole orClusterRole to thedefault service account. Kubernetes might assign thedefaultservice account to a Pod that doesn't need the access granted in those roles.
Don't automatically mount service account tokens
TheautomountServiceAccountToken field in the Pod specification tellsKubernetes to inject a credential token for a Kubernetes service account intothe Pod. The Pod can use this token to make authenticated requests to theKubernetes API server. The default value for this field istrue.
In all GKE versions, setautomountServiceAccountToken=false inthe Pod specification if your Pods don't need to communicate with the APIserver.
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 mountsthis token on the Pod as aprojected volumeunless you set theautomountServiceAccountToken field tofalse in the Podspecification. Any calls to the Kubernetes API from the Pod use this token toauthenticate to the API server.
If you're manually retrieving service account tokens, avoid using KubernetesSecrets to store the token. Secret-based service account tokens are legacycredentials that don't expire and aren't rotated automatically. If you needcredentials for service accounts, use theTokenRequest API to obtain short-lived tokens that are automatically rotated.
Continuously review RBAC permissions
Review your RBAC roles and access regularly to identify potential escalationpathways and redundant rules. For example, consider a situation where you don'tdelete aRoleBinding that binds aRole with special privileges to a deleteduser. If an attacker creates a user account in that namespace with the same nameas the deleted user, they'd be bound to thatRole and would inherit the sameaccess. 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
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-12-15 UTC.