We’re very excited to announce our new open source tool for managing policies in Kubernetes called jsPolicy. Watch this YouTube video for more info and a demo, or read the transcript below if you prefer.
Hi, I’m Rich with Loft Labs and I’m here to share with you another exciting open source tool that we’ve released for Kubernetes called jsPolicy. Policies are a hot topic in the Kubernetes community and for good reason. Many people operate Kubernetes clusters in regulated environments, and they’re subject to audits like PCI-DSS, HIPAA or SOC 2. And even if you don’t deal with external auditors, you may have internal security audits, or you may just want to enforce policy for your own peace of mind.
Up until now the main option for enforcing policies in Kubernetes has been Open Policy Agent. OPA is great, and people have built a lot of cool things with it. But here at Loft, we’ve been hearing from users who were having trouble with writing and maintaining policies long-term. OPA is complex and uses its own language called Rego which isn’t intuitive for everyone. We believe that platform engineers deserve the same high quality workflows, testing frameworks, and easy to reuse libraries as backend and front end engineers.
Let’s take a look now at how jsPolicy works.
For this demo, I’m using a local Kubernetes cluster running with Docker Desktop, but you can use jsPolicy with any Kubernetes cluster.
Here’s the GitHub repo for jsPolicy. The instructions are in the README.
jsPolicy comes with a number of example policies broken out by use cases and jsPolicy features. We’re going to use one of the example policies in the file called deny-default-namespace.yaml. Let’s have a quick look at the code.
This is an admission control policy. When new resources are created we check the namespace. If it’s set to default we deny the action and return the deny message. That namespace could be a different one than the default namespace or even an array of multiple namespaces. Okay. Let’s get to a shell and see how this works.
We install jsPolicy using Helm.
$ helm install jspolicy jspolicy -n jspolicy --create-namespace --repo https://charts.loft.sh NAME: jspolicy LAST DEPLOYED: Wed May 12 13:24:54 2021 NAMESPACE: jspolicy STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Thank you for installing jspolicy. Your release is named jspolicy. To learn more about the release, try: $ helm status jspolicy -n jspolicy $ helm get all jspolicy -n jspolicy Learn more about using jsPolicy here: https://github.com/loft-sh/jspolicy
I’m in the examples/by-use-case directory and there’s our deny-default-namespace.yaml file. Let’s apply that.
$ cd examples/by-use-case $ kubectl apply -f deny-default-namespace.yaml jspolicy.policy.jspolicy.com/deny-default-namespace.example.com created
You can see that we’ve created a policy. We can see the details of it with kubectl get or describe.
$ kubectl get jspolicy NAME AGE deny-default-namespace.example.com 47s
And there’s our policy.
$ kubectl get jspolicybundle -o yaml apiVersion: v1 items: - apiVersion: policy.jspolicy.com/v1beta1 kind: JsPolicyBundle metadata: creationTimestamp: "2021-05-12T20:26:10Z" generation: 1 name: deny-default-namespace.example.com ownerReferences: - apiVersion: policy.jspolicy.com/v1beta1 blockOwnerDeletion: true controller: true kind: JsPolicy name: deny-default-namespace.example.com uid: 4d654623-679a-418f-b774-299d137cf69b resourceVersion: "1262" selfLink: /apis/policy.jspolicy.com/v1beta1/jspolicybundles/deny-default-namespace.example.com uid: 3e5aa437-7184-462f-8705-9eb7801c7db6 spec: bundle: H4sIAAAAAAAA/0SNwUoDMRRFf+U1iyGBMrg2xI1r0X0p5Tm5QyMxGV9eWssw/y4F0e3lnnOsdeFpvbAQwrp5EzFzz2pCCIKvjqZj4U+0hScMQ0S5WfMsYE21UJ1J0GqXCY2uSc+pkJ5BvxL6Iyk1KlWJc65XxJ1x/p7kgO+lijY/V7H3RSgVguODHAMOcvQYTye0lxp7xjC8vn9g0jFiTgVvUheI3izvzf/J7NcL547H3cPmNmed/wEAAP//AQAA//9BhjR34wAAAA== kind: List metadata: resourceVersion: "" selfLink: ""
Now let’s try to spin up something in the default namespace to see the policy in action. I have a very simple Nginx deployment YAML here that runs two Nginx pods.
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: selector: matchLabels: app: nginx replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.19.10 ports: - containerPort: 80
Let’s try to start it up in the default namespace.
$ kubectl apply -f nginx.yaml Error from server (Forbidden): error when creating "nginx.yaml": admission webhook "deny-default-namespace.example.com" denied the request: Creation of resources within the default namespace is not allowed!
So let’s create a new namespace for Nginx and launch our deployment there instead.
$ kubectl create namespace nginx namespace/nginx created $ kubectl apply -f nginx.yaml -n nginx deployment.apps/nginx-deployment created
That works as expected.
Of course using any programming language inside a YAML file isn’t ideal. So with jsPolicy, you can use our TypeScript starter project to write policies. With TypeScript, you can import the official Kubernetes TypeScript definitions and get types and auto-completion while writing your policies.
We’re very excited about jsPolicy and we’re looking forward to seeing what people do with it. We built jsPolicy because our Loft customers were asking us for a simpler solution for managing policies, but we’ve open sourced it so people who aren’t Loft customers can benefit too. If you’re interested in learning more head over to the jsPolicy GitHub page and try out some of the examples. It’s github.com/loft-sh/jspolicy. Or check out the website on jspolicy.com.