Skip to content

Policy Testing

Terrateam Configuration Terrateam behavior can be configured via a config.yml. This file is located in a directory named .terrateam at the root of your Terraform repository: .terrateam/config.yml.

See Configuration documentation for details.

Policy testing against Plan operations with OPA and Conftest can be configured with a custom Workflow.

Conftest

When a Plan operation runs, the exit status of conftest against the generated Terraform plan file can be used to determine the success or failure of the entire operation. This grants users the ability to enforce custom policies against any Terraform-related change in a pull request.

In the screenshots below, the terraform plan step succeeds but the conftest step fails causing the entire Terrateam Plan operation to fail.

Steps

Conftest Plan Failure

Plan

Conftest Plan Failure

Configuration

The Terrateam configuration file can be configured to execute conftest with a custom workflow. Tags and Tag Queries can be used to target specific Dirspaces.

.terrateam/config.yml

workflows:
  - tag_query: ""
    plan:
      - type: init
      - type: plan
      - type: run
        cmd: ['conftest-wrapper']
        capture_output: true

Directory structure

If a pull request contains a change for the file foo/bar/main.tf in the root of your repository, then conftest will look for rego policy files in the foo/bar/policy/ directory.

josh@ringo:~/terraform$ tree foo
foo
└── bar
    ├── main.tf
    └── policy
        └── main.rego

2 directories, 2 files
josh@ringo:~/terraform$

Rego policy

Conftest policies are written using the Rego query language.

Example main.rego policy denying any resources created using the null_resource provider:

package main

resource_types = {"null_resource"}

resources[resource_type] = all {
    some resource_type
    resource_types[resource_type]
    all := [name |
        name:= input.resource_changes[_]
        name.type == resource_type
    ]
}

num_creates[resource_type] = num {
    some resource_type
    resource_types[resource_type]
    all := resources[resource_type]
    creates := [res |  res:= all[_]; res.change.actions[_] == "create"]
    num := count(creates)
}

deny[msg] {
    num_resources := num_creates["null_resource"]
    num_resources > 0
    msg := "Resource 'null_resource' detected in Terraform plan file. Denied."
}

Policy directory

By default, conftest will look for policies in the policy directory where Terrateam is operating against.

Example with custom options

All available conftest configuration options can be passed using environment variables.

For example, to specify a different policy directory, the CONFTEST_POLICY environment variable can be set using a custom Terrateam workflow.

.terrateam/config.yml

workflows:
  - tag_query: "dir:aws/us-east-1/production/iam"
    plan:
      - type: init
      - type: plan
      - type: env
        name: CONFTEST_POLICY
        cmd: ["echo", "$TERRATEAM_ROOT/aws/policies/iam/"]
      - type: run
        cmd: ['conftest-wrapper']
        capture_output: true 

The above configuration would instruct conftest to look for rego policy files in the aws/policies/iam directory when creating a Terraform pull request against the aws/us-east-1/production/iam directory.

aws/us-east-1/production/iam/main.tf

josh@elmer:~/terraform $ cat aws/us-east-1/production/iam/main.tf 
resource "null_resource" "foo" {
  provisioner "local-exec" {
    command = "echo foo"
  }
}
josh@elmer:~/terraform $ 

aws/policies/iam/main.rego

josh@elmer:~/terraform $ cat aws/policies/iam/main.rego 
package main
 
resource_types = {"null_resource"}
 
resources[resource_type] = all {
    some resource_type
    resource_types[resource_type]
    all := [name |
        name:= input.resource_changes[_]
        name.type == resource_type
    ]
}
 
num_creates[resource_type] = num {
    some resource_type
    resource_types[resource_type]
    all := resources[resource_type]
    creates := [res |  res:= all[_]; res.change.actions[_] == "create"]
    num := count(creates)
}
 
deny[msg] {
    num_resources := num_creates["null_resource"]
    num_resources > 0
    msg := "Resource 'null_resource' detected in Terraform plan file. Denied."
}
josh@elmer:~/terraform $ 

If a user were to initiate a pull request against the aws/us-east-1/production/iam/main.tf file then the Terrateam Plan operation would execute conftest using the main.rego policy file in the aws/policies/iam directory. The entire Plan operation would fail because the main.rego policy file does not allow the creation of a null_resource.