Applying Kubernetes security best practices to Helm charts

Helm charts are an easy way to package, version and deploy applications on Kubernetes. They can be used to deploy application services or even Kubernetes components and tools.

They make scaling deployments internally and externally easier, as Kubernetes manifests and commands are bundled together with pre-vetted default values. As a user of a Helm, open source packages, known as charts, are readily at your disposal in repositories such as Artifact Hub. Launched in 2019, Artifact Hub has thousands of charts to quickly deploy pre-configured services such as databases into your cluster.

However, our recent research found that over 70% of Helm charts in Artifact Hub contained misconfigurations, such as not setting resource limits and running root containers, that violated CIS Kubernetes Benchmarks. Even the most popular dependency chart, PostgreSQL, contained multiple misconfigurations such as forgetting to add allowPrivilegeEscalation = false, which if left out defaults to true.

Part of the problem is that securing Helm charts is not as straightforward as securing a Kubernetes manifest.

What are Helm charts?

We should start with an exploration at a high level into how Helm charts work. Without Helm charts, you would write multiple Kubernetes manifests (YAML files) to take an application such as a container image, deploy it to your cluster and manage the additional settings of that image and how Kubernetes manages the container.

For example: If you want an ingress gateway, you may need to deploy the NGINX proxy with a certain number of replicas, set it as the ingress gateway and configure applications to interface with it. That alone could be three different manifests with default values across all three.

Instead, Helm bundles those manifests together, including dependencies like monitoring tools, and includes a central location for default but configurable values (values.yaml). If you come from the Terraform world, think of this as your vars.tf file.

Prior to deploying, helm install will construct the Kubernetes manifests and deploy them for you, just like kubectl apply.

How does Kubernetes security apply?

You may have already picked up on it, but by the time Kubernetes sees the Helm chart, it looks like just another manifest. That’s why most (we’ll talk about the exceptions later) of the misconfigurations for Kubernetes manifests are still relevant for Helm charts. Helm can still be set up to deploy a container as root or with PID 1.

However, it’s not as straightforward as scanning Kubernetes manifests. For example, the CIS Kubernetes Benchmarks 5.2.6 says to “minimize the admission of containers with added capabilities.” Even if there is a YAML line for allowedCapabilities, it may look like:

allowedCapabilities: {{- toYaml .Values.speaker.securityContext.capabilities.add | nindent 2 }}.

We’d have to dig into the values.yaml to find the right line: