Using open policy agent to implement kubernetes pod security policy

Time:2020-9-16

Kubernetes is the most popular container choreography platform in today’s cloud native ecosystem. Therefore, the security of kubernetes has attracted more and more attention.

In this blog post, I will first discuss the pod security policy admission controller. Then we’ll see how the open policy agent implements the pod security policy. In fact, open policy agent is considered as a potential alternative to pod security policy.

First, a brief introduction to containers, security and access controllers.

Introduction to containers and safety

The container is light, light and easy to manage. Containers running on the same host do not have separate physical / virtual machines. In other words, containers share the resources, hardware, and OS kernel of the host on which they are running. Therefore, it is very important to have appropriate security, which involves which processes can run in the container, what privileges these processes have, whether the container will allow privilege escalation, what kind of image is used, and so on.

The simplest unit of creation or kunetberes is the smallest unit of your application or kunetd. It is a group of one or more containers with shared storage / networks and specifications on how to run containers. Therefore, when we implement the security policy on the container, we will check the security policy and apply it to the pod specification. So, how are these strategies implemented? Use access controller.

What are permission controllers?

Admission controller is a part of Kube apiserver. They block requests to the kubernetes API server before the configuration is stored in the cluster settings (etcd). The admission controller can be validating (one used to verify an incoming request) or mutating (one used to modify an incoming request) or both. Refer to the kubernetes documentation for a quick overview of the various admission controllers.

Open policy agent as admission controller

Open policy agent (OPA) is a general open source policy engine, which can write policies into code. OPA provides a high-level declarative language – Rego – with policies as code. With OPA, we can execute policies across microservices, CI / CD pipelines, API gateways, etc. One of the most important use cases of OPA is kubernetes’ policy implementation as access controller.

As an access controller, OPA can enforce policies such as non root users, require specific resource tags, and ensure that all pods specify resource requests and restrictions. Basically, OPA allows you to code any custom policies in the Rego language.

These policies are written in Rego and loaded into OPA and run as access controllers on the kubernetes cluster. OPA will evaluate any resource creation / update / delete requests to the kubernetes API server based on the Rego policy. If the request satisfies all policies, the request is allowed. However, even if a single policy fails, the request is rejected.

Read more about OPA, Rego here and use it as access controller in OPA documentation.

Pod Security Policy

Pod security policy (PSP) is a cluster level resource implemented as access controller. PSP allows users to translate security requirements into specific policies that manage the pod specification. First, when the podsecuritypolicy resource is created, it does nothing. In order to use it, the service account requesting the user or target pod must be authorized to use the policy by allowing the use verb. You can refer to the enabling pod security policy on the kubernetes documentation.

Note that the PSP admission controller acts both as a validation role and as a mutation admission controller. For some parameters, the PSP admission controller uses default values to change incoming requests. In addition, the sequence is always mutation first and then verification.

What are all the parameters we can control with PSP?

The following table provides a brief overview of the various parameters and fields used in the PSP. Detailed instructions are provided in the kubernetes documentation here.

So, can we implement PSP in OPA?

As mentioned earlier, the Rego language allows us to code any custom policy. This means that we can use Rego to write the above pod security policy and execute it with OPA as the access controller.

Let’s take a quick look at the Rego policy that implements the “privileged” pod security policy. You can try this strategy in Rego playground.

package kubernetes.admission

deny[message] {
    #applies for Pod resources
    input.request.kind.kind == "Pod" 
    #loops through all containers in the request
    container := input.request.object.spec.containers[_]
    #for each container, check privileged field
    container.securityContext.privileged
    #if all above statements are true, return message
    message := sprintf("Container %v runs in privileged mode.", [container.name])
}

So, what is the role of this strategy? If any container in the input request is running as a privileged container, it returns a message.

PSP practice

Let’s take a mini cube based tutorial to see how this strategy works. First, set OPA as access controller according to the tutorial in OPA document here. This tutorial loads the entry validation policy. Instead, we will load the privilege policy shown above.

After you set OPA to the access controller on minicube, create the file using the above policy privileged.rego 。 Then, create the policy as configmap in the “OPA” namespace.

kubectl create configmap privileged-policy --from-file=privileged.rego -n opa

Wait for the policy to load into OPA. When the configmap comment is addedopenpolicyagent.org/policy-status:'{"status":"ok"}'Item indicates that the policy has been loaded.

Now, let’s create a deployment with a privileged container using the following listing:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    securityContext:
      privileged: true

When you try to create this pod, you will notice that the open policy agent rejected the pod.

Error from server (Container nginx runs in privileged mode.): error when creating "privileged-deploy.yaml": admission webhook "validating-webhook.openpolicyagent.org" denied the request: Container nginx runs in privileged mode.

Similarly, we can write policies for other pod security policy parameters and implement them using OPA.

In this tutorial, we used configmap to load the policy for simplicity, but this is not the best strategy for production deployment. For production deployment, OPA can be configured to periodically download policy bundles from external bundling servers. All of your policies can be maintained in this bundle server. OPA will keep up-to-date by regularly downloading policies. Refer to the bundle API for more details.

In short, with OPA, we can implement pod security policy. Not only that, we can use the same settings to implement any other custom based.

What are the main benefits of using OPA for PSP?

Some of the main benefits we get from this approach are:

  • Centralized management of all policies (PSP and other custom policies) in one access controller without having to manage them separately
  • The same policy is implemented in the CI / CD pipeline to implement code by code throughout the stack.
  • Ability to maintain OPA policies in a source controlled repository such as GIT. OPA provides an HTTP API to dynamically manage loaded policies.
  • Stream policy decisions to an external logging / monitoring tool of your choice.
  • Customize the reject message according to your settings / implementation.

In addition, we can deploy OPA as mutation admission controller. In this way, you can also implement the mutation behavior of PSP permission controller.

conclusion

We can effectively implement pod security policy through OPA. In addition, this enables us to model security policies as code. And all of this is in an OPA access controller.

PS: This article belongs to translation