Using Admission Controllers to Enhance Kubernetes Security

SHARE:

Facebook logo LinkedIn logo X (formerly Twitter) logo

If you work with Kubernetes, you’re probably familiar with Kubernetes’s basic security features, like RBAC and network policies. These tools are useful for enforcing basic rules about which actions can be performed by various users or services within your cluster.

But sometimes you need more granularity or policy features than RBAC or network policies support. Or, you may want to perform extra checks to validate a resource before it is allowed to join your cluster.

This is where Kubernetes admission controllers come in. Admission controllers offer a highly extensible solution for performing security checks that go above and beyond the authentication, authorization, and network security rules you enforce through other types of Kubernetes policy frameworks. They also play a central role in connecting Kubernetes to external security tools that can deliver even more advanced analytics and compliance features.

Admission controllers are an optional feature, and you may not need them for simple configurations that can be adequately secured using basic RBAC or network policies. For securing complex, large-scale clusters, however, admission controllers are a resource you’ll very likely want to leverage.

This article defines Kubernetes admission controllers, explains how they work, and walks through the typical process for using them for security.

What are Admission Controllers in Kubernetes?

A Kubernetes admission controller is code that evaluates requests to the Kubernetes API server, then determines whether or not to allow the request.

The evaluation happens after the API server has already authenticated and authorized the request, but before the request is granted and implemented.

In other words, even if the API server has determined a request to be valid (which it would do based on the RBAC Roles and ClusterRoles you have set up), admission controllers will evaluate the request and make a determination about whether or not to accept it based on their own set of rules.

Benefits of Admission Controllers

Admission controllers offer several important advantages as part of a Kubernetes security strategy:

  • Double-check requests: Admission controllers serve in a sense as a second line of defense against invalid requests that may have slipped past your RBAC controls (perhaps because of a misconfiguration in an RBAC policy, for example).
  • Rule flexibility: Admission controllers can evaluate requests and enforce rules based on parameters that you can’t configure (at least not easily) via RBAC. This is important because RBAC defines rules based only on identities and actions. Admission controllers offer more nuance, like the ability to limit resource requests or prevent the execution of commands on a privileged container.
  • Third-party integrations: Some admission controllers enable webhooks. You can use webhooks to trigger actions in third-party security systems. This means that admission controllers offer a way of integrating external security tools into Kubernetes without actually having to run those tools directly in the Kubernetes API. Arguably, this is the most powerful feature of admission controllers.

Working with Admission Controllers

Here’s the process for using admission controllers in Kubernetes.

Enabling Admission Controllers in the Cluster

To use admission controllers in Kubernetes, you must first ensure that the admission controller feature is enabled in your cluster’s kube-apiserver.yaml file (which in most cases will be stored in the /etc/kubernetes/manifests/ directory on your Kubernetes master or master Kubernetes nodes).

If the flag –enable-admission-plugins is present, admission controllers are enabled for your cluster.

Choosing Specific Admission Controllers

The –enable-admission-plugins flag may be followed by a comma-separated list, like this:

--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,TaintNodesByCondition
,Priority,DefaultTolerationSeconds,DefaultStorageClass,StorageObjectInUseProtection
,PersistentVolumeClaimResize,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,RuntimeClass
,ResourceQuota

This list identifies the specific admission controllers that are turned on for your cluster. The Kubernetes documentation details all of the available admission controllers.

If the –enable-admission-plugins flag is present but is not followed by a list, Kubernetes enables a default set of admission controllers. In current versions of Kubernetes, these are:

  • NamespaceLifecycle
  • LimitRanger
  • ServiceAccount
  • TaintNodesByCondition
  • Priority
  • DefaultTolerationSeconds
  • DefaultStorageClass
  • StorageObjectInUseProtection
  • PersistentVolumeClaimResize
  • RuntimeClass
  • CertificateApproval
  • CertificateSigning
  • CertificateSubjectRestriction
  • DefaultIngressClass
  • MutatingAdmissionWebhook
  • ValidatingAdmissionWebhook
  • ResourceQuota

