Skip to main content

Command Palette

Search for a command to run...

Terraform + AI: Write Infrastructure as Code 10x Faster with GitHub Copilot (2025 Complete Guide)

Stop writing Terraform from scratch. Use GitHub Copilot, tfsec, Checkov, and Infracost to generate, validate, secure, and cost-check your IaC — all before you hit terraform apply.

Updated
24 min read
C
Hi, I’m Vikas Ratnawat, Founder of CloudDevOpsHub — one of India's biggest Cloud & DevOps learning communities. With 15+ years of IT industry experience, I work across AWS, Azure, GCP, Linux, DevOps, Automation, Kubernetes, Terraform, AI integrations, and Multi-Cloud architectures. I am passionate about helping students and working professionals build real-world skills that companies actually look for. Through CloudDevOpsHub, I have trained thousands of engineers, conducted live workshops, mock interviews, and career mentorship sessions focused on Cloud, DevOps, and AI. On this blog, I share practical tutorials, real project implementations, interview preparation content, career guidance, architecture discussions, troubleshooting guides, and industry insights from real production environments. My goal is simple: make Cloud, DevOps, and AI easy to learn, practical to implement, and accessible to everyone. Available for CloudDevOpsHub Blogs, Technical Articles, Workshops, Corporate Training, Mentorship, and Community Learning Initiatives. 🚀 Founder: CloudDevOpsHub 🌐 Website: www.clouddevopshub.com ✍️ Hashnode: @clouddevopshub ☁️ Multi-Cloud | DevOps | AI | Linux | Automation

slug: terraform-ai-github-copilot-iac-faster-2025 tags: [Terraform, GitHubCopilot, IaC, DevOps, AI, AWS, Azure, GCP, InfrastructureAsCode, CloudDevOps, Checkov, tfsec, Infracost, CI/CD] cover: https://cdn.hashnode.com/res/hashnode/image/upload/v1/terraform-ai-copilot-cover.png canonical: https://blog.clouddevopshub.com/terraform-ai-github-copilot-iac-faster-2025 seo_title: "Terraform + GitHub Copilot Tutorial 2025: Write IaC 10x Faster with AI" seo_description: "Learn how to use GitHub Copilot to generate Terraform modules, tfsec and Checkov to validate security, and Infracost to estimate costs — all in one AI-powered IaC workflow. Real examples for AWS, Azure, GCP."

TL;DR: Writing Terraform from scratch is slow. Hunting down security misconfigs is tedious. Discovering your infrastructure costs $3,000/month after deploying it is painful. This guide shows you how GitHub Copilot generates production-ready Terraform in seconds, how tfsec and Checkov catch security issues before they hit production, and how Infracost shows you the bill before you run terraform apply. Real code. Real tools. Real workflow.


Why Every DevOps Engineer Needs AI for Terraform in 2025

Let's be honest about what writing Terraform actually looks like most of the time:

  1. Open a blank main.tf

  2. Stare at it for 30 seconds

  3. Open the Terraform Registry docs

  4. Copy a resource block, adjust 12 variables

  5. Forget the depends_on, break the plan

  6. Fix it. Deploy. Get a Slack message at 3 AM — S3 bucket is publicly exposed

  7. Fix the security issue. Deploy again. Get a $4,200 AWS bill at month-end

  8. Repeat

This is the Infrastructure-as-Code experience for most teams. Not because Terraform is bad — it's excellent — but because writing correct, secure, cost-aware IaC from scratch requires holding an enormous amount of context in your head simultaneously.

AI changes this. GitHub Copilot doesn't just autocomplete code — it understands Terraform's resource structure, cloud provider APIs, and best practices well enough to generate production-quality configurations from a plain English comment. Pair that with AI-integrated security scanners and cost estimators, and you have a completely different IaC workflow.

Here's what the same workflow looks like with AI:

  1. Type a comment describing what you need

  2. Copilot generates the Terraform module in seconds

  3. tfsec + Checkov scan it for security issues instantly

  4. Infracost shows estimated monthly cost in your PR

  5. terraform planterraform apply with confidence

That's the workflow you're going to build in this guide.


What You'll Learn

  • Set up GitHub Copilot for Terraform in VS Code

  • Use Copilot to generate real modules — AWS VPC, EC2, S3, RDS, EKS

  • Write the perfect Copilot prompts for Terraform (with templates)

  • Validate and secure IaC with tfsec and Checkov

  • Estimate cloud costs before deploying with Infracost

  • Build a complete AI-powered Terraform CI/CD pipeline with GitHub Actions

  • Common Copilot mistakes to avoid

