Infrastructure as Code (IaC)
Last reviewed: August 2026
Overview
Section titled “Overview”Creating infrastructure with console clicks is fast, but it’s not reproducible and change history can’t be tracked. Even if you automate with CLI scripts, the code has no way of knowing “what the current state actually is.” When the person in charge changes, no one knows why a server is configured the way it is.
IaC (Infrastructure as Code) defines the desired state of infrastructure as code, enabling version control, code review, automated deployment, and change tracking. It replaces the documents that used to describe server configuration on-premises with executable code.
| Approach | Problem | Solved by IaC |
|---|---|---|
| Console clicks | Not reproducible, no history, hard to trace mistakes | Code = documentation = an executable blueprint |
| CLI scripts | Current state unknown, no idempotency | Declarative: compares against current state and applies only the diff |
| Manual documentation | Docs and reality drift apart | Code is always the current state (single source of truth) |
Imperative vs Declarative
Section titled “Imperative vs Declarative”- Imperative — “Create this, delete that” executed in order. CLI scripts.
- Declarative — Defines “this is the final state.” The tool compares against the current state and applies only the difference. The IaC mainstream.
Product Comparison
Section titled “Product Comparison”Vendor-native IaC
Section titled “Vendor-native IaC”| Vendor | Product | Language/format | Notes |
|---|---|---|---|
| AWS | CloudFormation | YAML, JSON | AWS-only. Managed by stack |
| AWS | CDK (Cloud Development Kit) | TypeScript, Python, Java, Go, C# | Generates CloudFormation from a programming language |
| Azure | Bicep | Bicep DSL | A concise alternative to ARM Templates |
| Azure | ARM Templates | JSON | Azure-native. Complex but full-featured |
| Google Cloud | Infrastructure Manager / Config Connector | HCL (Terraform) / K8s YAML | Managed Terraform service (successor to the discontinued Deployment Manager) and K8s-based management |
| OCI | OCI Resource Manager | HCL (Terraform) | Terraform-based. OCI-native managed offering |
Multicloud IaC
Section titled “Multicloud IaC”| Product | Language | Notes |
|---|---|---|
| Terraform / OpenTofu | HCL (HashiCorp Configuration Language) | Most widely used. Supports every vendor. Terraform 1.15 / OpenTofu 1.13 (as of 2026) |
| Pulumi | TypeScript, Python, Go, C#, Java | Uses general-purpose programming languages. Easy to test. Pulumi Neo (agentic infrastructure) launched |
| Crossplane | Kubernetes YAML | Manages cloud resources from a K8s cluster |
Unified Resource Management API
Section titled “Unified Resource Management API”For an IaC tool to manage resources, it must call each service’s individual API. AWS has standardized this into a single API.
| Vendor | Product | Notes |
|---|---|---|
| AWS | Cloud Control API | Manages all AWS + 3rd-party resources through a single CRUD-L API. Used as a backend by IaC tools like Terraform |
| Azure | Azure Resource Manager (ARM) REST API | Controls every Azure resource through a single management layer. Can be called directly via the AzAPI Terraform provider |
| Google Cloud | Infrastructure Manager API / individual APIs | Managed Terraform execution API and Config Connector (K8s API) |
| OCI | OCI Resource Manager API | Terraform state management + resource provisioning API |
Because Terraform can use Cloud Control API as the backend for new AWS resources instead of an individual service API, IaC support for newly released services arrives faster.
Key Differences
Section titled “Key Differences”AWS CloudFormation / CDK — Integrates fastest with AWS services. CloudFormation support is typically the first to arrive when a new service launches. CDK can leverage a programming language’s conditionals, loops, and abstractions, making it advantageous for managing large-scale infrastructure. CDK Mixins GA (Mar 2026) makes composing reusable infrastructure patterns easier. CDK v2 remains current, with the Construct Library and CLI split into separate packages.
Azure Bicep — Replaces the complex JSON of ARM Templates with a concise DSL. The VS Code extension provides autocomplete and validation.
Terraform — The de facto standard in multicloud environments. A single language (HCL) can manage AWS, Azure, and Google Cloud all at once. Requires state file management. The latest stable version is 1.15, adding dynamic module sources (variables in source/version fields), a formal variable/output deprecation mechanism, inline type conversion functions, and Windows ARM64 support.
OpenTofu — An MPL-2.0 open-source fork of Terraform and CNCF Sandbox project (joined Apr 2025). The latest stable version is 1.13. It independently develops differentiating features such as state file encryption, early variable evaluation, and ephemeral values, while maintaining high compatibility with Terraform HCL.
OCI Resource Manager — A Terraform-based managed IaC service that lets you operate state file management and resource provisioning together from the OCI console.
Terraform State Management
Section titled “Terraform State Management”Terraform stores the current infrastructure state in a terraform.tfstate file. This file serves the following roles:
- Resource mapping — Links resources in code to actual cloud resource IDs
- Dependency tracking — Determines which resources to process first/last on a change
- Performance optimization — Uses cached state instead of querying every resource each time
Local vs Remote Backend
Section titled “Local vs Remote Backend”| Approach | Advantages | Disadvantages |
|---|---|---|
| Local state | Simple to configure | No team collaboration, risk of file loss, secrets stored as plaintext |
| Remote backend | Team collaboration, locking, encryption, version control | Requires initial setup |
Remote Backend Options
Section titled “Remote Backend Options”| Backend | Use case |
|---|---|
| S3 + DynamoDB | AWS environment. S3 stores state, DynamoDB provides concurrent-execution locking |
| Azure Storage | Azure environment. Blob Storage + Lease-based locking |
| GCS | Google Cloud environment. Object versioning tracks history |
| OCI Resource Manager | OCI-managed backend. Manages state and execution together within OCI |
| Terraform Cloud / HCP Terraform | Multicloud. Integrated UI, policy, and team management |
Module Design Best Practices
Section titled “Module Design Best Practices”A Terraform module is a reusable unit of infrastructure.
Hierarchical Structure
Section titled “Hierarchical Structure”environments/├── dev/│ └── main.tf # module calls├── staging/│ └── main.tf└── prod/ └── main.tf
modules/├── vpc/ # general-purpose VPC module├── eks-cluster/ # EKS cluster module└── rds-instance/ # RDS moduleBest Practices
Section titled “Best Practices”- Break things down small — If one module manages too many resources, reuse becomes difficult
- Use input variables for flexibility — Avoid hardcoding; expose values through
variables.tf - Declare dependencies via outputs — So other modules can reference them
- Pin versions — Pin to a Git tag or a Terraform Registry version
- Be careful with defaults — Avoid defaults unsuitable for production (e.g.,
deletion_protection = false)
Drift Management
Section titled “Drift Management”If a resource is changed manually outside of IaC, the code and the actual state fall out of sync (drift).
| Vendor | Drift detection tool |
|---|---|
| AWS | CloudFormation Drift Detection, Config Rules |
| Azure | Policy, Blueprints Compliance |
| Google Cloud | Config Connector (auto-corrects drift using the K8s model) |
| OCI | Resource Manager Drift Detection |
| Terraform | terraform plan (compares current state against code) |
To fundamentally prevent drift, restrict manual changes from the console using SCP/Azure Policy/Organization Policy, and enforce that all changes go through the IaC pipeline only. For security validation of the IaC code itself (Checkov, tfsec, etc.), see DevSecOps.
Common Mistakes
Section titled “Common Mistakes”- Modifying directly in the console and leaving drift unaddressed — Manually changing a resource in the console causes the code and actual state to diverge (drift). Leaving this unaddressed causes unexpected changes at the next
apply. - Storing the state file locally — Storing
terraform.tfstatelocally makes team collaboration impossible, and losing the file makes infrastructure management impossible. - Copy-pasting instead of modularizing — Copying the same code across multiple environments means every location must be manually updated on a change, causing inconsistency.
- Running IaC under a user account on Azure — Starting October 2025, MFA is enforced for the Azure CLI/PowerShell/ARM API. If the CI/CD pipeline doesn’t use
az login --identity(Managed Identity) or a service principal + Federated Credential, it will break. See IAM — Azure MFA Enforcement for details.
Checklist
Section titled “Checklist”- Are you using a remote state store (S3+DynamoDB, Azure Storage, GCS, etc.)?
- Do you perform drift detection regularly (
terraform plan, Config Rules, etc.)? - Is common infrastructure separated into reusable modules?
- Is there a process to review
planresults during code review?