Testing your code, adherence to agreed standards, and verification of compliance towards security guidelines, is crucial for building high-quality infrastructures. You should apply these principles to infrastructure code, to keep it predictable and reliable. In this article, we will go through tools for continuous integration and local development that we, at sysdogs, use daily, and we highly recommend you to incorporate them into your workflow.
Continuous Integration is an essential part of code development. Terraform is not a special citizen - it should be validated and tested, like it was a regular programming language, although technically it is not. Here is a list of usefull tools, that we, as Sysdogs, recommend to leverage in Terraform Continous Integration pipelines.
terraform fmt and
You should never undermine the importance of consistent formatting for code readability, and efficient development, among the team. You could leverage IDE integrations to perform auto-formatting for you, but additional verification in one of the pull request checks is also worth it. Do not forget to add
-recursive option to make sure you are also checking files in child directories. Another thing worth mentioning is the
terraform validate command. It will validate all Terraform files inside the directory, yet accessing no remote services, such as remote state or provider APIs.
`terraform fmt` command example
terraform fmt -check -recursive
`terraform validate` command example
If you use GitHub, HashiCorp GitHub Action is worth looking at.
Intention of tfsec is to perform a static analysis of your Terraform code, and spot potential security issues. It contains the best security practices for major cloud providers such as AWS, GCP and Azure. To give you an example, it can mark insecure security group rules such as wide open ingress, not encrypted S3 buckets, and much, much more.
`tfsec` example usage
We also highly recommend reviewdog tfsec GitHub Action which creates a comment, with an error description, directly inside the pull request.
At sysdogs, we are over-paranoid in terms of security. That is why we use another static code analysis tool for security and compliance misconfiguration called checkov. It is very similar to tfsec, however, it is always nice to hear a second opinion, and we also use it to validate our hand-made Kubernetes manifests.
`checkov` example usage
checkov -d path_to_your_tf_codebase
Compliance is bliss. Every organization needs to have a set of compliance policies, and continuously test the code against them. We leverage terraform-compliance to perform negative testing and write our compliance policies using behavior-driven development. Terraform-compliance performs policy validation on the plan instead of static code analysis, and therefore, it can pinpoint violations with higher accuracy.
For everything else, that cannot be tracked down with terraform-compliance or if you just want to validate anything besides Terraform, you can use config-lint. It is a linter, supporting multiple formats, that checks the files against a set of rules written in YAML.
TFLint is a Terraform linter that focuses on finding errors, validating best practices and much, much more. It has over 700 rules built-in, which include both regular Terraform rules, and AWS specific ones (and other major cloud providers in the experimental state). Its primary purpose is to find misconfiguration that will never flag as an error before running apply, for example wrong EC2 instance type. TFLint is created in Go and has a plugin system that makes it extendable by anyone acquainted with Go language.
`tflint` example usage
tflint --deep --module path_to_your_tf_codebase
If you are a happy GitHub user, we suggest looking at reviewdog TFLint GitHub Action that creates a comment with an error description, directly inside the pull request.
Testing is a wide topic that deserves a separate article. At sysdogs, as I have already mentioned before, we believe that you must test ANY code and Terraform is no exception.. For our tests, we use a regular gotest testing suite with one special library. Terratest is a Go library that makes it easier to write automated tests. It contains helpers, functions and patterns for common infrastructure testing tasks. With it, you can rest assured that the Terraform module you change is still behaving as expected, basing your certainty on unit tests that will create an actual infrastructure, run tests and destroy it afterwards.
Versioning your code is crucial. There are multiple ways to achieve this, but the easiest we have found so far is to utilize something that will automatically tag the code based on pull request labels. Our pick is Release on Push GitHub Action - it creates a new GitHub release after merging to the main branch. You just add a label to your pull request that marks the change as patch, minor or major, and the action creates a new GitHub release, leveraging semantic versioning, to reflect this. If there is something you wish to introduce into the main branch without release creation, "norelease" label is the way to go.
To limit the time you spend on waiting for continuous integration checks to fail, we also provide our suggestion of several tools that will improve your quality of life while working with Terraform.
Multiple Terraform versions
Sometimes you need multiple Terraform versions on your local machine. For example, you are migrating from 0.12 to 0.13 and you need both of them at the same time. Python has its pyenv, Ruby has its rbenv, Node has its nvm and Terraform has its tfenv! It is a simple Terraform version manager that allows you to switch between multiple versions without hassle.
It does not really matter which text editor you use daily to work with Terraform. We highly recommend an editor that understands HCL and can highlight errors before you even push your code to the repository. One of our favorites would be IntelliJ IDEA, which has excellent support for HCL, or Visual Studio Code, where there's a selection of nice extensions handling Terraform. It is also a good idea, to enable auto-formatting on save, to ensure that the code you create is always in flawless form.
An alternative to using fully fledged IDE is usage of git hooks with pre-commit framework. Anton Babenko has created an excellent pre-commit hook for Terraform that will format your code, validate it using
validate command, TFLint, tfsec, checkov, and generate docs using terraform-docs.
Properly leveraging tools and configuring your local environment with additional utilities will boost your efficiency, productivity and quality of the code that you produce. There are many, many more tools available, and we invite you to explore the possibilities, to seek the solution that will suit you and your own style. Let us know if you find something helpful or worth adding to this list. We love expanding our arsenal!
- hashicorp/setup-terraform - Github Action. (n. d.). https://github.com/hashicorp/setup-terraform (accessed October 19, 2020).
- tfsec/tfsec - Github. (n. d.). https://github.com/tfsec/tfsec (accessed October 19, 2020).
- Check AWS006 - Tfsec Official Docs. (n. d.). https://www.tfsec.dev/docs/aws/AWS006/ (accessed October 19, 2020).
- Check AWS017 - Tfsec Official Docs. (n. d.). https://www.tfsec.dev/docs/aws/AWS017/ (accessed October 19, 2020).
- reviewdog/tfsec - Github. (n. d.). https://github.com/reviewdog/action-tfsec (accessed October 19, 2020).
- bridgecrewio/checkov - Github. (n. d.). https://github.com/bridgecrewio/checkov (accessed October 19, 2020).
- bridgecrewio/checkov-github-action - Github Action Marketplace. (n. d.). https://github.com/marketplace/actions/checkov-github-action (accessed October 19, 2020).
- Feature request - Checkov action Reviewdog support - Github. (n. d.). https://github.com/bridgecrewio/checkov/issues/510 (accessed October 19, 2020).
- terraform-compliance/cli - Github. (n. d.). https://github.com/terraform-compliance/cli (accessed October 19, 2020).
- stelligent/config-lint - Github. (n. d.). https://github.com/stelligent/config-lint (accessed October 19, 2020).
- terraform-linters/tflint - Github. (n. d.). https://github.com/terraform-linters/tflint (accessed October 19, 2020).
- reviewdog/action-tflint. (n. d.). https://github.com/reviewdog/action-tflint (accessed October 19, 2020).
- gruntwork-io/terratest - Github. (n. d.). https://github.com/gruntwork-io/terratest (accessed October 19, 2020).
- rymndhng/release-on-push-action - Github. (n. d.). https://github.com/rymndhng/release-on-push-action (accessed October 19, 2020).
- tfutils/tfenv - Github. (n. d.). https://github.com/tfutils/tfenv (accessed October 19, 2020).
- antonbabenko/pre-commit-terraform - Github. (n. d.). https://github.com/antonbabenko/pre-commit-terraform (accessed October 19, 2020).