DEV Community

Cover image for Kubernetes policy management: IV - jsPolicy
Ashok Nagaraj
Ashok Nagaraj

Posted on • Updated on

Kubernetes policy management: IV - jsPolicy

This is the final post of the series.

Other parts:
I - Introduction
II - OPA Gatekeeper
III - Kyverno


jsPolicy offers a simple alternative to OPA. You can use it to write policy logic in JavaScript or TypeScript, and it offers Turing completeness, easy cluster access, and a huge ecosystem of libraries. Other features include validating, mutating, or changing policies, and defining controller policies. It uses Chrome V8 engine underneath, so performance and stability are battle tested

Installation

❯ helm install jspolicy jspolicy -n jspolicy --create-namespace --repo https://charts.loft.sh
NAME: jspolicy
LAST DEPLOYED: Tue Mar  8 20:46:34 2022
NAMESPACE: jspolicy
STATUS: deployed
...
❯ kubectl get crds | grep jspolicy
jspolicies.policy.jspolicy.com           2022-03-08T15:16:28Z
jspolicybundles.policy.jspolicy.com      2022-03-08T15:16:28Z
jspolicyviolations.policy.jspolicy.com   2022-03-08T15:16:28Z

Enter fullscreen mode Exit fullscreen mode

Architecture
jsPolicy architecture from loft labs

Creating and instantiating policies
Validating policy to disallow workload creation under namespaces default and restricted

❯ cat /tmp/policy.yaml
# policy.yaml
apiVersion: policy.jspolicy.com/v1beta1
kind: JsPolicy
metadata:
  name: "deny-default-namespace.example.com"
spec:
  operations: ["CREATE"]
  resources: ["*"]
  scope: Namespaced
  javascript: |
    var namespacesToDeny = ["default", "restricted"];
    if (namespacesToDeny.includes(request.namespace)) {
      deny("Creation of resources is not allowed in the following namespaces: " + namespacesToDeny.toString());
    }

❯ kubectl create -f /tmp/policy.yaml
jspolicy.policy.jspolicy.com/deny-default-namespace created
Enter fullscreen mode Exit fullscreen mode

Mutating policy to add a foo=bar label to pods

❯ cat /tmp/mutate.yaml
apiVersion: policy.jspolicy.com/v1beta1
kind: JsPolicy
metadata:
  name: "create-foo-bar-label.example.com"
spec:
  type: Mutating
  operations: ["CREATE", "UPDATE"]
  resources: ["pods"]
  javascript: |
    if (request.object.metadata.labels?.["foo"] !== "bar") {
      request.object.metadata.labels = {...request.object.metadata.labels, 'foo': 'bar'};

      // tell jspolicy to calc the patch and exit
      mutate(request.object);
    }

❯ kubectl create -f /tmp/mutate.yaml
jspolicy.policy.jspolicy.com/create-foo-bar-label.example.com created
❯ kubectl run test-pod --image=nginx -n test-ns
pod/test-pod created
❯ kubectl get pod -n test-ns --show-labels
NAME       READY   STATUS              RESTARTS   AGE   LABELS
test-pod   1/1     Running             0          14s   foo=bar,run=test-pod

Enter fullscreen mode Exit fullscreen mode

Testing

❯ kubectl run test-pod --image=nginx --restart=Never
Error from server (Forbidden): admission webhook "deny-default-namespace.example.com" denied the request: Creation of resources is not allowed in the following namespaces: default,restricted
Enter fullscreen mode Exit fullscreen mode

Extra tools
Policies created for jsPolicy are regular javascript files =>

  • You can develop policies with your favorite editor
  • You can test(unit, functional, scale) with any javascript test frameworks like Jest, Mocha ..
  • You can write policies as external JavaScript files and load them as a dependency This is a programming library so it can be scaled, evolved and maintained with relative ease over time.

More info
jsPolicy configuration
jsPolicy custom javascript functions
Comparison with OPA


I love the rationale(improve understandability) behind JSPolicy

Top comments (0)