Terraform Deployment Solution for GitLab

TL;DR: This guide shows how to set up a scalable, modular Terraform deployment solution using GitLab CI/CD and Docker for Azure. It covers prerequisites, pipeline structure, variables, and project setup. The solution ensures consistent, automated, and secure deployments from local development to production, leveraging reusable pipeline definitions and best practices for Infrastructure as Code (IaC) and Configuration as Code (CoC)
- Overview
- Solution
- Pipeline Overview
- Prerequisites
- How-To
- Terraform Deployment
- Pipeline Variables
- Example
- Related Links
Overview
This guide describes a centralized and scalable Terraform Deployment Solution designed for efficient infrastructure deployment using Terraform, Azure CLI, and GitLab pipelines. The solution is modular and reusable, following best practices for Infrastructure as Code (IaC).
Solution
The following image illustrates the layered architecture of the Terraform Deployment Solution:
- Docker Layer: The
terraform-base-image
provides the foundational Docker image with all necessary tools for deployments within the pipeline or in a local dev container. - CI/CD Layer (GitLab): The
terraform-deployment-solution
builds on the base image and provides the centralized pipeline definitionterraform.gitlab-ci.yml
. - Projects (GitLab): Individual deployments of infrastructure (e.g.,
deployment 1
,deployment 2
, etc.) that include the pipeline definition from theterraform-deployment-solution
and represent specific Azure deployment scenarios. - Local Development Layer: The local development environment (VS Code) uses Visual Studio Code and a dev container, leveraging the same image for consistency across environments.
Arrows labeled image
indicate which Docker image the pipeline will use, while arrows labeled include
show how projects include the centralized and versioned pipeline definition terraform.gitlab-ci.yml
. This structure ensures modularity, reusability, and consistency from local development to cloud deployment.
terraform-base-image
and the terraform-deployment-solution
repositories are versioned and can be updated by a dependency bot like Renovate.
Benefits
- Declarative: Infrastructure as code for predictable, repeatable deployments.
- Clear Output: Actionable pipeline outputs for easy troubleshooting.
- Consistent & Portable: Same tools and process from local dev to production using Docker and dev containers.
- Automated & Auditable: Fast, transparent, reliable CI/CD with full change tracking in Git.
- Collaborative & Testable: Team workflows with code reviews and pre-deployment validation.
- Scalable & Integrated: Manage multiple environments with seamless GitLab, Azure, and Bicep integration.
- Secure: Built-in secrets and permissions management.
Pipeline Overview
The image illustrates a high-level overview of the CI/CD pipeline stages and their roles in automating Bicep deployments to Azure.
When a developer pushes Terraform code changes to GitLab using Visual Studio Code, the action triggers a GitLab CI pipeline defined in the terraform.gitlab-ci.yml
file. This pipeline runs within a Docker-based GitLab Runner that uses the terraform-base-image
to ensure a consistent environment. The pipeline first lints with tflint
and makes a security check with tfsec
, then init
the Terraform code, generating the tfstate
files as artifacts. These artifacts are then passed to the plan and apply stages. The pipeline plans the deployments for both test and production environments, and upon successful plan, deploys the code with Azure CLI to the respective Azure test and production environments.
Prerequisites
Before you begin, ensure you have the following:
- Active Azure subscriptions
- Access to a GitLab instance (self-hosted or gitlab.com)
- Docker installed on your local machine or CI environment
- Basic knowledge of Terraform, Azure Resource Manager (ARM), and CI/CD concepts
- Visual Studio Code
- Storage Account for Terraform State files
How-To
- Create two Azure Subscriptions (Test and Production Environment).
- Create an App Registration with a Client Secret. Add a Role Assignment with the
Contributor
role to your Subscriptions. - Create three new repositories on GitLab:
- Repository for the base image with the Dockerfile.
- Repository for the deployment solution.
- Repository for deploying your actual infrastructure to Azure.
Add the following GitLab CI/CD variables to your terraform-deployment-solution
group in GitLab:
AZURE_TENANT_ID
: Azure Active Directory Tenant IDAZURE_SUBSCRIPTION_TEST_ID
: Test Azure Subscription IDAZURE_SUBSCRIPTION_PROD_ID
: Production Azure Subscription IDAZURE_APPLICATION_ID
: Azure App Registration (Client) IDAZURE_CLIENT_SECRET
: Azure App Registration Secret (Masked/Secret)
NOTE:
For large-scale environments and improved security, it is recommended to use your own GitLab Runner infrastructure with Kubernetes. For each purpose, use a different service principal without client secrets, or use managed identities and assign permissions directly via RBAC.
Terraform Deployment
To use the deployment solution, include the terraform.gitlab-ci.yml
file in your project, specifying the correct version ref
.
1
2
3
4
include:
- project: 'YOUR_TERRAFORM_DEPLOYMENT_SOLUTION_PATH'
file: 'terraform.gitlab-ci.yml'
ref: '1.0.xx'
Here is the required file structure for your projects.
├── .gitignore
├── .gitlab-ci.yml
├── README.md
├── config
│ ├── backend-dev-westeurope.tfbackend
│ ├── backend-test-westeurope.tfbackend
│ ├── backend-prod-westeurope.tfbackend
│ ├── main-dev-westeurope.tfvarsc
│ ├── main-test-westeurope.tfvarsc
│ └── main-prod-westeurope.tfvars
└── src
├── main.tf
├── outputs.tf
├── providers.tf
└── variables.tf
Pipeline Variables
Below are key variables defined in the terraform-deployment-solution
pipeline. Adjust them to fit your Azure environment and project requirements.
NOTE:
For example, if you want to deploy to another region, you can set theLOCATION
variable toswitzerlandnorth
.
Make sure there is an appropriatetfvars
file in theconfig
directory of the project.
1
2
3
4
5
6
7
8
variables:
LOCATION: "westeurope"
DEPLOYMENT_NAME: "terraform-${ENVIRONMENT}-${LOCATION}-deployment"
TERRAFORM_BACKEND_CONFIG: "./config/backend-${ENVIRONMENT}-${LOCATION}.tfbackend"
TERRAFORM_SOURCE_DIR: "./src"
TERRAFORM_VAR_FILE: "./config/main-${ENVIRONMENT}-${LOCATION}.tfvars"
OUTPUT_DIR: "./artifacts"
SKIP_TEST: "false"
Example
A complete example project demonstrating the Terraform Deployment Solution, including pipeline configuration and sample infrastructure code, is available in the following repository:
Related Links
- Docker - Documentation
- GitLab - CI/CD Documentation
- Microsoft - Azure CLI
- Microsoft - Infrastructure as Code (IaC) Concepts
- Microsoft - Developing inside a Container
- HashiCorp - Terraform Documentation
- Paul Hammant - Trunk-Based Development
For more details or questions, feel free to reach out or open an issue in the repository.