Terraform and Gitlab: Better Together

Standard AWS practice today is to use multiple accounts to seperate infrastructure. This is done for a number of reasons, one of the most common is to seperate environment such as development, staging, and production. When initiating AWS API calls locally a common method is to run an “assume role” script, which will ingest an MFA token and AWS credentials to temporarily receive an token allowing the user to assume a role in a different account with appropriate privileges. Then the API calls, or the Terraform commands, are kicked off locally.

There are a number of issues with this approach. One of my biggest pet peeves is the lack of enforcement around source control.

Example

We expect that all IAC changes are formatted, committed and reviewed before any infrastructure is created. However this specific day there is an application going to production and the engineer is about to go on vacation so some Terraform is written real quick and then applied and our engineer is off to Costa Rica. Unfortunately the next day there seems to be an issue with the application. The other engineers are reviewing the code in version control and everything looks good. This strays away with one of the core ideas of infrastructure as code, which is that all infrastructure should be created in a consistent repeatable way. As soon as there are undocumented resources created, management become significantly more difficult.

What’s the solution? Well if build jobs only kick off when code is merge to specific branches, and not when an engineer feels like it, we can enforce the desired workflow.

In this Gitlab-CI/CD example, I’ve use the git branch as the workspace name, with the exception of master because I want my interpolations to be prod as opposed to master.

before_script:
- case "$CI_COMMIT_REF_SLUG" in
master) WORKSPACE_NAME="prod" ;;
*) WORKSPACE_NAME="$CI_COMMIT_REF_SLUG" ;;
esac
- rm -rf .terraform
- terraform --version
- terraform init
- terraform workspace select $WORKSPACE_NAME || terraform workspace new $WORKSPACE_NAME

This allows development branches and production branches, as well as their matching environments to remain separate with minimal human interference.