Prerequisites: VS Code installed, GitHub account (free or paid), basic Terraform knowledge, an AWS/Azure/GCP account for examples.


Part 1 — Set Up GitHub Copilot for Terraform

Install GitHub Copilot in VS Code

GitHub Copilot has a free tier — 2,000 code completions and 50 chat messages per month. That's enough to try everything in this guide.

Step 1 — Enable Copilot:

Go to github.com/settings/copilot and enable it on your account. Free tier is available.

Step 2 — Install the VS Code extension:

Open VS Code → Extensions (Ctrl+Shift+X) → Search "GitHub Copilot" → Install both:

  • GitHub Copilot (inline completions)

  • GitHub Copilot Chat (conversational AI)

Step 3 — Sign in:

Click the Copilot icon in the VS Code status bar → Sign in with GitHub. You'll see a checkmark when active.

Step 4 — Install the HashiCorp Terraform extension:

While you're in Extensions, also install:

  • HashiCorp Terraform — syntax highlighting, validation, resource documentation

Now open any .tf file and Copilot is active. It reads the context of your file and suggests completions as you type.

Configure VS Code for the Best Copilot + Terraform Experience

Add these to your VS Code settings.json (Ctrl+Shift+P → "Open User Settings JSON"):

{
  "github.copilot.enable": {
    "*": true,
    "terraform": true,
    "hcl": true
  },
  "editor.inlineSuggest.enabled": true,
  "editor.suggestOnTriggerCharacters": true,
  "github.copilot.editor.enableAutoCompletions": true,

  "[terraform]": {
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "hashicorp.terraform"
  }
}

Key shortcuts to memorize:

Action Shortcut
Accept Copilot suggestion Tab
Reject suggestion Esc
See next suggestion Alt + ]
Open Copilot Chat Ctrl + Shift + I
Trigger inline suggestion Alt + \

Part 2 — Generate Terraform with GitHub Copilot

The Golden Rule: Comments Drive Quality

Copilot's output quality is directly proportional to the specificity of your comment. Vague comments produce vague code. Detailed comments produce production-ready code.

Poor prompt:

# create an S3 bucket

Great prompt:

# Create a private S3 bucket for application logs
# - Enable versioning
# - Enable server-side encryption with AES256
# - Block all public access
# - Add lifecycle rule: move to Glacier after 90 days, delete after 365 days
# - Tag with environment, project, and owner

The second comment will generate a complete, secure, production-grade S3 resource. The first will generate 3 lines of bare minimum HCL.


Example 1: Generate a Production AWS VPC Module

Create a new file modules/vpc/main.tf and type this comment:

# Terraform module for a production-grade AWS VPC
# - CIDR: 10.0.0.0/16
# - 3 public subnets across 3 AZs (10.0.1.0/24, 10.0.2.0/24, 10.0.3.0/24)
# - 3 private subnets across 3 AZs (10.0.4.0/24, 10.0.5.0/24, 10.0.6.0/24)
# - Internet Gateway for public subnets
# - NAT Gateway in each AZ for private subnet egress
# - Route tables for public and private subnets
# - Tags: Environment, Project, ManagedBy=Terraform

Press Enter. Copilot generates something like this:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

variable "environment" {
  description = "Environment name (dev, staging, prod)"
  type        = string
}

variable "project" {
  description = "Project name for tagging"
  type        = string
}

locals {
  azs             = ["\({var.aws_region}a", "\){var.aws_region}b", "${var.aws_region}c"]
  public_subnets  = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  private_subnets = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"]

  common_tags = {
    Environment = var.environment
    Project     = var.project
    ManagedBy   = "Terraform"
  }
}

resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = merge(local.common_tags, { Name = "\({var.project}-\){var.environment}-vpc" })
}

resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
  tags   = merge(local.common_tags, { Name = "\({var.project}-\){var.environment}-igw" })
}

resource "aws_subnet" "public" {
  count             = 3
  vpc_id            = aws_vpc.main.id
  cidr_block        = local.public_subnets[count.index]
  availability_zone = local.azs[count.index]

  map_public_ip_on_launch = true

  tags = merge(local.common_tags, {
    Name = "\({var.project}-\){var.environment}-public-${count.index + 1}"
    Tier = "public"
  })
}

