Infrastructure as Code (IaC) is an essential practice for modern DevOps and Agile teams to manage cloud infrastructure consistently, efficiently, and with increased resilience. Terraform has emerged as the leading tool for IaC, enabling teams to provision cloud infrastructure across multiple providers regardless of organization size. With Terraform, DevOps engineers can quickly and easily manage cloud infrastructure with code, speeding up the deployment process and ensuring consistency.
In addition to Terraform, Gitlab has become a popular choice for CI/CD management among developers and DevOps engineers. Gitlab’s vast integration with different tools allows for better management of the deployment process, making it an essential tool for organizations looking to streamline their DevOps workflow. By leveraging both Terraform and Gitlab, organizations can manage their cloud infrastructure and deployment processes efficiently and effectively, improving their overall DevOps Process.
Let’s look at some of the advantages that Terraform and Gitlab together provide along with a walkthrough of how to Integrate Gitlab and Terraform for the management of cloud infrastructure.
For the purpose of demonstration, we have published terraform code to the public Gitlab repository here Terraform-Gitlab-Pipeline
Terraform states are like a database for your infrastructure deployment. It keeps track of all the cloud resources deployed and managed by Terraform.
With GitLab, you can:
Gitlab offers CI/CD pipelines which are defined with the help of gitlab-ci.yml files in the project repository’s root directory. The pipelines feature was initially designed for application code deployments but is now widely used to manage infrastructure deployments also.
A typical pipeline includes Gitlab’s standard Merge request based workflow for infrastructure deployment
For any infrastructure change required, a feature branch is created from the mainline branch. Once the required changes are done, a Merge Request is raised to integrate the changes in the mainline branch, say main
As per this workflow, a new branch is created for an infrastructure change request, from the main branch ( e.g. branch name — CR1/demo_change_request_for_vpc ). The branch is then worked upon, for required changes, and a Merge Request is raised in GitLab for review.
As soon as an MR is raised, the pipeline gets triggered to perform certain terraform tasks related to the first level check of the recent changes. This is stage 1, which includes –
The generated plan[file] is then saved as a pipeline artifact, to ensure the exact planned changes are applied when this Merge Request gets approved
Upon review and approval of the Merge request, the Change is merged into the main branch, leading to stage 2 of the pipeline, this time, taking the pre-generated plan and applying the changes to cloud deployment. The steps are
This entire workflow is defined herein gitlab-ci.yml file
With the concepts fully explained and the code prepared, the next step is to set up the deployment pipeline for AWS Cloud Resource Provisioning. We will go through a step-by-step guide on how to build this pipeline and expected output results.
The credentials for your AWS account can be configured under the variables section <mention the path, e.g. Settings -> CI/CD-> Variables ( The sensitive tokens need to be masked)
Gitlab is configured as a remote state storage backend in terraform’s backend.tf file
The Gitlab project-specific configuration for backend configuration is defined in the Variables section of the .gitlab-ci.yml file
In order to simulate the behavior explained above, in the core concepts section,
The last stage in the gitlab-ci.yml file consists of the destroy or the clean up action. When manually approved, it executes the terraform destroy command.
Let’s summarize the entire deployment process and how it’s helpful :
Terraform is an Infrastructure as Code (IaC) tool that allows you to define, provision, and manage infrastructure. GitLab CI/CD can automate Terraform workflows by running pipelines that plan, apply, and destroy infrastructure configurations based on changes in a Git repository.
To set up a pipeline, create a .gitlab-ci.yml file in your repository with stages for terraform init, terraform plan, and terraform apply. Define jobs within each stage to automate infrastructure provisioning based on changes committed to the repository.
GitLab environment variables are used to securely store sensitive data such as AWS credentials, API keys, and Terraform variables. These variables are accessed within the CI/CD pipeline without exposing them in code, ensuring secure and flexible configuration.
The terraform plan command generates an execution plan, showing what actions Terraform will take to align the current state with the desired state defined in the code. Running terraform plan in a pipeline allows you to review changes before applying them to production.
Use remote backends (e.g., AWS S3, Azure Blob Storage) to store Terraform state files, ensuring they’re not stored locally within GitLab. This enables collaboration, secure storage, and access controls for the state, which tracks infrastructure changes.
Use GitLab pipeline rules to control when terraform apply runs. You can restrict the apply job to only run on specific branches (like main or production) or require manual approval for added control, reducing risks of unintended changes.
Use separate Terraform workspaces or create different directories for each environment, each with its own .tfvars file. Configure the pipeline to select the appropriate workspace or file based on the branch or environment specified in the job.
Use terraform fmt to enforce code formatting and terraform validate to check for syntax errors. Additionally, integrate static analysis tools like tflint to catch potential issues and ensure best practices in your Terraform code.
Best practices include using remote state storage, encrypting sensitive variables, organizing infrastructure by environment, running automated plan and apply steps, and reviewing all changes in terraform plan output before applying to production.
Check GitLab’s job logs for error messages, confirm environment variables are correctly set, and ensure credentials and remote backend configuration are accurate. Running terraform init before each plan or apply stage can also help resolve common issues with dependencies and backends.