Menu

Topic 8 of 8

Infrastructure As Code Awareness

Learn Infrastructure As Code Awareness for free with explanations, exercises, and a quick test (for Backend Engineer).

Published: January 20, 2026 | Updated: January 20, 2026

Why this matters

Infrastructure as Code (IaC) lets you define servers, networks, databases, and permissions as versioned code. As a Backend Engineer, you will:

  • Review and merge pull requests that change infrastructure (e.g., add an API gateway, adjust an IAM role).
  • Spin up dev/test environments on demand from code, not tickets.
  • Automate plan/apply in CI to make releases repeatable and auditable.
  • Detect and fix configuration drift between environments.
  • Rollback safely by reverting code instead of clicking in consoles.

Concept explained simply

IaC means describing what you want your infrastructure to look like in files that can be version-controlled and executed by tools to create or update real resources.

Mental model

Think of your cloud as a state machine:

  • Desired state: the code you commit.
  • Current state: what currently exists in the cloud (tracked by a state file or inventory).
  • Plan: a diff between desired and current state.
  • Apply: the tool reconciles the diff to reach the desired state, ideally idempotently.
Key terms (open me)
  • Declarative vs Imperative: Declarative says “what” (end state). Imperative says “how” (commands).
  • Idempotency: Running the same code twice doesn’t change the result the second time.
  • State: A record mapping your code to real resources to compute safe changes.
  • Drift: Real infra doesn’t match code (manual changes or failed applies).
  • Modules/Roles: Reusable blocks that standardize patterns (e.g., a service + DB + monitoring).

Core pieces of IaC for Backend Engineers

  • Small, composable modules for repeatable patterns (service, queue, storage).
  • Version control and code reviews for infra changes.
  • Plan on pull requests; apply only on protected branches after approval.
  • Remote state storage with locking to avoid concurrent apply conflicts.
  • Separate configs per environment with shared modules and different variables.
  • Secrets kept outside code (secure variables, vaults, or masked CI vars).
  • Automated drift detection and scheduled conformance checks.

Worked examples

Example 1: Minimal declarative resource (Terraform-style)

Goal: Create a versioned object storage bucket with tags using declarative IaC.

# main.tf (illustrative)
terraform {
  required_version = ">= 1.4.0"
}

provider "aws" {
  region = var.region
}

resource "aws_s3_bucket" "logs" {
  bucket = var.bucket_name
  tags = {
    app   = var.app
    env   = var.env
    owner = var.owner
  }
}

resource "aws_s3_bucket_versioning" "logs_v" {
  bucket = aws_s3_bucket.logs.id
  versioning_configuration { status = "Enabled" }
}

variable "region" {}
variable "bucket_name" {}
variable "app" {}
variable "env" {}
variable "owner" {}

Mental check: Re-running apply should show no changes unless inputs change. Tags and versioning are enforced.

Example 2: CI pipeline gates (plan on PR, apply on main)

# Pseudo-CI steps (tool-agnostic)
# pull_request:
- checkout
- setup-terraform
- terraform init -backend-config=... (remote state)
- terraform validate
- terraform plan -out=plan.out
- upload plan summary as PR comment

# main branch (after review & approvals):
- checkout
- setup-terraform
- terraform init -backend-config=...
- terraform apply -auto-approve plan.out

Result: Reviewers see the exact changes before they land. Production applies only on approved, protected branches.

Example 3: Drift detection

Say someone manually disabled bucket versioning in the console. Your next plan shows a diff:

~ resource "aws_s3_bucket_versioning" "logs_v" {
    versioning_configuration {
-     status = "Suspended"
+     status = "Enabled"
    }
}

Action: Apply the code or re-enable via code. Avoid manual fixes without code changes to prevent recurring drift.

Exercises

Practice here, then scroll to the Quick Test at the end.

Exercise 1: Author a minimal declarative resource

Create a minimal IaC snippet that:

  • Declares a storage bucket named via a variable.
  • Enables versioning.
  • Adds tags: app, env, owner (variables too).

Output: a single code file (e.g., main.tf-like) with variables and resources. Do not include secrets.

Exercise 2: Read a plan and spot change types

Given this plan excerpt, identify creates, updates, and destroys, and whether it’s safe to apply now:

+ aws_s3_bucket.logs (new resource)
~ aws_iam_role.app_role (in-place update: policy doc change)
-/+ aws_security_group.web (replace: name changed)

Explain: Which lines correspond to create/update/replace? What risk does replace carry? What review should happen?

Exercise checklist

  • Solution is declarative (no shell loops to create resources).
  • Idempotent: second apply yields “no changes”.
  • Variables isolate env and ownership (no hard-coded names).
  • You can explain each plan symbol: + create, ~ update, - destroy, -/+ replace.

Common mistakes and self-check

  • Mistake: Hard-coding names or regions. Self-check: Are env, region, and naming derived from variables?
  • Mistake: No remote state/locking. Self-check: Does your backend lock during apply to prevent concurrent changes?
  • Mistake: Applying plans straight from PRs. Self-check: Is apply restricted to protected branches only?
  • Mistake: Secrets committed to repo. Self-check: Are secrets pulled from secure providers or masked CI vars?
  • Mistake: Manual hotfixes in console. Self-check: Can you fix by code and verify with a clean plan?

Practical projects

  • Reusable service module: One module that provisions a service + log storage + alarms using variables for env.
  • Ephemeral preview env: On pull request, create a short-lived environment; destroy it on merge/close.
  • Drift watcher: A scheduled pipeline that runs plan in read-only mode and posts a summary to team chat.

Learning path

  1. Write a tiny declarative resource (storage + tags + versioning).
  2. Add variables, remote state, and locking.
  3. Introduce modules to remove duplication.
  4. Wire CI: validate → plan on PR → apply on main.
  5. Add drift detection and environment promotion (dev → staging → prod).

Who this is for

  • Backend Engineers who touch cloud resources or run services in production.
  • Engineers integrating deployments into CI/CD pipelines.

Prerequisites

  • Basic Git (branches, pull requests, reviews).
  • Familiarity with a cloud provider’s basic services (compute, storage, IAM).
  • Comfort running command-line tools.

Next steps

  • Finish the exercises and take the Quick Test below.
  • Refactor your IaC into modules and add CI plan/apply gates.
  • Propose an IaC code review checklist for your team.

Mini challenge

Time-box (30–45 min): Convert a manual environment setup you did recently (e.g., a queue + permissions) into declarative code with variables for env and tags. Write a short README explaining how to plan/apply safely and how to rollback by code.

Quick Test

This test is available to everyone. If you’re logged in, your progress will be saved.

Practice Exercises

2 exercises to complete

Instructions

Create a minimal IaC snippet that:

  • Declares a storage bucket named via a variable.
  • Enables versioning.
  • Adds tags: app, env, owner (variables too).

Output: a single code file (e.g., main.tf-like) with variables and resources. Do not include secrets.

Expected Output
A single file that declares variables (bucket_name, app, env, owner) and a storage bucket resource with versioning enabled and tags applied. Re-applying should be idempotent (no changes on second run).

Infrastructure As Code Awareness — Quick Test

Test your knowledge with 10 questions. Pass with 70% or higher.

10 questions70% to pass

Have questions about Infrastructure As Code Awareness?

AI Assistant

Ask questions about this tool