DevOps & Cloud Topic
DevOps Infrastructure as Code (IaC)
What is Infrastructure as Code?
Infrastructure as Code (IaC) is the practice of managing and provisioning computing infrastructure through machine-readable definition files, rather than physical hardware configuration or interactive configuration tools.
Core Principles of IaC:
-
Declarative vs Imperative approaches
-
Idempotency - same result regardless of how many times applied
-
Version Control - infrastructure definitions in Git
-
Automation - eliminate manual processes
-
Reproducibility - consistent environments
Terraform Fundamentals
1. Core Concepts & Architecture
How Terraform Works:
text
Terraform Configuration (.tf files)
↓
Terraform Core (Planning & Execution)
↓
Provider Plugins (AWS, Azure, GCP, etc.)
↓
Cloud APIs
Key Components:
-
Configuration Files (.tf, .tfvars)
-
State Files (.tfstate) - current state of infrastructure
-
Providers - plugins that interact with APIs
-
Resources - infrastructure components
-
Data Sources - read-only information about existing infrastructure
2. Basic Terraform Syntax
Main Configuration Blocks:
hcl
# Provider Configuration
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
# Provider Block
provider "aws" {
region = "us-east-1"
}
# Resource Block
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = {
Name = "main-vpc"
}
}
# Data Source
data "aws_availability_zones" "available" {
state = "available"
}
# Output Values
output "vpc_id" {
value = aws_vpc.main.id
}
# Variable Definitions
variable "environment" {
description = "Deployment environment"
type = string
default = "dev"
}
3. Terraform Workflow
Standard Commands:
bash
# Initialize Terraform
terraform init
# Validate configuration
terraform validate
# Plan changes
terraform plan -out=tfplan
# Apply changes
terraform apply tfplan
# Destroy infrastructure
terraform destroy
Advanced Workflow:
bash
# Format code
terraform fmt
# Security scanning
terraform tfsec
# Cost estimation
terraform plan -out=tfplan && terraform show -json tfplan | infracost breakdown --path=-
Pulumi Fundamentals
1. Pulumi vs Terraform Approach
Key Differences:
-
Programming Languages: TypeScript, Python, Go, C#, Java vs HCL
-
State Management: Similar concepts but different implementation
-
Abstraction Level: Higher-level abstractions available
2. Basic Pulumi Syntax
TypeScript Example:
typescript
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// Create an AWS resource (S3 Bucket)
const bucket = new aws.s3.Bucket("my-bucket", {
website: {
indexDocument: "index.html",
},
tags: {
Environment: "Dev",
},
});
// Export the bucket name
export const bucketName = bucket.id;
export const bucketEndpoint = pulumi.interpolate`http://${bucket.websiteEndpoint}`;
Python Example:
python
import pulumi
import pulumi_aws as aws
# Create a VPC
vpc = aws.ec2.Vpc("main-vpc",
cidr_block="10.0.0.0/16",
enable_dns_hostnames=True,
tags={
"Name": "main-vpc"
}
)
# Export the VPC ID
pulumi.export("vpc_id", vpc.id)
3. Pulumi Architecture
text
Pulumi Program (TypeScript/Python/Go)
↓
Pulumi CLI
↓
Language Host (Node.js/Python/Go)
↓
Resource Providers
↓
Cloud APIs
Pulumi State Backends:
-
Pulumi Service (cloud-based)
-
Self-hosted (S3, Azure Blob, Google Cloud Storage)
-
Local (file-based)
Modules & Reusability
1. Terraform Modules
Module Structure:
text
modules/vpc/ ├── main.tf ├── variables.tf ├── outputs.tf └── README.md
Creating a Reusable VPC Module:
hcl
# modules/vpc/variables.tf
variable "vpc_name" {
description = "Name of the VPC"
type = string
}
variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
default = "10.0.0.0/16"
}
variable "availability_zones" {
description = "List of availability zones"
type = list(string)
}
# modules/vpc/main.tf
resource "aws_vpc" "this" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
tags = {
Name = var.vpc_name
}
}
resource "aws_subnet" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.this.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = var.availability_zones[count.index]
tags = {
Name = "${var.vpc_name}-private-${count.index}"
}
}
# modules/vpc/outputs.tf
output "vpc_id" {
value = aws_vpc.this.id
}
output "private_subnet_ids" {
value = aws_subnet.private[*].id
}
Using the Module:
hcl
# root module
module "network" {
source = "./modules/vpc"
vpc_name = "production"
vpc_cidr = "10.1.0.0/16"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
# Reference module outputs
resource "aws_instance" "web" {
subnet_id = module.network.private_subnet_ids[0]
# ... other configuration
}
2. Pulumi Components
Creating Reusable Components:
typescript
// components/WebService.ts
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
export interface WebServiceArgs {
vpcId: pulumi.Input<string>;
subnetIds: pulumi.Input<string>[];
instanceType?: pulumi.Input<string>;
minSize?: pulumi.Input<number>;
maxSize?: pulumi.Input<number>;
}
export class WebService extends pulumi.ComponentResource {
public readonly loadBalancerDns: pulumi.Output<string>;
constructor(name: string, args: WebServiceArgs, opts?: pulumi.ComponentResourceOptions) {
super("custom:app:WebService", name, {}, opts);
// Create security group
const webSg = new aws.ec2.SecurityGroup(`${name}-sg`, {
vpcId: args.vpcId,
ingress: [{
protocol: "tcp",
fromPort: 80,
toPort: 80,
cidrBlocks: ["0.0.0.0/0"],
}],
}, { parent: this });
// Create launch template
const launchTemplate = new aws.ec2.LaunchTemplate(`${name}-lt`, {
imageId: "ami-0c02fb55956c7d316",
instanceType: args.instanceType || "t3.micro",
vpcSecurityGroupIds: [webSg.id],
userData: `#!/bin/bash
echo "Hello, World!" > index.html
nohup python -m SimpleHTTPServer 80 &`,
}, { parent: this });
// Create auto scaling group
const asg = new aws.autoscaling.Group(`${name}-asg`, {
launchTemplate: {
id: launchTemplate.id,
version: "$Latest",
},
vpcZoneIdentifiers: args.subnetIds,
minSize: args.minSize || 1,
maxSize: args.maxSize || 3,
targetGroupArns: [targetGroup.arn],
}, { parent: this });
this.loadBalancerDns = alb.dnsName;
this.registerOutputs({
loadBalancerDns: this.loadBalancerDns
});
}
}
Using the Component:
typescript
// index.ts
import { WebService } from "./components/WebService";
const webService = new WebService("app", {
vpcId: vpc.id,
subnetIds: privateSubnets.map(s => s.id),
instanceType: "t3.small",
minSize: 2,
maxSize: 5
});
export const url = webService.loadBalancerDns;
Remote State Management
1. Terraform Remote State
Backend Configuration:
hcl
# terraform.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "production/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
State Locking with DynamoDB:
hcl
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
tags = {
Name = "Terraform Lock Table"
}
}
Workspaces for Environment Isolation:
bash
# Create workspaces
terraform workspace new dev
terraform workspace new staging
terraform workspace new production
# Switch between workspaces
terraform workspace select dev
2. Pulumi State Management
Stack Configuration:
yaml
# Pulumi.dev.yaml
config:
aws:region: us-east-1
my-project:environment: dev
my-project:instanceCount: 2
# Pulumi.prod.yaml
config:
aws:region: us-east-1
my-project:environment: production
my-project:instanceCount: 5
Using Stacks:
typescript
// Get stack-specific configuration
const config = new pulumi.Config();
const environment = config.require("environment");
const instanceCount = config.getNumber("instanceCount") || 1;
Policy as Code
1. Terraform - Sentinel & OPA
Sentinel Policies:
python
# Enforce tagging policy
import "tfplan"
main = rule {
all tfplan.resources as _, instances {
all instances as index, r {
all r.applied.tags as _ {
r.applied.tags contains "Environment"
}
}
}
}
# Cost control policy
import "tfplan"
import "decimal"
allowed_instance_types = ["t3.micro", "t3.small", "t3.medium"]
main = rule {
all tfplan.resources.aws_instance as _, instances {
all instances as _, r {
r.applied.instance_type in allowed_instance_types
}
}
}
Open Policy Agent (OPA) with Terraform:
rego
# policies/terraform.rego
package terraform
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_instance"
instance_type := resource.change.after.instance_type
not startswith(instance_type, "t3.")
msg := sprintf("Instance type %v not allowed. Use t3 series.", [instance_type])
}
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_db_instance"
resource.change.after.allocated_storage > 100
msg := "Database storage exceeds 100GB limit"
}
2. Pulumi Policy Pack
TypeScript Policy Pack:
typescript
import * as policy from "@pulumi/policy";
import { PolicyPack } from "@pulumi/policy";
new PolicyPack("aws-security-policies", {
policies: [{
name: "s3-bucket-no-public-read",
description: "Prohibits S3 buckets with PUBLIC_READ access.",
enforcementLevel: "mandatory",
validateResource: (args, reportViolation) => {
if (args.type === "aws:s3/bucket:Bucket") {
const acl = args.props.acl;
if (acl === "public-read" || acl === "public-read-write") {
reportViolation("S3 buckets should not have public read access.");
}
}
},
}, {
name: "ec2-instance-type-check",
description: "Ensures EC2 instances use approved instance types.",
enforcementLevel: "mandatory",
validateResource: (args, reportViolation) => {
if (args.type === "aws:ec2/instance:Instance") {
const allowedTypes = ["t3.micro", "t3.small", "t3.medium"];
if (!allowedTypes.includes(args.props.instanceType)) {
reportViolation(`EC2 instance type ${args.props.instanceType} not allowed.`);
}
}
},
}],
});
Production-Grade Infrastructure Patterns
1. Multi-Region Deployment
Terraform Multi-Region:
hcl
# providers.tf
provider "aws" {
alias = "primary"
region = "us-east-1"
}
provider "aws" {
alias = "secondary"
region = "us-west-2"
}
# multi-region resources
resource "aws_dynamodb_table" "primary" {
provider = aws.primary
name = "my-table"
# ... configuration
}
resource "aws_dynamodb_table" "secondary" {
provider = aws.secondary
name = "my-table"
# ... configuration
}
2. Blue-Green Deployment
Pulumi Blue-Green Pattern:
typescript
// Create two identical environments
const blue = new WebService("blue", {
vpcId: vpc.id,
subnetIds: privateSubnets.map(s => s.id),
desiredCapacity: 2
});
const green = new WebService("green", {
vpcId: vpc.id,
subnetIds: privateSubnets.map(s => s.id),
desiredCapacity: 0 // Initially scaled down
});
// Route traffic based on deployment phase
const listener = new aws.lb.Listener("app", {
loadBalancerArn: alb.arn,
port: 80,
defaultActions: [{
type: "forward",
targetGroupArn: blue.targetGroup.arn // Start with blue
}]
});
3. Disaster Recovery Setup
Terraform DR Strategy:
hcl
# dr.tf - Disaster Recovery configuration
module "primary_region" {
source = "./modules/multi-region"
providers = {
aws = aws.primary
}
region = "us-east-1"
vpc_cidr = "10.1.0.0/16"
is_primary = true
}
module "secondary_region" {
source = "./modules/multi-region"
providers = {
aws = aws.secondary
}
region = "us-west-2"
vpc_cidr = "10.2.0.0/16"
is_primary = false
}
# Cross-region replication
resource "aws_s3_bucket" "primary_backup" {
provider = aws.primary
bucket = "primary-backup-bucket"
}
resource "aws_s3_bucket_replication" "cross_region" {
provider = aws.primary
bucket = aws_s3_bucket.primary_backup.id
replication_configuration {
role = aws_iam_role.replication.arn
rules {
status = "Enabled"
destination {
bucket = aws_s3_bucket.secondary_backup.arn
storage_class = "STANDARD"
}
}
}
}
Advanced Patterns & Best Practices
1. Terragrunt for DRY Code
Terragrunt Structure:
hcl
# terragrunt.hcl - Root configuration
remote_state {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
# Generate provider configuration
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
region = "us-east-1"
default_tags {
tags = {
Environment = "production"
ManagedBy = "terraform"
}
}
}
EOF
}
2. Pulumi Automation API
Programmatic Infrastructure:
typescript
import * as automation from "@pulumi/pulumi/x/automation";
async function deployStack(environment: string) {
const stackArgs = {
stackName: `${environment}`,
projectName: "my-infrastructure",
};
// Create or select stack
const stack = await automation.LocalWorkspace.createOrSelectStack(stackArgs);
// Set configuration
await stack.setConfig("aws:region", { value: "us-east-1" });
await stack.setConfig("environment", { value: environment });
// Preview changes
const preview = await stack.preview();
console.log(preview.stdout);
// Deploy
const up = await stack.up();
console.log(up.stdout);
}
// Deploy multiple environments
deployStack("dev");
deployStack("production");
3. Security Best Practices
Secrets Management:
hcl
# Use AWS Secrets Manager or Parameter Store
data "aws_secretsmanager_secret_version" "db_password" {
secret_id = "production/db/password"
}
resource "aws_db_instance" "database" {
# ... other configuration
password = data.aws_secretsmanager_secret_version.db_password.secret_string
}
Infrastructure Security Scanning:
yaml
# GitHub Actions workflow for security scanning
name: Security Scan
on:
push:
branches: [main]
pull_request:
jobs:
tfsec:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run tfsec
uses: aquasecurity/[email protected]
with:
soft_fail: true
Learning Path & Certification
Recommended Learning Journey:
Phase 1: Fundamentals (1-2 months)
-
Terraform Basics: Resources, providers, state management
-
Pulumi Introduction: Choose your preferred language
-
Basic Modules: Create reusable components
-
Hands-on: Deploy simple infrastructure (VPC, EC2, S3)
Phase 2: Intermediate (2-3 months)
-
Remote State: Backend configuration, state locking
-
Workspaces/Stacks: Environment management
-
Policy as Code: Sentinel, OPA, Pulumi Policy Packs
-
CI/CD Integration: GitHub Actions, GitLab CI
Phase 3: Advanced (3-4 months)
-
Enterprise Patterns: Multi-account, multi-region
-
Security: Secrets management, compliance
-
Performance: Large-scale deployments, state optimization
-
Testing: Terratest, kitchen-terraform
Certification Preparation:
-
HashiCorp Terraform Associate
-
Cloud-specific IaC patterns (AWS/Azure/GCP)
-
Security and compliance frameworks
This extensive IaC foundation will enable you to manage complex, production-grade infrastructure with confidence, applying best practices for security, reliability, and maintainability.
Comments (0)
No comments yet. Be the first to comment!