Apply for invite to IaCP

Open Policy Agent (OPA)

Overview

Policy is one of the most important aspects to scaling cloud adoption. You want to ensure that your users can provision resources as needed and avoid a ticketing/review process that could slow down a deployment process. Adding policy to a pipeline ensures yours users are able to provision resources within a defined set of guardrails reducing security, financial, and operational risk.

Open Policy Agent (OPA) is a code based policy engine allowing users to write policy to check Terraform plans as they come through the Scalr pipeline. OPA is a growing open source community that has already been widely adopted in the Kubernetes community and is the future of policy as code. Scalr guarantees all Terraform plans are checked against OPA policy, in addition to there being different enforcement levels per policy. Scalr also allows for different pipelines/environments/accounts to follow different policies based on customer or business need. A few examples of commonly created policies are:

  • Naming Conventions - Enforce workspace, instance name, and tagging standards.

  • Cost - Avoid unexpected costs.

  • Blast Radius - Avoid changes to critical components (security groups, autoscaling, etc) that could potentially break an application.

  • Compliance Checks - Ensure your deployments following company and compliance standards.

  • Image Selection - Only allow images that have been approved by your organization.

  • And many many more..

The advantage of using policy as code is that there are no limitations to what policies can be created. You do not have to wait on a new release, a feature request, or anything else as you have full control over the types of policies that are written. To learn more about OPA, please visit the following site: Open Policy Agent NEWWIN

OPA policies are stored in VCS repositories and pulled into Scalr, no code is stored directly in Scalr. Learn more about linking with a VCS repository here.

Policy Checking Process

If an OPA policy is created and linked to an environment, this process will be followed:

../_images/policy_diagram.png

At the beginning of the policy stage in the Terraform plan, Scalr prepares all-inclusive input data for policies to evaluate against. It is a JSON object that contains both the Terraform plan and it’s artefacts, as well as the run context data that supports proper policy evaluation.

The JSON has the following structure:

When VCS is used:

{
   "tfplan": "<terraform plan content>",
   "tfrun": {
     "workspace": {
       "name": "input_plans",
       "description": null,
       "auto_apply": false,
       "working_directory": "",
       "tags": {}
     },
     "environment": {
       "id": "env-t0hgc5b1lea4l0g",
       "name": "tf-env-1"
     },
     "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:

{
   "tfplan": "<terraform plan content>",
   "tfrun": {
     "workspace": {
       "name": "input_policy",
       "description": null,
       "auto_apply": false,
       "working_directory": "",
       "tags": {}
     },
     "environment": {
       "id": "env-t0hgc5b1lea4l0g",
       "name": "tf-env-1"
     },
     "vcs": 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": "tfe-cli",
     "message": "Queued manually using Terraform",
     "is_destroy": false,
     "is_dry": true,
     "created_by": {
       "name": "Mrs. Test",
       "email": "test@scalr.com",
       "username": "test@scalr.com"
     }
   }
 }
  • 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.

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

  • input.tfrun contains a few more keys:

    • Workspace tags

    • Cloud credentials that are linked to the Scalr environments. Cloud names are transformed through mapping to match the ones Terraform is using for providers (“gce” -> “google”, “azure” -> “azurerm”, etc).

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

    • created_by: username, full name and email of a user who triggered the run.

    • cost_estimate: this is populated with results of the cost estimate stage of the run.

Creating the OPA Policy

OPA policy requirements:

  • The policy must end in a .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.

You will need to create the OPA policy in a VCS provider, here is example policy name 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])
}

The policy or policies must then be referenced in a single scalr-policy.hcl file within the same repository, which instructs the Scalr if the policy should be enabled and at what enforcement level. The following enforcement levels are allowed:

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

  • Soft - The Terraform run must be approved if a violation occurs.

  • Advisory - A notification occurs if a violation occurs.

version = "v1"

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

The syntax for multiple policies in the scalr-policy.hcl is as follows:

version = "v1"

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

policy "workspace-name" {
    enabled = true
    enforcement_level = "advisory"
}

You should now have two files created:

$ls -1a
.
..
cost-check.rego
scalr-policy.hcl

Push both of these files into the VCS repository and then link them to a Scalr environment in the next section.

Linking the Policy

After creating the policy and linking Scalr to the VCS repository, you can link the policy to an environment . To link the policy in Scalr, you must navigate to the account scope, click on the Scalr icon on the top left, and then “policy engine”:

  • Navigate to the account scope:

    ../_images/acct_level.png
  • Go to the policy engine:

    ../_images/navigate_to_policy.png
  • Click on “new policy group” and select “Open Policy Agent” as the type:

    ../_images/opa_policy.png
  • Click on “new policy”, select VCS repository, and enter in the information for the repository where the OPA policy resides:

    ../_images/opa_vcs.png
  • If everything is setup correctly, the policies will appear with the corresponding enforcement levels:

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

    ../_images/link1.png

As seen above, you can add multiple OPA policies to a single environment. OPA is the only policy type that allows multiple policies linked to a single environment. Scalr will not check the contents of the policies to ensure they do not conflict, it is important that policies are tested prior to implementation to avoid conflicts.

  • Once the policy is applied to the environment you will then see a new tab for it in your runs:

    ../_images/opa_check.png

Policy Group Checks

As a DevSecOps team or general administrator, you may want to see how many workspaces are failing based on policy that is put in place.

A policy check gives the account administrator the ability to see how many workspaces are failing policy checks in a single dashboard. As workspaces are created, the policy check will continually update based on the results of runs:

../_images/policy_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/policy_check2.png

This will apply to all workspaces, existing and new.

OPA Dry Runs

To test a policy prior to implementing it in production, you can open a pull request on a policy to preview the impact on the Terraform runs. This will help you understand how impactful the change will be, who it impacts, and what updates are needed. A preview will never fail a run, it is informative prior to merging to master. 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