Goodbye PSPs, Hello Kyverno!

Goodbye PSPs, Hello Kyverno!

Pod Security Policies (PSPs) are being deprecated in Kubernetes. In this post, we will discuss alternatives including the proposed in-tree replacements and why you should consider using Kyverno to address pod and other configuration security concerns for your clusters.

Image by Marco Antonio Reyes from Pixabay 

Pod Security Policies in Kubernetes

Pods are the basic unit of execution and control in Kubernetes. A Pod is composed of one or more containers, typically a single “application” container and optionally one or more helper containers for initialization or auxiliary functions such as periodically fetching data (like secrets) from an external source.

Each Pod has a securityContext that controls runtime security configurations for the pod. The securityContext contains fields that manage the pod’s runtime group and user settings, SELinux options, Seccomp (Linux kernel secure computing mode) profiles, and kernel parameters using Sysctls. 

Additionally, each container in a pod can also specify a securityContext to override pod-wide settings and define additional security settings such as whether the container runs in a privileged mode (basically runs with root access), whether a container process can gain more privileges than its parent process, the additional Linux kernel capabilities the container can use, whether the container root file system is read-only, and if the container has visibility to other processes via the /proc filesystem.

These settings are very powerful and allow a lot of flexibility. However, they can also be dangerous. Misconfigurations, or lack of proper enforcement of security best practices, can lead to exploits where a bad pod is used to gain access to container hosts or the control plane.

Pod Security Policies (PSPs) were designed to control security related settings for a pod by defining a set of conditions that the pod must pass for it to run. Otherwise, if a pod does not comply, the pod is rejected. For example, a PSP can prevent running a pod as a root user.

This sounds very useful, so why are PSPs being deprecated? 

Well, several reasons actually! PSPs have been stuck in beta as they are difficult, if not impossible, to implement and manage in real-world scenarios. When enabled, PSPs can immediately impact all workloads and so can be a non-starter for clusters with production workloads. Role bindings are used to map PSPs to workloads, but this quickly gets confusing as most pods are run by pod controllers and not users, and PSPs use a dual permission model. And, If there are multiple PSPs that a pod has access to, the one that applies is determined by alphabetical order, which may lead to unintended consequences.  PSPs also are focused on pod security and do not cover other aspects of configuration security. And, PSPs are focused on Linux runtimes and do not support other platforms like Windows.

Due to these challenges PSPs are being deprecated in version Kubernetes version 1.21 and will be removed in version 1.25 of Kubernetes. For more information, refer to the Kubernetes blog post PodSecurityPolicy Deprecation: Past, Present, and Future by Tabitha Sable, co-chair of the  Kubernetes SIG Security.

A Kubernetes Enhancement Proposal (KEP) has been accepted to replace PSPs with a more flexible in-tree implementation. We will discuss what this proposal provides, but first it’s important to discuss Pod Security Standards as the proposal is based on these definitions.

Pod Security Standards

The Kubernetes Pod Security Standards definition provides recommended security profiles to use for pod security. Currently three levels are defined:

  1. Privileged: not secure and allows all settings.
  2. Baseline: a minimally restrictive policy that prevents known privilege escalations. This level contains nine (9) controls to manage pod configuration security settings:
    1. Host Namespaces
    2. Privileged Containers
    3. Capabilities
    4. HostPath Volumes
    5. Host Ports
    6. AppArmor
    7. SELinux
    8. /proc mount type
    9. Sysctls
  1. Restricted: a heavily restrictive policy that enforces best practices. This level includes all controls from the baseline profile and contains five (5) additional controls to further harden the pod configuration:
    1. Volume Types
    2. Privilege Escalation
    3. Running as Non-root
    4. Not-root Groups
    5. Seccomp

Pod Security Standards provide a common definition for pod security that is decoupled from any implementation. In fact, PSPs are an implementation of Pod Security Standards and the upcoming PSP replacements will also implement the Pod Security Standards. This decoupling also allows external policy engines like Kyverno and OPA/Gatekeeper to implement Pod Security Standards and provide additional capabilities that will not be supported by the in-tree replacement.

KEP #2582

The proposal for an in-cluster PSP replacement (the name is still being decided on) will provide a new built-in Kubernetes admission controller that enforces the three levels defined in the Pod Security Standards. The full proposal is available in Kubernetes Enhancement Proposal (KEP) #2582. At a high level, the intent is to allow the use of Namespace labels to specify what security profile should be enabled. 

For example, a Namespace that should block all pods that do not comply with the restricted profile can be defined as follows:

kind: Namespace
apiVersion: v1
metadata:
  name: restricted-ns
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: v1.22

NOTE: the label names will change based on the feature name, and other behaviors are also subject to change as the KEP is implemented.

