Adding Some Sweetness to your Infra-as-Code with Confectionery
Tags: security, terraform
Published: 2021-06-01 22:40:05

Recently the [Confectionery](https://github.com/Cigna/confectionery) tool was open-sourced after some internal iterations within Cigna. The project was a combined effort from multiple teams and we're excited to see the wider community be able to leverage it.

So what is Confectionery anyways?  It is a rule library for the [Conftest](https://www.conftest.dev/) tool. By leveraging Conftest, teams can validate various configuration files via static scanning and policies written in the Rego language. The Confectionery ruleset as of the writing of this article is focused on Terraform. We plan to expand to other formats in the near future (Dockerfiles and Kubernetes manifests). I've previously written about how Conftest can be used to scan Terraform files, please see my [article](https://dev.to/prince_of_pasta/securing-your-terraform-pipelines-with-conftest-regula-and-opa-4hkh) from last year on the topic.

## Trying out Confectionery

As noted in our [Getting Started Guide](https://github.com/Cigna/confectionery#getting-started) Conftest is a pre-requisite to being able to consume the Confectionery rule library. Feel free to use the [install option](https://www.conftest.dev/install/) that makes the most sense for you. You can confirm it successfully installed by running the version command as shown below:

![Conftest version command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/74shng7vmuxidfav9g21.png)

Next lets set up a directory that will house our terraform files and rules. These command should work across Windows(Powershell), Mac, and Linux

```
cd ~ #switching to our home directory
mkdir testdrive #making a directory
cd testdrive # switching into our directory
```
Next, lets save the contents of one of our test files as ``kms.tf`` in our ``testdrive`` directory. The contents can be found [here](https://raw.githubusercontent.com/Cigna/confectionery/v1.0.0/test-files/terraform/aws/kms/kms_rotate.tf)

Reviewing the file we can see that we're planning to creating three KMS keys, and expecting two of the three to fail our rules. 

Before invoking Conftest, lets generate our terraform plan. These steps assume Terraform is installed, and AWS credentials (with at least ReadOnlyAccess) are saved in ``~/.aws/credentials``. If that is not the case please skip to next section where alternate instructions will be provided. Before we begin, I am changing the ``profile`` on line 7 of kms.tf to ``default`` since that is the name of my aws profile as it appear on ``~/.aws/credentials``. It is also the default when setting up credentials via the aws cli. If you use a different profile please feel free to change it to that value.

```
terraform init
terraform plan -out tf-plan.binary
terraform show -json tf-plan.binary > tf-plan.json
```

Running these three commands should download the AWS provider, generate a binary representation, and produce a JSON version as well. The output will note that there the three keys would be created.

### Alternate Commands

If you do not have the ability to leverage terraform/AWS but would still like to follow along, we can grab a pre-generated plan from one of the other test files. In this [file](https://raw.githubusercontent.com/Cigna/confectionery/v1.0.0/test-files/terraform/aws/kms/kms_rotate_test.rego) You can save the value of ``mock_plan_input`` (include the starting and closing brackets as ``tf-plan.json`` in our ``testdrive`` directory. 

## First Run

At this point our ``testdrive`` directory should have the following files (no binary file if the alternate commands were used):

![contents of testdrive directory](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/48p8t3htw51ojnagcyi1.png)
 
The command we'll run is shown below. By running the test sub command with the update flag, Conftest will download the  Confectionery rule files into a ``policy`` directory (inside the ``testdrive`` directory) then run the rules against the tf-plan.json file. The command is also specifying the tag/release to use, which in this case is ``v1.0.0``

```
conftest test --update "git::https://github.com/cigna/confectionery.git//rules/terraform?ref=v1.0.0" tf-plan.json
```

Upon running the command you should see the following:

![Conftest test command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h9c096b0m7l2z4c2sobt.png)

As expected we see that our two invalid keys were flagged while the one with rotation enabled was not. The command also returns a non-zero exit code, which should trigger a failure in a pipeline in most CI systems.

##Exceptions

In order to give some flexibility to consumers of the library, [exceptions](https://github.com/Cigna/confectionery#how-to-use-exceptions) are also supported. As noted in the documentation this leverages [Regula's implementation](https://regula.dev/configuration.html#waiving-rule-results). This allows waiving or disabled of rules on a number of factors. Let's try waiving the rule that is failing on our two keys

Inside our ``testdrive`` directory lets make an ``exceptions`` directory using the ``mkdir`` command. Inside the ``exceptions`` directory please make a file called ``config.rego`` with the following contents:

```
package fugue.regula.config

waivers[waiver] {
    waiver := {
        "rule_name": "kms_rotate",
    }
}
```

As you can see we're specifying the rule name as it appears in the above output. Let's switch back to our ``testdrive`` directory and run the following command:

```
conftest test -p policy -p exceptions --update "git::https://github.com/cigna/confectionery.git//rules/terraform?ref=v1.0.0" tf-plan.json
```

This command is similar to our first run, but we've specified both our ``policy`` and ``exceptions`` directories, to allow for the waiver to be process successfully. After executing the command the output should look something like this:

![Conftest test command with exception](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e9py8pbm4oeqhckkzbk8.png)

## Conclusion

Confectionery provides a great way to enable a fast feedback loop to infrastructure-as-code developers. It can easily be consumed locally on a laptop or from within a CI system to prevent misconfigurations from reaching a live environment. We'll continue to add more rules over time, and will expand to other configuration file formats to gain additional coverage. If you have any rules/feature requests you'd like to see please feel free to [Submit an issue](https://github.com/Cigna/confectionery/issues).