Immutable Infrastructure and Configuration Drift Prevention

Immutable infrastructure is a paradigm where servers are never modified after deployment. Instead of patching existing systems, you replace them entirely with new instances built from a common image. This approach eliminates configuration drift and improves reliability.

Benefits of Immutable Infrastructure

  • Consistency: Every deployment is identical
  • Reliability: No configuration drift over time
  • Rollback: Easy to revert to previous versions
  • Security: Reduced attack surface, no manual changes
  • Auditability: Complete history in version control

Building Immutable AMIs with Packer

# packer.pkr.hcl
packer {
  required_plugins {
    amazon = {
      version = ">= 1.0.0"
      source  = "github.com/hashicorp/amazon"
    }
  }
}

source "amazon-ebs" "app" {
  ami_name      = "app-{{timestamp}}"
  instance_type = "t3.medium"
  region        = "us-east-1"
  
  source_ami_filter {
    filters = {
      name                = "amzn2-ami-hvm-*-x86_64-gp2"
      root-device-type    = "ebs"
      virtualization-type = "hvm"
    }
    owners      = ["amazon"]
    most_recent = true
  }
  
  ssh_username = "ec2-user"
  
  tags = {
    Name        = "app-server"
    Environment = "production"
    BuildTime   = "{{timestamp}}"
  }
}

build {
  sources = ["source.amazon-ebs.app"]
  
  provisioner "shell" {
    scripts = [
      "scripts/install-dependencies.sh",
      "scripts/configure-app.sh",
      "scripts/harden-os.sh"
    ]
  }
  
  provisioner "file" {
    source      = "configs/"
    destination = "/etc/app/"
  }
  
  post-processor "manifest" {
    output = "manifest.json"
  }
}

Blue-Green Deployment

# Terraform - Blue-Green with ASG
resource "aws_autoscaling_group" "blue" {
  name                = "app-blue"
  desired_capacity    = var.blue_active ? var.desired_capacity : 0
  max_size            = var.max_size
  min_size            = var.blue_active ? var.min_size : 0
  target_group_arns   = [aws_lb_target_group.app.arn]
  vpc_zone_identifier = var.subnet_ids
  
  launch_template {
    id      = aws_launch_template.blue.id
    version = "$Latest"
  }
  
  instance_refresh {
    strategy = "Rolling"
    preferences {
      min_healthy_percentage = 90
    }
  }
}

resource "aws_autoscaling_group" "green" {
  name                = "app-green"
  desired_capacity    = var.blue_active ? 0 : var.desired_capacity
  max_size            = var.max_size
  min_size            = var.blue_active ? 0 : var.min_size
  target_group_arns   = [aws_lb_target_group.app.arn]
  vpc_zone_identifier = var.subnet_ids
  
  launch_template {
    id      = aws_launch_template.green.id
    version = "$Latest"
  }
}

Drift Detection with AWS Config

# Terraform - Drift detection rule
resource "aws_config_config_rule" "ec2_managed_instance" {
  name = "ec2-managedinstance-inventory-blacklisted"

  source {
    owner             = "AWS"
    source_identifier = "EC2_MANAGEDINSTANCE_INVENTORY_BLACKLISTED"
  }

  input_parameters = jsonencode({
    inventoryNames = "AWS:Application"
  })
}

# CloudWatch alarm for drift
resource "aws_cloudwatch_metric_alarm" "config_drift" {
  alarm_name          = "config-drift-detected"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 1
  metric_name         = "NonCompliantResourceCount"
  namespace           = "AWS/Config"
  period              = 300
  statistic           = "Average"
  threshold           = 0
  alarm_actions       = [aws_sns_topic.alerts.arn]
}

Container-Based Immutability

# Dockerfile with immutable best practices
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt

FROM python:3.11-slim
WORKDIR /app

# Create non-root user
RUN useradd -r -s /bin/false appuser

# Copy dependencies
COPY --from=builder /root/.local /home/appuser/.local
COPY --chown=appuser:appuser . .

# Make filesystem read-only where possible
RUN chmod -R 555 /app

USER appuser
ENV PATH=/home/appuser/.local/bin:$PATH

CMD ["python", "app.py"]

CI/CD Pipeline

# GitHub Actions - Immutable deployment
name: Deploy
on:
  push:
    branches: [main]

jobs:
  build-ami:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Build AMI
        run: packer build packer.pkr.hcl
        
      - name: Update Terraform
        run: |
          AMI_ID=$(jq -r '.builds[0].artifact_id' manifest.json | cut -d: -f2)
          sed -i "s/ami-[a-z0-9]*/\$AMI_ID/" terraform/variables.tf
          
      - name: Deploy
        run: |
          cd terraform
          terraform apply -auto-approve

Conclusion

Immutable infrastructure eliminates configuration drift and improves system reliability. By combining tools like Packer for image building, Terraform for deployment, and AWS Config for drift detection, teams can achieve truly immutable deployments.