Share and distribute Open Policy Agent Bundles with OpenFaaS functions

One of the features of OpenFaaS is an auto-scaling mechanism. The auto-scaling means is that you can scale up/down your function instances as demand increases. Also, OpenFaaS provides a feature called zero-scale. By enabling this feature, you can scale to zero to recover idle resources is available in OpenFaaS.

Using OpenFaaS as an OPA’s Bundle API, you can have all the features by default with less effort. Also, you can’t have to manage to build/push and deploy phases with your Bundle API.

In this post we are gonna learn:

OPA describes itself as a general-purpose policy engine, for more detail you can look at the official documentation.

OPA’s main goal is to decouple policy decision-making from policy enforcement. When your software needs to make policy decisions it queries OPA and supplies structured data (e.g., JSON) as input. OPA accepts arbitrary structured data as input.


When it comes to deploying OPA, you have more than one option depending on your specific scenario:

  • As a Go library
  • As a daemon

The recommended way is to run OPA is as a daemon. The reason is that this design increases performance and availability. By default, all of the policy and data that OPA uses to make decisions is kept in-memory for the low-latency and we should colocate OPA and the service to avoid the network latency also.


OPA exposes a set of APIs that enable unified, logically centralized policy management which is called “Management API’s”. Think of them as a Control Plane for the OPA instances working as a Data Plane. With the Management API's you can control the OPA instances like enable decision logging, configure the Bundle API, etc.

Let’s focus on Bundle API which is one of the Management API for OPA.

Bundle API’s purpose is to help OPA to load policies across the stack to the OPA instances.OPA can periodically download bundles of policy and data from remote HTTP servers. The policies and data are loaded on the fly without requiring a restart of OPA.

In this demo, we create a serverless function that mimics an OPA’s Bundle API. Simply, this serverless function designed as a plain file server. When OPA’s asks for the policies it basically returns bundles that ready on the filesystem as a response.

You can find all the details about this demo in the Github repo.


  • A Kubernetes cluster (kind, minikube, etc.)
  • OpenFaaS CLI
  • Arkade
  • Kubectl
  • KinD


  • Arkade
$ curl -sLS | sudo sh
  • KinD
$ arkade get kind
  • Kubectl
$ arkade get kubectl
  • faas-cli
$ arkade get faas-cli

You can start a Kubernetes cluster with KinD if you don't have one already

$ arkade get kind
$ kind create cluster
  • Install OpenFaaS using Arkade
$ arkade install openfaas
  • Verify Deployment
$ kubectl rollout status -n openfaas deploy/gateway
  • Enable local access to Gateway
$ kubectl port-forward -n openfaas svc/gateway 8080:8080 &
  • Access password that available in the basic-auth secret in openfaas namespace
$ PASSWORD=$(kubectl get secret -n openfaas basic-auth -o jsonpath="{.data.basic-auth-password}" | base64 --decode; echo)
  • Login with using the password to Gateway
$ echo -n $PASSWORD | faas-cli login --username admin --password-stdin
  • Go to the functions directory, pull the right template and deploy the function
$ cd functions
$ faas-cli template store pull golang-middleware
$ faas-cli up -f bundle-api.yml
  • Load images from Docker Hub to the KinD
$ docker image pull openpolicyagent/opa:latest
$ kind load docker-image openpolicyagent/opa:latest
$ docker image pull openpolicyagent/demo-restful-api:0.2
$ kind load docker-image openpolicyagent/demo-restful-api:0.27. Deploy the application
$ cd ../hack/manifests <br>
$ kubectl apply -f deployment.yaml
  • Verify Deployment
$ kubectl rollout status deployment demo-restful-api
  • Enable local access to the application
$ kubectl port-forward svc/demo-restful-api 5000:80 &


Rego is the DSL for the OPA. We can author our policies using the rego.

For this tutorial, our desired policy is:

  • People can see their own salaries (GET /finance/salary/{user} is permitted for {user})
  • A manager can see their direct reports’ salaries (GET /finance/salary/{user} is permitted for {user}’s manager)
  • This command will succeed because Alice wants to see your own salary.
$ curl --user alice:password localhost:5000/finance/salary/alice
  • bob is not charlie’s manager, so the following command will fail.
$ curl --user bob:password localhost:5000/finance/salary/charlie
  • bob is Alice's manager, so the following command will succeed.
$ curl --user bob:password localhost:5000/finance/salary/alice

I do mostly Go, Kubernetes, and cloud-native stuff ⛵️🐰🐳