/example-tf-circleci-part-2

A CI/CD pipeline integrating Fugue with Regula, Terraform, GitHub, and CircleCI

Primary LanguageShellApache License 2.0Apache-2.0

CI/CD with Fugue, Terraform, GitHub, CircleCI: Part 2

Regula + Fugue = <3

In part 1 of this walkthrough, we set up a CI/CD pipeline to define, commit, deploy, and secure infrastructure as code. To recap, here are the components:

  • Amazon Web Services (AWS): Provide cloud infrastructure (a VPC and security group)
  • Terraform: Define infrastructure as code
  • GitHub: Store infrastructure as code in version control
  • CircleCI: Deploy infrastructure via Terraform and kick off Fugue scan
  • Fugue: Scan infrastructure for any noncompliant resources and set a new baseline

Here, in part 2, we'll add a new component to the front of the pipeline:

  • Regula: Evaluate Terraform infrastructure-as-code for compliance

Our open source tool Regula uses the Open Policy Agent (OPA) engine to check Terraform plans against a library of compliance policies. The policy-as-code is written in Rego, OPA's query language.

With the addition of Regula, the pipeline demonstrates end-to-end security and compliance. Regula validates resource configuration pre-deployment and Fugue ensures it stays compliant post-deployment.

We'll also implement an open source utility called Conftest, which is a test runner for configuration files that use Rego for policy-as-code. Regula integrates seamlessly with Conftest, so we'll get the advantages of both:

  • Easy CI integration and policy retrieval from Conftest
  • Terraform plan parsing and the rule set from Regula

(For a version of this example that does not use Conftest, see Alternate Configuration Without Conftest.)

Getting Started

Part 1 is a prerequisite, since this walkthrough assumes you've completed it. (If you haven't yet, visit the repo!)

Once you've done that, you're golden. There aren't any additional prerequisites for this walkthrough.

Steps

Here's what we'll do today:

  1. Download ZIP of GitHub repo
  2. Copy files into your repo from part 1
  3. Uncomment terraform apply step
  4. Commit and push changes
  5. Watch the CI/CD magic!

And, there's an optional step:

  1. Bring Terraform into compliance to pass Regula check

If you'd like a sneak peek at the new files and what they do, jump ahead to step 3a.

Step 1: Download example repo ZIP

Once again, we've conveniently created a GitHub repo (this one!) with all the code you need. Download the ZIP here.

Step 2: Copy files into your repo

Unzip the archive and copy the following files into the root of the repo you set up in part 1:

cp -R .circleci main.tf regula-check.sh staging ../path-to-your-repo

We'll go over what each file does shortly in step 3a.

Step 3: Uncomment terraform apply step

Action recommended (but not required)! We've commented out the terraform apply step in .circleci/config.yml again just to be on the safe side, because this example will deploy infrastructure into your account (a VPC, security group, and if you follow step 6 later, the resources listed here). Feel free to comment it back in when you're comfortable doing so -- it's line 97 this time. (If you're using the no-Conftest alternate configuration, it's line 91.)

If you'd rather, however, you can keep the line commented out -- it's not strictly necessary for the walkthrough, since we're focusing on the Regula part of the pipeline. Just note that you'll really get the full effect of the pipeline when CircleCI deploys your updated infrastructure and Fugue scans it in context with other resources in the environment.

Step 3a: Understand the pipeline

Before we go further, let's take a look at the new and updated files.

Our CircleCI workflow has a new job, regula. The job does a few different things:

Here's where the cool stuff happens. The Conftest/Regula script uses Conftest with Regula's integration to check all of the Terraform projects in directories specified in regula-check.sh, evaluating each one for compliance with Regula's library of rules.

Then, one of the following things happens:

  • If the Terraform configuration files pass the compliance rules in Regula's library, the build continues to the next step, ultimately allowing Terraform to deploy the infrastructure, and Fugue to scan your environment and set a baseline.
  • If Regula finds any compliance violations, the build fails. No Terraform is deployed, and Fugue does not scan the environment or update the baseline.

Because we use Conftest to run the tests against Regula's library, we can validate multiple files at once, and we end up with some nicely formatted output. (You can see for yourself in step 5!)

We've also modified the workflows section of config.yml. This time, regula is the first step, and the next step, terraform-init, only happens if regula passes.

Another change is that the regula job happens on every pushed commit. The rest of the pipeline, from deployment to scan, only happens on commits to master. The reason we've configured CircleCI to run Regula on every commit is in order to provide earlier notice in case someone has pushed noncompliant Terraform. This way, you'll get the benefit of Regula's pre-deployment checks and be alerted to compliance violations long before merging PRs into master and triggering deployment.

We've added a script, regula-check.sh. The script carries out several tasks:

The main.tf file in the root of the repo still defines a VPC and security group, but it also defines a VPC flow log, which is currently commented out. Without a VPC flow log, the Terraform file violates the Center for Internet Security AWS Foundations Benchmark (CIS AWS). CIS AWS 2-9 recommends that you "Ensure VPC flow logging is enabled in all VPCs."

You can view the Rego policy for this rule in the Regula repo.

