Skip to main content

Hands on with RBAC in Kubernetes 1.8

With the release of Kubernetes 1.8, role-based access control (RBAC) has been promoted from beta to general availability. CoreOS, through our participation in the Kubernetes SIG Auth group, played a significant role in getting RBAC implemented in upstream Kubernetes. With its graduation to general availability, the feature and its core APIs can be considered stable.

RBAC policies are powerful tools to limit authorization permissions within a cluster. There's been much discussion about how RBAC works in Kubernetes; for a brief overview, see the Kubernetes project blog post on the topic. But how, exactly, does an admin work with RBAC? For this post, we'll demonstrate how to setup RBAC with a service account and verify that the access controls are working. Note: All examples assume Kubernetes 1.8.

Viewing ClusterRoles

Central to RBAC is the concept of roles, which are essentially just collections of permissions. A "developer" role might grant one set of privileges, for example, while an "administrator" role grants another set.

Kubernetes's RBAC implementation includes both Roles and ClusterRoles. Roles are limited to a single namespace, while ClusterRoles can be applied to any namespace or cluster wide. This allows for finer control of privileges; for example, it makes it possible to assign a user (perhaps a developer) to just one or a handful of namespaces (prod-project1, staging-project1), or to the entire cluster as an administrator.

The default ClusterRoles are a great place to start for a basic set of permissions. To view all the ClusterRoles, cluster wide:

$ kubectl get clusterroles

NAME                   KIND                                       RULES
admin                  ClusterRole.v1.rbac.authorization.k8s.io   11 item(s)
cluster-admin          ClusterRole.v1.rbac.authorization.k8s.io   2 item(s)
edit                   ClusterRole.v1.rbac.authorization.k8s.io   9 item(s)
view                   ClusterRole.v1.rbac.authorization.k8s.io   7 item(s)
… [truncated] …

Note that there are a number of system accounts and four default user-facing Roles. For Tectonic users, another way to view ClusterRoles and other RBAC objects is through the Tectonic Console:

Screenshot showing RBAC administration via the Tectonic Console
Tectonic makes managing Kubernetes role-based access control (RBAC) settings easy.

Granting default view permissions on a namespace

To get a read-only view of a particular namespace, we can use the default ClusterRole named view. By binding the view ClusterRole to a user, and then impersonating that user, we will be able to test out their privileges.

To create the binding, we create an object aptly called a RoleBinding. To create the RoleBinding we pass a name, a Role or ClusterRole, a user, and optionally a namespace.

$ kubectl create namespace dev
$ kubectl create rolebinding joe-view --clusterrole view --user joe --namespace dev
# to view the rolebindings
$ kubectl get rolebindings --namespace dev

Verifying Access

We have created the RoleBinding, but how does an administrator verify the Roles for a user? For this, we'll use the auth can-i command to impersonate users and test their accounts against the RBAC policies in place.

For example, to verify Joe’s access to pods in the dev namespace:

$ kubectl auth can-i get pods --namespace dev --as joe
yes

Does Joe have access to nodes in the dev namespace?

$ kubectl auth can-i create deployments --namespace dev --as joe
no

Service accounts

So far we've been working with user accounts, but our goal for this exercise is to create policies for service accounts. While user accounts are for humans, service accounts are used to manage privileges for processes. Typically they are used to generate credentials for automated systems, such as Jenkins or Travis. In the Kubernetes ecosystem, service accounts are created and then attached to pods to allow access to the Kubernetes API.

Service accounts require a Service Account object, a Role object, and a RoleBinding object.

Creating the service account

The following yaml file creates the service accounts sa-read-deployments and sa-write-deployments. The sa-read-deployments account will only be able to read deployments. The sa-write-deployments account will be able to write.

$ kubectl create serviceaccount --namespace dev sa-read-deployments
$ kubectl create serviceaccount --namespace dev sa-write-deployments

In practice, a service account is managed just like a regular user. We can impersonate these service accounts just like we do user accounts, but first we need to assign the Roles with a RoleBinding to the service accounts.

Assigning the RoleBinding

This RoleBinding example creates a two new RoleBindings: rb-write-deployments and rb-read-deployments. We attach the ServiceAccount and reference to each Role to create the binding:

rb-deployments.yml:

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: rb-read-deployments
subjects:
- kind: ServiceAccount
  name: sa-read-deployments
roleRef:
  kind: ClusterRole
  name: view
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: rb-write-deployments
subjects:
- kind: ServiceAccount
  name: sa-write-deployments
roleRef:
  kind: ClusterRole
  name: edit
  apiGroup: rbac.authorization.k8s.io

$ kubectl create -f rb-deployments.yml --namespace dev
# to view the rolebindings
$ kubectl get rolebindings --namespace dev

Now that we have the RoleBindings setup we can create a Deployment with a running application.

Creating the Deployments

To test the RBAC privileges for our new service accounts, first create the following deployment.yml:

deployment.yml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.13
        ports:
        - containerPort: 80

Now let's see what we can do with it. First, let's try creating our Deployment using the sa-read-deployments service account:

$ kubectl create -f deployment.yml --as system:serviceaccount:dev:sa-read-deployments  --namespace dev
Error from server (Forbidden): error when creating "deployment.yml": deployments.extensions is forbidden: 
User "system:serviceaccount:dev:sa-read-deployments" cannot create deployments.extensions in the namespace "dev".

The read-only service account is forbidden from completing the action, which is exactly what we want. Now let's try running the same command, only using the sa-write-deployments account:

$ kubectl create -f deployment.yml --as system:serviceaccount:dev:sa-write-deployments  --namespace dev
deployment "nginx-deployment" created

This time, the Deployment is created and the pod starts running:

$ kubectl get pod --namespace dev
NAME                                READY     STATUS    RESTARTS   AGE
nginx-deployment-7d749c9b8b-cjpcp   1/1       Running   0          1h

Namespaces can also contain more than one service account, and each account can have its own distinct Roles, giving the administrator an extremely flexible and secure, policy-based method of granting and restricting access.

Extending RBAC in Tectonic

With the RBAC APIs moving to stable, enterprises can have increased confidence in the security mechanisms built into Kubernetes. CoreOS was an early adopter of RBAC, and it has been enabled in our Tectonic Kubernetes platform since version 1.4. Tectonic Identity further extends user management with authentication using LDAP and SAML.

If you'd like to see for yourself how Tectonic makes Kubernetes user management easy and seamless, the Tectonic Sandbox is an easy, pain-free way to set up a complete Tectonic test and experimentation environment on your local machine. Try it today!


Try Sandbox