Policies as Code in Kubernetes using jsPolicy

Pavan Kumar
Nerd For Tech
Published in
6 min readSep 24, 2022

--

DevSecops in Kubernetes using jsPolicy

Kubernetes clusters are now everywhere. To run an ML Model you need a Kubernetes cluster, you want to run Data analytics you need a Kubernetes cluster, to deploy your frontend application, backend application, or any type of application you’d need a Kubernetes cluster. But is your cluster secured? Did you ever worry about the security of the cluster? Assume you are trying to run some automation scripts and it accidentally deleted all the namespaces in Production. Boom, it is going to be the longest day in the life of a DevOps Engineer. Even thinking about this might be giving chills to the DevOps engineers reading this. Is there a way to avoid this? Is there a way to effectively control such disasters? jsPolicy to the rescue. jsPolicy is a policy engine for Kubernetes that allows you to write policies in JavaScript or TypeScript.

Advantages of jsPolicy

Advantages of jsPolicy

a) Lightning Fast & Secure Policy Execution: jsPolicy runs policies with Google’s super-fast V8 JavaScript engine in a pool of pre-heated sandbox environments. Most policies do not even take a single millisecond to execute.

b) Great Language For Policies: JavaScript is made for handling and manipulating JSON objects (short for “JavaScript Object Notation” (!)) and Kubernetes uses JSON by converting your YAML to JSON during every API request.

What is the entire story all about? (TLDR)

  1. Securing your K8s cluster using jsPolicy.
  2. Creating secure policies in JavaScript using jsPolicy.

Prerequisites

  1. A Kubernetes Cluster ( EKS, AKS, Kind, etc ).

Story Resources

  1. GitHub Link: https://github.com/pavan-kumar-99/medium-manifests
  2. GitHub Branch: jsPolicy

jsPolicy Installation and Architecture

jsPolicy Architecture

Components

Although jsPolicy runs all of its components in a single container (not considering replicas when you scale up the replica number for high availability), jsPolicy logically consists of three main components:

Webhook Manager

The webhook manager is responsible for registering and managing admission webhooks with the Kubernetes API server so that API server requests will apply the mutating and validating webhooks that are defined as JsPolicy objects.

V8 JavaScript Sandbox Pool

For faster execution of policy code, jsPolicy maintains a pool of pre-heated V8 JavaScript sandboxes that can be used to run JavaScript code containing policy logic.

Policy Compiler

The policy compiler is a controller that monitors JsPolicy resources and that creates and updates JsPolicyBundle objects for all JsPolicy objects that define the spec.javascript field. The compilation process looks about like this:

  1. Retrieve all required npm packages specified in spec.dependencies (similar to npm install downloading the dependencies specified in a package.json file of a regular JavaScript project)
  2. Run webpack to create a highly optimized bundle of JavaScript code that contains the code from spec.javascript and all dependencies while only bundling the functions that are needed for the execution of the code.
  3. Compress the bundle using gzip.
  4. Encode the bundle using base64.
  5. Store the bundle in spec.bundle within the respective JsPolicyBundle object.

Install jsPolicy

The jsPolicy runs all of its components in a single container. This can be easily installed using the helm chart.

$ helm install jspolicy jspolicy -n jspolicy --create-namespace --repo https://charts.loft.sh
jsPolicy pods

Time to see jsPolicy in Action

The Policies are of three types

a) Mutating: Mutating policies are executed as part of kubectl requests right after the API server performs authentication and authorization (RBAC). The objective of mutating policies is to change the payload (Kubernetes object) provided in a request, e.g. automatically add a sidecar container when the pod is created.

b) Validating: Validating policies are executed as part of kubectl requests after the execution of mutating policies. The objective of validating policies is to inspect the request and then to either deny or allow it. e.g. deny the creation of a pod if the namespace is default or deny the creation of the pod if the image is from a public repository.

c) Controller: Unlike mutating and validating policies, controller policies are not part of the lifecycle of a request to the Kubernetes API server. Controller policies are triggered by the Events that Kubernetes creates for each change of the cluster state in etcd.e.g. Automatically creating certain resources in every newly created namespace (e.g. LimitRange, NetworkPolicy etc.)

Let us see all the 3 of them in Action.

Mutate Policy:

This jsPolicy says that it is of type Mutating( Line 6 ) and it is applicable while creating pods ( Line 7,8 ) and the policy says that if the pods that are being created have the annotation “inject-agent”: “true” ( Line 10 ) then the pod should be mutated by an extra sidecar container ( Line 16 ). Let us now create the policy and the pod to test this.

$ git clone https://github.com/pavan-kumar-99/medium-manifests.git \
-b jsPolicy
$ cd medium-manifests$ kubectl apply -f mutate-policy.yaml$ kubectl apply -f pod.yaml

The pod has the required annotations, and the pod should now be created with 2 containers ( And the sidecar being automatically mutated ).

Sidecar automatically Injected

Validation Policy:

Let us delete the pod that we created earlier and then apply the validation Policy.

Default Deny

The validation policy says to Deny the creation of any resources in the default namespace.

$ git clone https://github.com/pavan-kumar-99/medium-manifests.git \
-b jsPolicy
$ cd medium-manifests## Delete the Pod created earlier$ kubectl delete -f pod.yaml## Apply the validation webhook$ kubectl apply -f default-ns-deny.yaml

Let us now try to create the same pod again.

$ kubectl apply -f pod.yaml

Error from server (Forbidden): error when creating “pod. yaml”: admission webhook “deny-default-namespace.devsecops.com” denied the request: Creation of resources within the default namespace is not allowed!

This is what you’d see when you try to create any resource in the default namespace.

Controller Policy:

In this example, we will try to create a resource quota automatically whenever the namespace is created. Provided the namespace should have the labels “create-rq”: “true”.

$ git clone https://github.com/pavan-kumar-99/medium-manifests.git \
-b jsPolicy
$ cd medium-manifests$ kubectl apply -f controller-policy.yaml## Let us now create the namespace with the required labels$ kubectl apply -f namespace.yaml

Once the namespace is created, you can find the ResourceQouta also gets automatically created.

Resource Quota is automatically created

Well, that is how you utilize jsPolicy to write various types of policies in JavaScript and in TypeScript using jsPolicy. Please feel free to share your experience while working on these policies in the comment section.

Until next time…..

Recommended

--

--

Pavan Kumar
Nerd For Tech

Senior Cloud DevOps Engineer || CKA | CKS | CSA | CRO | AWS | ISTIO | AZURE | GCP | DEVOPS Linkedin:https://www.linkedin.com/in/pavankumar1999/