_images/login_button.png _images/signup_button.png



Open Policy Agent (OPA)

Reading time: 5 minutes

Overview

Scalr IaCP provides the capability to inject governance policies into Terraform runs. These policies are written using the Open Policy Agent (OPA) language and can be evaluated against the output of the “plan” phase (resources and attributes) and also data relating to the run time environment, such as source repositories, user, credentials, cost and more.

OPA policies are held in VCS repositories and can be added to Scalr in groups and linked to appropriate environments. Different groups of policies can be linked to different environments as required.

The flow that occurs when policies are linked to environments is as shown in this diagram.

_images/policy_diagram.png

If policy evaluation yields a failure the “apply” phase will not be run.

Policies can be implemented with one of three levels of enforcement.

  • Advisory : A warning is given but the run will continue.

  • Soft mandatory : Policy failure can be overridden. The run will pause and a suitable authorized person can choose to override the failure.

  • Hard mandatory : The run will fail.

To use OPA with Scalr you will need to set up a VCS provider if you have not already done so.

Policy Input Data

All OPA policies for Terraform start with a package definition and statements specifying the required input data. You can include tfplan and/or tfrun as per your requirements for individual policies.

package terraform

import input.tfplan as tfplan
import input.tfrun as tfrun
  • input.tfplan contains Terraform plan data created with the terraform show -json [planfile] command. It serves as the main input for the OPA evaluation stage and it’s exact content depends upon the resources in the Terraform configuration. In general though it will contain

    • Providers and attributes

    • Changes to be made to each resource with “before” and “after” attributes

    • Prior state with all resource attributes

To learn more about the extent of the tfplan context, please visit the Terraform documentation on this: Terraform JSON Output Format NEWWIN

  • input.tfrun is best shown by an example.

    {
        "tfplan": "<terraform plan content>",
        "tfrun": {
        "workspace": {
          "name": "input_plans",
          "description": null,
          "auto_apply": false,
          "working_directory": "",
          "tags": {}
        },
        "vcs": {
          "repository_id": "Scalr/examples",
          "path": "aws",
          "branch": "master",
          "commit": {
            "sha": "8a4a401f1696cfa0584rg5hrth30ce93004142f",
            "message": "Update main.tf",
            "author": {
              "email": "noreply@github.com",
              "name": "GitHub",
              "username": "null"
            }
          }
        },
        "cost_estimate": {
          "prior_monthly_cost": 0,
          "proposed_monthly_cost": 5.03,
          "delta_monthly_cost": 5.03
        },
        "credentials": {
          "azure": "cred-sssaltmagskedbo",
          "ec2": "cred-sssaltmf02ci9g8",
          "gce": "cred-sssaltma7op3vjg"
        },
        "source": "ui",
        "message": "Update README.md",
        "is_destroy": false,
        "is_dry": false,
        "created_by": {
          "name": "Mr. Test",
          "email": "test@scalr.com",
          "username": "test@scalr.com"
        }
      }
    

    When VCS is not used the “vcs” block will be "vcs": null

    • source: source type of a run. Can have one of the following values:

      • api: The run was kicked off via the Terraform API

      • cli: The run was kicked off via the Terraform CLI

      • configuration-version: The run was kicked off by uploading a new configuration version via the API

      • template registry: The run was kicked off by requesting a template from the template registry

      • ui: The run was kicked off manually through the UI

      • vcs: The run was kicked off by a merge/commit/pull request webhook from the VCS repository linked to the workspace.

Creating the OPA Policy

Policies are implemented in groups of one or more policies in a VCS repository.

  • policy must use the .rego extension.

  • The policy package used must be terraform.

  • Each policy must be an autonomous object. You cannot declare an object in one policy and use it in another policy.

Blow is example policy cost-check.rego to deny any deployment that will cost more than $10 per month:

package terraform

import input.tfplan as tfplan
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])
}

Enabling and Enforcing Policy

The policy repository must also include a scalr-policy.hcl file that specifies which policies are enabled and what their enforcement level is. The following enforcement levels are allowed:

  • hard-mandatory - The Terraform run is stopped if a violation occurs.

  • soft-mandatory - The Terraform run will be paused and the violation must be overridden if the run is to continue.

  • advisory - A notification occurs if a violation occurs.

This is an example of a scalr-policy.hcl file.

version = "v1"

policy "cost-check" {
    enabled = true
    enforcement_level = "hard-mandatory"
}

The name of the policy must match the name of the policy file without the .rego extension. You must include policy blocks for each policy file in the repository.

Policy Group Checks

The “Policy Check” column in the policy group allows an account administrator to see a summary of recent evaluations of each policy.

_images/policy_check.png

The colored summary bar is a link to a detailed and filterable list of all the evaluations.

_images/policy_check2.png

OPA Pull Request Previews

Scalr provides a preview of future policy changes based pull requests against the repository linked to the Policy Group. This allows impact assessment of planned changes without disrupting workflows. These previews do not cause a run to fail. To do start an OPA dry run, open a pull request against master with the changes.

New Runs

Once the pull request is made, you will see it appear in the existing policy:

_images/opa_pr.png

The preview mode can be turned on and off as needed:

_images/start_preview.png

In the next run, the workspace owner will see the implemented policy vs the preview policy:

_images/preview_run.png

Once the pull request is merged to master, the preview will disappear and the new policy will be applied to all runs.

Existing Workspaces

When a pull request is opened on an existing policy, Scalr will automatically check all existing workspaces for violations and report back after a few minutes. The time will very depending on the size of the environment it is evaluating:

_images/existing_ws_check.png

By clicking on the policy check section it will redirect you to see exactly what has failed, where the workspace is, and who owns it:

_images/existing_ws_check_detail.png

This will help the administrator understand the blast radius that the policy could potentially have prior to merging it to master.

OPA Examples

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