resource "aws_subnet" "private" {
  count             = 3
  vpc_id            = aws_vpc.main.id
  cidr_block        = local.private_subnets[count.index]
  availability_zone = local.azs[count.index]

  tags = merge(local.common_tags, {
    Name = "\({var.project}-\){var.environment}-private-${count.index + 1}"
    Tier = "private"
  })
}

resource "aws_eip" "nat" {
  count  = 3
  domain = "vpc"
  tags   = merge(local.common_tags, { Name = "\({var.project}-\){var.environment}-nat-eip-${count.index + 1}" })
}

resource "aws_nat_gateway" "main" {
  count         = 3
  allocation_id = aws_eip.nat[count.index].id
  subnet_id     = aws_subnet.public[count.index].id

  tags = merge(local.common_tags, { Name = "\({var.project}-\){var.environment}-nat-${count.index + 1}" })

  depends_on = [aws_internet_gateway.main]
}

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }

  tags = merge(local.common_tags, { Name = "\({var.project}-\){var.environment}-public-rt" })
}

resource "aws_route_table" "private" {
  count  = 3
  vpc_id = aws_vpc.main.id

  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.main[count.index].id
  }

  tags = merge(local.common_tags, { Name = "\({var.project}-\){var.environment}-private-rt-${count.index + 1}" })
}

resource "aws_route_table_association" "public" {
  count          = 3
  subnet_id      = aws_subnet.public[count.index].id
  route_table_id = aws_route_table.public.id
}

resource "aws_route_table_association" "private" {
  count          = 3
  subnet_id      = aws_subnet.private[count.index].id
  route_table_id = aws_route_table.private[count.index].id
}

output "vpc_id"          { value = aws_vpc.main.id }
output "public_subnets"  { value = aws_subnet.public[*].id }
output "private_subnets" { value = aws_subnet.private[*].id }

That's a complete, production-ready VPC module — generated from a comment. Manually, this would take 30–45 minutes and at least two rounds of fixing mistakes.


Example 2: Generate a Secure S3 Bucket

# AWS S3 bucket for storing application artifacts
# Security requirements:
# - Block ALL public access (all 4 block settings = true)
# - Enable AES-256 server-side encryption by default
# - Enable versioning
# - Enable access logging to a separate log bucket
# - Force destroy = false (protect against accidental deletion)
# - Lifecycle: transition to STANDARD_IA after 30 days, GLACIER after 90 days

Copilot output:

resource "aws_s3_bucket" "artifacts" {
  bucket        = "\({var.project}-\){var.environment}-artifacts"
  force_destroy = false

  tags = local.common_tags
}

resource "aws_s3_bucket_public_access_block" "artifacts" {
  bucket = aws_s3_bucket.artifacts.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_s3_bucket_server_side_encryption_configuration" "artifacts" {
  bucket = aws_s3_bucket.artifacts.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
    bucket_key_enabled = true
  }
}

resource "aws_s3_bucket_versioning" "artifacts" {
  bucket = aws_s3_bucket.artifacts.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_lifecycle_configuration" "artifacts" {
  bucket = aws_s3_bucket.artifacts.id

  rule {
    id     = "transition-and-expire"
    status = "Enabled"

    transition {
      days          = 30
      storage_class = "STANDARD_IA"
    }

    transition {
      days          = 90
      storage_class = "GLACIER"
    }
  }
}

Notice: Copilot split the S3 configuration into separate resources — aws_s3_bucket_public_access_block, aws_s3_bucket_versioning, etc. This is the correct AWS provider v4+ approach. Copilot knows this. A developer copy-pasting from old Stack Overflow answers would miss it.


Example 3: Use Copilot Chat for Complex Infrastructure

For more complex tasks, use Copilot Chat (Ctrl+Shift+I) with a detailed conversational prompt:

@workspace Create a Terraform module for an AWS EKS cluster with:
- Kubernetes version 1.30
- 2 managed node groups: one for system workloads (t3.medium, 2-5 nodes) 
  and one for application workloads (t3.large, 2-10 nodes, with auto-scaling)
- OIDC provider configured for IAM Roles for Service Accounts (IRSA)
- CloudWatch logging enabled for API server and audit logs
- Private endpoint access only (no public API server)
- Security group allowing only VPC internal communication
- Tags for environment and project
- All required IAM roles and policies

Copilot Chat will generate the full module — cluster, node groups, IAM roles, security groups, OIDC provider — and explain each section.


