For most Kubernetes users, security is either irrelevant or not that important, and even when it is considered, it is only perfunctory. In fact, Kubernetes offers a wide range of options that can greatly improve the security of your application, and if you use them well, you can keep most attacks at bay. To make it easier to get started, I’ve summarized them into a few best practice configurations that you can use once you’ve read them. Of course, the security best practices described in this article are limited to the Pod level, that is, the container level, in the container life cycle, as for the security configuration outside the container (such as the operating system, k8s components, etc.), I will talk about it in detail in future articles.

1. Configure Security Context for the container

In most cases containers don’t need many permissions, we can restrict the permissions and access control of the container through Security Context, just add the SecurityContext field.

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Pod
metadata:
  name: <Pod name>
spec:
  containers:
  - name: <container name>
  image: <image>
+   securityContext:

2. disable allowPrivilegeEscalation

allowPrivilegeEscalation=true indicates that any child process of the container can be granted more privileges than the parent process. It is best to set this to false to ensure that the RunAsUser command cannot bypass its existing set of privileges.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
apiVersion: v1
kind: Pod
metadata:
  name: <Pod name>
spec:
  containers:
  - name: <container name>
  image: <image>
    securityContext:
  +   allowPrivilegeEscalation: false

3. Don’t use the root user

To prevent privilege escalation attacks from inside the container, it is best not to use the root user to run applications inside the container. set the UID larger than 3000.

1
2
3
4
5
6
7
8
apiVersion: v1
kind: Pod
metadata:
  name: <name>
spec:
  securityContext:
+   runAsUser: <UID higher than 1000>
+   runAsGroup: <UID higher than 3000>

4. limit CPU and memory resources

It goes without saying that you should add both requests and limits.

5. No need to mount Service Account Token

ServiceAccount provides an identity for the processes running in the Pod, how do you identify them? Through a Token, of course. With a Token, you can prevent counterfeit processes. If your application doesn’t need this identity, you don’t have to mount it.

1
2
3
4
5
6
apiVersion: v1
kind: Pod
metadata:
  name: <name>
spec:
+ automountServiceAccountToken: false

6. Make sure seccomp is set correctly

For Linux, all resource-related operations at the user level are done through system calls, so as long as the system calls are manipulated in a certain way, user-level programs can’t make any waves, and even malicious programs can only hang around in their own process memory space, and disappear like the wind once the process terminates. seccomp (secure computing mode) is a security mechanism that restricts system calls and allows you to specify which system calls are allowed.

For Kubernetes, most container runtimes provide a default set of allowed or disallowed system calls. The defaults can be easily applied in Kubernetes by using the runtime/default annotation or by setting the seccomp type in the security context of the Pod or container to RuntimeDefault.

1
2
3
4
5
6
apiVersion: v1
kind: Pod
metadata:
  name: <name>
  annotations:
  + seccomp.security.alpha.kubernetes.io/pod: "runtime/default"

7. Restrict the capabilities of containers

Containers rely on the traditional Unix security model to achieve control over resources by controlling the permissions of the users and groups to which the resources belong. A container running as root has far more privileges than its workload requires, and in the event of a breach, an attacker could use these privileges to further attack the network.

By default, NET_RAW capability is enabled when running with Docker as a container, which can be abused by malicious attackers. Therefore, it is recommended to define at least a PodSecurityPolicy (PSP) to prevent containers with NET_RAW capabilities from starting.

By limiting the capabilities of a container, you can ensure that an attacked container cannot provide an attacker with a valid path to a lateral attack, thus narrowing the scope of the attack.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
apiVersion: v1
kind: Pod
metadata:
  name: <name>
spec:
  securityContext:
  + runAsNonRoot: true
  + runAsUser: <specific user>
  capabilities:
  drop:
  + -NET_RAW
  + -ALL

8. read-only

If the container does not need to write to the root filesystem, it is best to load the container’s root filesystem in a read-only manner, which can further limit attackers.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
apiVersion: v1
kind: Pod
metadata:
  name: <Pod name>
spec:
  containers:
  - name: <container name>
  image: <image>
  securityContext:
  + readOnlyRootFilesystem: true

9 Summary

In summary, Kubernetes provides a very large number of options to enhance the security of a cluster. There is no one-size-fits-all solution, so one needs to be very familiar with these options and how they enhance the security of the application in order to make the cluster more stable and secure.