WSS
On this page
Infrastructure & ProvisioningRequiredUpdated

Infrastructure as Code principles

Core principles of defining environments through machine-readable code, enabling idempotency, desired state configuration, and automated reconciliation.

Reference Card

  • Origin/Prior Art: CFEngine (1993), Puppet (2005), Chef (2009).
  • Related Practices: Version control, Continuous Integration, GitOps.
  • Key Concepts: Declarative vs Imperative, Idempotency, Desired State.
  • Primary Failure Modes: Drift, State mismatch, Privilege escalation, Out-of-band modifications.

Introduction

Infrastructure as Code (IaC) defines computing environments through machine-readable definition files rather than physical hardware configuration or interactive configuration tools. It replaces manual provisioning via cloud provider dashboards or manual SSH scripts. The definitions reside in version control systems, treated with the same rigor as application source code.

Changes to infrastructure happen through standard code review processes. This brings the benefits of software engineering - traceability, rollback capabilities, and automated testing - to operations.

Mental Model

Think of IaC as an architectural blueprint combined with an automated construction crew. The blueprint describes the exact specifications of the building (the desired state). The automated crew compares the empty lot (or an existing building) to the blueprint, identifies the differences, and performs the exact labor required to match the blueprint.

A declarative approach focuses on this end state. The operator writes a file stating “three web servers must exist behind a load balancer.” The configuration management tool calculates the difference between the current state and the desired state. It then executes the exact commands needed to bridge that gap.

Imperative approaches, by contrast, specify the exact steps to reach the end state (“spin up server 1, spin up server 2, attach to load balancer”). Declarative models are far more common and robust for modern infrastructure because they handle pre-existing state more predictably.

Operational Pattern

The operational lifecycle of IaC relies on a continuous pipeline, often termed GitOps when applied to Kubernetes or modern cloud native environments.

  1. An operator commits a configuration file to a version control repository.
  2. A continuous integration server triggers on the commit and validates the syntax and internal logic (e.g., terraform validate or ansible-lint).
  3. An automated pipeline runs a planning phase to calculate changes against the live environment. This outputs a precise diff of what will be created, modified, or destroyed.
  4. The pipeline pauses for manual or automated approval based on policy (e.g., changes affecting databases require a human).
  5. The pipeline applies the changes to the target environment.
  6. The state file or central repository is updated to reflect the new actual state.
Commit -> Syntax Check -> Security Scan -> Plan/Diff -> Approve -> Apply -> Record State

Failure Modes

Out-of-Band Modifications

Manual changes break the declarative model. If an operator logs into the AWS console to manually open a security group port during an incident, the configuration tool detects a mismatch between its recorded state and the actual environment state on its next run. This creates configuration drift. The tool will aggressively revert the manual change to match the codebase, potentially causing a secondary incident if the out-of-band change was load-bearing.

State Corruption

Declarative tools require a state file to map abstract resources in the code to real-world identifiers (like AWS ARN or GCP resource IDs). Corruption or loss of this file causes the tool to lose track of existing resources. It then attempts to recreate them from scratch, causing massive disruption and resource duplication.

Blast Radius Miscalculation

Monolithic configuration repositories group all resources - networking, databases, and application servers - into a single execution context. A typo in a tagging rule might cause the tool to mistakenly mark a core database cluster for recreation, taking down the entire environment.

Security

Configuration files often require highly privileged access to cloud APIs. The pipeline executing these files must have highly restricted permissions. Running an IaC pipeline locally with developer credentials circumvents audit logs and violates the principle of least privilege.

Credentials must not exist in the code repository. Passwords, API keys, and TLS certificates must be injected at runtime using secure secret stores.

Scanning IaC code before execution prevents security misconfigurations. Tools analyze the code to block the provisioning of public S3 buckets or open SSH ports before the resources are actually created.

Operational Guidance

Keep modules small and logically separated. Split infrastructure by lifecycle and ownership. Core networking (VPCs, subnets) changes rarely and should be managed separately from application deployments, which change daily. This reduces the time it takes to plan and apply changes, and limits the blast radius of an error.

Store state files in remote backends that support locking (such as an AWS S3 bucket combined with a DynamoDB lock table). This prevents concurrent modifications from two pipelines or operators corrupting the state simultaneously.

Enforce idempotency. Running the exact same IaC script twice against the same environment should result in zero changes on the second run.

Diagnostics

When a deployment fails, check the plan output first. The tool usually indicates exactly which resource failed and why the cloud provider API rejected the request (e.g., hitting a quota limit, or a dependency failing to provision).

If the tool reports a state lock error, verify if another pipeline is currently running. Clear stale locks manually only if the previous process crashed without releasing them, and only after confirming the process is truly dead.

Track the time required to execute the pipeline. An IaC pipeline that takes an hour to run discourages operators from committing small, frequent changes, pushing them toward dangerous out-of-band modifications.

Related topics

Sources & further reading