Infrastructure as Code: Fundamentals

Infrastructure & Cloud

Table of Contents

  1. What is Infrastructure as Code
  2. Why IaC Matters
  3. Core IaC Concepts
  4. IaC Approaches
  5. Security Considerations for IaC
  6. Getting Started

What is Infrastructure as Code

Infrastructure as Code (IaC) is the practice of managing and provisioning infrastructure through machine-readable definition files rather than manual processes or interactive configuration tools.

Core Definition

IaC treats infrastructure configuration as software code that can be:

  • Version controlled
  • Reviewed and tested
  • Automatically deployed
  • Repeatedly applied with consistent results
  • Shared and reused across teams

What IaC Manages

Compute Resources:

  • Virtual machines
  • Containers
  • Serverless functions
  • Auto-scaling groups

Networking:

  • Virtual networks and subnets
  • Load balancers
  • DNS records
  • Firewalls and security groups
  • VPNs and network gateways

Storage:

  • Block storage volumes
  • Object storage buckets
  • File systems
  • Databases

Identity and Access:

  • IAM roles and policies
  • Service accounts
  • API keys
  • Security credentials

Application Services:

  • Message queues
  • Caching layers
  • CDN configurations
  • Monitoring and logging

Traditional vs. IaC Approach

Aspect Traditional (Manual) Infrastructure as Code
Provisioning Point-and-click in console Code execution
Documentation Separate documents (often outdated) Code is documentation
Consistency Manual steps = human error Automated = consistent
Speed Hours to days Minutes
Scalability Manual replication Automated replication
Version Control Limited or none Full git history
Disaster Recovery Manual rebuild from docs Automated rebuild from code
Testing Manual verification Automated testing

Why IaC Matters

Speed and Efficiency

Faster Provisioning:

  • Deploy complete environments in minutes, not hours
  • Automate repetitive infrastructure tasks
  • Reduce time from request to deployment

Parallel Execution:

  • Provision multiple resources simultaneously
  • Scale infrastructure quickly
  • Handle traffic spikes automatically

Consistency and Reliability

Eliminate Configuration Drift:

  • Infrastructure matches code definition
  • Detect and correct drift automatically
  • Prevent “snowflake” servers with unique configurations

Repeatable Deployments:

  • Same code produces identical infrastructure
  • Reduce environment-specific bugs
  • Predictable outcomes

Risk Reduction

Testing Before Production:

  • Test infrastructure changes in staging
  • Validate configurations before applying
  • Preview changes before execution

Quick Recovery:

  • Rebuild infrastructure from code
  • Disaster recovery becomes deployment
  • Reduce MTTR (Mean Time To Recovery)

Rollback Capability:

  • Version control enables rollback
  • Revert to known-good configurations
  • Minimize downtime from bad changes

Cost Optimization

Resource Lifecycle Management:

  • Automatically tear down unused environments
  • Schedule resources (dev environments off at night)
  • Right-size infrastructure based on metrics

Visibility:

  • Track infrastructure costs in code
  • Review infrastructure changes like code reviews
  • Identify cost optimization opportunities

Collaboration and Knowledge Sharing

Code Review Process:

  • Infrastructure changes reviewed like code
  • Knowledge sharing through pull requests
  • Documented decisions in commit history

Standardization:

  • Reusable modules and templates
  • Organization-wide best practices
  • Reduced learning curve

Transparency:

  • Clear visibility into infrastructure
  • Self-service for developers
  • Reduced dependency on ops team

Core IaC Concepts

Declarative vs. Imperative

Declarative (What): Describe the desired end state; the tool figures out how to achieve it.

# Terraform example - Declarative
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  count         = 3
}

Characteristics:

  • Define desired state
  • Tool determines steps to reach that state
  • Idempotent by nature
  • Easier to reason about

Tools: Terraform, CloudFormation, Pulumi (declarative mode)

Imperative (How): Specify the exact steps to execute to achieve the desired state.

# Imperative approach
for i in range(3):
    create_ec2_instance(
        ami="ami-0c55b159cbfafe1f0",
        instance_type="t2.micro"
    )

Characteristics:

  • Define specific actions
  • Explicit control over execution
  • Must handle state checking manually
  • More flexible but more complex

Tools: Ansible (can be declarative), scripts, SDKs

Idempotency

Definition: Running the same IaC code multiple times produces the same result without unintended side effects.

Why it matters:

  • Safe to re-run deployments
  • Automatic drift correction
  • Simplified automation
  • Predictable outcomes

Example:

# First run: Creates 3 instances
# Second run: No changes (3 instances already exist)
# Third run: Still no changes
resource "aws_instance" "web" {
  count = 3
  # ...
}

Achieving idempotency:

  • Check current state before acting
  • Use unique identifiers
  • Avoid hardcoded values that change
  • Design for re-execution

Immutability

Immutable Infrastructure: Rather than updating existing resources, replace them with new versions.

