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