Introduction to Open Policy Agent: A Hands-on Guide

Open Policy Agent is an open-source policy engine that decouples policy decisions from enforcement. It provides a unified framework for defining and enforcing policies across infrastructure, from Kubernetes to API gateways and CI/CD pipelines.

6 days ago   •   10 min read

By Ayaan Bordoloi
In this article

Running applications is has become more complicated as teams work with different programming languages, use a mix of servers, cloud platforms, and hybrid setups, and rely on tools like Kubernetes to manage containers. Data flows in from various sources such as application logs, user interactions, APIs, external services, and databases making things even more complex.

With so much data flowing in, organizations need a clear way to govern how it's managed keeping it secure, consistent, and compliant. To tackle this, they often turn to various tools for specific tasks. But over time, this can lead to a tangled mess of tools and technologies, making it harder to manage policies and maintain order across all these systems.

To bridge this fragmentation, unify policy management, and offer a declarative approach to handling these challenges easily, Open Policy Agent (OPA) acts as a powerful tool designed to bring order to the chaos by unifying policy enforcement across diverse and distributed environments.

What is Open Policy Agent (OPA)?

First, let’s understand what a policy is. To put it simply a policy is nothing but a set of rules that needs to be followed. Every organization, big or small, relies on policies to create structure and ensure things run smoothly. Even organizations without formal policies still need to comply with regulations, agreements, and laws.

Policies are essential because they provide clarity, consistency, and control. They define who can do what, establish security measures, and ensure compliance with legal and industry standards. Without clear policies, there’s a risk of confusion, errors, and even serious breaches, making them a critical part of any well-functioning system.

A software policy consists of things like; What roles are required to perform different actions in a system, Which machines on a network should be considered trusted, Default resource allocation for new application deployments, etc. To enforce these policies effectively, you need a way to evaluate them against real-world scenarios. This is where a policy engine comes in. A policy engine is a tool that takes in a set of rules and evaluates them against incoming data to decide whether something is allowed or denied. 

Why Open Policy Agent (OPA)?

As we already discussed at the start of this blog, running applications these days has become increasingly complicated with organizations adopting distributed architectures, multi-cloud strategies, and microservices. This technological diversity creates new challenges like enforcing and managing so many policies across such diverse systems.

Imagine trying to manage rules across such diverse systems. Let’s say that you are running your applications on a managed Kubernetes cluster such as EKS. The Kubernetes cluster might need one set of policies for managing the different Kubernetes resources, AWS might need a completely different set of rules, and your API gateways might require another for access control. This fragmented approach leads to several issues including gaps in policy enforcement as policies are applied differently across systems, leading to potential security and compliance risks. It also becomes time-consuming and error-prone when managing policies across multiple tools. It would also be a nightmare to update and maintain policies across the different operational systems when organizations grow.

Open Policy Agent (OPA) steps in to make things easier for us. It is like your go-to decision-maker for enforcing rules, no matter where your applications are deployed or what technologies you use. With Open Policy Agent (OPA), you don’t have to juggle separate rules for each system. You define your policies in one place, and OPA applies them everywhere. It works across everything such as Kubernetes, application APIs, cloud provider infrastructure, and more ensuring that policy enforcement is consistent across all environments and closes the gaps caused by diverse systems. It also automates the decision-making process which means there is less manual work and fewer errors.

How Open Policy Agent (OPA) works?

Imagine you’re managing an application for a company that stores sensitive employee data in a database. One day, an employee named Bob tries to access this database to view certain records. Here’s how Open Policy Agent (OPA) would handle this scenario step by step:

Open Policy Agent (OPA) Architecture
[Fig.1] Open Policy Agent (OPA) Architecture

Receiving a Request

Bob clicks a button in the app to view specific employee data. This triggers a request from the app to the database. Before granting access, the app needs to decide: Does Bob have the necessary permissions to view this data?

Sending a Policy Query to OPA

The app forwards the details of Bob’s request to OPA as a policy query. This query includes information like:

  • Who is making the request? (Bob, who has a "viewer" role)
  • What is the action? (Trying to "read" employee data)
  • What is the resource? (A specific section of the database)

OPA receives this query and prepares to evaluate it based on the policies that have been defined.

Evaluating the Policy

OPA evaluates the query against its policy rules. For example, one policy might say:

“Only users with the 'admin' role can access sensitive employee data.”

OPA compares Bob’s role ("viewer") with this rule. Additionally, OPA can reference extra data, like role definitions or work hours, if needed. In this case, OPA sees that Bob’s role doesn’t match the required "admin" role.

Making a Decision

Based on the evaluation, OPA decides to deny the request. It sends a response back to the app with the decision:

Decision: “No”

Explanation: “Access denied because the user doesn’t have the 'admin' role.

Acting on the Decision

The app receives OPA’s response and blocks Bob’s access to the database. It might also show a message explaining why access was denied:

"You don’t have the required permissions to view this data. Please contact an administrator if you need access."

This process ensures that access is granted or denied based on clear, consistent rules. Whether it’s a database request, a Kubernetes resource, or an API call, OPA enforces policies in the same way, maintaining security and governance across all systems.

Policy Authoring & Rego

When it comes to defining policies in Open Policy Agent (OPA), we use a query language called Rego. It is a declarative, high-level language designed specifically for expressing policies. Think of it as similar to SQL, but instead of querying databases, Rego is used to query and enforce rules. Policies in Rego are made up of rules, where each rule defines a condition and the result. For example, a rule might state that only certain users can access a resource. These rules can return various outputs, like “allow” or “deny,” or even more detailed JSON responses like lists, booleans, or strings. 

  • Lists are useful for returning multiple values, such as a list of permitted actions or accessible resources.
  • Booleans are ideal for simple yes/no decisions, like whether access should be granted.
  • Strings provide descriptive feedback, such as reasons for denial or additional context for logging.

Rego is packed with tools to make policy writing easier. It includes over 150 built-in functions for things like verifying JSON Web Tokens (JWTs), handling IP address ranges, and working with dates and times. However, Rego doesn’t stop there. It empowers you to create fully custom policies tailored to your specific requirements. While the built-in functions handle many scenarios, you can define your own rules and logic to address unique challenges in your environment. It also includes a framework for unit testing policies, ensuring that your policies behave as expected. To make Rego more approachable, Open Policy Agent (OPA) provides tools like the Rego Playground, an interactive, web-based environment where you can write and test policies without needing to set up anything locally.

Policy Data

Policies need context to make decisions, and that’s where policy data comes in. This data provides the background that Open Policy Agent (OPA) uses to evaluate a rule. For instance, if a policy says only admins can access a system, Open Policy Agent (OPA) needs data to know who is an admin. This data can be passed along with a request, like a token showing the user’s role. Or, it can be included in the input you send to OPA, such as user details and their permissions.

Let’s take an example here to understand it more clearly-

Suppose you have a request to access a resource, and Open Policy Agent (OPA) needs to decide if the user is allowed to proceed. The request might include data like:

  • User’s ID
  • User's Role (Admin, User, Guest)

The policy data in this case would be information like:

  • "User 123 is an Admin."
  • "User 456 is a Regular User."

When Open Policy Agent (OPA) gets the request, it checks the policy data to see if the user has the admin role. If the data says "User 123 is an Admin," Open Policy Agent (OPA) would allow the request. But if it says "User 456 is a Regular User," Open Policy Agent (OPA) would deny access.

In a more advanced scenario, this data could come from a database, a token, or an external API. You can either send this data directly with the request or have Open Policy Agent (OPA) fetch it from a source beforehand.

Open Policy Agent (OPA) Installation and Testing

Now that we’ve explored what Open Policy Agent (OPA) is, why it’s essential, and how it operates, let’s move on to the next step: installing Open Policy Agent (OPA) and verifying its functionality.

Download the binary with the following curl command and save it under the name opa.

Linux (64-bit):

curl -L -o opa https://openpolicyagent.org/downloads/latest/opa_linux_amd64

This command downloads the latest version of the Open Policy Agent (OPA) binary for Linux systems.

macOS (64-bit):

curl -L -o opa https://github.com/open-policy-agent/opa/releases/download/v0.11.0/opa_darwin_amd64

This command downloads the latest version of the Open Policy Agent (OPA) binary for macOS systems.

After downloading the file, execute the chmod command to grant permission.

chmod 755 ./opa

To make opa accessible globally, move it to a directory in your system's PATH

sudo mv opa /usr/local/bin/

Test if Open Policy Agent (OPA) is installed correctly by running:

opa version

You should see the version details of OPA.

Open Policy Agent Version
[Fig.2] Open Policy Agent Version

How to deploy OPA in Kubernetes

