Using XACML with OPA and Rego: The Best of Both Worlds

3 min read

Preface 

XACML is an OASIS standard for implementing declarative authorization policy. It was intended to be a widely adopted technology that would move authorization policy decisions out of application code and into a specialized Policy Decision Point (PDP). The terms often used in the OPA world, such as PDP, PIP (Policy Information Point) and PEP (Policy Enforcement Point) all come from the XACML standard. You can read more about XACML in this post on architecting authorization for entitlements.

The downside of XACML is its XML-based policy. In truth, it’s more of an XML configuration file than a  policy language, which probably contributed heavily to XACML’s limited uptake in the past 10 years. In this blog post, my intention is not to bash XACML; rather I want to focus on how existing XACML applications can be integrated with OPA and Rego policy for a best-of-both-worlds solution.

Let’s take a look at an XACML policy from the official Oasis docs:

This policy allows all “ServerAction / login” actions between 9 AM and 5 PM. We can see how hard this policy is to read and reason around. 

As Brad Cox put it: “[XACML has] a XML-based syntax so hideous it makes your eyes bleed. Compared to XACML even COBOL and MUMPS look good.” That might be a bit harsh, but it shows why the Rego policy language is typically be much better at expressing policy.

OPA and XACML

As opposed to XACML, OPA is not a standard defined by committee, but rather an open source project that has evolved over the years, driven by its users. With a significant uptake (130M+ downloads), it is fast becoming a de-facto standard for authorization in the cloud-native landscape of technologies. The main difference between OPA and XACML is that OPA only has one implementation, which leads to less fragmentation of the technology. Even more importantly, OPA uses the Rego declarative programming language to define policy.

So, how can we get that best-of-both-worlds solution? By using XACML JSON Profile, we can send XACML requests to OPA and receive XACML responses back. As OPA is, essentially, an engine that processes input JSON and turns it into a JSON output, it can also talk to an XACML client.


Let’s try to convert the above policy to Rego. In JSON the request will look like this:

Our policy will either allow or deny this request — or in the language of XACML, it will produce a Permit or Deny decision.

Let’s write unit tests for both the “Permit” and “Deny” cases. Here we can see another advantage of the Rego language: unit testing. Rego has first-class support for creating elegant unit tests. Such a simple and straightforward way for testing policies simply doesn’t exist for XACML. 

Now that we have our expectations set, let’s create the policy that will pass this test. To make it easier to create complex policies, we need to divide our Rego rules into ones that, on the one hand, make the actual decision, and the other, create the correct output.

To create the right output message, we can define rules like this:

It’s overly simple, but does the job for basic XACML responses. All of the actual decision logic can now be delegated to the permit rule. 

The permit rule can then be written as such:

This should produce the same result as the original XACML rule. We can see how much more concise and readable the Rego rule is compared to XACML. Note that time_today is not a built-in function, but a helper defined by me for this rule. You can see the full example in this repo.

More complex policies and rules combining algorithms

Currently, we only have a single policy rule — but in a realistic scenario, the situation would be more complex than that. Let’s add two more rules:

  • A user can log out at any time
  • All actions except logout are denied during the weekend

In this case, we will have to be able to handle priorities between permit and deny decisions. XACML has a well-defined mechanism for this in the form of rule combining algorithms. The user can choose which algorithms to apply for resolving these conflicting priorities. Examples are:

  • Deny-overrides: If any decision is “Deny,” the result is “Deny”
  • Permit-overrides: If any decision is “Permit,” the result is “Permit”

OPA doesn’t have this concept because it’s not really needed. We can implement such algorithms easily using Rego language primitives. We basically want a “Deny-overrides” overall policy decision if any deny rules are activated, then the overall result is deny; otherwise, the result is permit, as long as at least one permit rule has been activated.

To achieve this, we can modify our Response rule like this:

Now we can implement our two new policy rules:

Summary

Rego policies executed with OPA can transparently take the place of XACML policies in systems that are built for XACML. The XACML JSON Profile enables XACML clients to communicate with OPA. Rego policy can be written in a way to process XACML requests and return valid XACML responses.

To learn more about OPA policy authoring, be sure to check out our Styra Academy courses, in addition to our many blogs about everything OPA.


Read More from Styra Blog:

OPA vs XACML

Kubernetes Compliance

Microservices Authorization

What is Kubernetes Security

Granular Authorization

Cloud native
Authorization

Entitlement Explosion Repair

Join Styra and PACLabs on April 11 for a webinar exploring how organizations are using Policy as Code for smarter Access Control.

Speak with an Engineer

Request time with our team to talk about how you can modernize your access management.