Additional labels can be used to control reporting of violations in the audit logs and via warnings in the API response. It will also be possible to configure defaults and exceptions.

The built-in PSP replacement will provide a solution for pod security that is simpler and easier to use than PSPs. However, the solution intentionally does not allow granular customizations. And, it is intentionally focused on pod security only, and does not address other configuration security concerns and best practices required for production workloads like limiting access to service accounts, restricting image registries,, dropping all capabilities and restricting addition of advanced capabilities like NET_RAW, requiring a read-only root filesystem, requiring probes, requiring quotas, requiring standard labels, and several other policies that are recommended for production workloads.

Hence, a policy engine like Kyverno or OPA/Gatekeeper will be required to provide additional flexibility for pod security and address other configuration security concerns.

Kyverno 

Kyverno (a Greek word for “govern”) is a policy engine that was built for Kubernetes and uses Kubernetes Custom Resources to define policies. Kyverno was created by Nirmata and is now a CNCF Sandbox project.

Kyverno runs as an admission controller. This means that all Kubernetes API requests can be validated or mutated by Kyverno policies. When Kyverno installs itself in your cluster, it will create a ValidatingWebhookConfiguration and a MutatingWebhookConfiguration to apply policies to API requests.

Kyverno policies can validate, mutate, and generate Kubernetes resource configurations. The Kyverno policy library has a full implementation of Pod Security Standards and several other policies to help secure configurations and apply best practices.

Since Kyverno is native to Kubernetes, the project will align with the PSP replacement as the implementation evolves. Hence with Kyverno, you can immediately start auditing or enforcing Pod Security Standards and then later decide if you should enable the built-in PSP replacement when it’s ready and continue using Kyverno for additional policies. 

Installing Kyverno with Pod Security Policies for Kubernetes

Getting started with Kyverno is easy! Let’s install Kyverno using the Helm chart:

Add the Kyverno Helm repository:

helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update

Install Kyverno:

helm install kyverno kyverno/kyverno \
--namespace kyverno – create-namespace \
--set podSecurityStandard=restricted \
--set validationFailureAction=enforce

Once Kyverno is installed you should see the following output from Helm:

 NAME: kyverno
 LAST DEPLOYED: Mon May 24 01:59:49 2021
 NAMESPACE: kyverno
 STATUS: deployed
 REVISION: 1
 NOTES:
 Thank you for installing kyverno v1.3.6 �

 Your release is named kyverno.

 We have installed the "restricted" profile of Pod Security Standards and set them in enforce mode.

 Visit https://kyverno.io/policies/ to find more sample policies.

The Kyverno Helm chart includes policies that implement Pod Security Standards. By default (if no parameters are set), the Helm chart will install the “baseline” profile and the policies will be installed in “audit” mode.

Here we set the parameter “podSecurityStandard” to the value “restricted” and also set the parameters “validationFailureAction” to the value “enforce”. These settings will block any pods or workloads that do not conform to the restricted profile level in the Pod Security Standards. 

Once installed, you can view and customize Kyverno policies using kubectl (cpol is the short name for ClusterPolicy):

λ kubectl get cpol
 NAME                             BACKGROUND   ACTION
 deny-privilege-escalation        true         enforce
 disallow-add-capabilities        true         enforce
 disallow-host-namespaces         true         enforce
 disallow-host-path               true         enforce
 disallow-host-ports              true         enforce
 disallow-privileged-containers   true         enforce
 disallow-selinux                 true         enforce
 require-default-proc-mount       true         enforce
 require-non-root-groups          true         enforce
 require-run-as-non-root          true         enforce
 restrict-apparmor-profiles       true         enforce
 restrict-seccomp                 true         enforce
 restrict-sysctls                 true         enforce
 restrict-volume-types            true         enforce

Conclusion

Kyverno is a powerful and easy to use policy engine designed for Kubernetes that does not require learning a new language to write policies, and does not require adopting new tools to manage policies.

Kyverno already supports the Kubernetes Pod Security Standards, and will align with the future PSP replacement. If you are currently not using PSPs, this makes Kyverno a safe bet to get started with. If you are currently using PSPs, you can easily migrate to Kyverno using the equivalent pod security policies and hence prepare for the deprecation of PSPs. 

In addition, you can also use Kyverno’s powerful generate policies to automate workflows to generate default resources and fine-grained configurations for users and workloads, and enable secure self-service for users. 

If you are already using Kyverno and looking to simplify policy management across your clusters, please checkout the Nirmata Policy Manager for Kyverno. You can register for early access here: https://nirmata.com/nirmata-policy-manager/.

Want High Availability? Get Kyverno 1.4!
What's new in Kyverno 1.3.6!
No Comments

Post a Comment