By: Tim Hinrichs
Today, if you’re running Kubernetes, you know that security is not “built-in.” To secure your clusters, you have to configure, add or build in additional controls. Some are part of Kubernetes, like role-based access control (RBAC), but other best practices include specifying trusted repositories for known-good containers and then layering in runtime scanning tools as well. But the reality is that in Kubernetes, you can do all of these things “right” and yet everything can still go wrong. Your RBAC controls can be watertight, you can use only trusted and signed images, and you can scan your containers until the end of time — but still, your cluster can break or become breached. In other words, even a clean and trusted image, deployed incorrectly, can result in a misconfigured cluster — which leads to the risk of rework, downtime, or (worse) data loss.
However, one of the beautiful things about Kubernetes is that it offers an elegant control for preventing the right things from behaving in the wrong ways. Kubernetes Admission Control allows developers to enforce security policies directly on their cluster, to govern and control what can be deployed in order to limit risk and prevent many security issues from ever arising. Such policies might, for instance, preclude software from running as root, prevent unwanted ingress from the web, or ensure that newly deployed containers can’t steal traffic from existing internet-exposed workloads — all potential security issues that tools like RBAC or runtime security cannot account for. Indeed, Admission Control is not only powerful but is fast becoming a mandatory tool for securing Kubernetes. Strategies like RBAC, trusted repositories and runtime — while wonderful and necessary in their own right — are simply not enough.
Kubernetes, make it so
To understand why developers need Admission Control, let’s first take a look at the limitations of RBAC for K8s, trusted repositories and runtime tools. That requires us to look at the source of those tools: the pre-cloud era of development. In the traditional IT security model, the core factors that developers evaluated were:
- Identity and the network — who can access what?
- Known vulnerabilities — which known exploits can be executed in our environment?
Those concepts, in Kubernetes, map pretty closely to RBAC and code scanning in containers; both before and during runtime. It’s only natural then, that security-minded teams would adopt these tools as first lines of defense in securing their clusters. But in a fully software-defined environment, with the granular control that Kubernetes allows for, traditional approaches on their own leave inevitable gaps in these cloud native environments.
Take RBAC, for instance. RBAC controls who or what can put code into your cluster; and typically, those permissions are automated through the CI/CD pipeline. In theory, that means only trusted actors can put trusted or approved images into your cluster. But human error, automated at scale by CI/CD processes, introduces problems at scale. And, because the Kubernetes API is intent-based and requires the inspection of an arbitrary chunk of YAML, RBAC actually provides far less control in Kubernetes than in other systems.
Trusted repositories, meanwhile, ensure images never come from unknown or untrusted sources. They contain ratified images, typically with code that has been scanned for vulnerabilities. However, even trusted images can be deployed in the wrong way, as we will see.
Runtime tools, finally, allow you to monitor your deployed environment. These tools help detect anomalous activity, monitor communications among containers and between external clients and services, as well as spot newly discovered vulnerabilities. Still, your runtime environment can be fully clean, vulnerability-free, and still get breached.
In practice, traditional tools fail to solve born-in-the-cloud problems. For example, even a clean and trusted image, deployed incorrectly, can be used by a malicious actor to move laterally to other containers. Or, it can just plain talk to the internet in ways that it should not. These “clean image, bad outcome” scenarios are manifold:
A clean image, deployed by the right pipeline, and continuously scanned can:
- Allow unintended egress from the internet;
- Unintentionally scale to capture CPU resources and crash other processes;
- Run with privilege, making it a compromisable, lateral-movement-enabling risk;
- “Talk” to containers outside its namespace and put data and risk;
- Be named “latest” and prevent the roll-back of a cluster;
- And much, much more.
Kubernetes Admission Control provides the means to stop each of these unwanted scenarios in their tracks — all you need to do is to define the rules that allow what’s right, and stop what’s not. More specifically, you can use an admission controller to prevent misconfigurations before they cause problems. That’s because K8s admission controllers are “purposeful bottlenecks” that let you intercept requests to the Kube API and enforce security policies on them, before they’re ever deployed as objects in Kubernetes. In general, there are two kinds of Kubernetes admission controllers: admission mutating webhooks and validating webhooks.
By the powers vested in Kubernetes Admission Control
We hear a fair amount about Kubernetes Admission Control from our developer community, because one of the unexpectedly most popular use cases of our open-source policy engine, Open Policy Agent (OPA), has been just that — as a Kubernetes admission controller. OPA is a good fit for Admission Control, because it lets you translate enterprise security policies — often stored in wikis, PDFs or in people’s heads — into policy-as-code and, via the admission control webhook, enforce them directly on the cluster.
Regardless of your choice of controller (even if it’s just custom code), Admission Control can be used to prevent all manner of Kubernetes misconfigurations. For instance, you can create policies to:
- Prevent containers from running as root (can only run as “non-root”);
- Deploy only images marked as release;
- Ensure correct labels/tags;
- Expose only certain IPs and ports;
- Mount only permitted file systems.
You can also, just as crucially, enforce policies for the configurations around your container. For instance, you can control factors like:
- Blocking public ingress.
- Minimum reliability (mandating that you run three replicas, for instance).
However, in the world of Admission Control, the universe of possibilities (or limitations) is endless: you can write a policy over the configuration for any software running on Kubernetes. The key point is that using Kubernetes Admission Control, you can enforce guardrails that basically guarantee security, compliance and operational safety — by preventing misconfigurations before they happen.
By no means is Admission Control the alpha and the omega of Kubernetes security. Indeed, the very tools discussed here, like RBAC and scanning, are all “delicious parts of a complete breakfast” as they used to say. But put simply, without Admission Control they are not enough.
This article first appeared in The New Stack on November 17, 2020.
Learn more in our white paper on Kubernetes security via Admission Control.
What is Admission Control in Kubernetes?
Kubernetes uses two Admission Controllers, the Kubernetes mutating webhook and validating webhook, that teams can use to control which resources or objects are allowed onto their K8s clusters. In general, the validating webhook returns allow/deny decisions, while the mutating webhook can modify the object.
How to Use Kubernetes Admission Controllers?
Using OPA, users can define policies that govern K8s Admission Control decisions. For instance, using the validating webhook, they can write a policy that specifies containers may not run as root. Using the mutating webhook, meanwhile, they can write a policy that says any container must have the correct label, and modify the object to have the correct label, if no label or the wrong label was specified.