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


* * *

## 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 plan` → `terraform 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](https://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"):

```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:**

```hcl
# create an S3 bucket
```

**Great prompt:**

```hcl
# 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:

```hcl
# 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:

```hcl
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

```hcl
# 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:

```hcl
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:

```plaintext
@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)**

```plaintext
# 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**

```plaintext
# 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**

```plaintext
# 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**

```plaintext
# 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**

```plaintext
# 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**

```plaintext
# 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**

```plaintext
# 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

```bash
# 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

```bash
# 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:**

```plaintext
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

```bash
# 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:**

```plaintext
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:

```plaintext
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:

```bash
pip3 install pre-commit
```

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

```yaml
# .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:

```bash
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

```bash
# 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

```bash
# Navigate to your Terraform directory
cd terraform/

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

**Example output:**

```plaintext
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:

```plaintext
💰 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:

```yaml
# .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:**

```plaintext
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:

```hcl
# 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:

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

### Mistake 2: Hardcoded Secrets in Variables

Copilot sometimes generates this:

```hcl
# 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:

```hcl
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:

```hcl
# 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:

```hcl
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:

```plaintext
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 →**](https://clouddevopshub.com/batch-42)

* * *

## 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*](https://blog.clouddevopshub.com) *for weekly deep-dives on Terraform, Kubernetes, and AI-powered DevOps.*
