Kubernetes Policy Enforcement: OPA vs jsPolicy
Tags: kubernetes, vcluster, devspace, loft
Published: 2022-06-16 16:22:58

By [Sanni Michael](https://twitter.com/sannimichaelse)

If you need a policy management tool for your Kubernetes clusters, you have several options to choose from. Two popular policy tools are Open Policy Agent and jsPolicy.

Open Policy Agent, or OPA, is a domain-agnostic and general-purpose policy engine that allows you to decouple policy- and decision-making from a system so enforcement is handled separately. OPA uses high-level declarative language to define policies as code. It can be used to enforce policies in microservices, Kubernetes, CI/CD pipelines, and API gateways.

The tool jsPolicy was recently launched as a policy management tool for Kubernetes and 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.

This article will compare OPA and jsPolicy in Kubernetes as well as their language and learning curves in relation to developer experience; we’ll then look at policy testing so that you can select the best tool for your projects.

## Language

OPA uses Rego, which is a domain- and platform-agnostic declarative language for defining and enforcing policies in a cloud-native environment. Rego allows users to focus on what the queries should return rather than how they should be returned. The language also optimizes queries to improve performance. According to the Rego documentation, it is designed in layers and therefore not Turing complete, meaning it isn’t a language that can [perform every type of computation](https://stackoverflow.com/questions/7284/what-is-turing-complete). 

To read more about Rego’s design pattern, check out [this article](https://blog.openpolicyagent.org/rego-design-principle-3-optimize-performance-automatically-2d29ad3ce96d).

With jsPolicy you can define policies using JavaScript or TypeScript. Its large community of users means that you can easily reuse and share policies via a package manager like npm. You can also access the libraries and reuse them in policy definition, or import an external dependency or module. Also, jsPolicy is Turing-complete, providing loops, Promises, linting, test frameworks, and all other modern JS language features and development best practices so you can write clean and easy-to-maintain policies.

A developer or operator who already knows JavaScript could quickly adapt to jsPolicy, since they wouldn’t need to learn a new language to define policies in a Kubernetes cluster.  

Rego is not a platform-dependent language, but the developer or operator would still need to learn it as well as how to use it to define policies in the cluster.

## Developer Experience

There are several ways to set up OPA. If you are using Go, you can import the OPA policy package into your application as a dependency. You can also set up OPA as a daemon, which is a separate process. You can run the daemon deployment as a sidecar container in one of your pods, which makes it easy to access the OPA container. It’s also possible to run the OPA process in one of your Kubernetes nodes. 

The most important thing is to ensure your applications can access the OPA daemon easily without sacrificing latency. For example, it doesn’t make sense to deploy the daemon on a node while your application resides on a separate node. This can cause your application to make unnecessary calls between nodes. 

This image (courtesy of magalix.com)  shows the various deployment options:

![Courtesy of magalix.com](https://loft.sh/blog/images/content/opa-vs-jspolicy-1.png)

To set up jsPolicy in your cluster, just install the charts via `Helm v3`, then create a YAML file and apply it to your cluster. It’s also possible to write the entire policy in a separate JavaScript or TypeScript file and load the policy from the file. A sample YAML file to set up jsPolicy is given below, or you can check [here](https://www.jspolicy.com/docs/quickstart) for more instructions.

To install the policy via Helm v3, you can run:

```
helm install jspolicy jspolicy -n jspolicy --create-namespace --repo https://charts.loft.sh
```

Then, create a sample `policy.yaml` file and apply it to your cluster:

```
​​# policy.yaml
apiVersion: policy.jspolicy.com/v1beta1
kind: JsPolicy
metadata:
  name: "deny-default-namespace.company.tld"
spec:
  operations: ["CREATE"]
  resources: ["*"]
  scope: Namespaced
  javascript: |
    if (request.namespace === "default") {
      deny("Creation of resources within the default namespace is not allowed!");
    }
```

The intuitive nature of jsPolicy makes it easier to write more understandable and easy-to-maintain policies. You don't have to be a JavaScript expert to use it, and there are plenty of resources online for learning the language.

OPA also contains several tools for building and developing policies, which makes it easier to define policies during the development stage. A [VS Code plugin](https://marketplace.visualstudio.com/items?itemName=tsandall.opa) can be installed to ease testing, debugging, and analysis of policies for a particular project. 

## Maintainability

While OPA allows you to create several policies using Rego, there is no limit to the number of policies that can be created and tested with the OPA test framework (`opa test`). Maintaining a large number of policies written in Rego can be a problem because it’s hard to use for writing policies in the first place and even harder to understand. When the number of policies written with Rego goes up, this can be difficult to maintain due to the complexity of the language and the learning curve. Since OPA allows you to write and verify the correctness of your policies, you will need to maintain the test files and various test cases and ensure it’s always passing at all times. This can improve and validate the quality of the policies as new ones are added over time, making it easy to maintain and scale the policies.

If you use jsPolicy, you can write policies as external JavaScript files and load them as a dependency. You can create policies for a particular use case and add more as the situation demands. This means that you can scale, import, and add policies on the fly without worrying about how the policies will be applied to the cluster. In addition, jsPolicy is easier to maintain because the language is simple to understand and doesn’t require much expertise to get started. You will need to maintain these files through a version control system like Git, GitHub, Bitbucket, or another repository, ensuring the configuration files are always up to date. 

## Testability of Policies

OPA makes it easy to test and verify your policies. This can speed up the development of policies as well as the addition of new ones. OPA provides the CLI `opa test` for testing policies, which are usually written in Rego. For example, running this command against some Rego files in a particular folder outputs the results of OPA tests. 

For running tests in `opa`, run:

```
 opa test . -v
```

This will run all the tests in the directory with Rego files, *ie*, with `.rego` file extension.

An `opa test` will execute any Rego file with the rule name prefixed with `test_`.  The OPA test CLI also discovers tests in a folder by loading the contents of the folders recursively and executing with the rule name prefixed with `test_`. Other features supported by the OPA CLI include:

* data mocking
* coverage
* modifying test result outputs

On its website, OPA provides comprehensive details on how to verify and test policies. You can learn more [here](https://www.openpolicyagent.org/docs/latest/policy-testing/).

Since policies created with jsPolicy are written in JavaScript or TypeScript, you can use a testing framework like Mocha or Jest. You can use unit tests, functional tests, integration tests, or end-to-end tests. Note that it’s easier to verify the correctness of policies when they are loaded as an external JavaScript file. This also makes it easier to scale, isolate, and test the policies. For an example of creating tests with jsPolicy, check [here](https://github.com/loft-sh/jspolicy-sdk).

## Conclusion

While OPA and jsPolicy both help you to create and test policies in a cluster, each policy engine comes with advantages and disadvantages depending on the context, learning curve, and previous domain experience of a developer. If you have previous experience using JavaScript you might prefer jsPolicy for its quick learning curve. On the other hand, if you’re looking for a language- and domain-agnostic tool, OPA is a good choice. 

OPA is widely used in organizations. Netflix uses OPA to control access to its internal API resources. Chef uses it to provide IAM capabilities for its end-user products. Cloudflare and Pinterest also use it to enforce policies on their platforms. You can read more about this [here](https://www.cncf.io/blog/2020/08/13/introducing-policy-as-code-the-open-policy-agent-opa/).

[Loft Labs](https://loft.sh/), the company that created and maintains jsPolicy, is gaining traction due to innovative tools like [vcluster](https://www.vcluster.com/), an open source tool for creating virtual Kubernetes clusters. This visibility will likely help increase the adoption of jsPolicy.

Either engine could be a good choice for your business. Consider which factors are most relevant to your project and your use case before you make a decision. You can learn more about jsPolicy [here](https://www.jspolicy.com/) and about OPA [here](https://www.openpolicyagent.org/).

*Photo by [Coffee Geek](https://unsplash.com/@coffeegeek?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/compare?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)*