Ravindra BagaleCourses & study guides मराठी

Chapter 81: DevOps Projects Part 11: GitHub Actions GitLab CI Node Matrix Docker OIDC Terraform Runner Releases

81.5 Project 81: Terraform plan on pull request

Friends, apply without a reviewed plan is gambling. Today we run terraform plan on every PR, post the plan as a comment tip, and apply only on main after approve.

What you will build in this project

  1. Workflow: plan on pull_request.
  2. OIDC to the Terraform role.
  3. Save plan artifact.
  4. Apply only on main.

1. Start from a real company story

At ShareChat in Bengaluru, someone applied from a laptop and deleted a prod subnet by mistake.

Rough cost: about ₹35 lakh in downtime that afternoon.

Ritu forced plan-on-PR and apply-on-main with OIDC.

Today we build that gate.

PRterraform planartifactplan.binreviewhumanmainapply
Picture 1: PR → terraform plan → artifact/comment → merge → main apply

Ravindra Bagale's Tip

Students run apply on every branch. Limit apply to main or a release tag. Keep that habit.

2. Start and prepare

Step 1: Why plan on PR

Why: Catch destroy before merge. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: echo why. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 1: a1

Type this:

echo 'terraform plan on PR shows adds changes destroys before merge'

You will see:

terraform plan on PR shows adds changes destroys before merge

What it means: Why.

Example 2: a2

Type this:

mkdir -p /tmp/gha81/infra/.github/workflows && echo 'Today: plan on PR, apply on main, OIDC'

You will see:

Today: plan on PR, apply on main, OIDC

What it means: Scope.

Example 3: a3

Type this:

echo 'Never apply unreviewed plans to prod'

You will see:

Never apply unreviewed plans to prod

What it means: Rule.

Step 2: Tiny module

Why: Sample tf. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: printf main.tf. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 4: b1

Type this:

printf '%s\n' 'terraform {' '  required_version = ">= 1.5.0"' '  required_providers {' '    aws = { source = "hashicorp/aws", version = "~> 5.0" }' '  }' '}' 'provider "aws" { region = "ap-south-1" }' 'resource "aws_s3_bucket" "web" { bucket = "shop-web-lab-unique" }' > /tmp/gha81/infra/main.tf && head -5 /tmp/gha81/infra/main.tf

You will see:

terraform {

What it means: main.tf.

Example 5: b2

Type this:

echo 'Remote state from Terraform projects 52 stays required in real life'

You will see:

Remote state from Terraform projects 52 stays required in real life

What it means: State.

Example 6: b3

Type this:

echo 'Use a unique bucket name or a random suffix in labs'

You will see:

Use a unique bucket name or a random suffix in labs

What it means: Unique.

Step 3: Plan job

Why: PR workflow. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: YAML tip. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 7: c1

Type this:

printf '%s\n' 'name: tf' 'on:' '  pull_request:' '    paths: [ "infra/**" ]' '  push:' '    branches: [ main ]' '    paths: [ "infra/**" ]' 'jobs:' '  plan:' '    if: github.event_name == \'pull_request\'' '    runs-on: ubuntu-latest' '    permissions: { id-token: write, contents: read }' '    defaults: { run: { working-directory: infra } }' '    steps:' '      - uses: actions/checkout@v4' '      - uses: hashicorp/setup-terraform@v3' '      - uses: aws-actions/configure-aws-credentials@v4' '        with: { role-to-assume: arn:aws:iam::123456789012:role/tf-plan, aws-region: ap-south-1 }' '      - run: terraform init -input=false' '      - run: terraform plan -input=false -out=tfplan' '      - uses: actions/upload-artifact@v4' '        with: { name: tfplan, path: infra/tfplan }' > /tmp/gha81/infra/.github/workflows/tf.yml && grep -E 'plan:|terraform plan' /tmp/gha81/infra/.github/workflows/tf.yml

You will see:

plan:\n      - run: terraform plan -input=false -out=tfplan

What it means: Plan job.

Example 8: c2

Type this:

echo 'paths filter avoids running tf on docs-only PRs'

You will see:

paths filter avoids running tf on docs-only PRs

What it means: Filter.

Example 9: c3

Type this:

echo 'Plan role needs read IAM; apply role is separate and tighter'

You will see:

Plan role needs read IAM; apply role is separate and tighter

What it means: Roles.

3. Build the main pieces

Step 4: Apply job

Why: Main only. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: apply tip. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 10: d1

Type this:

printf '%s\n' '  apply:' '    if: github.ref == \'refs/heads/main\' && github.event_name == \'push\'' '    runs-on: ubuntu-latest' '    permissions: { id-token: write, contents: read }' '    environment: production' '    defaults: { run: { working-directory: infra } }' '    steps:' '      - uses: actions/checkout@v4' '      - uses: hashicorp/setup-terraform@v3' '      - uses: aws-actions/configure-aws-credentials@v4' '        with: { role-to-assume: arn:aws:iam::123456789012:role/tf-apply, aws-region: ap-south-1 }' '      - run: terraform init -input=false' '      - run: terraform apply -input=false -auto-approve' >> /tmp/gha81/infra/.github/workflows/tf.yml && grep -A2 'apply:' /tmp/gha81/infra/.github/workflows/tf.yml

You will see:

apply:\n    if: github.ref == 'refs/heads/main' && github.event_name == 'push'\n    runs-on: ubuntu-latest

What it means: Apply.

Example 11: d2

Type this:

echo 'environment: production can require a forge reviewer'

You will see:

environment: production can require a forge reviewer

What it means: Env.

Example 12: d3

Type this:

echo 'Prefer apply saved plan file in stricter teams'

You will see:

Prefer apply saved plan file in stricter teams

What it means: Saved plan.

Step 5: fmt validate

Why: Fast gates. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: steps. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 13: e1

Type this:

printf '%s\n' '- run: terraform fmt -check -recursive' '- run: terraform validate' > /tmp/gha81/FMT.txt && cat /tmp/gha81/FMT.txt

You will see:

- run: terraform fmt -check -recursive

What it means: fmt.

Example 14: e2

Type this:

echo 'Put fmt+validate before plan to fail fast'

You will see:

Put fmt+validate before plan to fail fast

What it means: Order.

Example 15: e3

Type this:

echo 'tflint can join later for style rules'

You will see:

tflint can join later for style rules

What it means: tflint.

Step 6: Comment tip

Why: Human readable plan. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: PR comment. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 16: f1

Type this:

printf '%s\n' 'Optional: terraform show -no-color tfplan > plan.txt' 'Upload plan.txt or post via a comment action' > /tmp/gha81/COMMENT.txt && cat /tmp/gha81/COMMENT.txt

You will see:

Optional: terraform show -no-color tfplan > plan.txt

What it means: Comment.

Example 17: f2

Type this:

echo 'Reviewers must read destroys carefully'

You will see:

Reviewers must read destroys carefully

What it means: Review.

Example 18: f3

Type this:

printf '%s\n' 'Acceptance: PR shows plan; main apply succeeds after merge' > /tmp/gha81/ACCEPT.txt && cat /tmp/gha81/ACCEPT.txt

You will see:

Acceptance: PR shows plan; main apply succeeds after merge

What it means: Gate.

4. Automate and verify

Step 7: State locking

Why: Still required. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: backend tip. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 19: g1

Type this:

echo 'S3 backend + DynamoDB lock from project 52'

You will see:

S3 backend + DynamoDB lock from project 52

What it means: Lock.

Example 20: g2

Type this:

echo 'Two applies at once without a lock corrupt state'

You will see:

Two applies at once without a lock corrupt state

What it means: Why.

Example 21: g3

Type this:

echo 'Plan also takes a lock — do not cancel mid-plan casually'

You will see:

Plan also takes a lock — do not cancel mid-plan casually

What it means: Cancel.

Step 8: Cost tip

Why: Infracost on PR. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: bridge. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 22: h1

Type this:

echo 'Add Infracost from project 60 as a PR check'

You will see:

Add Infracost from project 60 as a PR check

What it means: Infracost.

Example 23: h2

Type this:

echo 'Fail when monthly delta exceeds a team budget'

You will see:

Fail when monthly delta exceeds a team budget

What it means: Budget.

Example 24: h3

Type this:

echo 'Cost and plan together make better reviews'

You will see:

Cost and plan together make better reviews

What it means: Together.

Step 9: Secrets

Why: No cloud keys. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: OIDC. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 25: i1

Type this:

echo 'Reuse OIDC from project 80 for tf-plan and tf-apply roles'

You will see:

Reuse OIDC from project 80 for tf-plan and tf-apply roles

What it means: OIDC.

Example 26: i2

Type this:

echo 'Separate plan and apply roles — plan cannot create most resources'

You will see:

Separate plan and apply roles — plan cannot create most resources

What it means: Split.

Example 27: i3

Type this:

echo 'Never echo terraform.tfvars with secrets in logs'

You will see:

Never echo terraform.tfvars with secrets in logs

What it means: Logs.

5. Harden and accept

Step 10: Story ShareChat

Why: Laptop apply. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: story. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 28: j1

Type this:

printf '%s\n' 'At ShareChat in Bengaluru, a laptop apply deleted a prod subnet.' 'Ritu forced plan-on-PR and apply-on-main with OIDC.' > /tmp/gha81/STORY.txt && wc -l /tmp/gha81/STORY.txt

You will see:

2 /tmp/gha81/STORY.txt

What it means: Story.

Example 29: j2

Type this:

echo 'Rough cost: about ₹35 lakh in downtime that afternoon'

You will see:

Rough cost: about ₹35 lakh in downtime that afternoon

What it means: Cost.

Example 30: j3

Type this:

echo 'Ritu: PASS'

You will see:

Ritu: PASS

What it means: Sign-off.

Step 11: Proof

Why: Workflow. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: grep. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 31: k1

Type this:

grep -E 'terraform plan|terraform apply' /tmp/gha81/infra/.github/workflows/tf.yml

You will see:

- run: terraform plan -input=false -out=tfplan\n      - run: terraform apply -input=false -auto-approve

What it means: Commands.

Example 32: k2

Type this:

test -f /tmp/gha81/ACCEPT.txt && echo 'accept ok'

You will see:

accept ok

What it means: accept.

Example 33: k3

Type this:

echo 'Next: GitLab CI pipeline with stages project 82'

You will see:

Next: GitLab CI pipeline with stages project 82

What it means: Bridge.

Step 12: Acceptance

Why: Plan on PR apply on main. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: final. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 34: z1

Type this:

echo 'PR runs terraform plan'

You will see:

PR runs terraform plan

What it means: Plan.

Example 35: z2

Type this:

echo 'main runs terraform apply'

You will see:

main runs terraform apply

What it means: Apply.

Example 36: z3

Type this:

echo 'OIDC roles separate'

You will see:

OIDC roles separate

What it means: OIDC.

Check yourself

Q1. Who fixed ShareChat laptop apply?

Ritu

Q2. PR runs?

plan

Q3. Main runs?

apply

Q4. Auth?

OIDC

Q5. Artifact?

plan file

Q6. Apply on feature branch?

no

Friends, you planned Terraform on every PR. Did you understand? Let us try it once more. Add a fmt and validate job that fails on bad formatting.

Lab: try at home

  1. Plan workflow.
  2. OIDC role.
  3. Artifact.
  4. Main apply.

Recap

  • Plan before apply.
  • PR only plans.
  • Main applies.
  • OIDC no keys.
  • fmt+validate first.