The 7 Best Copilot Prompt Templates for Terraform

Save these as comments in a copilot-prompts.md file in your repo:

1. Database (RDS)

# AWS RDS PostgreSQL instance - production grade
# - Instance: db.t3.medium, Multi-AZ enabled
# - Storage: 100GB gp3, encrypted with KMS
# - Automated backups: 7 day retention
# - Deletion protection: true
# - Parameter group: PostgreSQL 15
# - Subnet group using private subnets
# - Security group: allow port 5432 from app security group only

2. Load Balancer

# AWS Application Load Balancer for web application
# - Internet-facing, in public subnets
# - HTTPS listener on port 443 with SSL certificate from ACM
# - HTTP listener on port 80 that redirects to HTTPS
# - Target group: port 8080, health check path /health
# - Access logs enabled to S3
# - Deletion protection: true in production

3. Lambda Function

# AWS Lambda function for image processing
# - Runtime: Python 3.12, memory 512MB, timeout 30s
# - IAM role with S3 read/write and CloudWatch Logs permissions
# - Environment variables from SSM Parameter Store (not hardcoded)
# - Dead letter queue (SQS) for failed executions
# - CloudWatch log group with 30 day retention
# - VPC config: private subnets, security group allowing outbound only

4. Kubernetes Namespace + RBAC

# Kubernetes namespace with RBAC for the payments team
# - Namespace: payments-prod
# - ResourceQuota: 4 CPU, 8Gi memory, 10 pods max
# - LimitRange: default 100m CPU / 256Mi memory per container
# - ServiceAccount with IAM annotations for IRSA
# - Role: read pods/logs, write deployments/services
# - RoleBinding: bind role to payments-team group

5. CI/CD Variables

# Terraform variables for a complete 3-tier application
# - Include: environment, region, project, vpc_cidr
# - Database: instance type, storage size, engine version
# - Application: instance type, min/max ASG, AMI ID
# - Networking: allowed CIDR blocks for SSH, HTTPS
# - All variables with descriptions, types, and sensible defaults
# - Sensitive variables marked as sensitive = true

6. Azure Resource Group + VNet

# Azure Resource Group and Virtual Network - production
# - Resource Group: region East US, standard tags
# - VNet: 10.0.0.0/16 with DNS servers
# - 4 subnets: web (10.0.1.0/24), app (10.0.2.0/24), 
#   data (10.0.3.0/24), management (10.0.4.0/24)
# - NSG per subnet with deny-all default, allow specific rules
# - DDoS Standard protection plan
# - Network Watcher enabled

7. GCP Cloud Run + Cloud SQL

# GCP Cloud Run service with Cloud SQL PostgreSQL backend
# - Cloud Run: container image from Artifact Registry, 
#   min 1 max 10 instances, 1 vCPU, 512Mi memory
# - Cloud SQL: PostgreSQL 15, db-g1-small, private IP only
# - VPC connector for Cloud Run to reach Cloud SQL
# - Service Account with Cloud SQL Client role
# - Secret Manager for database password
# - Cloud Armor for WAF on the frontend

Part 3 — Validate and Secure Terraform with AI-Powered Scanners

Generating Terraform with Copilot is fast. But AI can also hallucinate security misconfigs — an S3 bucket with public ACLs, a security group open to 0.0.0.0/0, or an unencrypted RDS instance. You need automated security validation in your workflow.

Three tools form your security layer:

Tool What it does Speed
terraform validate Syntax + logical errors ~1 sec
tfsec Security misconfiguration scan ~5 sec
Checkov Security + compliance (CIS, SOC2, HIPAA) ~10 sec

Install the Security Tools

# tfsec (macOS)
brew install tfsec

# tfsec (Linux)
curl -s https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_linux.sh | bash

# Checkov (all platforms via pip)
pip3 install checkov

# Verify installations
tfsec --version
checkov --version

Run tfsec on Your Terraform

# Scan current directory
tfsec .

# Scan with minimum severity (only show HIGH and CRITICAL)
tfsec --minimum-severity HIGH .

# Output as JSON for CI/CD
tfsec --format json --out tfsec-report.json .

Example tfsec output catching a real vulnerability:

