Open Policy Agent

Introduction

Scalr utilizes Open Policy Agent (OPA) to govern Terraform and OpenTofu deployments. OPA is policy-as-code that uses the rego language to evaluate Terraform input data against administrator defined rules. Any data which is in the Terraform JSON can be evaluated as part of the OPA checks. The evaluation returns a result which is then interpreted by the Scalr to determine what course of action to take. To be clear, OPA does not make any decisions regarding a policy, it simply returns a result (true, false, some text) which Scalr then uses to make a decision.

The OPA code is treated similarly to your Terraform code in that it is stored in a VCS provider and managed through a GitOps model. Administrators create, manage, and open pull requests on the policies directly in VCS providers as well as trigger speculative runs to preview the impact of policy changes.

There are two main sections that the policies can evaluate, the tfplan and tfrun. The Terraform input data will be the output of Terraform plan (tfplan in rego) and the run time (tfrun in rego) environment data, such as workspace details, username, etc. From this data, OPA can be used to evaluate the attributes of all Terraform providers, resources, data, and anything mentioned in the plan.

tfplan & tfrun

📘

OpenTofu Support

The information below references Terraform, but the same applies for OpenTofu.

Example data - tfplan

The tfplan data is the output from terraform plan in JSON format. There are multiple sections to the plan data to enable checks on planned_values, resource_changes, configuration etc. OPA policies will most often use resource_changes to evaluate changes to attribute values. The structure of tfplan, with details omitted, is shown below.

{
   "tfplan": {
       "format_version": "0.1",
       "terraform_version": "0.13.4",
       "variables": {

       },
       "planned_values": {

       },
       "resource_changes": [

       ],
       "output_changes": {

       },
       "configuration": {

       }
   },
   "tfrun": {
   }
 }

See a full example of the tfplan by downloading a policy mock.

Example data - tfrun

The tfrun data can be evaluated by OPA to check on data related to the run time environment in Scalr, such as user names, VCS provider details, cloud credentials, cost estimation, and more. Here is an example of a tfrun:

  "tfrun": {
    "workspace": {
      "name": "OPA_Example_workspace",
      "description": null,
      "auto_apply": false,
      "working_directory": "",
      "tags": [
        "dev"
      ],
      "module": null
    },
    "environment": {
      "id": "env-u0b83rvjmsj1234",
      "name": "Research-Development"
    },
    "vcs": {
      "repository_id": "myrepo/example",
      "path": "",
      "branch": "main",
      "commit": {
        "sha": "e12e1ff687ddb67ce8bf08388aecb357a2412345",
        "message": "Update main.tf",
        "author": {
          "name": "Ryan",
          "email": "[email protected],
          "username": "github_username",
          "teams": null
        }
      },
      "pull_request": null
    },
    "cost_estimate": {
      "prior_monthly_cost": 0.0,
      "proposed_monthly_cost": 0.0,
      "delta_monthly_cost": 0.0
    },
    "source": "vcs",
    "message": "Update main.tf",
    "is_destroy": false,
    "is_dry": false,
    "created_by": {
      "name": null,
      "email": "[email protected]",
      "username": "[email protected]",
      "teams": [
        {
          "id": "team-v0o0g6d3ga4q1234",
          "name": "ops_team"
        }
      ]
    },
    "shell_variables": [
      {
        "key": "SCALR_RUNNER_ROLE",
        "value": "runner-account-access"
      },
      {
        "key": "AWS_DEFAULT_REGION",
        "value": "us-east-1"
      }
    ]
  }

See a full example of the tfrun by downloading a policy mock.

Policy Mocks

Policy mocks in Scalr are very helpful in creating OPA policies as they present all of the tfrun and tfplan information that is possible to use within an OPA policy. A policy mock can be downloaded per run in the individual run dashboard:

Using OPA in Scalr

OPA policies are stored in a VCS repository and registered in Scalr as policy groups. The VCS repository contains one or more policy rego files and a scalr-policy.hcl file that sets the enforcement level of each policy:

  • Hard Mandatory - Cannot be overridden
  • Soft Mandatory - Can be overridden by account admins and other authorized roles
  • Advisory - Provides a warning only

Once the policy groups are created, the groups are linked to specific environments to enforce the policies in those environments. The policies are evaluated against every run in every workspace in the linked environments.

When writing an OPA policy to be used in Scalr, the package must be namedterraform as seen in the example below.

Scalr requires that the OPA evaluation returns an array of strings named deny. The presence of any values in the array will be interpreted by Scalr as a policy failure. Thus, in policies used with Scalr there must always be a rule named deny that performs the evaluation. Here is a very simple example that checks the cost of the resources in a Terraform run using the cost estimation data:

package terraform

import input.tfrun as tfrun

deny[reason] {
    cost_delta = tfrun.cost_estimate.delta_monthly_cost
    cost_delta > 10
    reason := sprintf("Plan is too expensive: $%.2f, while up to $10 is allowed", [cost_delta])
}

An evaluation that detects the cost to be higher than $10 would return a result like this:

{
  "deny": [
    "Plan is too expensive: $12.00, while up to $10 is allowed"
  ]
}

Creating Policy Groups

A policy group is the collection of one or more OPA policies stored in a repository with a scalr-policy.hcl file declaring if the policies are enabled and what the enforcement level is. One or more policies can be attached to each environment and it is normal to have a common policy shared across all environments as well as environment-specific policies to ease overhead. Common shared policies could include restricting network access, preventing public S3 buckets, allowing specific Terraform modules, and much more. Follow these steps to create a policy group:

Create policy rego files in a VCS repo:

Add a scalr-policy.hcl file to set the enforcement levels and if the policy is enabled or not for each policy file in the repo, as shown in this example. Note the version is required:

version = "v1"

policy "limit_modules" {
    enabled = true
    enforcement_level = "advisory"
}

policy "workspace_name_convention" {
    enabled = true
    enforcement_level = "advisory"
}

Create the policy group in Scalr at the account level. To use policy groups it is necessary to create a VCS provider if this has not already been done. Go to the "run policy engine" at the account scope and create a run policy group:

2666

Create a new policy group with the VCS details:

1150

Once saved, the policy can be enforced on environments by clicking on "Enforce run policy group":

Policy reports will appear within a few seconds (maybe longer depending on the amount of workspaces) once the policy is enforced.

Policy Reports

Once a policy is created and enforced, it will automatically start checking runs, but from an administrative perspective, you likely want to see the status of the policies across all environments and workspaces. Policy checks give you a single view of the current results of policies across all environments and workspaces. To view this click on “Policy Reports”:

1803

Policy Impact Analysis

Scalr provides a preview of future policy changes based on pull requests against the repository linked to the policy group. Similar to a Terraform dry run, but for OPA! This report gives administrators the piece of mind to know if they made an error updating the policy or if there are workspaces that will violate the upcoming policy change, allowing the administrator to give workspace owners a warning before merging the PR. The results of the previews are also pushed back to the VCS provider with checks for branch policies. These previews do not cause current runs to fail.

More Resources

For examples of OPA policies, please visit our GitHub repository: Open Policy Agent Examples

To learn more about using the terraform plan data with OPA please review our Scalr OPA Blog series, in particular OPA Series Part 3: How to analyze the JSON plan.

To learn more about writing OPA policies for Terraform and Scalr we recommend the following resources:

Video

More of a visual learner? Check out this feature on YouTube.