Benefits:

  • Prevents configuration drift
  • Easier rollback (keep old version)
  • Simplified testing (test exact deployment artifact)
  • Reduced debugging complexity

Mutable vs. Immutable:

Approach Update Process Pros Cons
Mutable Modify existing resources Faster updates Configuration drift, harder to reproduce
Immutable Replace with new resources Consistent, reproducible Longer deployment, more complex

Implementation:

  • Blue-green deployments
  • Canary deployments
  • Container-based deployments
  • AMI/image-based deployments

IaC Approaches

Declarative Approach

Philosophy: Describe what you want, not how to get there.

How it works:

  1. Define desired state in configuration files
  2. Tool compares desired state to current state
  3. Tool calculates and executes necessary changes

Advantages:

  • Simpler to understand (what, not how)
  • Automatically idempotent
  • Easier to maintain
  • Tool handles complexity

Disadvantages:

  • Less control over execution order (sometimes)
  • Abstraction can hide underlying operations
  • Learning curve for tool-specific syntax

Best for:

  • Cloud infrastructure provisioning
  • Consistent, repeatable deployments
  • Teams preferring simplicity
  • Complex state management

Imperative Approach

Philosophy: Define exact steps to execute.

How it works:

  1. Write scripts/code with specific actions
  2. Execute actions in defined order
  3. Handle state checking and updates manually

Advantages:

  • Full control over execution
  • Use familiar programming languages
  • Fine-grained error handling
  • Flexibility for complex scenarios

Disadvantages:

  • Must implement idempotency manually
  • More code to write and maintain
  • Higher risk of errors
  • State management complexity

Best for:

  • Complex orchestration workflows
  • Migration tasks
  • Custom automation
  • When declarative tools don’t fit

Hybrid Approach

Philosophy: Combine declarative and imperative as needed.

How it works:

  • Use declarative tools for infrastructure provisioning
  • Use imperative scripts for configuration management
  • Orchestrate with higher-level tools

Example:

# Terraform for infrastructure (declarative)
# Ansible for configuration (imperative playbooks)
# CI/CD pipeline orchestrates both

Advantages:

  • Best of both worlds
  • Right tool for each job
  • Flexibility where needed

Disadvantages:

  • Multiple tools to learn
  • Integration complexity
  • Potential consistency issues

Security Considerations for IaC

Never Commit Secrets to Code

The problem: IaC templates often need credentials, API keys, and passwords. Hardcoding these in files that go into version control is a critical security risk.

Terraform example:

# ❌ NEVER do this
resource "aws_db_instance" "db" {
  password = "MyPassword123!"  # Committed to git = exposed
}

# ✅ Use variables marked as sensitive
variable "db_password" {
  type      = string
  sensitive = true
}

resource "aws_db_instance" "db" {
  password = var.db_password
}

CloudFormation example:

# ✅ Reference secrets from AWS Secrets Manager
Resources:
  Database:
    Type: AWS::RDS::DBInstance
    Properties:
      MasterUserPassword: !Sub '{{resolve:secretsmanager:${DBSecret}:SecretString:password}}'

Use Secret Management Services

Don’t pass secrets as plain text - retrieve them from secure stores:

State Files Contain Secrets

Critical: IaC state files (like Terraform’s terraform.tfstate) contain the actual values of all resources, including secrets.

Protect state files:

  • Always use remote state with encryption (covered in IaC State Management)
  • Restrict access to state storage (S3 bucket policies, IAM roles)
  • Never commit state files to version control

Scan IaC Before Applying

Static analysis tools catch security issues before deployment:

  • Checkov: Multi-framework scanner (Terraform, CloudFormation, Kubernetes)
  • tfsec: Terraform-focused security scanner
  • cfn-lint: CloudFormation linter with security checks
  • Terrascan: Policy-as-code scanner

Run security scans before deployment and integrate them into your CI/CD pipeline to automatically fail builds with security issues.


Getting Started

Choosing Your First IaC Tool

For AWS-only projects:

For multi-cloud or flexibility:

  • Start with Terraform (most popular, broad ecosystem, declarative)

For developers who prefer code:

  • AWS CDK (AWS-focused, TypeScript/Python/Java/C#/.NET, generates CloudFormation)
  • Pulumi (multi-cloud, TypeScript/Python/Go/C#/Java, own state management)

For configuration management:

  • Start with Ansible (agentless, easy to learn, YAML-based)

Learning Path

1. Start Small

  • Deploy a single resource (S3 bucket, EC2 instance)
  • Understand the workflow: write configuration, preview changes, apply
  • Practice with non-production resources

2. Add Complexity Gradually

  • Multiple resources with dependencies
  • Variables and outputs
  • Modules and reusable components

3. Implement Best Practices

4. Production Readiness

  • Security scanning integration
  • Multi-environment management
  • CI/CD pipeline integration
  • Disaster recovery procedures

Found this guide helpful? Share it with your team:

Share on LinkedIn