Result #1 HIGH  S3 Bucket does not have logging enabled
────────────────────────────────────────────────
  main.tf:12-28

    12 ┌ resource "aws_s3_bucket" "data" {
    13 │   bucket = "my-data-bucket"
    14 └ }

  Impact:     No audit trail for bucket access
  Resolution: Enable access logging

  More info: https://aquasecurity.github.io/tfsec/v1.28.4/checks/aws/s3/enable-logging/

──────────────────────────────────────────────────────────────

Result #2 HIGH  S3 Bucket does not have encryption enabled
────────────────────────────────────────────────
  main.tf:12-28

  Impact:     Data at rest is not encrypted
  Resolution: Add server-side encryption configuration

tfsec caught two issues that Copilot didn't include because the original comment didn't mention them. This is why you always scan — not because Copilot is wrong, but because your prompts may have gaps.

Run Checkov for Compliance Checks

# Scan Terraform directory
checkov -d .

# Scan with specific framework
checkov -d . --framework terraform

# Only check specific compliance standard (CIS AWS)
checkov -d . --check CKV_AWS_*

# Skip a specific check (with justification comment in code)
checkov -d . --skip-check CKV_AWS_144  # Skip cross-region replication for dev env

# Output SARIF format for GitHub Security tab
checkov -d . --output-file-path . --output sarif

Example Checkov output:

Check: CKV_AWS_18: "Ensure the S3 bucket has access logging enabled"
  FAILED for resource: aws_s3_bucket.artifacts
  File: /terraform/main.tf:5-15

Check: CKV_AWS_52: "Ensure S3 bucket has MFA delete enabled"
  FAILED for resource: aws_s3_bucket.artifacts
  File: /terraform/main.tf:5-15

Check: CKV_AWS_21: "Ensure all data stored in the S3 Bucket have versioning enabled"
  PASSED for resource: aws_s3_bucket.artifacts

Passed checks: 18, Failed checks: 4, Skipped checks: 0

Use Copilot Chat to Fix Security Findings

Once you have tfsec or Checkov output, paste it into Copilot Chat:

I ran tfsec on my Terraform and got these security findings:

[paste tfsec output here]

Please fix all of these issues in my main.tf and explain what each fix does.

Copilot will read the findings and generate the fixes. This is the AI-powered security fix loop — scan, paste findings to Copilot, get fixes, rescan.

Set Up Pre-commit Hooks (Scan Before Every Commit)

Never let broken or insecure Terraform reach your repo:

pip3 install pre-commit

Create .pre-commit-config.yaml in your repo root:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.92.0
    hooks:
      # Format all .tf files
      - id: terraform_fmt

      # Validate Terraform syntax
      - id: terraform_validate

      # Security scan with tfsec (block on HIGH+)
      - id: terraform_tfsec
        args:
          - --args=--minimum-severity=HIGH

      # Compliance scan with Checkov
      - id: terraform_checkov
        args:
          - --args=--skip-check CKV_AWS_144,CKV_AWS_273

      # Auto-generate module documentation
      - id: terraform_docs
        args:
          - --hook-config=--path-to-file=README.md
          - --hook-config=--add-to-existing-file=true

  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.6.0
    hooks:
      - id: detect-private-key
      - id: check-merge-conflict
      - id: trailing-whitespace

Install the hooks:

pre-commit install

Now every git commit automatically runs format, validate, tfsec, and Checkov. Bad Terraform never leaves your machine.


Part 4 — Estimate Costs Before You Deploy with Infracost

You've generated Terraform with Copilot. You've secured it with tfsec and Checkov. Now answer the most important question: how much will this cost?

Infracost is an open-source tool that reads your Terraform files and shows you the estimated monthly AWS/Azure/GCP cost — before you deploy anything.

Install Infracost

# macOS
brew install infracost

# Linux
curl -fsSL https://raw.githubusercontent.com/infracost/infracost/master/scripts/install.sh | sh

# Authenticate (free API key, no credit card)
infracost auth login

Get Your First Cost Estimate

# Navigate to your Terraform directory
cd terraform/

# Get a full cost breakdown
infracost breakdown --path .

Example output:

