Rego, the language powering the Open Policy Agent (OPA), has become an indispensable tool for developers and security professionals alike. In order to kickstart your journey with Rego, it makes sense to first understand some of the basics. I put the cart before the horse by first posting how to use Rego in Rego Based Policies in Cyral. In this guide, we will delve into the depths of Rego and explore how you can leverage its capabilities to enhance your policy as code practices.

Understanding Rego

Rego is a declarative programming language specifically designed for expressing policy across diverse systems. It represents a radical departure from traditional imperative languages such as Python or Javascript, bearing a closer resemblance to SQL in its syntax and structure.

Rego’s primary role is to craft policies that influence decision-making within applications, services, and infrastructure. It is used to write rules that, when evaluated by the OPA, dictate whether a particular action is allowed or denied based on pre-defined criteria.

The Significance of Rego

The ability to codify policies in a language like Rego, thereby enabling automated execution of rules, has profound implications for modern development and operational practices. The policy as code approach eliminates the need for intricate, purpose-specific user interfaces or hard-coded policy rules that are difficult to manage and maintain.

Instead, Rego allows for the creation of flexible, scalable, and easily readable rules that govern system behavior. By learning to write in Rego, you gain the ability to express comprehensive authorization policies in a format that is both machine and human-readable.

Dive into Rego Syntax

The syntax of Rego may seem unconventional to those accustomed to imperative programming languages, but once understood, it offers a powerful and expressive means of crafting policy rules. Rego’s syntax is designed to effortlessly express complex policy requirements in a succinct and clear manner.

In Rego, rules are evaluated based on a return value and a set of statements. If all the statements in the rule hold true, the rule returns the defined value. If any statement is false, the rule returns an undefined value unless a default value is specified.

Writing Your First Rego Policy

Let’s take a look at writing a simple Rego policy. This example policy will dictate the terms of access to a hypothetical payroll microservice. We will define two main rules, the first allowing users to view their own salary information and the second permitting finance department staff to view the salary information of all users.

package play

default allow = false

# Rule 1: Users can view their own salary info
allow = true { 
    input.method = "GET"
    input.path = ["getSalary", user_id]
    input.user = user_id 
}

# Rule 2: Finance department can view any user's salary info
allow = true { 
    input.method = "GET"
    input.path = ["getSalary", user_id]
    finance[input.user] 
}

finance = {"John","Mary","Peter","Vivian"}

In this policy, by default, the allow value is false. The allow value changes to true if all the conditions inside the curly braces are satisfied. The input variable represents the JSON data provided to Rego.

Understanding and Using Rego Packages

Every Rego file belongs to a package that defines the scope of the policy. Multiple policy files using the same package name share the same namespace. For instance, package aserto.InviteUser is the package name for a Rego policy that governs the rules for inviting a user.

Making Decisions with Rego

The primary function of Rego is to make policy decisions based on the rules defined. Each decision is represented as a header within a block. For instance, allowed { true } returns true for the allowed decision.

Working with Input Documents in Rego

In Rego, the inputs to a policy are contained within an input variable. The input variable represents the JSON data provided to Rego for policy evaluation. Elements of the input variable can be used within policy rules to make contextual decisions.

For instance, in the rule allowed { input.foo == "bar" }, the allowed decision will evaluate to true only if the foo attribute on the input map equals the string "bar".

Understanding and Using Data Documents in Rego

Rego allows you to embed a data document within a policy. This document is namespaced based on the directory it resides in. For example, roles/data.json will be available as an object called data.roles in the policy evaluation context.

Expressions and Arrays in Rego

Rego incorporates set operators that enable the construction of expressions over each value in an array. This is particularly useful when dealing with array inputs such as user roles. Rego’s set operators allow for the creation of rules that iterate over each value in an array, effectively performing a scan of the array’s contents.

Advanced Policy Authoring with Rego

With a solid understanding of Rego’s basic constructs, you can begin to explore advanced policy authoring. Rego provides support for higher-order functions such as mapping and filtering, allowing for the creation of sophisticated rules. For instance, you can filter a list by a predicate rule, or map a function onto a list.

As your proficiency with Rego increases, you will find it an extraordinarily powerful tool for expressing complex policy requirements. Whether you’re defining access control rules for a microservice, setting deployment policies for a Kubernetes cluster, or anything in between, Rego provides a flexible, expressive, and efficient language for policy as code.

By harnessing the power of Rego, you can make your systems more secure, more compliant, and more manageable, all while enhancing the productivity and effectiveness of your development and operations teams. So why wait? Start your journey with Rego today!