Policy as Code

Note

The Open Policy Agent integration is only available on paid tiers. See Scalr pricing here.

Scalr utilizes Open Policy Agent (OPA) to govern Terraform 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 similar to your Terraform code in that it is stored in a VCS provider and managed through a GitOps model. Adminstrators create, manage, and open pull requests on the policies directly in VCS providers as well as trigger speculitve 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 to all Terraform providers, resources, data and anything mentioned in the plan.

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 {
   "tfplan": {
       "format_version": "0.1",
       "terraform_version": "0.13.4",
       "variables": {

       },
       "planned_values": {

       },
       "resource_changes": [

       ],
       "output_changes": {

       },
       "configuration": {

       }
   },
   "tfrun": {
   }
 }

A more complete example of the tfplan data, with an example policy, can be viewed here: tfplan example data.

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. The structure of tfrun, with details omitted, is shown below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
 "tfplan": "<terraform plan content>",
 "tfrun": {
   "workspace": {

   },
   "vcs": {

   },
   "cost_estimate": {

   },
   "credentials": {

   },
   "source": "ui",
   "message": "Update README.md",
   "is_destroy": false,
   "is_dry": false,
   "created_by": {

   }
 }
}

A more complete example of the tfrun data, with an example policy, can be viewed here: tfrun example data.

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 polices on those environments. The policies are evaluated against every run in every workspace in the linked environments.

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 enforment 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:

  1. Create policy rego files in a VCS repo:

    _images/opa_repo.png
  2. 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"
}
  1. 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 “Policy Engine” then “Policy Groups” by clicking on the Scalr icon on the top left.

    • Create a new policy group of type “Open Policy Agent” and add the details of the VCS provider and repository:

      _images/opa_vcs.png
    • Save and a summary of the policies will be displayed:

      _images/opa_enforced.png
    • Now that the policy is created, link it to an environment by clicking on “environments”, “policies”, then click on “link policy groups” on the right and save.

      _images/link1.png

Policy Group Checks

Once a group is created and assigned to an environment, it will automatically start checking runs, but from an adminstrative perspective you likely want to see the status of the polcies across all environments and workspaces. Policy checks give you a single view into the current results of policies across all environments and workspaces. To view this, click on the policy and look at the “Policy Check” column on the bottom right.

_images/policy_check.png

By clicking on the colored summary bar, you will be link to a detailed and filterable list of all the policies with the results.

_images/policy_check2.png

OPA Previews

Note

The policy preview feature is only available on the pro tiers. See Scalr pricing here.

Scalr provides a preview of future policy changes based on pull requests against the repository linked to the policy group. This allows the policy adaminstator to view an impact assessment of planned changes without disrupting workflows. This tells an adminstrator if they made an error updating the policy or if their are workspaces that will violate the upcoming policy change and gives the adminstrator time to contact the workspace owner prior to merging. The results of the previews are also pushed back to the VCS provider to allow for a GitOps model. These previews do not cause current runs to fail. To do start an OPA dry run, open a pull request against master with the changes.

Viewing Previews on 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

Clicking on the policy check section it will provide details of 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.

Viewing Previews on New Runs

Once the pull request is made, it will be displayed in the policy group screen:

_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.

More Resources

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

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

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 NEWWIN.