Infrastructure as Code (IaC) is the practice of defining and provisioning infrastructure such as networks, virtual machines, Kubernetes clusters, databases and cloud services through machine-readable files kept in version control. Tools like Terraform, OpenTofu, Pulumi or AWS CloudFormation compare that definition with reality and apply the changes, making environments reproducible, reviewable and auditable.
What is Infrastructure as Code?
Infrastructure as Code (IaC) replaces clicking through cloud consoles and running ad-hoc scripts with code that describes the infrastructure you want. A VPC, a managed database, an IAM role or a Kubernetes cluster becomes a block of text in a Git repository. Changes go through the same workflow as application code: a pull request, a review, an automated plan that shows what will change, and an apply step in CI.
The benefits follow from that workflow. Environments can be recreated identically, staging and production stop diverging, every change has an author and a history, and repetitive manual provisioning, a classic form of toil, disappears. IaC is also a foundation of platform engineering, where internal platforms offer reusable modules instead of tickets.
Declarative vs. imperative IaC
There are two basic styles:
- Declarative: you describe the desired end state ("three subnets, one load balancer"), and the tool works out the steps. Terraform, OpenTofu, CloudFormation and Kubernetes manifests work this way. Running the same definition twice changes nothing the second time, which makes declarative IaC idempotent.
- Imperative: you describe the steps ("create subnet, then attach route table"). Shell scripts and cloud CLIs are imperative; configuration management tools such as Ansible are largely procedural, executing tasks in order.
Pulumi and the AWS CDK sit in between: you write general-purpose code with loops and functions, but the result is a declarative desired state that an engine reconciles.
Common Infrastructure as Code tools
| Tool | Language | Notes |
|---|---|---|
| Terraform | HCL | Multi-cloud via providers, state file, plan/apply; Business Source License since 2023 |
| OpenTofu | HCL | Open-source fork of Terraform under the Linux Foundation, MPL 2.0, largely compatible |
| Pulumi | TypeScript, Python, Go, C#, Java, YAML | Real programming languages, testing with standard frameworks |
| AWS CloudFormation | YAML or JSON | AWS-native, stacks with change sets and built-in drift detection; AWS CDK generates it |
| Azure Bicep / ARM | Bicep, JSON | Azure-native templates |
| Crossplane | Kubernetes resources | Cloud resources managed by Kubernetes controllers |
Example: a Terraform resource
resource "aws_sqs_queue" "orders_dlq" {
name = "orders-dlq"
message_retention_seconds = 1209600 # 14 days
tags = { team = "payments", env = "prod" }
}
Running terraform plan (or tofu plan) shows that one queue will be created. After review, apply creates it and records it in the state file. If someone later changes the retention in the console, the next plan reports the difference.
Drift detection
Drift is any difference between the code and what actually runs, caused by manual hotfixes, console changes or other automation. Drift undermines the main promise of IaC, because the repository no longer describes reality. Typical countermeasures: scheduled terraform plan -refresh-only or pulumi preview runs in CI that alert on differences, CloudFormation drift detection on stacks, restricting write access to production so that changes flow through the pipeline, and GitOps controllers that continuously reconcile Kubernetes resources.
Observability as code
The same principle applies to monitoring. Observability as code means that dashboards, alert rules, SLO definitions, synthetic checks and OpenTelemetry Collector configurations live in Git and are deployed through the pipeline. New services then get standard dashboards and alerts automatically, alert thresholds are reviewed like code, and a deleted dashboard can be restored from history. Tagging every resource consistently (service, team, environment) in IaC also pays off in observability, because the same tags become filterable attributes. A practical starting point is to keep Prometheus or OTel alert rules and Collector YAML in the same repository as the service, validated in CI before rollout, so a broken pipeline config never reaches production unreviewed.
Best practices and common mistakes
- Store state remotely and lock it; never commit state files, which can contain secrets.
- Use small, reusable modules with clear inputs instead of one huge configuration.
- Keep secrets out of code and reference a secrets manager.
- Review plans, not just diffs; a one-line change can replace a database.
- Avoid mixing manual and coded changes on the same resources.
- Prefer open formats to limit vendor lock-in in both infrastructure and telemetry.
How Obseria helps
Obseria offers an API and a CLI for managing configuration programmatically, and Automation lets you define workflows as code. Deployment events from your pipelines can be correlated with metrics, logs and traces, so an infrastructure change that degrades a service is visible next to its effect.