Use Role-Based Access Control with Oracle Cloud Native Environment
Introduction
As the number of deployments to your Kubernetes cluster increases, you may need help managing it. The Kubernetes API provides the ability to add users and define their permissions to the cluster.
Once the user has authenticated, Kubernetes verifies what actions the user is authorized to perform. Role-Based Access Control (RBAC) is natively supported by Kubernetes and enabled by default in Oracle Cloud Native Environment (Oracle CNE). Making it one of the access control methods commonly used. RBAC allows you to manage access to resources deployed to the Kubernetes environment by applying rules that restrict users’ access to cluster resources. These rules can be either namespace-restricted using a Role, or cluster-wide using a ClusterRole.
You will find it helpful to have an understanding of the key components of Role-Based Access Control (RBAC) in Kubernetes, which are:
- Roles: A defined set of permissions that define allowed actions within a namespace.
- RoleBindings: Used to bind a Role to a user or service account within a namespace.
- ClusterRole: A defined set of permissions defining allowed actions across all namespaces in the cluster.
- ClusterRoleBindings: Used to bind a ClusterRole to a user or service accounts across all namespaces in the cluster.
- Subjects: These are users, groups, or service accounts that are bound to Roles or ClusterRoles.
- Permissions: These define the permitted actions a Role, or ClusterRole, can perform on a specified resource. They are associated with roles & cluster roles rather than users or service accounts.
Another way to manage access to the Kubernetes cluster is Attribute-Based Access Control (ABAC), which allows finer tuning of policies compared to RBAC. But this is outside the scope of this tutorial.
This tutorial covers the basics of using RBAC to manage access to your Kubernetes cluster and demonstrates a simple use case.
For more information about Oracle Cloud Native Environment 2, please refer to the current Release Documentation site.
Objectives
In this tutorial, you’ll learn to:
- Create a Role to demonstrate restricting user permissions by namespace.
- Create a ClusterRole to demonstrate granting user permissions cluster-wide.
Prerequisites
- Installation of Oracle Cloud Native Environment (Oracle CNE)
- A single control node and one worker node
Configure Oracle Cloud Native Environment
Note: If running in your own tenancy, read the linux-virt-labs
GitHub project README.md and complete the prerequisites before deploying the lab environment.
-
Open a terminal on the Luna Desktop.
-
Clone the
linux-virt-labs
GitHub project.git clone https://github.com/oracle-devrel/linux-virt-labs.git
-
Change into the working directory.
cd linux-virt-labs/ocne2
-
Install the required collections.
ansible-galaxy collection install -r requirements.yml
-
Deploy the lab environment.
ansible-playbook create_instance.yml -e localhost_python_interpreter="/usr/bin/python3.6" -e install_ocne_rpm=true -e create_ocne_cluster=true -e "ocne_cluster_node_options='-n 1 -w 1'"
The free lab environment requires the extra variable
local_python_interpreter
, which setsansible_python_interpreter
for plays running on localhost. This variable is needed because the environment installs the RPM package for the Oracle Cloud Infrastructure SDK for Python, located under the python3.6 modules.The default deployment shape uses the AMD CPU and Oracle Linux 8. To use an Intel CPU or Oracle Linux 9, add
-e instance_shape="VM.Standard3.Flex"
or-e os_version="9"
to the deployment command.Important: Wait for the playbook to run successfully and reach the pause task. At this stage of the playbook, the installation of the Oracle CNE is complete, and the instances are ready. Take note of the previous play, which prints the public and private IP addresses of the nodes it deploys and any other deployment information needed while running the lab.
Access the Kubernetes Cluster
-
Open a terminal and connect via SSH to the ocne instance.
ssh oracle@<ip_address_of_instance>
-
Wait for the cluster to stabilize and all pods to report in a running state.
watch kubectl get pods -A
Once all the pods show a STATUS of Running, type
Ctrl-C
to exit thewatch
command. -
Confirm how many nodes are present.
kubectl get nodes
Confirm The Current RBAC Configuration
RBAC manages the permissions for the actions you perform on resources deployed onto your Kubernetes cluster. You will check that RBAC is enabled and review the default roles in your cluster.
-
Confirm RBAC is enabled.
If the
rbac.authorization.k8s.io
API is visible, it means that RBAC is configured and is used to control which actions users or service accounts can undertake on cluster resources.kubectl api-versions | grep rbac
Example Output:
[oracle@ocne ~]$ kubectl api-versions | grep rbac rbac.authorization.k8s.io/v1
-
Show the built-in cluster roles.
kubectl get clusterroles | grep admin
Example Output:
[oracle@ocne ~]$ kubectl get clusterroles | grep admin admin 2025-07-23T10:21:55Z cluster-admin 2025-07-23T10:21:55Z system:aggregate-to-admin 2025-07-23T10:21:55Z system:kubelet-api-admin 2025-07-23T10:21:55Z
Normal users use the
admin
andcluster-admin
roles, while the RBAC API reserves thesystem:
roles for internal components. -
List the permissions for
cluster-admin
.kubectl describe clusterrole cluster-admin
Example Output:
[oracle@ocne ~]$ kubectl describe clusterrole cluster-admin Name: cluster-admin Labels: kubernetes.io/bootstrapping=rbac-defaults Annotations: rbac.authorization.kubernetes.io/autoupdate: true PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- *.* [] [] [*] [*] [] [*]
The asterisks in the Verbs and the Resources columns mean that the
cluster-admin
role can perform any action. A high-level list of the operations (Verbs) available for each Kubernetes release is available in the API Overview for that release. For example, in Kubernetes v1.33.0. A detailed list of valid operations (Verbs) available for each Resource type is available by executingkubectl api-resources -o wide
from the command line.However, because you don’t log in to
kubectl
, how does Kubernetes know who the user executing the command is? Production systems usually use an LDAP server for authentication. A ServiceAccount can be used if an external authentication system is not available.Note: ServiceAccounts are used by automated workloads, such as CI/CD pipelines, but can also be used for testing.
Create a Role
A Role is a namespace-restricted resource defining the permissions for accessing Kubernetes resources within a single namespace.
Create a Namespace and a Role
-
Create a Namespace.
Create a new namespace for this example.
kubectl create namespace rbac-example
-
Create a Role.
Create a Role that grants read-only access (‘get’ and ‘list’ permissions) to pods and deployments within the rbac-example namespace.
cat << EOF | tee pod-reader-role.yaml > /dev/null apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: pod-reader namespace: rbac-example rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list"] - apiGroups: ["apps"] resources: ["deployments"] verbs: ["get", "list"] EOF
Where:
rules:
- Defines the permissions granted to the Role. This example defines two rules (see below).apiGroups: [""]
- Permits the user or service account bound to this rule to retrieve and list pods in therbac-example
namespace.apiGroups: ["apps"]
- Permits the user or service account bound to this rule to retrieve and list deployments in therbac-example
namespace.
-
Apply the file.
kubectl apply -f pod-reader-role.yaml
-
Check the permissions for the newly created pod-reader role.
kubectl describe role/pod-reader -n rbac-example
Example Output:
[oracle@ocne ~]$ kubectl describe role/pod-reader -n rbac-example Name: pod-reader Labels: <none> Annotations: <none> PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- pods [] [] [get list] deployments.apps [] [] [get list]
Create a User and Bind to the Role
-
Create a new ServiceAccount user called pod-reader-user and bind it to the pod-reader role.
cat << EOF | tee pod-reader-user.yaml > /dev/null apiVersion: v1 kind: ServiceAccount metadata: name: pod-reader-user namespace: rbac-example --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: pod-reader-binding namespace: rbac-example roleRef: name: pod-reader kind: Role subjects: - kind: ServiceAccount name: pod-reader-user namespace: rbac-example EOF
Where:
- The ServiceAccount creates the service account.
name:
- The service account user’s name (pod-reader-user
).namespace
- The namespace where it is created (rbac-example
).
- The RoleBinding grants the namespace-related permissions to the service account.
roleRef:
- Specifies the binding Role. In this example, it references a Role calledpod-reader
.subjects:
- Specifies the entity to grant permissions. In this example, a service account calledpod-reader-user
.
- The ServiceAccount creates the service account.
-
Apply the file.
kubectl apply -f pod-reader-user.yaml
Test the RoleBinding
Next, test the RoleBinding by creating a new Pod and accessing it using the newly created pod-reader-user service account.
-
Create a new test deployment.
cat << EOF | tee testpod.yaml > /dev/null apiVersion: v1 kind: Pod metadata: name: test-pod namespace: rbac-example spec: containers: - name: test-container image: ghcr.io/oracle/oraclelinux9-nginx:1.20 ports: - containerPort: 80 serviceAccountName: pod-reader-user EOF
Where:
- The
spec:
defines the pod’s desired state.containers:
- Specifies the list of containers to run in the pod. In this example, there is only one container.name:
- The name of the container (test-container
).image:
- The image to use (ghcr.io/oracle/oraclelinux9-nginx:1.20
).ports:
- Specifies the port exposed by the container. In this example, it is port 80 (containerPort: 80
).
serviceAccountName:
- Specifies the service account to use for the Pod. In this configuration, the Pod uses the permissions and credentials assigned to thepod-reader-user
service account.
- The
-
Apply the file.
kubectl apply -f testpod.yaml
-
Now, try to access the Pod using the pod-reader-user ServiceAccount.
kubectl auth can-i get pod/test-pod --as=system:serviceaccount:rbac-example:pod-reader-user -n rbac-example
You should see
yes
as the output, indicating that the pod-reader-user has permission to access the pod.Note: Use the
kubectl auth can-i
functionality to execute commands as the newly created ServiceAccount user account to verify that an action is allowed. -
Confirm the ServiceAccount works as expected.
kubectl --as=system:serviceaccount:rbac-example:pod-reader-user get pods -n rbac-example
Example Output:
[oracle@ocne ~]$ kubectl --as=system:serviceaccount:rbac-example:pod-reader-user get pods -n rbac-example NAME READY STATUS RESTARTS AGE test-pod 1/1 Running 0 109s
-
Try to delete a Pod using the
pod-reader-user
role.kubectl --as=system:serviceaccount:rbac-example:pod-reader-user delete pod test-pod -n rbac-example
Example Output:
[oracle@ocne ~]$ kubectl --as=system:serviceaccount:rbac-example:pod-reader-user delete pod test-pod -n rbac-example Error from server (Forbidden): pods "test-pod" is forbidden: User "system:serviceaccount:rbac-example:pod-reader-user" cannot delete resource "pods" in API group "" in the namespace "rbac-example"
The
pod-reader-user
role cannot delete pods in therbac-example
. Perhaps they can start new pods? -
Try to run a Pod using the
pod-reader-role
role.kubectl run nginx1 --image=ghcr.io/oracle/oraclelinux9-nginx:1.20 --as=system:serviceaccount:default:my-serviceaccount -n rbac-example
Example Output:
[oracle@ocne ~]$ kubectl run nginx1 --image=ghcr.io/oracle/oraclelinux9-nginx:1.20 --as=system:serviceaccount:rbac-example:pod-reader-user -n rbac-example Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:rbac-example:pod-reader-user" cannot create resource "pods" in API group "" in the namespace "rbac-example"
This error is correct because the
pod-reader-user
role is only allowed to performget
andlist
actions against Pod resources in the rbac-example namespace of the cluster. Any other actions, delete or create, are not allowed.
Create a ClusterRole
ClusterRoles are similar to Roles, but they define allowed permissions on resources across the entire cluster.
Note: Be cautious when granting permissions that are too broad. Instead, use the least ‘principle of least privilege’ to grant users and service accounts only the permissions needed to complete their assigned tasks.
Create a ClusterRole and ClusterRoleBinding
The previous example showed how to create a namespace-specific user and role. The following steps demonstrate how to create a ClusterRole and bind it to a user to grant them cluster-wide admin access.
-
Create a new ClusterRole.
This ClusterRole allows users added to it to conduct any action on all resources across the cluster.
cat << EOF | tee cluster-admin-clusterrole.yaml > /dev/null apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: cluster-admin-cr rules: - apiGroups: ["*"] resources: ["*"] verbs: ["*"] EOF
Where:
rules:
- Defines the permissions granted to the ClusterRole. This example only has one rule:apiGroups: ["*"]
- Specifies the rule applies to all API groups.resources: ["*"]
- Specifies that the rule applies to all resources of the API groups.verbs: ["*"]
- Specifies that the rule grants all possible verbs on the resources, includingget
,list
,create
,delete
, etc.
-
Apply the file.
kubectl apply -f cluster-admin-clusterrole.yaml
-
Create a ClusterRoleBinding to bind the ClusterRole to a new user.
The ClusterRoleBinding is similar to the RoleBinding you created earlier, but it’s cluster-scoped.
cat << EOF | tee cluster-admin-user.yaml > /dev/null apiVersion: v1 kind: ServiceAccount metadata: name: cluster-admin-user namespace: rbac-example --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: cluster-admin-crb roleRef: name: cluster-admin-cr kind: ClusterRole subjects: - kind: ServiceAccount name: cluster-admin-user namespace: rbac-example EOF
Where:
subjects:
- Defines the entities to grant permissions in the ClusterRole. In this example, it is thecluster-admin-user
service account.
-
Apply the file.
kubectl apply -f cluster-admin-user.yaml
Test the ClusterRoleBinding
-
Test the cluster role by trying to access a resource in a different namespace. For example, the default namespace.
kubectl auth can-i list pods --as=system:serviceaccount:rbac-example:cluster-admin-user -n default
You should see
yes
as the output, indicating that the cluster-admin-user has cluster-admin access. -
Confirm the newly created ClusterRole works as expected.
kubectl --as=system:serviceaccount:rbac-example:cluster-admin-user get pods -A
Example Output:
[oracle@ocne ~]$ kubectl --as=system:serviceaccount:rbac-example:cluster-admin-user get pods -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-flannel kube-flannel-ds-ptwkz 1/1 Running 0 6h58m kube-flannel kube-flannel-ds-wn2g6 1/1 Running 0 6h58m kube-system coredns-7cbdbfd99c-7xqkl 1/1 Running 0 6h59m kube-system coredns-7cbdbfd99c-k2ssb 1/1 Running 0 6h59m kube-system etcd-ocne-control-plane-1 1/1 Running 0 6h59m kube-system kube-apiserver-ocne-control-plane-1 1/1 Running 0 6h59m kube-system kube-controller-manager-ocne-control-plane-1 1/1 Running 0 6h59m kube-system kube-proxy-48rm5 1/1 Running 0 6h59m kube-system kube-proxy-h4kd2 1/1 Running 0 6h58m kube-system kube-scheduler-ocne-control-plane-1 1/1 Running 0 6h59m ocne-system ocne-catalog-577b7cd5f9-bnvtm 1/1 Running 0 6h58m ocne-system ui-846bddd4b-lnrwm 1/1 Running 0 6h58m rbac-example test-pod 1/1 Running 0 6h34m
This output confirms that the newly created ClusterRole can access all namespaces defined on the cluster.
Confirm the ClusterRole User can Create a New Deployment
Test the ClusterRole to see if it allows assigned users to create a new deployment. Then, try to access it using the newly created ClusterRole.
-
Create a new test deployment.
cat << EOF | tee testpod2.yaml > /dev/null apiVersion: v1 kind: Pod metadata: name: test-pod2 namespace: default spec: containers: - name: test-container image: ghcr.io/oracle/oraclelinux9-nginx:1.20 ports: - containerPort: 8080 EOF
Note that this deployment deploys to the ‘default’ namespace, and not the rbac-example namespace used previously.
-
Apply the file.
kubectl apply -f testpod2.yaml
-
Confirm the deployment completed successfully.
kubectl --as=system:serviceaccount:rbac-example:cluster-admin-user get pods -A
Example Output:
[oracle@ocne ~]$ kubectl --as=system:serviceaccount:rbac-example:cluster-admin-user get pods -A NAMESPACE NAME READY STATUS RESTARTS AGE default test-pod2 1/1 Running 0 28s kube-flannel kube-flannel-ds-shgh7 1/1 Running 0 38m kube-flannel kube-flannel-ds-zzrgh 1/1 Running 0 38m kube-system coredns-7cbdbfd99c-jg6lz 1/1 Running 0 38m kube-system coredns-7cbdbfd99c-wh5g4 1/1 Running 0 38m kube-system etcd-ocne-control-plane-1 1/1 Running 0 38m kube-system kube-apiserver-ocne-control-plane-1 1/1 Running 0 38m kube-system kube-controller-manager-ocne-control-plane-1 1/1 Running 0 38m kube-system kube-proxy-5qngx 1/1 Running 0 38m kube-system kube-proxy-6fz2q 1/1 Running 0 38m kube-system kube-scheduler-ocne-control-plane-1 1/1 Running 0 38m ocne-system ocne-catalog-577b7cd5f9-vz782 1/1 Running 0 38m ocne-system ui-846bddd4b-bbhtj 1/1 Running 0 38m rbac-example test-pod 1/1 Running 0 21m
Confirming that the new ClusterRole allows new deployments to a different namespace.
Next Steps
This tutorial demonstrated how to set up and use Role-Based Access Control (RBAC) with Kubernetes by creating Roles to manage access to Kubernetes resources. You achieved this by defining roles and bindings to control what permitted actions were allowed on resources within a namespace, or on a cluster-wide basis. In this way, the granular control RBAC provides is essential for securing your Kubernetes environment, especially for large deployments. Check out the Oracle Linux Training Station for additional tutorials and content.
Related Links
- Oracle Cloud Native Environment Documentation
- Oracle Cloud Native Environment Track
- Oracle Linux Training Station
More Learning Resources
Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.
For product documentation, visit Oracle Help Center.
Use Role-Based Access Control with Oracle Cloud Native Environment
G40561-01