The file defines some other resources to support the flow log:

The staging folder contains another main.tf, which defines two IAM policies. One of them violates CIS AWS 1-22, "Ensure IAM policies that allow full "*:*" administrative privileges are not created."

View the Rego policy for CIS AWS 1-22 in the Regula repo.

What's the deal with the backend?

Due to a Terraform bug, it's impossible to output a Terraform plan in JSON without first running terraform init. And when terraform init is executed, Terraform detects backend.tf and determines that it requires backend reinitialization. This is not ideal here because it involves setting up the backend configuration again, copying existing state, and so on. We only need to generate a plan for Regula, so unsetting and resetting the S3 backend is unnecessary and undesirable.

For this reason, we rename backend.tf to backend.tf.backup in the directories we run Regula in, and when we're done, we return it to the original name. This allows us to simply generate a plan and validate it without affecting the backend.

Step 4: Commit and push changes

Now, it's time to stage, commit, and push the changes:

git add .circleci main.tf regula-check.sh staging
git commit -m "Add files for example part 2"
git push

This push triggers the CI/CD pipeline, and it doesn't matter what branch you make the commit to -- the Regula step happens whenever a commit is pushed. This is in contrast to the rest of the pipeline, which only occurs on commits to master -- say, after you've merged a PR from a hotfix branch.

We've arranged it this way to maximize the benefit from Regula's pre-deployment checks.

Step 5: Watch the CI/CD magic!

Assuming you've kept the same repo and CircleCI configuration as in part 1, navigate to your CircleCI dashboard to see what's happening.

CircleCI should be running the regula job:

Running tests

Whoops! Looks like our Terraform failed the Regula check:

Failed workflow

If you view the job results, you'll see the following error message:

Failed job

FAIL - regula-plan-project.json - main - regula: tf_aws_vpc_flow_log: aws_vpc.my_fugue_cicd_vpc: VPC flow logging should be enabled
FAIL - regula-plan-staging.json - main - regula: tf_aws_iam_admin_policy: aws_iam_policy.basically_allow_all: IAM policies should not have full "*:*" administrative privileges

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

Exited with code exit status 1

Because main.tf and staging/main.tf defined noncompliant resources, they failed the Regula check, and therefore the workflow as a whole failed.

Let's reflect on this for a second, because it's worth emphasizing: Regula's pre-deployment check just saved us from provisioning noncompliant infrastructure!

Step 6 (optional): Bring Terraform into compliance

Now that you've seen what happens when Regula flags a noncompliant resource, you have the option to see what happens when all resources are compliant.

Action required! You'll need to make a couple of edits:

  • In main.tf (root), uncomment lines 24-77 to add the VPC flow log and associated resources.
  • In staging/main.tf, comment out lines 6-23 to remove the "allow all" IAM policy.

Once that's done, go ahead and stage, commit, and push the changes:

git add main.tf staging/main.tf
git commit -m "Bring resources into compliance"
git push

Head to the CircleCI dashboard, and you'll see that the Regula check passes this time:

Passing workflow

When you view the job results, you'll see the following message:

Passing job

3 tests, 3 passed, 0 warnings, 0 failures, 0 exceptions

CircleCI received exit code 0

Congratulations! Once again, Regula has checked your infrastructure-as-code, and this time the resources have passed the library of rules.

The build goes on to the next job, terraform-init, and will continue to the hold-for-approval step. At this point, you can manually approve the deployment and allow Terraform to apply it. Then, Fugue kicks off a scan to validate the new and existing infrastructure, and sets a baseline to facilitate drift detection.

Even though Regula is able to catch compliance violations before they happen, Fugue provides an extra layer of protection by checking for compliance violations in context of existing infrastructure.

What's Next?

If you missed it the first time, check out example-tf-circleci, which has the code for part 1.

We'll continue to add more rules to Regula, so bookmark the repo and keep checking back!

Don't forget -- if you'd like to sign up for a free Enterprise trial, or a free-forever Developer account, register here.

Finally, for more about Fugue, see the Fugue docs and fugue.co.

Alternate Configuration Without Conftest

If you'd prefer to use a CircleCI configuration that does not involve Conftest, rename both configurations in the .circleci folder and commit the changes:

git mv .circleci/config.yml .circleci/config-with-conftest.backup
git mv .circleci/config-no-conftest.backup .circleci/config.yml
git commit -m "Switch to non-Conftest version of CircleCI config"

This renames the configuration files so CircleCI uses the no-Conftest version whenever a commit is pushed to master, and ignores the Conftest version.

The no-Conftest version uses the script regula-check-no-conftest.sh. Instead of using Conftest to pull in the Regula library and then check the Terraform, the script uses only Regula to check the Terraform. The script also parses the results with jq to get Conftest-like human-readable output.

The output looks slightly different but the effect is the same -- you'll still see a failed build if there are compliance violations in your Terraform, and if there aren't, your build succeeds.

Here's an example of how the CircleCI build looks when Regula detects compliance violations:

Failing job - no Conftest

And here's how it looks when no violations are detected:

Passing job - no Conftest