DevOps
Lesson 4 of 8About 3 min readSuggest an edit

Infrastructure as code

Infrastructure as code (IaC) means your servers, networks, databases and DNS records are described in files kept in version control, and a tool makes the real world match those files. A cloud console cannot tell you who changed a firewall rule last month, or rebuild an environment on demand. With IaC, every change has a diff, a reviewer and a history.

Declarative and imperative

An imperative approach lists steps: create this VPC, then add this subnet, then attach this gateway. Run the script twice and you may get two VPCs. A declarative approach describes the end state: there should be one VPC with these subnets. The tool compares that description with what exists and works out the steps itself. Running it again changes nothing, so it is safe to repeat.

Terraform and its open-source fork OpenTofu are the most common declarative tools and share one language, HCL. Pulumi and AWS CDK use general-purpose languages to produce a declarative model.

resource "aws_s3_bucket" "logs" {
  bucket = "acme-prod-logs"

  tags = {
    team = "platform"
    env  = "prod"
  }
}

Plan, then apply

The core workflow has two steps:

terraform plan -out=tfplan   # show what would change
terraform apply tfplan       # apply exactly that plan

The plan lists every resource to be created, updated in place, or destroyed and recreated. Read it carefully. A small change to an attribute that cannot be modified in place, such as a database’s name or a subnet’s range, shows up as a replacement, and replacing a database means losing its data. Applying a saved plan file guarantees you apply exactly what you reviewed.

State and why it matters

Terraform keeps a state file that maps each resource in your code to a real object in the cloud, such as aws_s3_bucket.logs to a bucket ID. Without it, the tool cannot tell which objects it owns. State also often contains sensitive values in plain text, such as generated passwords.

For anything shared, keep state in a remote backend (an S3 bucket, Google Cloud Storage, Terraform Cloud and so on), not on a laptop. Turn on state locking, so two people or two pipeline runs cannot apply at the same time and corrupt it. Encrypt state, restrict access to it and never commit it to Git.

Split state per environment and per system. One huge state is slow to plan, and a mistake in it can touch everything.

Modules

A module is a reusable group of resources with inputs and outputs: “a service with its load balancer, security group and alarms”. Modules remove copy and paste between environments. Pin module versions, so an update to a shared module reaches production only when you choose.

Drift

Drift is when the real infrastructure no longer matches the code, usually because someone fixed something by hand during an incident. The next plan will try to undo that change, sometimes at a bad moment. Run a scheduled plan in CI and alert when it is not empty. When you find drift, either put the manual change into code or let the apply revert it. Do not leave it.

Reviewing infrastructure changes

Treat infrastructure changes like application code. Open a pull request, have the pipeline run a plan and post it on the pull request, and apply from CI after merge rather than from a laptop. Reviewers should read the plan, not only the code, since the plan shows what will actually happen.

Secrets in IaC

Never put secret values in .tf files or variable files in Git. Store them in a secrets manager (AWS Secrets Manager, Vault, and similar) and reference them, or let the resource generate its own credentials. Marking a variable sensitive hides it from plan output, but the value can still end up in state, which is another reason to lock state down.

Habits

  • Every change goes through a pull request with the plan attached.
  • Remote state with locking, split by environment.
  • Read every “destroy” and “replace” line before approving.
  • Detect drift on a schedule and resolve it promptly.
  • Pin provider and module versions and upgrade them on purpose.

Next: Kubernetes fundamentals

Pods, deployments, services, configuration, resource requests, probes, rolling updates and when to skip Kubernetes.