Since we have a good grasp of OPA, let’s integrate it with Kubernetes using Gatekeeper, a Kubernetes-native admission controller built for OPA. Gatekeeper is an admission controller that works alongside OPA, making it easier to enforce policies across a Kubernetes cluster. Instead of manually configuring OPA as a webhook, Gatekeeper simplifies enforcement with native Kubernetes resources. 

In this hands-on demo, we’ll install OPA Gatekeeper and create policies to manage how resources are deployed in our cluster. 

Step 1: Installing OPA Gatekeeper in Kubernetes

To follow this tutorial, ensure you have Kubectl and Helm installed, along with access to a Kubernetes cluster.

Add the Gatekeeper Helm Repository

helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts helm repo update

Now, install Gatekeeper in your cluster with this command.

helm install gatekeeper/gatekeeper \
--namespace gatekeeper-system \
--create-namespace

Verify installation

kubectl get pods -n gatekeeper-system

You should see multiple Gatekeeper pods running, which proves that Gatekeeper is now ready to use.

Step 2: Create a Constraint Template

Constraint templates define reusable policies using Rego. Let's create a policy that prevents pods from using the "latest" tag in container images.

Save the following YAML file as constraint-template.yaml:

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8sdenylatest
spec:
  crd:
    spec:
      names:
        kind: K8sDenyLatest
      validation:
        openAPIV3Schema:
          properties:
            message:
              type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sdenylatest

        violation[{"msg": msg}] {
          input.review.kind.kind == "Pod"
          input.review.object.spec.containers[_].image == "latest"
          msg := "Using 'latest' tag is not allowed."
        }

Let’s understand what’s happening in the above YAML manifest.

  • Defines a policy to deny pods using the "latest" tag for images.
  • Uses Rego to check if any container in the pod has "latest" as its tag.
  • Triggers a violation with the message: "Using 'latest' tag is not allowed."
  • This applies to Kubernetes admission requests through Gatekeeper.

Apply the constraint:

kubectl apply -f constraint.yaml

Step 3: Create a Constraint

Now, we need to enforce the policy by creating a Constraint. This applies the policy template to Kubernetes objects.

Save the following YAML as a constraint.yaml:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyLatest
metadata:
  name: deny-latest-tag
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    message: "Pods using the 'latest' tag are not allowed."

Apply the constraint:

kubectl apply -f constraint.yaml

Now, any pod using the latest tag will be blocked before creation.

Step 4: Testing the Constraint Policy

You can now test your constraint! Based on the rule we’ve created, the following behavior should be observed:

  • Pods with a specific image tag (not latest) will be allowed.
  • Pods using the latest tag will trigger an error and won’t be added to the cluster.

Save the following YAML as allowed-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: allowed-pod
spec:
  containers:
    - name: nginx
      image: nginx:1.21.6

Apply the pod:

kubectl apply -f allowed-pod.yaml

The pod will be created because it follows the policy.

Now, save the following YAML as denied-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: denied-pod
spec:
  containers:
    - name: nginx
      image: nginx:latest

Try applying the pod:

kubectl apply -f denied-pod.yaml

This time your request will be denied by Gatekeeper, and you’ll see an error message:

Error from server: admission webhook "validation.gatekeeper.sh" denied the request: Pods using the 'latest' tag are not allowed

This confirms that the OPA Gatekeeper is correctly enforcing the policy in the Kubernetes Cluster.

FAQ

What is OPA?
OPA is a general-purpose policy engine that allows you to define and enforce policies across various systems using a declarative language called Rego, effectively decoupling policy decisions from application logic.
What is Rego?
Rego is the policy language used in OPA, designed to be easy to read and write, enabling users to express complex policy rules in a structured way.
What are the benefits of using OPA?
OPA provides advantages like centralized policy management, improved security, flexibility to adapt policies quickly, better auditability, and separation of concerns between application logic and policy decisions.
Can I use OPA with Kubernetes?
Yes, OPA can be easily integrated with Kubernetes as an admission controller to enforce policies on deployments and other resources before they are created
How do I test OPA policies?
OPA supports policy testing by allowing you to write test cases that simulate different input scenarios and verify expected results.

Conclusion

To wrap it up, Open Policy Agent (OPA) is a simple yet powerful tool for managing and enforcing policies across your systems. With its easy-to-use policy language, Rego, OPA ensures that policies are consistently applied, no matter how complex or distributed your environment is. With easy installation, simple integration, and support for dynamic policy evaluation, OPA is a valuable tool for modern cloud-native architectures, helping ensure that security and compliance are maintained without compromising performance.

Related articles

Spread the word

Keep reading