GitLab CI Guide

Terraform Security in GitLab CI:
Complete Integration Guide

A complete .gitlab-ci.yml configuration for automated terraform security scanning — with plan scanning, fail-on-violation, and MR blocking.

April 6, 2026 TFGaurd Team 10 min read GitLab CI · DevSecOps · Consideration

GitLab CI is the pipeline of choice for thousands of enterprise DevOps teams. Adding terraform security in GitLab CI with TFGaurd takes less than 10 minutes — and turns every merge request into a security gate.

This guide covers the complete .gitlab-ci.yml pipeline: initializing Terraform, generating a plan, scanning it with TFGaurd, uploading reports as artifacts, and configuring the pipeline to fail on high-severity violations.

Key Advantage: TFGaurd runs entirely on your GitLab Runner. No code is sent to external servers. Your Terraform HCL and plan JSON stay within your self-hosted or GitLab.com runner environment.

Pipeline Architecture Overview

A well-structured GitLab CI pipeline for Terraform security has four stages, each with a clear responsibility:

validate

Syntax validation. Run terraform validate to catch HCL syntax errors before investing runner minutes in a full plan.

plan

Generate plan JSON. Run terraform plan and export to JSON. This is the input TFGaurd needs for deep plan-file analysis.

security

TFGaurd scan. Scan the plan JSON against 1200+ security rules. Fail the pipeline if violations exceed your configured threshold.

apply

Optional apply. Only runs if all previous stages pass. Protect this stage with when: manual for production environments.

Complete .gitlab-ci.yml Configuration

Paste this configuration into your project root. Adjust TF_ROOT to match your Terraform directory.

YAML — .gitlab-ci.yml # ── TFGaurd Security Pipeline ───────────────────────────────────── variables: TF_ROOT: ${CI_PROJECT_DIR}/infra TF_VERSION: "1.7.5" TFGAURD_FAIL_ON: "high" # critical | high | medium | none stages: - validate - plan - security - apply # ── Reusable before_script ───────────────────────────────────────── .tf_base: image: hashicorp/terraform:${TF_VERSION} before_script: - cd ${TF_ROOT} - terraform init -backend=false # ── Stage 1: Validate ────────────────────────────────────────────── tf:validate: extends: .tf_base stage: validate script: - terraform validate only: - merge_requests - main # ── Stage 2: Plan → JSON ─────────────────────────────────────────── tf:plan: extends: .tf_base stage: plan script: - terraform plan -out=tfplan -input=false - terraform show -json tfplan > tfplan.json artifacts: name: terraform-plan paths: - ${TF_ROOT}/tfplan.json expire_in: 1 hour only: - merge_requests - main # ── Stage 3: TFGaurd Security Scan ──────────────────────────────── tfgaurd:scan: stage: security image: ubuntu:22.04 needs: - job: tf:plan artifacts: true script: - apt-get update -qq && apt-get install -y curl - curl -sSL https://tfgaurd.com/install.sh | bash - tfgaurd scan --file ${TF_ROOT}/tfplan.json --fail-on ${TFGAURD_FAIL_ON} --output json > tfgaurd-report.json artifacts: name: tfgaurd-security-report paths: - tfgaurd-report.json expire_in: 7 days when: always # upload even on failure only: - merge_requests - main # ── Stage 4: Apply (manual, protected) ──────────────────────────── tf:apply: extends: .tf_base stage: apply script: - terraform apply -auto-approve when: manual only: - main

Configuring GitLab CI/CD Variables

Store sensitive values in Settings → CI/CD → Variables. Mark cloud credentials as Masked and Protected:

  • AWS_ACCESS_KEY_ID — AWS access key (masked, protected)
  • AWS_SECRET_ACCESS_KEY — AWS secret key (masked, protected)
  • TFGAURD_API_KEY — Optional; unlocks premium GCP/Azure/Oracle rules
  • TFGAURD_FAIL_ON — Override severity threshold per environment

Environment-Scoped Variables: Set TFGAURD_FAIL_ON=high for production and TFGAURD_FAIL_ON=critical for staging environments using GitLab's environment-scoped variable feature.

Blocking Merge Requests on Violations

TFGaurd returns exit code 1 when violations meet or exceed your --fail-on threshold. GitLab CI automatically marks the pipeline as failed, which prevents the merge request from being merged if you've configured pipelines must succeed in your branch protection rules.

Enable this in Settings → Repository → Protected Branches → check "Pipelines must succeed" for your main branch.

Important: The tfgaurd:scan job runs with when: always for artifacts — meaning the report is uploaded even when the scan fails. This lets you review the full violation list before fixing and retrying.

Secure Your GitLab Terraform Pipeline

Free for all AWS rules. Premium plan unlocks 1200+ rules for GCP, Azure, and Oracle.

Start Free — No Card Required