Infrastructure Code Testing
Introduction
A lot of software design principles, such as “Keep It Simple, Stupid” ( KISS), “Do-not Repeat Yourself” (DRY) or even conventional design patterns to certain extent, can be applied to infrastructure as code (IaC).
The goal is the same: we want easily extensible, maintainable and testable IaC. So the question is what kind of testing we can use for IaC?
Infrastructure Testing
As far as I can see it, there are three areas of infrastructure testing:
Unit testing is referring to the testing of smallest testable components. Here, we take the testable code blocks and verify their execution. Formatters and linters are also falling into this category in case you are also familiar with those.
Integration testing plays central role in our overall testing strategy. With integration testing we validate the actual build and runtime. It focuses on testing the interaction of system components in an assembled and running system.
Security testing is another vital step. In this phase, we look for security tests for both positive and negative security attributes. Our intent is to validate expected hardening of the system or test for possible weak spots, security vulnerabilities and misconfigurations.
In this post, we’re going to look more closely into security IaC testing, but before that, let’s briefly revise unit and integration infrastructure testing.
IaC Unit Testing
Let’s dive into unit testing for IaC.
We like unit testing, since unit tests are easy to implement and they naturally become an integral part of our development flow. With unit tests we can quickly assess our code for issues, without having to provision a full system. That means they are executed quickly and can be run in our development environment and CI pipelines.
We can include formatters and linters in this section as well, as they often catch low hanging fruit, usually related to coding standards, naming conventions and other style checks, It allows us to catch those kind of problems early. In Terraform IaC for example, popular linter is tflin and for Chef we can opt to use FoodCritic.
The essence of unit testing focuses on declaring what we expect a piece of functionality to do under a variety of scenarios, and validating that behavior.
We have a wide variety of unit testing frameworks for IaC, below are some examples:
IaC Integration Testing
Now let’s look at IaC integration testing.
In integration testing we actually deploy our infrastructure and then validate that it worked as we expect. Integration testing in infrastructure is very important, because actually deployed system often depends on third party services, such as package repositories, artifact repository managers, backend services or other network resources.
One good example of IaC integration testing framework is Serverspec. It’s written in RSpec and it works with almost any infrastructure provider. Another great tool that you can use for end-to-end tests on Kubernetes is Kubetest.
IaC Security Testing
Let’s shift to another very important type of IaC testing — security testing. Security testing is crucial in order to validate that our infrastructure code meets compliance, security and policy requirements.
With security testing, we want to be able to find and address poorly configured or vulnerable IaC files as early as possible.
Lack of adequate IaC security testing may lead to security loopholes and compromised cloud environments, leading to issues such as, network exposures, drifting configurations, privileged escalations, compliance violations and many others.
That’s where SAST tools such as KICS come into play. KICS can help us to find security vulnerabilities, compliance issues, and infrastructure misconfigurations early in the development cycle. We in Checkmarx are already using it as part of our CI/CD pipelines in internal and production environments.
Conclusion
All right, let’s wrap up this short post on infrastructure testing.
Infrastructure as code builds on software-defined technologies to bring more speed and consistency to our cloud applications provisioning and configuration. While IaC enables us to speed up application development and deployment, it relies on code that requires thorough testing.
We briefly covered a few aspects of infrastructure testing: unit, integration and security testing. Having all those types covered in our IaC testing strategy is vitally important in order to build confidence in the IaC codebase and application deployments.