So, you can either use the default admission controllers, or you can explicitly define which admission controllers to enable.

Disabling Admission Controllers

If desired, you can explicitly disable admission controllers using the flag –disable-admission-plugins=… in the kube-apiserver.yaml file.

This flag is handy if you are using the default set of controllers but want to disable certain controllers within that set.

Checking Active Admission Controllers

If you’re unsure which admission controllers are enabled in your cluster, run this command for a list:

kube-apiserver -h | grep enable-admission-plugins

Configuring Admission Controllers

Kubernetes will automatically enforce whichever admission controllers you enable within your cluster. You don’t need to create additional policy files (as you would with RBAC, for example).

However, for certain admission controllers, you may need to specify configuration details. For example, to use the EventRateLimit controller, which limits how many requests the API server can accept, you’ll need to create a configuration file in YAML format and point the API server to it using the –admission-control-config-file flag.

The configuration file will look something like this:

apiVersion: eventratelimit.admission.k8s.io/v1alpha1
kind: Configuration
limits:
- type: Namespace
  qps: 50
  burst: 100
  cacheSize: 2000
- type: User
  qps: 10
  burst: 50Code language: PHP (php)

In this file, qps stands for queries per second, and burst defines how many queries the API server will accept before enforcing the limit established by qps. So, a qps of 50 with a burst of 100 means that the server will accept up to 100 queries before it begins enforcing the qps limit of 50. The limits are defined for specific types of resources (in the example above, namespaces and users).

For full details on configuring specific admission controllers, refer to the Kubernetes documentation.

Creating Custom Admission Controllers with Webhooks

When properly configured, the various built-in admission controllers can significantly enhance many aspects of your cluster’s security.

However, as noted above, the most powerful aspect of admission controllers is their ability to integrate with external security tools via webhooks.

For example, you can use the ImagePolicyWebhook controller to connect to a remote server. To do this, you must first ensure that the ImagePolicyWebhook is enabled in kube-apiserver.yaml.

Then, create a file (we’ll call it admission-config.yaml) that includes the ImagePolicyWebhook configuration details you’ll use to connect to the remote server. Point the API server to this file with:

kube-apiserver --admission-control-config-file=admission-config.yaml

The admission-config.yaml file itself should contain a stanza that looks like this:

apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: ImagePolicyWebhook
  configuration:
    imagePolicy:
      kubeConfigFile: <path-to-kubeconfig-file>
      allowTTL: 50
      denyTTL: 50
      retryBackoff: 500
      defaultAllow: trueCode language: HTML, XML (xml)

You’ll also need a separate kubeconfig file to configure the remote server, such as:

# clusters refers to the remote service.
clusters:
- name: name-of-remote-imagepolicy-service
  cluster:
    certificate-authority: /path/to/ca.pem    # CA for verifying the remote service.
    server: https://images.example.com/policy # URL of remote service to query. Must use 'https'.
# users refers to the API server's webhook configuration.
users:
- name: name-of-api-server
  user:
    client-certificate: /path/to/cert.pem # cert for the webhook admission controller to use
    client-key: /path/to/key.pem          # key matching the certCode language: PHP (php)

When properly configured, this will allow the Kubernetes API server to connect to a remote service (i.e., the remote server we defined above) when making admissions decisions. Again, the beauty of this approach is that you can define admission rules externally, without having to embed whichever policy engine you want to use into the Kubernetes API server itself (because, honestly, the API server config is complicated enough on its own).

In short, Kubernetes admission controllers are a powerful and – by the standards of Kubernetes, at least – relatively easy-to-use resource for adding another layer of security to your clusters. The specific admission controllers you choose to enable may vary depending on your workloads, and you may or may not have a reason to define custom controllers using webhooks.

But at a minimum, you’ll very likely want to enable at least the default admission controllers for every Kubernetes cluster that you intend to use for any type of production workload.