Using  Kitchen-Terraform with the GCP CIS Benchmark Profile 
Tags: devops, googlecloud, terraform, security
Published: 2020-09-05 19:27:13

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/nu76ifdpv6t49cw36vvu.png)

In the last [post](https://dev.to/brettcurtis/gcp-cis-benchmark-terraform-module-testing-with-chef-inspec-kitchen-terraform-github-actions-4gpl) we covered "local" development. In the spirit of [continuous integration](https://martinfowler.com/articles/continuousIntegration.html), we want to be able to have team members integrate their work. If you remember, the violations we had from running the [inspec-gcp-cis-benchmark](https://github.com/GoogleCloudPlatform/inspec-gcp-cis-benchmark) profile, we've got some work to do! We will do that using [Kitchen-Terraform](https://github.com/newcontext-oss/kitchen-terraform) and run the workflow in [GitHub Actions](https://github.com/learn/devops). In this post, we will cover Kitchen-Terraform.

## Project Setup

The directory structure is essential when using Kitchen-Terraform. My current structure looks like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/z2bpkcd5fl99zv60gshx.png)

### Fixtures

You'll need to have a [`fixtures`](https://github.com/lzysh/terraform-google-project/tree/master/test/fixtures) directory. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gjbbr5o5c3pssiq8v498.png)

This directory is where your Terraform root modules will live or in Kitchen-Terraform language, "test fixtures." It will call the child module, the module we are developing. That language aligns with the [module documentation](https://www.terraform.io/docs/configuration/modules.html), so in our case, the child module is in the root of the [repository](https://github.com/lzysh/terraform-google-project), and it's the module we are publishing through GitHub for reuse. In this example, we only have [one root module](https://github.com/lzysh/terraform-google-project/tree/master/test/fixtures/default-project) or test fixture we are testing against. There could and most likely will be more if we can't cover multiple test scenarios in a single fixture. I also have a shared directory for common code across numerous test fixtures if needed. 


### Integration

The [`integration`](https://github.com/lzysh/terraform-google-project/tree/master/test/integration) directory will hold your [profile](https://docs.chef.io/inspec/profiles/) with the [Chef Inspec DSL controls](https://docs.chef.io/inspec/dsl_inspec/) you want to run against a test fixture. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/hedmaizkn2136k8xf6cb.png)

For this post, we will focus only on the [`cis_benchmark.rb`](https://github.com/lzysh/terraform-google-project/blob/master/test/integration/default-project/controls/cis_benchmark.rb) and the [`inspec.yml`](https://github.com/lzysh/terraform-google-project/blob/master/test/integration/default-project/inspec.yml) files. Since Google did all the heavy lifting for us by writing the controls for the specific benchmarks we are testing for, [3.1 Networking](https://github.com/GoogleCloudPlatform/inspec-gcp-cis-benchmark/blob/master/controls/3.01-networking.rb) and [4.4 VMS](https://github.com/GoogleCloudPlatform/inspec-gcp-cis-benchmark/blob/master/controls/4.04-vms.rb), we can add them very quickly. First, you add the repository you depend on: 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/y053ldnd71azo4tes8r9.png)

*NOTE: The input `gcp_project_id` is what the inspec-gcp-cis-benchmark profile expects in order to know what project to run the tests against. Kitchen-Terraform can do attribute and Terraform output mapping. I'll touch on why that's important when we look at the `kitchen.yml` file.*

Then to call a specific control, we add it into the [`cis_benchmark.rb`](https://github.com/lzysh/terraform-google-project/blob/master/test/integration/default-project/controls/cis_benchmark.rb) like so:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qyk4ju7sqx82qf0h83o0.png)

### kitchen.yml

The last thing we need to do is tell Kitchen-Terraform what to do! We do this by creating a [`kitchen.yml`](https://github.com/lzysh/terraform-google-project/blob/master/.kitchen.yml) file:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vfl61d3j005bmw78bsm6.png)

You can read the documentation about the [kitchen.yml](https://docs.chef.io/workstation/config_yml_kitchen/) if you want to know more. However, I do want to touch on a couple of things. 

Lines three and four are a way you can pass `-var="foo=bar"` to Terraform from inside Kitchen-Terraform. In this example, I'm using the billing ID as a [secret in GitHub](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets). We can talk about that a bit more when we set up the workflow in GitHub Actions. 

The other thing is the lines twenty-four and twenty-five. This has to do with the attribute and Terraform output mapping I talked about earlier. I took me a bit of [learning out loud](https://github.com/GoogleCloudPlatform/inspec-gcp-cis-benchmark/issues/44) to get this squared away, but with some help, I was able to get it. To make a long story short, this is how I mapped my Terraform output of `project_id` to the attribute needed to run the inspec-gcp-cis-benchmark profile.

### Running Kitchen-Terraform

Now we can run kitchen [converge](https://docs.chef.io/workstation/ctl_kitchen/#kitchen-converge) and see what we have:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/68ewfzu8aovl6ox18wav.png)

This is going to do all kinds of work for you. It will verify the Terraform client version, [initialize](https://www.terraform.io/docs/commands/init.html) the Terraform working directory as well as create and switch to a [workspace](https://www.terraform.io/docs/commands/workspace/index.html):

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/phgjq6zwsjlxgp6akvzx.png)

It will also [validate](https://www.terraform.io/docs/commands/validate.html) the Terraform configuration files and finally run the Terraform [apply](https://www.terraform.io/docs/commands/apply.html):

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/m0nkfebqvmyh5st04jmd.png)

Next, we can run the tests using kitchen [verify](https://docs.chef.io/workstation/ctl_kitchen/#kitchen-verify) and see the results:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/n5dtam1k5kwoffhticty.png)

Finally, we can destroy the infrastructure using kitchen [destroy](https://docs.chef.io/workstation/ctl_kitchen/#kitchen-destroy). You could also do all of the above in one command by running kitchen [test](https://docs.chef.io/workstation/ctl_kitchen/#kitchen-test).

In the next post, I will talk about running the testing workflow through [GitHub Actions](https://github.com/lzysh/terraform-google-project/runs/1059655434?check_suite_focus=true#step:4:1)!