In Kubernetes 1.8, RBAC was introduced to improve the security. Prior RBAC, any pod is more or less able to interact with the rest of the cluster without constraints. This means you can create new pods, delete other deployments etc from any other pod. Needless to say, this is not ideal and RBAC sets out to address this.

While RBAC is a rather complicated topic, this brief article sets out to give a very simplistic crash course to get you started (while intentionally leaving big parts out).

What I wanted to do was to grant the deployment(s) the bare minimum permission to operate. For instance, if you have a simple app that neither uses Secrets or ConfigMaps, you can configure this using RBAC.

Below I’ll walk through two examples. One deployment that is fully locked down, and one that only has access to Secrets.

Please do note that you need to have an RBAC enabled cluster for this to work. minikube for instance comes with this by default.

RBAC in 15 seconds

RBAC can be used for many things, but in this article we will purely focus on the runtime side of RBAC and not for cluster authentication. With that in mind, there are three main concepts that you need to keep in mind:

  • Role: A role is what defines the actual RBAC permission
  • Service Account: This is what you associate with your deployment (or similar)
  • RoleBinding: This is what applies the Role to the Service Account

This is vastly simplified, but that should hopefully help you wrap your head around the concept.

A fully locked down deployment

(You can find the files referenced below here.)

First, we create namespace to stash our deployment into:

$ kubectl create ns lockdown

Next, we need to create a service account (which we will call ‘sa-lockdown’):

$ kubectl create serviceaccount --namespace lockdown sa-lockdown

We now need to create the role that defines a fully locked down RBAC role.

The role will look like this:

kind: Role
  name: lockdown
- apiGroups: [""] # "" indicates the core API group
  resources: [""]
  verbs: [""]

Simply apply the role using kubectl create -f role.yaml.

The important part here to note is that we simply do not define any explicit rules.

Next, we need to define a RoleBinding to map the Role to the Service Account we created earlier:

kind: RoleBinding
  name: rb-lockdown
- kind: ServiceAccount
  name: sa-lockdown
  kind: Role
  name: lockdown

Apply the role using kubectl create -f rolebinding.yaml.

With that applied, we can now check the permission using the can- feature:

$ kubectl auth can-i get pods \
        --namespace lockdown \
        --as system:serviceaccount:lockdown:sa-lockdown

Lastly, we can create our Nginx deployment:

apiVersion: extensions/v1beta1
kind: Deployment
  name: nginx-deployment
    app: nginx
  replicas: 1
        app: nginx
      serviceAccountName: sa-lockdown
      - name: nginx
        image: nginx:1.13
        - containerPort: 80

Again, apply this using kubectl create -f deployment.yaml.

That’s it. You are now running a fully locked down Nginx container (as far as RBAC goes at least).

RBAC with Secrets enabled

Many (most?) deployments require things like ConfigMaps and Secrets. As such, we need to modify our approach slightly and grant explicit access to this. Fortunately, this is very straight forward too. All we really need to do (in addition to creating the Secrets) is to modify our role definition to look something like this:

kind: Role
  name: role-lockdown-secrets
    namespace: lockdown-secrets
    - apiGroups: [""] # "" indicates the core API group
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]

As you can see, that provides explicit permission to read secrets. Other than that the setup is the same and you can find the full example here.

That’s it. Hopefully this helped you get started with locking down your system using RBAC.