Flexible policy composition - Local & export variables in Cerbos policies

Published by Aldin Kiselica on July 26, 2023
Flexible policy composition - Local & export variables in Cerbos policies

Cerbos has continuously evolved to provide you with cool features. Variables were first introduced experimentally in v0.8, offering a way to reduce duplication in policy conditions. Building on this foundation, they were further refined and stabilized in v0.9, making them even more valuable for crafting robust access control rules.

However, there was one limitation - variables were restricted to each individual policy, making it impossible to reuse them across multiple policies. When there was a need to use the same variable across the configuration, this led to repetition and sub-optimal policy maintainability. But with the latest release of Cerbos v0.29, this limitation has been overcome with the introduction of exportVariables - an enabler to share variables across the configuration. This enhancement empowers policy authors to define variables in a dedicated file and effortlessly import them into multiple policies. Not only does this reduce duplication within policies, but it also streamlines policy management across the entire access control system.

In this piece, we'll explore how to leverage Cerbos' new exportVariables feature and compare it with the old approach of using local variables within policies.

How to use exportVariables with Cerbos Policies?

The first thing you need to do is update your version of Cerbos accordingly. The feature we’re covering is available since v0.29 so that is the lowest you should aim for in order to be able to use exportVariables. See installation instructions for more information.

In earlier versions of Cerbos, only local variables existed, and were accessible from the policy they are defined in. Note that variables were defined in a top-level variables field in the policy file. 

Let’s say you had resource policy file named leave_request_policies.yaml, structured like this:

---
apiVersion: api.cerbos.dev/v1
variables:
      pending_approval: ("PENDING_APPROVAL")
      principal_location: (P.attr.ip_address.inIPAddrRange("10.20.0.0/16") ? "GB" : "")
resourcePolicy:
      # ...

Whenever you wanted to use any of these variables, there was no option other than to redefine them in every file you’d be using them in. Which, we admit, was not the smoothest way to go around it.

From Cerbos v0.29 onwards, variables can now be defined in a separate file known as the exportVariables policy and effortlessly imported into other policies. Let's see how this is done. You’ll need define a file named for example common_variables.yaml in which you will define variables you want to be able to import across your configuration:

---
apiVersion: api.cerbos.dev/v1
description: Common variables used within our app
exportVariables:
  name: our_common_variables
  definitions:
    pending_approval: ("PENDING_APPROVAL")
    principal_location: (P.attr.ip_address.inIPAddrRange("10.20.0.0/16") ? "GB" : "")

In the snippet above you see how the exportVariable keyword is being used, and nested below it are name and definitions, which respectively represent the name to use when importing this set of variables, and the map of variable name to expression.

With this approach, our leave_request_policies.yaml (and any other policy file) can simply import the our_common_variables anywhere you need them, like this:

---
apiVersion: api.cerbos.dev/v1
resourcePolicy:
  variables:
    import:
      - our_common_variables
  # ...

And that’s it! Usage of the variables within policy conditions stays unchanged.

---
apiVersion: api.cerbos.dev/v1
variables:
    import:
      - our_common_variables
resourcePolicy:
  version: "default"
  scope: "our.app.uk"
  resource: leave_request
  rules:
    - actions: ["delete"]
      condition:
        match:
          expr: request.resource.attr.geography == variables.principal_location
      effect: EFFECT_ALLOW

How to use local variables in Cerbos policies?

There still might be a lot of cases where you’d prefer to keep (some of) your variables local to the policy.

From Cerbos v0.29 onwards, the previously-used top-level variables approach is deprecated and replaced with a variables.local section within the policy definition.

---
apiVersion: api.cerbos.dev/v1
resourcePolicy:
  variables:
    local:
      pending_approval: ("PENDING_APPROVAL")
      principal_location: (P.attr.ip_address.inIPAddrRange("10.20.0.0/16") ? "GB" : "")
      # ...

You can define local variables as well as importing variables in the same policy, but you can’t define the same variable in multiple places.

In order to ensure backwards compatibility, the deprecated top-level field is merged with the variables.local section in derived roles, resource, and principal policies.

Conclusion

With the introduction of exportVariables in Cerbos v0.29, managing access control policies becomes more straightforward and flexible. By transitioning from the old approach of using local variables to the new method of importing exported variables, policy authors can streamline their policies, reduce duplication, and further improve overall readability. If you still have a case for using local variables, don’t forget to update to a variables.local approach as shown above.

DOCUMENTATION
GUIDE

Book a free Policy Workshop to discuss your requirements and get your first policy written by the Cerbos team