Terraform CI/CD with Azure DevOps Pipelines
Automate Terraform with Azure DevOps Pipelines. YAML pipelines, service connections, environment approvals, and Azure backend state configuration.
Terraform
Automate Terraform with GitLab CI/CD. Plan on merge requests, apply on main, remote state with HTTP backend, and environment-specific pipelines.
# .gitlab-ci.yml
stages:
- validate
- plan
- apply
image:
name: hashicorp/terraform:1.8
entrypoint: [""]
variables:
TF_ROOT: ${CI_PROJECT_DIR}
before_script:
- cd ${TF_ROOT}
- terraform init
validate:
stage: validate
script:
- terraform validate
- terraform fmt -check
plan:
stage: plan
script:
- terraform plan -out=tfplan
artifacts:
paths:
- tfplan
apply:
stage: apply
script:
- terraform apply -auto-approve tfplan
dependencies:
- plan
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manualstages:
- validate
- plan
- apply
image:
name: hashicorp/terraform:1.8
entrypoint: [""]
variables:
TF_ROOT: ${CI_PROJECT_DIR}/environments/${CI_ENVIRONMENT_NAME:-dev}
TF_IN_AUTOMATION: "true"
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- ${TF_ROOT}/.terraform/
.terraform_base:
before_script:
- cd ${TF_ROOT}
- terraform init -backend-config="address=${TF_STATE_ADDRESS}"
-backend-config="lock_address=${TF_STATE_ADDRESS}/lock"
-backend-config="unlock_address=${TF_STATE_ADDRESS}/lock"
-backend-config="username=gitlab-ci-token"
-backend-config="password=${CI_JOB_TOKEN}"
validate:
extends: .terraform_base
stage: validate
script:
- terraform validate
- terraform fmt -check -recursive
plan:dev:
extends: .terraform_base
stage: plan
environment:
name: dev
variables:
TF_STATE_ADDRESS: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/dev"
script:
- terraform plan -out=tfplan -var-file=dev.tfvars
artifacts:
paths:
- ${TF_ROOT}/tfplan
expire_in: 1 week
rules:
- if: $CI_MERGE_REQUEST_IID
- if: $CI_COMMIT_BRANCH == "main"
apply:dev:
extends: .terraform_base
stage: apply
environment:
name: dev
variables:
TF_STATE_ADDRESS: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/dev"
script:
- terraform apply -auto-approve tfplan
dependencies:
- plan:dev
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual
plan:prod:
extends: .terraform_base
stage: plan
environment:
name: production
variables:
TF_STATE_ADDRESS: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/prod"
script:
- terraform plan -out=tfplan -var-file=prod.tfvars
artifacts:
paths:
- ${TF_ROOT}/tfplan
rules:
- if: $CI_COMMIT_BRANCH == "main"
apply:prod:
extends: .terraform_base
stage: apply
environment:
name: production
variables:
TF_STATE_ADDRESS: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/prod"
script:
- terraform apply -auto-approve tfplan
dependencies:
- plan:prod
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual# Use GitLab's built-in HTTP backend — no S3 needed
terraform {
backend "http" {}
}# State is managed at:
# Settings → Infrastructure → Terraform statesAWS_ACCESS_KEY_ID (masked)AWS_SECRET_ACCESS_KEY (masked)AWS_DEFAULT_REGIONOr use OIDC:
assume_role:
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.com
script:
- >
STS=$(aws sts assume-role-with-web-identity
--role-arn ${ROLE_ARN}
--web-identity-token ${GITLAB_OIDC_TOKEN}
--role-session-name "gitlab-ci-${CI_JOB_ID}")
- export AWS_ACCESS_KEY_ID=$(echo $STS | jq -r '.Credentials.AccessKeyId')
- export AWS_SECRET_ACCESS_KEY=$(echo $STS | jq -r '.Credentials.SecretAccessKey')
- export AWS_SESSION_TOKEN=$(echo $STS | jq -r '.Credentials.SessionToken')plan:
stage: plan
script:
- terraform plan -out=tfplan -no-color 2>&1 | tee plan.txt
artifacts:
reports:
terraform: plan.json # GitLab renders this in MR widget
paths:
- tfplan
rules:
- if: $CI_MERGE_REQUEST_IIDGitLab CI with the built-in HTTP state backend gives you Terraform CI/CD with zero external dependencies. Plan on merge requests (with MR widget integration), manual apply on main, and use GitLab OIDC for keyless cloud authentication. Cache .terraform/ to speed up pipelines.
Automate Terraform with Azure DevOps Pipelines. YAML pipelines, service connections, environment approvals, and Azure backend state configuration.
Automate Terraform with GitHub Actions. Plan on PR, apply on merge, OIDC authentication, environment protection, and drift detection workflows.
Automate Terraform with Jenkins pipelines. Declarative and scripted pipelines, credentials management, approval gates, and multi-environment deployments.
Run Terraform in Docker containers for consistent CI/CD environments. Official HashiCorp image, custom Dockerfiles, and Docker Compose workflows.