We recently open sourced our tool Regula, which allows you to check your Terraform infrastructure as code for compliance prior to deployment. Regula can be used locally or as part of a CI/CD system, independently of Fugue or with Fugue.

In this post, we'll demonstrate how to use Regula with GitHub Actions to alert you to noncompliant Terraform. However, you can use Regula with other CI/CD systems, such as Travis. For extra credit -- and end-to-end cloud infrastructure security and compliance -- you can incorporate both Regula and Fugue into your own CI/CD system. This way, Regula validates resource configuration pre-deployment and Fugue ensures it stays compliant post-deployment.

What's Regula?

Regula uses the open source Open Policy Agent (OPA) engine to evaluate Terraform plans for compliance violations and misconfigurations. Compliance policies are written in Rego, OPA's query language, and check for misconfigurations such as unencrypted EBS volumes or overly permissive IAM policies. Regula validates the Terraform against the policies and returns a report of compliant and noncompliant files. You can customize which rules Regula uses to validate your Terraform, or even write your own if you're handy with Rego.

Ready to try it out? Let's go!

Prerequisites

Steps

1. Copy example files

For this example, we'll be using a GitHub Action that runs Regula on each git push to your repo. When triggered, Regula uses OPA to check Terraform files in the repo against a library of policies and, in this example, an additional custom rule. Then, Regula returns a list of the passing and failing compliance controls. If any Terraform files fail the compliance check, the workflow run itself fails. You'll see a summary at the end of the output either way.

To use this GitHub Action in your own repo, start by copying a few files from the cloned regula-ci-example into your repo:

.github/workflows/main.yml -- the GitHub Action workflow file

example_custom_rule/long_description.rego -- a custom compliance rule that requires IAM policy descriptions to be 25 characters or longer

main.tf -- an example Terraform file that Regula will test

cd into the root of your repo if you haven't already. If your repo and the Regula repo are in the same directory, run this command to copy the files:

cp -R ../regula-ci-example/.github ../regula-ci-example/example_custom_rule ../regula-ci-example/main.tf .

2. Configure GitHub Actions workflow file

.github/workflows/main.yml contains configuration details for the GitHub Action. Let's take a look at the inputs you'll need to provide:

terraform_directory specifies the directory containing the Terraform files. Here, it's set to . (the repo root), where main.tf lives.

specifies the directory containing the Terraform files. Here, it's set to (the repo root), where main.tf lives. rego_paths specifies the paths of the policies that need to be passed to OPA. The default is /opt/regula/rules, but here it's set to /opt/regula/rules example_custom_rule, which also includes the rule in the example_custom_rule folder.

Since the file is already configured for this example, you can leave it as is.

3. Set up environment variables

Because Regula runs terraform init, the environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must be set. Your AWS account will not be modified, but if you want to be absolutely certain about this you can always create a dummy IAM user within your account and allow programmatic access.

To set these variables, you'll need to create an encrypted secret in your repo for your user's AWS access key ID and secret access key:

Navigate to your repo's Settings page. Select Secrets from the left sidebar. Enter AWS_ACCESS_KEY_ID as the name of your secret. Enter your ID as the value and click "Add secret." Repeat the process for AWS_SECRET_ACCESS_KEY.

4. Commit the files

Next, we're going to add, commit, and push the files you've added to your repo.

From the root of the repo, git add all three copied files: git add main.tf .github/workflows/main.yml example_custom_rule/long_description.rego git commit the changes: git commit -m "Add Terraform, workflow file, custom rule" git push to the remote repository: git push

5. View the test results

Once you've pushed your changes, the GitHub Action will run automatically, and you can view the Regula test results in your repo:

Navigate to your repo on GitHub and select Actions. Under All Workflows, select the github/workflows/main.yml event: Select the Regula job in the left sidebar: In the logs on the right, expand the Regula section: Scroll down to find the Regula JSON output. This is a report detailing the compliance state of your Terraform. Below that, you'll see whether the test passed or failed (although the big red X on the page gives it away!)

6. Wait, what do the test results mean?

In the logs, Regula returns a list of controls and rules that passed or failed compliance, along with the names of every Terraform resource that passed or failed. (For an explanation of the difference between controls and rules, see the Regula README.) At the end of Regula's report, you'll see the compliance summary:

8 rules passed, 2 rules failed

12 controls passed, 2 controls failed

##[error] 2 rules failed

##[error]Docker run failed with exit code 1

In this case, the test failed. This is great, because now we know there's a policy violation in our Terraform! (You'll also see this information in the summary block of the output a little higher up.)

Dig a little deeper and you'll see exactly which resources violated which controls or rules. In this example, the controls block shows that the Terraform is noncompliant with CIS_1-22, and the mapped rules that failed are listed underneath (iam_admin_policy). And the rules block further down indicates that the resource aws_iam_policy.basically_allow_all failed the mapped rule, while aws_iam_policy.basically_deny_all passed:

"controls": { ... "CIS_1-22": { "rules": [ "iam_admin_policy" ], "valid": false }, }, ... "rules": { ... "iam_admin_policy": { "resources": { "aws_iam_policy.basically_allow_all": { "id": "aws_iam_policy.basically_allow_all", "message": "invalid", "type": "aws_iam_policy", "valid": false }, "aws_iam_policy.basically_deny_all": { "id": "aws_iam_policy.basically_deny_all", "message": "", "type": "aws_iam_policy", "valid": true } }, "valid": false },

The resource aws_iam_policy.basically_allow_all also failed the custom rule long_description:

"rules": { ... "long_description": { "resources": { "aws_iam_policy.basically_allow_all": { "id": "aws_iam_policy.basically_allow_all", "message": "invalid", "type": "aws_iam_policy", "valid": false }, "aws_iam_policy.basically_deny_all": { "id": "aws_iam_policy.basically_deny_all", "message": "", "type": "aws_iam_policy", "valid": true } }, "valid": false },

As you can see, the Regula check failed because one of the IAM policies violated the iam_admin_policy.rego rule by granting overly permissive access, and it also violated the custom rule long_description.rego by having a description shorter than 25 characters.

You can see the full results in action in our live example.

For more information about Regula test results, see the Regula README.

What's Next?

This tutorial showed you how to implement Regula using GitHub Actions, but you can use it with other CI/CD systems. For example, see our sample Travis configuration. You can also further customize this GitHub Action; to get started, check out the docs for configuring a workflow.

Further Reading

We encourage you to explore using Regula in your own CI/CD pipeline! For more information about Regula and how to use it, check out these resources: