Open Policy Agent — Conftest with Terraform

Policy As Code using Conftest with Terraform

Let’s first look at what is policy as code?

Aziz Zoaib
3 min readAug 29, 2020

--

Policy as code is the idea of writing code in a high-level language to manage and automate policies. By representing policies as code in text files, proven software development best practices can be adopted such as version control, automated testing, and automated deployment. More information about this topic can be accessed here

Since Im using conftest tool, now let’s look at what is conftest?

Conftest is a command line tool for testing configuration files and uses Open Policy Agent (OPA) under the hood. Also it is worth mentioning that OPA is hosted by the Cloud Native Computing Foundation (CNCF) as an incubating-level project.

Conftest uses the Rego language from Open Policy Agent for writing the assertions. You can read more about Rego in How do I write policies in the Open Policy Agent documentation.

Let’s see things in Action!

It starts by writing the rego policy which will be used as a validator against terraform code.

Let’s write a simple policy and see how terraform code is validated against this policy.

package main
import input
module_whitelist = {
"git@github.com:organization/terraform-aws-s3.git?ref=tags/v0.2",
}
module_changes[m] {
input.resource_changes[_].change.actions[_] != "no-op"
r := split(input.resource_changes[_].address, ".")
r[0] == "module"
m := input.configuration.root_module.module_calls[r[1]].source
not module_whitelist[m]
}
deny[msg] {
count(module_changes) > 0
msg := sprintf("module %s is not recommended use the newer version", [module_changes[_]])
}

By using above policy we are making sure that only specific versions (latest version) of the module are being used to create the resources in AWS.

Now let’s write the terraform code and validate it with above policy.

data "aws_region" "current" {} module "s3_bucket" {
source = "git@github.com:organization/terraform-aws-s3.git?ref=tags/v0.1"
region = "eu-west-2"
name = "test-bucket"

Now we have the terraform code ready, let’s see how we can run the conftest on it.

  • First step is to generate the terraform plan in json format by using below command.
terraform init && terraform plan -out=tfplan && terraform show -json ./tfplan > tfplan.json
  • Now you can run conftest on above generated planfile
conftest test ./tfplan.json -p ../policies
  • `-p` switch is to specify the policies scripts path.

and we can see below error.

FAIL - ./tfplan.json - module git@github.com:talabat-dhme/terraform-aws-s3.git?ref=tags/v0.1 is not recommended use the newer version

It means our policy is working and it only allows specific version of module. The above error will be replaced with below message if you change the `ref=tags/v0.1` to `ref=tags/v0.2`

1 tests, 1passed, 0 warnings, 0 failures, 0 exceptions

Now let’s discuss why are we writing policies and what are we achieving or can achieve by using it?

If you are following the source control strategy for infra as code in your organization, above policies can help in achieving below benefits:

  • Automating the Pull Requests reviews, above policies can validate all the use-cases against Human. Saving a lot of effort and time in manual reviews.
  • If you are using CI tool like Atlantis along with infra as code — you can automate end to end right from raising the Pull Request till creation of resources in Cloud.

So that’s all about Policy as Code & Conftest in this article, in next article I will show how to automate the process using Github custom hooks and Atlantis.

Stay tuned and happy conftesting!! ;)

--

--

Aziz Zoaib

DevOps, AWS, GCP, Terraform, Kubernetes, CI/CD