Who this is for
This lesson is for Platform Engineers who need consistent, secure, and repeatable dev/stage/prod environments using Infrastructure as Code (IaC). If you support multiple product teams or operate shared platforms, this skill is essential.
Prerequisites
- Basic IaC knowledge (e.g., Terraform, CloudFormation, or Pulumi)
- Familiarity with a major cloud provider (AWS, Azure, or GCP)
- Understanding of version control and CI/CD basics
Why this matters
Real tasks you will face:
- Create isolated dev/stage/prod environments on demand, consistently
- Prevent dev misconfigurations from reaching prod
- Apply different sizes, secrets, and policies per environment
- Enable safe, auditable changes with approvals and drift detection
Real-world scenario
A product team needs a new stage environment for a performance test. You spin it up in under an hour via IaC, seeded with sanitized data, with metrics and alerts enabled, and tear it down automatically after the test to save cost.
Concept explained simply
Environment provisioning is the practice of defining dev/stage/prod as code so you can create, change, and destroy them reliably. You use a single blueprint and feed it environment-specific inputs (names, sizes, policies).
Mental model
Think of a coffee machine (the blueprint) that makes different drinks (environments) by changing the capsule (variables). The machine stays the same; the capsule changes flavor, size, and strength.
Core building blocks
- Account or project isolation: separate cloud accounts/subscriptions or strict isolation via folders/projects
- IaC structure: reusable modules; environment stacks referencing modules
- Variables and defaults: dev smaller/cheaper, prod larger/safer
- State management: remote, locked state per environment/workspace
- Secrets: stored and injected securely (never hard-coded)
- Pipelines: automated plan/apply, approvals for prod
- Naming and tagging: deterministic names; tags for cost/ownership
- Guardrails: policies preventing risky changes in prod
- Observability: baseline logging, metrics, alerts per environment
- Data handling: seed dev/stage with synthetic or sanitized data
Worked examples
Example 1: One module, three environments via variables
Goal: Provision the same web stack in dev, stage, and prod using the same module but different inputs.
Show outline
module "web_stack" {
source = "./modules/web_stack"
env = var.env
size = var.size
}
# dev.tfvars: env = "dev", size = "small"
# stage.tfvars: env = "stage", size = "medium"
# prod.tfvars: env = "prod", size = "large"
Result: identical architecture, different capacity and naming per environment.
Example 2: Remote state per environment
Goal: Avoid state collisions and enable team collaboration.
Show outline
# Configure a different backend key per env
backend "remote" {
organization = "acme"
workspaces {
name = var.env
}
}
# Or key-based separation
# key = "envs/${var.env}/terraform.tfstate"
Result: each environment is planned/applied independently with proper locking.
Example 3: CI/CD with prod approval gate
Goal: Plans run on every commit; prod applies require a human approval.
Show outline
# Pseudo-pipeline
on: [pull_request, push]
jobs:
plan:
steps: [checkout, validate, plan]
apply_dev:
if: branch == "main" && env == "dev"
steps: [apply]
apply_stage:
if: tag matches "release-*" && env == "stage"
steps: [apply]
apply_prod:
needs: [plan]
if: manual_approval && env == "prod"
steps: [apply]
Result: safe promotion workflow with audit trail.
Step-by-step: build a minimal 3-env stack
- Create a reusable module for a simple service (network + compute + logging)
- Define env-specific variable files: dev.tfvars, stage.tfvars, prod.tfvars
- Set up remote state with a unique key or workspace per env
- Add naming/tagging convention with env prefix/suffix
- Create a pipeline job matrix to run plan/apply per env
- Add a manual approval step for prod applies
- Configure baseline monitors and alerts per env
- Document how to add a new environment from the same template
Exercises
Do these hands-on tasks. Progress is saved for logged-in users; the exercises and test are available to everyone.
- Exercise 1: Provision three environments from one module (see details below).
- Exercise 2: Add a prod approval gate and drift detection.
Exercise 1 — Provision three environments from one module
Build a reusable module and create dev, stage, and prod using separate variable files and remote state separation.
- Module with inputs: env, size, and tags
- dev/stage/prod tfvars defining names and sizes
- Remote state or workspace per environment
- Outputs showing the environment-specific resource names
Exercise 2 — Add prod approval and drift check
Set up a pipeline that plans on every change and requires manual approval for prod applies. Add a daily drift detection job.
- Pipeline matrix per env
- Manual gate for prod
- Scheduled drift detection with notifications
Checklist before you move on
- Environment naming is deterministic and unique
- State storage is isolated per environment
- Secrets are never stored in code or tfvars
- Prod requires approval; dev/stage can be automated
- Monitoring and tags are applied consistently
Common mistakes and self-check
- Single shared state for all envs. Fix: use workspace or per-env state keys.
- Copy-pasting code per environment. Fix: use modules + variables; avoid drift.
- Baking secrets into code. Fix: use a secrets store and data sources.
- Prod identical to dev sizing. Fix: parameterize sizes/quotas; test scale in stage.
- No guardrails. Fix: add policy checks and required approvals for prod.
Self-check prompts
- Can you destroy dev without affecting stage/prod?
- Does your plan for prod show only intended changes?
- Are tags/labels consistent across all resources?
- Can a new environment be added by adding a new tfvars file only?
Practical projects
- Spin up a multi-env web API platform with per-env databases and alerting
- Create an ephemeral preview environment on pull requests and auto-destroy after merge
- Implement policy checks that block public storage in prod but allow it in dev for testing
Learning path
- Start: Environment provisioning with variables, state, and tagging
- Next: Policy as Code and guardrails for prod
- Then: Observability baselines and SLOs per environment
- Finally: Ephemeral environments and cost optimization
Next steps
- Finish the exercises and verify with the checklist
- Run plans for all environments and review diffs
- When confident, take the quick test
Mini challenge
Your team needs a temporary staging environment for a load test, identical to prod except half the capacity and no real customer data. Using your module, create stage-loadtest that auto-destroys after 72 hours, with alerts and cost tags. Document the exact variables changed.
Quick Test
Take the short test below. Everyone can take it; logged-in users get saved progress.