Project: clouddevopshub/terraform-infra

 Name                                            Monthly Qty  Unit            Monthly Cost

 aws_eks_cluster.main
 └─ EKS cluster                                         730  hours                 $73.00

 aws_eks_node_group.system
 ├─ Instance usage (Linux/UNIX, on-demand, t3.medium)
 │  └─ 2 × 730 hours                                   1460  hours                $60.63
 └─ Root volume: 20 GB gp3                               40  GB-months              $3.20

 aws_eks_node_group.application
 ├─ Instance usage (Linux/UNIX, on-demand, t3.large)
 │  └─ 3 × 730 hours                                   2190  hours               $136.41
 └─ Root volume: 20 GB gp3                               60  GB-months              $4.80

 aws_nat_gateway.main (×3)
 ├─ NAT gateway                                        2190  hours               $97.74
 └─ Data processed                                 Cost depends on usage

 aws_rds_cluster.main
 └─ Database instance (db.t3.medium, multi-az)          730  hours               $106.58

 MONTHLY ESTIMATE                                                                $482.36
 ──────────────────────────────────────────────────────────────────────────────────────
 1 resource type wasn't estimated (aws_nat_gateway data transfer - usage-based)

That's your estimated cost before running a single terraform apply. You can now have an informed conversation with your team or manager about the infrastructure budget.

Show Cost Diff in Pull Requests

This is the killer feature. Every time a PR changes Terraform files, Infracost automatically comments on it with the cost impact:

💰 Infracost estimate: +$127.50/month

┌─────────────────────────────────────────────────────────┐
│ Changed resources                                       │
├─────────────────────────────────────────────────────────┤
│ ~ aws_eks_node_group.application                        │
│   instance_type: t3.large → t3.xlarge  +$127.50/month  │
└─────────────────────────────────────────────────────────┘

Your team can see, review, and approve cost increases as part of normal code review — just like reviewing security or functionality changes.


Part 5 — The Complete AI-Powered Terraform CI/CD Pipeline

Put it all together in a GitHub Actions workflow that runs on every PR touching Terraform files:

# .github/workflows/terraform-ai-pipeline.yml
name: Terraform AI Pipeline

on:
  pull_request:
    paths:
      - 'terraform/**'
      - '**.tf'
  push:
    branches: [main]
    paths:
      - 'terraform/**'

permissions:
  contents: read
  pull-requests: write  # needed for Infracost PR comments

env:
  TF_VERSION: "1.9.0"
  TF_WORKING_DIR: "./terraform"
  AWS_REGION: "ap-south-1"

