Infrastructure as Code (IaC) Concepts Cheat Sheet
Summarizes core IaC principles including declarative vs imperative approaches, idempotency, state management, and drift detection.
Core IaC Concepts
Foundational vocabulary shared across IaC tools.
- Declarative- You describe the desired end state; the tool figures out how to get there (Terraform, CloudFormation)
- Imperative- You specify the exact steps/commands to reach a state (shell scripts, older Chef recipes)
- Idempotency- Applying the same configuration repeatedly produces the same result without side effects
- State File- Record of the resources IaC currently manages and their real-world attributes
- Drift- When real infrastructure diverges from what's defined in code (e.g. manual console change)
- Plan/Diff- A dry-run showing what will change before applying, without modifying real resources
- Immutable Infrastructure- Servers are replaced rather than modified in place when a change is needed
IaC Tool Landscape
Common tools and where they fit.
- Terraform- Multi-cloud declarative provisioning using HCL, tracked via state files
- AWS CloudFormation- AWS-native declarative IaC using JSON/YAML templates
- Pulumi- Declarative infra defined using general-purpose languages (TypeScript, Python, Go)
- Ansible- Primarily configuration management, agentless, uses YAML playbooks
- AWS CDK- Defines CloudFormation stacks using imperative code that synthesizes to declarative templates
Minimal Terraform Example
Declarative resource definition demonstrating idempotent provisioning.
resource "aws_instance" "web" { ami = "ami-0abcdef1234567890" instance_type = "t3.micro" tags = { Name = "web-server" }}# terraform plan -> shows proposed changes# terraform apply -> reconciles real infra to match this file# terraform destroy -> tears down managed resources
Remote State with Locking
Store state remotely and lock it during writes so concurrent applies from a team or CI don't corrupt it.
terraform { backend "s3" { bucket = "my-org-tfstate" key = "prod/network/terraform.tfstate" region = "us-east-1" dynamodb_table = "tf-state-lock" encrypt = true }}# terraform init -reconfigure -> point at the backend# terraform force-unlock <LOCK_ID> -> break a stuck lock (use with caution)
Policy as Code (OPA/Rego)
Codify guardrails that block a plan/apply if generated infrastructure violates org policy, independent of the IaC tool.
package terraform.s3deny[msg] { resource := input.resource_changes[_] resource.type == "aws_s3_bucket_public_access_block" resource.change.after.block_public_acls == false msg := sprintf("%v must not allow public ACLs", [resource.address])}# Run with: conftest test plan.json -p policy/
Module Composition
Wrap repeated resource groups into a reusable, versionable module instead of copy-pasting configuration.
module "vpc" { source = "./modules/vpc" cidr_block = "10.0.0.0/16" azs = ["us-east-1a", "us-east-1b"]}output "vpc_id" { value = module.vpc.vpc_id}# terraform providers -> shows which modules pull in which providers# terraform get -update -> re-fetch module sources
Advanced State Management
Concepts that matter once a team, not just an individual, owns the state file.
- State Locking- A backend-level lock (e.g. DynamoDB) preventing two applies from racing on the same state
- Workspaces- Named, isolated state files sharing the same config, used to separate dev/stage/prod
- Partial/Targeted Apply- Applying or planning against a subset of resources (-target) — a smell if used routinely
- State Import- Bringing an existing, manually created resource under IaC management without recreating it
- State Migration- Moving resources between modules/state files (terraform state mv) without destroy/recreate
- Remote State Data Source- Reading another stack's outputs (e.g. terraform_remote_state) to wire stacks together
Testing IaC
Ways to validate infrastructure code before it ever touches a real environment.
- Static Validation- terraform validate / fmt catch syntax and type errors with no cloud calls
- Plan-based Testing- Assert on the JSON plan output (resource counts, attribute values) in CI before apply
- Policy as Code- OPA/Sentinel/Checkov gate plans against security and compliance rules
- Integration Testing- Tools like Terratest actually provision, assert, then tear down real (throwaway) resources
- Contract Testing- Verifying a module's declared outputs/inputs don't break consumers across versions
Never let engineers make manual console changes to IaC-managed resources — even small manual edits cause drift that silently gets reverted (or conflicts) on the next apply.