Kubernetes Series – 7: Kubernetes Security

In this article, we will talk about Kubernetes security. When we are using Kubernetes, we sometimes would like to limit the access of the network or limit some users to see and/or run some commands, etc. for security reasons. 

For these purposes, we have to use different Kubernetes concepts.

Network Policy

If we want to limit the network traffic from or to a Pod, we need to define a NetworkPolicy.

For instance, if we want to limit traffic on a specific port ( let’s say 80 ) to our nginx Pod and if we want to limit traffic from our nginx Port ( let’s say 8080 ), we need to define Ingress and Egress definitions respectively. Network policies are matched to the Pods with labels.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: nginx-network-policy
spec:
  podSelector:
    matchLabels:
      role: lb
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    ports:
    - protocol: TCP
      port: 80
  egress:
  - to:
    ports:
    - protocol: TCP
      port: 8080

So this NetworkPolicy will be applied to any Pod that has the label “role: lb”, limit in traffic on port 80, and out traffic on 8080.

RBAC

Role-based access control (RBAC – you can read it as ARBAC) is a method of regulating access to a computer or network resources based on the roles of individual users within your organization.

Imagine in your company, you have 50 people working in the IT department, grouped as developers, testers, and DevOps. If some resources are only for DevOps people ( for instance controlplane resources so developers and testers won’t make any mistake on those ) and that resource(s) should not be visible to other roles then we can limit their access by defining an RBAC. 

We can either define a Role or ClusterRole

The role is only for a specific Namespace.

ClusterRole is, as the name suggests, cluster-wide, and it is non-namespaced.

So if you need access control for a specific namespace define Role, if not define ClusterRole.

After creating roles, we have to bind them to either RoleBinding or ClusterRoleBinding according to our needs and/or usage.

The actions that users/roles may be allowed should be provided on the “verb” parameter, which can be any of the ones listed below:

[get, list, watch, create, update, patch, delete]

Please note that Kubernetes suggests usage of service accounts ( which are non-human accounts that are trying to authenticate ), so we have to create service accounts as well.

RBAC can be defined as both imperative and declarative.

For learning purposes, let’s create 3 different roles as mentioned above, developers, testers, and admins. Developers will have the rights to get, list, and update over Deployments and Pods on the “developers” namespace, testers will have rights to list the Pods on the “testers” namespace and DevOps will have the right for listing all pods cluster-wide.

Let’s start with creating a namespace called “developers”:

kubectl create namespace developers

Kubernetes Security

And then let’s create the role developers using the imperative method:

kubectl create role dev-role --verb=get,list,create --resource=deployments,pods -n developers

Kubernetes Security

In a declarative way, we can create as:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: developers
  name: dev-role
rules:
- apiGroups: [""]
  resources: ["pods","deployments"]
  verbs: ["get", "list", "create"]

Now if we want to use it with a single user we would have created a role binding for just one user “ege”:

kubectl create rolebinding dev-rb --role=developers --user=ege -n developers

Kubernetes Security

This was only for showing you how it would have done. But as I mentioned, Kubernetes suggests using a service account, and this will only be applied to user “ege” but actually, we don’t want it to be for only a user but for the entire role. So we need to create a service account for that:

kubectl create serviceaccount dev-sa -n developers

Kubernetes Security

Important note: Role and RoleBinding should be created on the specific namespace that they will be used but service accounts can be on different namespaces.

Now let’s bind our role developer once again this time with the service account created.

kubectl create rolebinding dev-sa-rb --role=dev-role --serviceaccount=developers:dev-sa

Kubernetes Security

As you can see when we are binding with a service account we first write the namespace and then the name of the service account, as in developers:dev-sa.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-sa-rb
  namespace: developers
subjects:
- kind: ServiceAccount
  name: dev-sa
  namespace: developers
roleRef:
  kind: Role
  name: dev-role
  apiGroup: rbac.authorization.k8s.io

Now let’s move on to creating a test role and role binding.

First the namespace:

kubectl create namespace testers

Kubernetes Security

Now let’s create the role with “list” permission on Pods at the “testers” namespace.

kubectl create role tester-role --verb=list --resource=pods -n testers

kubectl create role

A new service account for testers:

kubectl create serviceaccount tester-sa

kubectl create rolebinding tester-rb --role=tester-role --serviceaccount=testers:tester-sa -n testers

kubectl create clusterrolebinding

On to creating a cluster role for devops:

kubectl create clusterrole devops-role --verb=list --resource=pods

Create a service account for devops:

kubectl create serviceaccount devops-sa

kubectl create serviceaccount

kubectl create clusterrolebinding devops-rb --clusterrole=devops-role --serviceaccount=default:devops-sa

rolebinding in kubernetes

Now we can check out existing roles by:

kubectl get roles

kubectl get roles

No roles in the default namespace but you may see the roles in the specific namespaces:

kubectl get roles -n developers

kubectl get roles -n testers

roles in kubernetes

And describe any of them:

kubectl describe role dev-role -n developers

kubectl describe role

You may check access by using:

kubectl auth can-i create deployments

kubectl auth can-i create deployments

The answer is yes because we are an admin of our own cluster. To check with other users we need to add “–as <userName>

kubectl auth can-i list pods --as dev-sa

kubectl auth can-i list pods

We can list the pods with dev-sa let’s see we can delete deployments with tester-sa:

kubectl auth can-i delete deployments --as tester-sa

kubectl auth

This user as you can see does not have permission.

Security Context

A security context defines privilege and access control settings for a Pod or Container.

We use security context when we want to run a Pod or a Container as a specific user. So we can define the user that runs the Pod by adding the security context.

The path is “.spec.securityContext”. 

This is the demo YAML file taken from Kubernetes documentation:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  volumes:
  - name: sec-ctx-vol
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo
    securityContext:
      allowPrivilegeEscalation: false

We can check if it works by sshing into the Pod and checks the user:

kubectl exec -it nginx -- sh

and inside the container:

ps

kubectl exec -it

We can define a security context on the container level. Please note, container-level security context will override the Pod level. For example:

apiVersion: v1
kind: Pod
metadata:
  name: busybox
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 2000
  containers:
  - name: busybox
    image: busybox
    command: ["sh", "-c", "sleep 1h"]
    securityContext:
      runAsUser: 2000

and if we check the user inside cluster:

kubectl exec

we will observe that it is user 2000.

Kubernetes Series

Thanks for reading,
Ege Aksoz

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.