jobs:

  # ─────────────────────────────────────────────
  # STEP 1: Format + Validate
  # ─────────────────────────────────────────────
  validate:
    name: Format & Validate
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: ${{ env.TF_VERSION }}

      - name: Terraform Format Check
        run: terraform fmt -check -recursive
        working-directory: ${{ env.TF_WORKING_DIR }}

      - name: Terraform Init
        run: terraform init -backend=false
        working-directory: ${{ env.TF_WORKING_DIR }}

      - name: Terraform Validate
        run: terraform validate
        working-directory: ${{ env.TF_WORKING_DIR }}

  # ─────────────────────────────────────────────
  # STEP 2: Security Scan with tfsec
  # ─────────────────────────────────────────────
  security-tfsec:
    name: Security Scan (tfsec)
    runs-on: ubuntu-latest
    needs: validate
    steps:
      - uses: actions/checkout@v4

      - name: Run tfsec
        uses: aquasecurity/tfsec-action@v1.0.0
        with:
          working_directory: ${{ env.TF_WORKING_DIR }}
          minimum_severity: HIGH
          format: sarif
          sarif_file: tfsec.sarif

      - name: Upload SARIF results to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: tfsec.sarif

  # ─────────────────────────────────────────────
  # STEP 3: Compliance Scan with Checkov
  # ─────────────────────────────────────────────
  security-checkov:
    name: Compliance Scan (Checkov)
    runs-on: ubuntu-latest
    needs: validate
    steps:
      - uses: actions/checkout@v4

      - name: Run Checkov
        uses: bridgecrewio/checkov-action@v12
        with:
          directory: ${{ env.TF_WORKING_DIR }}
          framework: terraform
          output_format: sarif
          output_file_path: checkov.sarif
          skip_check: CKV_AWS_144,CKV_AWS_273  # document exceptions

      - name: Upload Checkov results to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: checkov.sarif

  # ─────────────────────────────────────────────
  # STEP 4: Cost Estimation with Infracost
  # ─────────────────────────────────────────────
  cost-estimation:
    name: Cost Estimate (Infracost)
    runs-on: ubuntu-latest
    needs: validate
    steps:
      - uses: actions/checkout@v4

      - name: Setup Infracost
        uses: infracost/actions/setup@v3
        with:
          api-key: ${{ secrets.INFRACOST_API_KEY }}

      - name: Checkout base branch for comparison
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.base.sha }}
          path: base-branch

      - name: Generate base cost estimate
        run: |
          infracost breakdown \
            --path=base-branch/${{ env.TF_WORKING_DIR }} \
            --format=json \
            --out-file=/tmp/infracost-base.json

      - name: Generate PR cost estimate
        run: |
          infracost breakdown \
            --path=${{ env.TF_WORKING_DIR }} \
            --format=json \
            --out-file=/tmp/infracost-pr.json

      - name: Post cost diff comment on PR
        run: |
          infracost comment github \
            --path=/tmp/infracost-pr.json \
            --repo=$GITHUB_REPOSITORY \
            --pull-request=${{ github.event.pull_request.number }} \
            --github-token=${{ github.token }} \
            --behavior=update
        if: github.event_name == 'pull_request'

  # ─────────────────────────────────────────────
  # STEP 5: Terraform Plan (on PRs)
  # ─────────────────────────────────────────────
  plan:
    name: Terraform Plan
    runs-on: ubuntu-latest
    needs: [security-tfsec, security-checkov, cost-estimation]
    if: github.event_name == 'pull_request'
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id:     ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region:            ${{ env.AWS_REGION }}

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: ${{ env.TF_VERSION }}

      - name: Terraform Init
        run: terraform init
        working-directory: ${{ env.TF_WORKING_DIR }}

      - name: Terraform Plan
        run: terraform plan -out=tfplan -no-color 2>&1 | tee plan.txt
        working-directory: ${{ env.TF_WORKING_DIR }}

      - name: Post Plan to PR
        uses: actions/github-script@v7
        if: github.event_name == 'pull_request'
        with:
          script: |
            const fs = require('fs');
            const plan = fs.readFileSync('${{ env.TF_WORKING_DIR }}/plan.txt', 'utf8');
            const truncated = plan.length > 65000
              ? plan.substring(0, 65000) + '\n... (truncated)'
              : plan;
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `## Terraform Plan\n\`\`\`hcl\n${truncated}\n\`\`\``
            });

  # ─────────────────────────────────────────────
  # STEP 6: Terraform Apply (on merge to main)
  # ─────────────────────────────────────────────
  apply:
    name: Terraform Apply
    runs-on: ubuntu-latest
    needs: [security-tfsec, security-checkov]
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    environment: production  # requires manual approval in GitHub Environments
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id:     ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region:            ${{ env.AWS_REGION }}

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: ${{ env.TF_VERSION }}

      - name: Terraform Init
        run: terraform init
        working-directory: ${{ env.TF_WORKING_DIR }}

      - name: Terraform Apply
        run: terraform apply -auto-approve
        working-directory: ${{ env.TF_WORKING_DIR }}

What this pipeline does on every PR:

PR opened / updated
        │
        ▼
  ┌─────────────┐
  │   Validate  │  terraform fmt + validate (30 sec)
  └──────┬──────┘
         │
   ┌─────┴──────┬───────────────┐
   ▼            ▼               ▼
 tfsec       Checkov        Infracost
 (security)  (compliance)   (cost diff)
   │            │               │
   └─────┬──────┘               │
         │                      │
         ▼                      ▼
    terraform plan          PR comment
    posted to PR            with $$ diff
         │
         ▼
   Human review + approve
         │
         ▼
  Merge to main
         │
         ▼
  terraform apply
  (with manual approval gate)

No insecure or expensive infrastructure ever reaches your cloud account without human sign-off.


Part 6 — Real-World Copilot Mistakes (and How to Avoid Them)

AI is powerful but not perfect. Here are the most common mistakes engineers make when using Copilot for Terraform:

Mistake 1: Accepting Outdated Provider Syntax

Copilot was trained on code that includes older AWS provider patterns. The most common one:

# WRONG — old AWS provider v3 pattern
resource "aws_s3_bucket" "example" {
  bucket = "my-bucket"
  acl    = "private"          # ← Deprecated in provider v4+

  server_side_encryption_configuration {    # ← Separate resource now
    rule { ... }
  }
}

# CORRECT — AWS provider v5 pattern
resource "aws_s3_bucket" "example" {
  bucket = "my-bucket"
}

resource "aws_s3_bucket_acl" "example" {
  bucket = aws_s3_bucket.example.id
  acl    = "private"
}

resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
  bucket = aws_s3_bucket.example.id
  rule { ... }
}

