Table of Contents
Why Infrastructure as Code Matters
Infrastructure as Code (IaC) means defining and managing your servers, networks, and services using machine-readable files instead of manual clicks in a web console.
At a high level, IaC gives you:
- Repeatability – The same config file produces the same infrastructure every time.
- Version control – Your infrastructure changes can be tracked, reviewed, and rolled back in Git.
- Automation – Provisioning is done by tools, not by humans following docs.
- Consistency across environments – Dev, test, and prod are built from the same definitions.
- Documentation by design – The code is the documentation of your infrastructure.
IaC is a foundational DevOps practice; many CI/CD pipelines assume that infrastructure is provisioned and updated automatically using IaC tools.
Declarative vs Imperative IaC
IaC tools usually follow one of two models:
- Declarative (desired state)
You describe what you want, and the tool figures out how to make it so. - Example (simplified Terraform-style):
resource "aws_instance" "web" {
ami = "ami-123456"
instance_type = "t3.micro"
}- You don’t specify the low-level API calls; you just declare the resources.
- Imperative (procedural)
You specify how to reach the desired state, step by step. - Example (pseudo-Ansible task sequence):
- name: Create subnet
...
- name: Create instance in subnet
...Many tools blend both styles, but:
- Provisioning tools (Terraform, Pulumi, CloudFormation) are mostly declarative.
- Configuration management tools (Ansible, Puppet, Chef) can be declarative but often feel more imperative because you write ordered tasks.
For infrastructure provisioning (VMs, networks, load balancers, managed services), the declarative model is more common and easier to reason about at scale.
Core Concepts in Infrastructure as Code
Regardless of tool, you’ll see similar concepts:
Resources
A resource is a unit of infrastructure defined in code, such as:
- Virtual machines, containers, serverless functions
- Networks, subnets, security groups, firewalls
- Load balancers, DNS records
- Databases, queues, storage buckets
Each resource has:
- A type (e.g.,
aws_instance,azurerm_storage_account) - A name (logical, used inside the code)
- A set of arguments or properties (e.g., size, region, tags)
Providers and Modules (High-Level Idea)
You’ll see these terms frequently:
- Provider – A plugin or integration that knows how to talk to an external API (cloud providers, SaaS, etc.).
- Module – A reusable collection of IaC definitions packaged together (for common patterns like “VPC + subnets + NAT” or “3-tier web app”).
This course has a separate chapter that dives into “Providers and resources” and “Modules”; here you only need to recognize that IaC is organized into building blocks and reusable components.
State
Many IaC tools keep track of state:
- The state file records what infrastructure currently exists and how it maps to your config.
- Allows the tool to:
- Detect what changed in your files.
- Compute an execution plan (what to create, modify, destroy).
- Avoid recreating everything from scratch.
Losing or corrupting state can be dangerous (the tool might try to recreate or destroy the wrong resources), so:
- Store state remotely and securely (e.g., S3 + lock, or the tool’s managed backend).
- Control access (only CI pipeline and a few admins).
- Back it up.
You’ll see concrete Terraform examples of this in the dedicated chapter.
Idempotency and Drift
Two important properties of well-designed IaC:
Idempotency
An IaC run should be idempotent:
- Applying the same configuration multiple times should lead to the same infrastructure state.
- Running
applyagain when nothing changed should have no effect.
This prevents “configuration snowballs” and makes your automation safe to run repeatedly (e.g., as part of CI).
Configuration Drift
Drift happens when the real infrastructure no longer matches the IaC definitions, typically because:
- Someone changed something manually in the cloud console.
- Another automation tool altered resources.
Drift causes:
- Surprises during deployments.
- Environments that are no longer consistent.
- Difficulty troubleshooting issues.
Controlling drift:
- Limit or disable manual console changes.
- Schedule regular plan or diff runs to detect drift.
- Use policies (e.g., “only changes via Git and CI”).
GitOps and IaC
IaC integrates naturally with GitOps practices:
- Infrastructure config is kept in Git repositories.
- Changes happen via pull/merge requests:
- Code review.
- Automated tests.
- Approval workflows.
- CI/CD pipelines:
- Run formatting and static checks.
- Run “plan” steps and attach the plan to the PR.
- Apply changes to environments when PRs are merged.
Benefits:
- Full change history and accountability.
- Easy rollback (revert a commit and re-apply).
- Clear review process for infrastructure changes, just like application code.
IaC vs Configuration Management
IaC usually refers to defining cloud/platform resources, but there is an overlap with configuration management tools that manage OS-level configuration.
Typical division of responsibilities:
- Infrastructure as Code tools (e.g., Terraform, CloudFormation, Pulumi):
- Create and change cloud resources: VMs, managed DBs, networks, DNS, load balancers, queues, etc.
- Integrate with many providers (clouds, SaaS, on-prem APIs).
- Configuration management tools (e.g., Ansible, Puppet, Chef):
- Configure inside the resources:
- Install packages.
- Configure services.
- Manage files and templates.
- Often used after resources are provisioned.
Hybrid patterns:
- Terraform provisions a VM and its networking.
- A configuration management tool configures the OS and applications on that VM.
- Some platforms (Kubernetes) blur the line: cluster resources (Deployments, Services) are declared as YAML and treated as IaC, while containers themselves might be configured by other tools.
Environments and Reuse
A common requirement is managing multiple environments (dev, staging, prod) with IaC while avoiding copy-paste.
Strategies include:
- Separate configs with shared modules:
- Put reusable logic in modules.
- Define thin environment-specific configs that call those modules with different parameters (e.g., different sizes or regions).
- Variables and parameterization:
- Use variables for values that differ by environment (e.g., instance counts, domain names).
- Keep common defaults and override where needed.
- Separate state per environment:
- Each environment should have its own state backend and credentials.
- Reduces the risk of accidentally affecting production.
These concepts generalize across IaC tools even though the details differ (naming, file layout, CLI commands).
Testing and Validating IaC
Treat IaC like application code:
- Syntax/formatting checks:
- Many tools provide
fmtandvalidatecommands to enforce formatting and catch obvious errors. - Static analysis:
- Linters and policy-as-code tools can enforce:
- Security rules (e.g., no open SSH to the internet).
- Compliance (e.g., encryption required on databases).
- Examples include tools that integrate into CI to fail builds when policies are violated.
- Unit and integration tests:
- Unit-like tests: Ensure modules behave as expected with given inputs.
- Integration tests: Deploy to a test environment and verify:
- Ports are open/closed correctly.
- Applications are reachable.
- Resources are tagged correctly.
Testing helps prevent misconfigurations that could cause outages, security gaps, or unexpected costs.
Cost and Security Considerations
Because IaC can create a lot of infrastructure quickly, you must consider:
Cost Control
- Use IaC to:
- Enforce tags/labels for cost tracking.
- Standardize instance sizes and regions.
- Spin up full test environments only when needed and tear them down automatically.
- Review changes that add expensive resources as part of code review.
Security
- Store secrets outside of the IaC files (e.g., in secret managers, encrypted variables).
- Lock down:
- State storage (it can contain sensitive information).
- CI credentials used to apply changes.
- Use policy-as-code to prevent insecure patterns:
- Public S3 buckets.
- Security groups open to the world.
- Unencrypted databases or volumes.
Typical IaC Workflow
A minimal, tool-agnostic workflow looks like:
- Edit infrastructure definitions in files (
.tf,.yaml, etc.). - Format and validate:
- Run the tool’s
fmtandvalidateor equivalent. - Plan / diff:
- Preview changes: see what will be created, updated, or destroyed.
- Review:
- Use a pull/merge request.
- Teammates review the code and the plan.
- Apply:
- CI/CD (or a controlled environment) applies the changes.
- Monitor:
- Verify that the infrastructure behaves as expected.
- Watch logs, metrics, and drift detection.
This workflow is the foundation you’ll refine as you move into specific tools and more advanced patterns.
Where to Go Next in This Course
In the following chapters, you’ll see this theory put into practice:
- Terraform fundamentals – A concrete, widely used IaC tool.
- Providers and resources – How Terraform integrates with clouds and services.
- Modules – Structuring IaC for reuse and multiple environments.
- Cloud provisioning with Terraform – Real-world examples of building Linux-based infrastructure on cloud platforms.
Understanding the general principles in this chapter will make those tool-specific topics easier to follow and apply.