Skip to main content

Command Palette

Search for a command to run...

A Workflow for Deploying Infrastructure Code with Terraform

Updated
6 min read
A Workflow for Deploying Infrastructure Code with Terraform

Infrastructure deployments are not just “application deployments with different tooling.” They operate under a fundamentally different risk model.

A bad application deploy might return a 500 error. A bad infrastructure deploy can delete a production database.

That difference is why Infrastructure as Code (IaC) demands a stricter, more deliberate workflow.

In this post, I walk through a complete 7-step Terraform deployment workflow, using a real change to a webserver cluster, and highlight the critical safeguards that make infrastructure deployments safe at scale.


🔁 The 7-Step Infrastructure Deployment Workflow

1. Version Control — Enforce Discipline Early

All Terraform code lives in Git, but the key is enforcement, not storage.

For my setup:

  • main branch is protected

  • At least one PR approval required

  • Status checks must pass No direct pushes allowed

This ensures every infrastructure change is:

  • Reviewed

  • Tested

  • Traceable


2. Run the Code Locally — Generate the Plan

Unlike application code, you don’t “run” Terraform.

You generate a diff against reality:

terraform workspace select dev
terraform plan -out=day21.tfplan

This step is non-negotiable.

What I reviewed:

  • Resources to be created: 1

  • Modified: 0

  • Destroyed: 0

Even a single “destroy” here would trigger deeper scrutiny.

👉 This is your first line of defense against unintended consequences.


3. Make the Change — Small, Isolated, Intentional

I created a feature branch and added a CloudWatch CPU alarm for my webserver cluster.

git checkout -b add-cloudwatch-alarms-day21
terraform plan -out=day21.tfplan
git commit -m "Add CPU alarm for webserver cluster"
git push origin add-cloudwatch-alarms-day21

Key principle:

Infrastructure changes should be small and reversible.


4. Submit for Review — The Plan Is the Diff

This is where infrastructure diverges sharply from application workflows.

In application code:

  • Reviewers read source code

In infrastructure:

  • Reviewers must understand what will happen in the real world

So I included the full terraform plan output in the PR:

📌 What this changes

Adds a CPU utilization alarm for the webserver cluster.

📌 Resources affected

  • Created: 1

  • Modified: 0

  • Destroyed: 0

⚠️ Blast Radius (Critical)

This is where most engineers underinvest.

For my change:

  • Impact is minimal (monitoring only)

  • No runtime disruption

But for shared infrastructure (VPCs, IAM, security groups), this section must answer:

  • What systems depend on this?

  • What breaks if apply fails halfway?

  • Is failure partial or total?

👉 If you can’t clearly define the blast radius, you shouldn’t deploy.


🔄 Rollback Plan (Equally Critical)

Rollback is not “we’ll figure it out.”

It must be explicit:

  • Revert the PR

  • Re-run Terraform apply with previous configuration

  • Restore state if necessary

For higher-risk changes, this may include:

  • Restoring from snapshots

  • Recreating deleted resources

  • Traffic failover strategies

👉 If rollback isn’t clear, your deployment isn’t safe.

5. Automated Tests — Gate Before Merge

My CI pipeline enforced:

terraform fmt --check
terraform validate
terraform test

Only after all checks passed could the PR be merged.

Important distinction:

  • These tests validate code correctness

  • They do NOT validate organizational policy

That’s where Sentinel comes in (more later).


6. Merge and Release — Version Infrastructure

After approval:

git tag -a "v1.4.0" -m "Add CPU alarm"
git push origin v1.4.0

Tagging matters because:

  • Infrastructure modules are versioned artifacts

  • Environments should consume explicit versions

This avoids accidental drift.


7. Deploy — Apply the Reviewed Plan

This is the most dangerous step.

So we eliminate uncertainty:

terraform apply day21.tfplan

Why this matters:

  • The plan was reviewed

  • The plan is now pinned

  • No new changes can sneak in

After apply:

terraform plan

Result:

No changes. Infrastructure is up-to-date.

🔐 Infrastructure-Specific Safeguards

These do not exist in application deployment workflows.

  1. Plan File Pinning
terraform plan -out=reviewed.tfplan
terraform apply reviewed.tfplan

Without this:

  • You risk applying unreviewed changes

2. Approval Gates for Destructive Changes

If a plan shows:

terraform plan -out=reviewed.tfplan
terraform apply reviewed.tfplan

It must require:

  • A separate explicit approval

This is enforced in Terraform Cloud.


  1. State Backup and Recovery

Terraform relies on a state file.

I configured:

  • S3 backend

  • Versioning enabled

This allows:

  • Rolling back to previous state versions

  • Recovering from failed applies


4. Blast Radius Documentation

Every PR touching shared infrastructure must include:

  • Dependencies

  • Failure scenarios

  • Impact scope

This is your risk model in writing.


🛡️ Sentinel — The Enforcement Layer

Validation checks syntax.

Sentinel enforces policy.

Here’s a policy I implemented:

import "tfplan/v2" as tfplan

allowed_instance_types = ["t2.micro", "t2.small", "t2.medium", "t3.micro", "t3.small"]

main = rule {
  all tfplan.resource_changes as _, rc {
    rc.type is not "aws_instance" or
    rc.change.after.instance_type in allowed_instance_types
  }
}

What this enforces:

  • Only approved EC2 instance types can be deployed

  • Any violation → deployment blocked

Why this matters:

Without Sentinel:

  • Engineers can deploy anything that passes validation

With Sentinel:

  • You enforce organizational rules automatically

⚖️ Infrastructure vs Application Workflows

  1. State Awareness
  • Infrastructure tracks real resources via state files.

  • Applications don’t.

2. Risk Profile

  • Infra changes can destroy systems.

  • App changes typically degrade behavior.

3. Plan → Review → Apply

  • Infrastructure requires a two-phase commit model.

  • Applications usually deploy directly.


📖 Key Insight

The most dangerous step is:

terraform apply

Because it executes real-world changes.

The most commonly skipped safeguard?

  • Applying from a saved plan file

Skipping this introduces drift and unpredictability.


🧠 Final Thoughts

Infrastructure deployment is not just engineering. It’s risk management.

The shift is subtle but critical:

  • You’re not shipping code

  • You’re modifying live systems

And that demands:

  • Explicit review Strict safeguards Enforced policies

Do this well, and Terraform becomes a force multiplier. Do it poorly, and it becomes a liability.

More from this blog

T

Terraform Tales

27 posts