Fix: Always include the provider version in your comment prompt:

# Using AWS provider v5.x — use separate resources for bucket properties

Mistake 2: Hardcoded Secrets in Variables

Copilot sometimes generates this:

# NEVER DO THIS — Copilot might suggest it
variable "db_password" {
  default = "MyPassword123!"  # ← Hardcoded secret in version control
}

Fix: Always use sensitive = true and pull from AWS Secrets Manager or SSM:

variable "db_password" {
  description = "RDS master password — pull from AWS Secrets Manager"
  type        = string
  sensitive   = true
  # No default — must be passed at runtime
}

# Or reference SSM directly
data "aws_ssm_parameter" "db_password" {
  name            = "/${var.environment}/rds/master-password"
  with_decryption = true
}

Mistake 3: Trusting Copilot on CIDR Ranges

Copilot sometimes generates security groups with 0.0.0.0/0 ingress rules:

# WRONG — never allow unrestricted SSH in production
ingress {
  from_port   = 22
  to_port     = 22
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"]   # ← tfsec will catch this
}

Run tfsec after every Copilot generation. It catches this immediately.

Mistake 4: Missing prevent_destroy on Critical Resources

Copilot won't add lifecycle blocks unless you ask. Always add them to databases and stateful resources:

resource "aws_rds_cluster" "main" {
  # ... configuration ...

  lifecycle {
    prevent_destroy = true   # Add this manually — Copilot often skips it
  }
}

Before vs. After: AI-Powered Terraform Workflow

Task Manual Approach With AI Tools
Write VPC module 45–60 min 2–3 min (Copilot)
Security review Manual code review (often missed) Automated (tfsec + Checkov, ~10 sec)
Cost check Deploy → surprise bill Before deploy (Infracost in PR)
Fix security issues Find + fix manually Paste findings to Copilot Chat, get fixes
Documentation Manually write README Auto-generated (terraform-docs)
PR review No cost/security context Full plan + cost diff + security report

Summary: Your AI-Powered IaC Toolkit

Here's your complete stack:

Tool Role Cost
GitHub Copilot Generate Terraform from comments Free tier / $10/mo
Copilot Chat Explain, fix, refactor Terraform Included
tfsec Security misconfiguration scanner Free (open source)
Checkov CIS/SOC2/HIPAA compliance scanner Free (open source)
Infracost Cloud cost estimation in PRs Free tier
terraform-docs Auto-generate module README Free (open source)
pre-commit-terraform Run all checks before every commit Free (open source)

The workflow:

Comment in .tf file
      ↓
GitHub Copilot generates module
      ↓
pre-commit: fmt → validate → tfsec → Checkov → docs
      ↓
git push → PR opened
      ↓
GitHub Actions: validate → tfsec → Checkov → Infracost → plan
      ↓
PR comment: security report + cost diff + terraform plan
      ↓
Human review → approve → merge
      ↓
Terraform apply (with manual gate for production)

This is the Terraform workflow that senior engineers at companies like Stripe, Airbnb, and Coinbase run internally — automated, auditable, and cost-aware at every step.


Learn This in a Live Bootcamp

Want to build this complete AI-powered Terraform pipeline on real AWS, Azure, and GCP infrastructure — with hands-on projects, live mentoring, and career support?

CloudDevOpsHub Batch 42 — 55-day Multi-Cloud + DevOps with AI bootcamp — covers Terraform, Kubernetes, GitOps, AIOps, CI/CD, and AI-integrated DevOps workflows end to end.

👉 Enroll in Batch 42 — CloudDevOpsHub →


SEO Keywords Covered

Terraform AI tutorial, GitHub Copilot Terraform, Terraform IaC AI 2025, write Terraform faster AI, GitHub Copilot IaC, tfsec tutorial, Checkov Terraform, Infracost GitHub Actions, Terraform security scanning, AI infrastructure as code, Terraform CI/CD pipeline, GitHub Copilot DevOps, Terraform best practices 2025, IaC security tools, Terraform cost estimation, terraform validate tfsec checkov, Infracost PR comment, Terraform AWS module Copilot, AI DevOps tools 2025, GitHub Copilot cloud infrastructure


Written by the CloudDevOpsHub team — practical hands-on training in Multi-Cloud, DevOps, and AI for engineers who want high-paying cloud roles. Follow CloudDevOpsHub on Hashnode for weekly deep-dives on Terraform, Kubernetes, and AI-powered DevOps.