Part I: Foundations
Chapter 1: Introduction to Infrastructure as Code
- The evolution of infrastructure management
- Challenges of manual infrastructure provisioning
- The case for infrastructure as code (IaC)
- How Terraform addresses these challenges
Chapter 2: Terraform Architecture
- Core components and workflow
- HCL syntax and structure
- Providers, resources, and modules
- Terraform state management
- Terraform CLI essentials
Chapter 3: Setting Up Your Terraform Environment
- Installation across operating systems
- Configuration best practices
- Authentication and secrets management
- Backend configuration
- Integration with version control
Part II: Multi-Cloud Infrastructure Deployment
Chapter 4: AWS Infrastructure Management
- AWS provider configuration
- Core resource types
- IAM and security implementation
- Network architecture
- Storage solutions
Chapter 5: Azure Resource Provisioning
- Azure provider setup
- Resource groups and organization
- Virtual networks and security
- PaaS service deployment
- Hybrid connectivity
Chapter 6: Google Cloud Platform
- GCP provider configuration
- Project structure
- Network design patterns
- GCP-specific services
- Performance optimization
Chapter 7: Multi-Cloud and Hybrid Deployments
- Cross-provider architecture
- Managing multiple providers
- Abstraction strategies
- Data sharing between clouds
- Hybrid cloud-on-premises solutions
Part III: Production Techniques
Chapter 8: State Management
- Remote state configuration
- State locking mechanisms
- State file security
- Import and migration strategies
- State file troubleshooting
Chapter 9: Security Best Practices
- Secrets management
- IAM implementation patterns
- Network security configurations
- Compliance as code
- Security scanning integration
Chapter 10: Testing Infrastructure Code
- Unit testing with Terraform
- Integration testing strategies
- Policy validation with Sentinel
- Automated validation workflows
- Test-driven infrastructure development
Part IV: DevOps Integration
Chapter 11: CI/CD Pipeline Integration
- Jenkins, GitHub Actions, and GitLab CI examples
- Automated plan and apply workflows
- Change management integration
- Approval processes
- Release automation
Chapter 12: Infrastructure as Code Ecosystem
- Integrating with Packer for image management
- Ansible, Chef, and Puppet integration
- Vault for secrets management
- Consul for service discovery and configuration
- Kubernetes deployment with Terraform
Chapter 13: Monitoring and Observability
- Infrastructure drift detection
- Cost management and optimization
- Performance monitoring
- Disaster recovery strategies
- Comprehensive logging
Part V: Advanced Topics
Chapter 14: Custom Providers and Extensions
- Building custom providers
- Using and creating provider plugins
- Extending Terraform’s functionality
- Contributing to the Terraform ecosystem
Chapter 15: Enterprise Patterns and Case Studies
- Financial services implementation
- Healthcare compliance scenarios
- Scaling for large enterprises
- Multi-region, multi-account strategies
Chapter 16: Future Trends in Infrastructure Management
- Terraform Cloud and Terraform Enterprise
- Policy as code evolution
- GitOps workflows
- AI and ML in infrastructure optimization
Part I: Foundations
Chapter 1: Introduction to Infrastructure as Code
Infrastructure management has evolved dramatically over the past decades. Initially, system administrators manually provisioned servers and networks through web consoles or command-line interfaces, a process that was error-prone, time-consuming, and difficult to scale. As cloud computing matured, programmatic APIs emerged, enabling infrastructure to be defined and managed through code.
Manual infrastructure provisioning presents several challenges:
- Inconsistency: Human error leads to configuration drift
- Documentation burden: Keeping track of infrastructure state
- Time consumption: Repetitive manual processes waste valuable time
- Lack of auditability: Difficult to track who changed what and when
- Limited collaboration: Siloed knowledge and processes
Infrastructure as Code (IaC) addresses these issues by:
- Providing reproducible, code-defined infrastructure
- Enabling version control for infrastructure definitions
- Creating consistent environments across development, testing, and production
- Reducing time to deploy new environments
- Supporting collaboration through code review
HashiCorp Terraform revolutionizes infrastructure management by offering:
- A unified workflow across all major cloud providers
- A simple, declarative configuration language
- A state-based approach to infrastructure management
- Dependency management between resources
- Plan and apply workflow for safe changes
flowchart LR
A[Manual Provisioning] --> B[Point-and-Click Console]
B --> C[Infrastructure Creation]
C --> D[Configuration Drift]
D --> A
E[Terraform Code] --> F[Version Control]
F --> G[Terraform Plan]
G --> H[Terraform Apply]
H --> I[Consistent Infrastructure]
I --> EChapter 2: Terraform Architecture
Terraform’s architecture is built around a core set of components that work together to manage infrastructure across different platforms:
Core Components:
- Configuration Files: HCL (HashiCorp Configuration Language) files that define infrastructure
- Providers: Plugins that interact with APIs of service providers
- Resources: The infrastructure objects managed by Terraform
- State: A representation of the real infrastructure and resource metadata
- Modules: Reusable, encapsulated collections of resources
HCL Syntax and Structure: Terraform uses HashiCorp Configuration Language (HCL), designed specifically for defining infrastructure:
# Provider configuration
provider "aws" {
region = "us-west-2"
profile = "production"
}
# Resource definition
resource "aws_instance" "web_server" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "WebServer"
Environment = "Production"
}
}
# Output values
output "instance_ip" {
value = aws_instance.web_server.public_ip
description = "The public IP of the web server"
}HCLTerraform Workflow:
sequenceDiagram
participant User
participant Terraform CLI
participant Providers
participant Infrastructure
participant State
User->>Terraform CLI: terraform init
Terraform CLI->>Providers: Download providers
User->>Terraform CLI: terraform plan
Terraform CLI->>State: Read current state
Terraform CLI->>Providers: Check current infrastructure
Providers->>Infrastructure: API calls to check resources
Providers-->>Terraform CLI: Return resource status
Terraform CLI-->>User: Show execution plan
User->>Terraform CLI: terraform apply
Terraform CLI->>Providers: Create/Update/Delete resources
Providers->>Infrastructure: API calls to modify resources
Providers-->>Terraform CLI: Return results
Terraform CLI->>State: Update state file
Terraform CLI-->>User: Show apply resultsTerraform State Management:
- State files track the real-world resources
- Mapping between Terraform configuration and real resources
- Metadata for dependency management
- Performance optimization information
- Sensitive data storage considerations
Terraform CLI Essentials:
terraform init– Initialize a Terraform working directoryterraform plan– Create an execution planterraform apply– Apply the changes required to reach the desired stateterraform destroy– Destroy the Terraform-managed infrastructureterraform fmt– Format configurations for readabilityterraform validate– Validate configuration syntaxterraform state– Advanced state managementterraform import– Import existing infrastructure into Terraform
Chapter 3: Setting Up Your Terraform Environment
Installation:
Terraform can be installed across various operating systems:
Linux:
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt-get update && sudo apt-get install terraformBashmacOS:
brew tap hashicorp/tap
brew install hashicorp/tap/terraformBashWindows:
choco install terraform
# or
winget install HashiCorp.TerraformBashConfiguration Best Practices:
- Organize configurations by environment or component
- Use variables for reusable values
- Structure projects with clear separation:
project/ ├── main.tf # Main configuration file ├── variables.tf # Variable definitions ├── outputs.tf # Output definitions ├── providers.tf # Provider configurations ├── terraform.tfvars # Variable values (gitignored) └── modules/ # Custom modules directory └── networking/ # Example module - Use
terraform validatebefore applying changes - Implement consistent naming conventions
Authentication and Secrets Management:
- Use environment variables for provider credentials
- Leverage cloud provider credential helpers
- Consider HashiCorp Vault for enterprise secret management
- Never hardcode secrets in configuration files
- Use
.gitignoreto prevent committing sensitive files
Backend Configuration: Remote backends store Terraform state files securely and enable collaboration:
terraform {
backend "s3" {
bucket = "terraform-states"
key = "production/network/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-lock"
}
}HCLCommon backend options include:
- S3 with DynamoDB locking (AWS)
- Azure Blob Storage (Azure)
- Google Cloud Storage (GCP)
- HashiCorp Terraform Cloud
- Consul
Version Control Integration:
- Store configurations in Git repositories
- Use branches for environment isolation
- Consider using Git hooks for validation
- Implement branch protection rules for production code
Part II: Multi-Cloud Infrastructure Deployment
Chapter 4: AWS Infrastructure Management
AWS Provider Configuration:
provider "aws" {
region = "us-west-2"
# Optional explicit credentials (better to use environment variables)
# access_key = "AKIAIOSFODNN7EXAMPLE"
# secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
default_tags {
tags = {
Environment = "Production"
ManagedBy = "Terraform"
Owner = "Infrastructure Team"
}
}
}HCLCore Resource Types:
Network Infrastructure:
# Create a VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = {
Name = "MainVPC"
}
}
# Create subnets
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index}.0/24"
availability_zone = "us-west-2${["a", "b"][count.index]}"
tags = {
Name = "Public-${count.index}"
}
}
# Create internet gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "MainIGW"
}
}
# Create route table
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "PublicRT"
}
}HCLCompute Resources:
# Create security group
resource "aws_security_group" "web" {
name = "web-sg"
description = "Allow web traffic"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Create EC2 instance
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
subnet_id = aws_subnet.public[0].id
vpc_security_group_ids = [aws_security_group.web.id]
root_block_device {
volume_size = 20
volume_type = "gp3"
}
tags = {
Name = "WebServer"
}
}HCLIAM and Security Implementation:
# Create IAM role
resource "aws_iam_role" "web_server" {
name = "web-server-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
}
]
})
}
# Create IAM policy
resource "aws_iam_policy" "s3_access" {
name = "s3-read-access"
description = "Allow S3 read access"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"s3:GetObject",
"s3:ListBucket"
]
Effect = "Allow"
Resource = [
"arn:aws:s3:::example-bucket",
"arn:aws:s3:::example-bucket/*"
]
}
]
})
}
# Attach policy to role
resource "aws_iam_role_policy_attachment" "s3_access" {
role = aws_iam_role.web_server.name
policy_arn = aws_iam_policy.s3_access.arn
}
# Create instance profile
resource "aws_iam_instance_profile" "web_server" {
name = "web-server-profile"
role = aws_iam_role.web_server.name
}
# Update instance to use profile
resource "aws_instance" "web" {
# ... other configuration ...
iam_instance_profile = aws_iam_instance_profile.web_server.name
}HCLNetwork Architecture:
flowchart TD
A[Internet Gateway] --- B[VPC: 10.0.0.0/16]
B --- C[Public Subnet: 10.0.0.0/24]
B --- D[Public Subnet: 10.0.1.0/24]
B --- E[Private Subnet: 10.0.2.0/24]
B --- F[Private Subnet: 10.0.3.0/24]
A --- G[Public Route Table]
G --- C
G --- D
H[NAT Gateway] --- I[Private Route Table]
I --- E
I --- F
H --- CStorage Solutions:
# Create S3 bucket
resource "aws_s3_bucket" "assets" {
bucket = "my-company-assets"
tags = {
Name = "AssetsStorage"
}
}
# Configure bucket versioning
resource "aws_s3_bucket_versioning" "assets" {
bucket = aws_s3_bucket.assets.id
versioning_configuration {
status = "Enabled"
}
}
# Configure bucket encryption
resource "aws_s3_bucket_server_side_encryption_configuration" "assets" {
bucket = aws_s3_bucket.assets.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}HCLChapter 5: Azure Resource Provisioning
Azure Provider Setup:
provider "azurerm" {
features {}
subscription_id = var.subscription_id
tenant_id = var.tenant_id
# client_id and client_secret better handled via environment variables
}
# Resource group
resource "azurerm_resource_group" "main" {
name = "production-resources"
location = "East US"
tags = {
environment = "Production"
managed_by = "Terraform"
}
}HCLResource Groups and Organization:
# Network resource group
resource "azurerm_resource_group" "network" {
name = "network-resources"
location = "East US"
tags = {
environment = "Production"
component = "Network"
}
}
# Application resource group
resource "azurerm_resource_group" "application" {
name = "app-resources"
location = "East US"
tags = {
environment = "Production"
component = "Application"
}
}
# Database resource group
resource "azurerm_resource_group" "database" {
name = "db-resources"
location = "East US"
tags = {
environment = "Production"
component = "Database"
}
}HCLVirtual Networks and Security:
# Virtual network
resource "azurerm_virtual_network" "main" {
name = "main-vnet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.network.location
resource_group_name = azurerm_resource_group.network.name
}
# Subnets
resource "azurerm_subnet" "web" {
name = "web-subnet"
resource_group_name = azurerm_resource_group.network.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.0.1.0/24"]
}
resource "azurerm_subnet" "app" {
name = "app-subnet"
resource_group_name = azurerm_resource_group.network.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.0.2.0/24"]
}
resource "azurerm_subnet" "db" {
name = "db-subnet"
resource_group_name = azurerm_resource_group.network.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.0.3.0/24"]
}
# Network security group
resource "azurerm_network_security_group" "web" {
name = "web-nsg"
location = azurerm_resource_group.network.location
resource_group_name = azurerm_resource_group.network.name
security_rule {
name = "HTTP"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "80"
source_address_prefix = "*"
destination_address_prefix = "*"
}
security_rule {
name = "HTTPS"
priority = 110
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "443"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
# Associate NSG to subnet
resource "azurerm_subnet_network_security_group_association" "web" {
subnet_id = azurerm_subnet.web.id
network_security_group_id = azurerm_network_security_group.web.id
}HCLPaaS Service Deployment:
# App Service Plan
resource "azurerm_app_service_plan" "main" {
name = "app-service-plan"
location = azurerm_resource_group.application.location
resource_group_name = azurerm_resource_group.application.name
kind = "Linux"
reserved = true
sku {
tier = "Standard"
size = "S1"
}
}
# App Service
resource "azurerm_app_service" "web" {
name = "webapp-${var.environment}"
location = azurerm_resource_group.application.location
resource_group_name = azurerm_resource_group.application.name
app_service_plan_id = azurerm_app_service_plan.main.id
site_config {
linux_fx_version = "DOCKER|nginx:latest"
always_on = true
}
app_settings = {
"WEBSITES_ENABLE_APP_SERVICE_STORAGE" = "false"
"DOCKER_REGISTRY_SERVER_URL" = "https://index.docker.io"
}
}
# SQL Server
resource "azurerm_sql_server" "main" {
name = "sql-server-${var.environment}"
resource_group_name = azurerm_resource_group.database.name
location = azurerm_resource_group.database.location
version = "12.0"
administrator_login = var.db_admin_username
administrator_login_password = var.db_admin_password
}
# SQL Database
resource "azurerm_sql_database" "main" {
name = "sql-db-${var.environment}"
resource_group_name = azurerm_resource_group.database.name
location = azurerm_resource_group.database.location
server_name = azurerm_sql_server.main.name
edition = "Standard"
requested_service_objective_name = "S1"
}HCLHybrid Connectivity:
# Virtual Network Gateway
resource "azurerm_virtual_network_gateway" "main" {
name = "vnet-gateway"
location = azurerm_resource_group.network.location
resource_group_name = azurerm_resource_group.network.name
type = "Vpn"
vpn_type = "RouteBased"
active_active = false
enable_bgp = false
sku = "VpnGw1"
ip_configuration {
name = "vnetGatewayConfig"
public_ip_address_id = azurerm_public_ip.vpn.id
private_ip_address_allocation = "Dynamic"
subnet_id = azurerm_subnet.gateway.id
}
}
# Local Network Gateway (on-premises endpoint)
resource "azurerm_local_network_gateway" "onpremise" {
name = "onpremise"
location = azurerm_resource_group.network.location
resource_group_name = azurerm_resource_group.network.name
gateway_address = var.onpremise_vpn_public_ip
address_space = ["192.168.0.0/16"]
}
# Connection between Azure and on-premises
resource "azurerm_virtual_network_gateway_connection" "onpremise" {
name = "azure-to-onpremise"
location = azurerm_resource_group.network.location
resource_group_name = azurerm_resource_group.network.name
type = "IPsec"
virtual_network_gateway_id = azurerm_virtual_network_gateway.main.id
local_network_gateway_id = azurerm_local_network_gateway.onpremise.id
shared_key = var.vpn_shared_key
}HCLChapter 6: Google Cloud Platform
GCP Provider Configuration:
provider "google" {
project = var.project_id
region = var.region
zone = var.zone
}
provider "google-beta" {
project = var.project_id
region = var.region
zone = var.zone
}HCLProject Structure:
# Create a GCP project (requires organization)
resource "google_project" "my_project" {
name = "My Project"
project_id = "my-project-id"
org_id = var.org_id
billing_account = var.billing_account
}
# Enable required APIs
resource "google_project_service" "compute" {
project = google_project.my_project.project_id
service = "compute.googleapis.com"
}
resource "google_project_service" "container" {
project = google_project.my_project.project_id
service = "container.googleapis.com"
}
resource "google_project_service" "cloudsql" {
project = google_project.my_project.project_id
service = "sqladmin.googleapis.com"
}HCLNetwork Design Patterns:
# VPC network
resource "google_compute_network" "vpc_network" {
name = "vpc-network"
auto_create_subnetworks = false
}
# Subnets
resource "google_compute_subnetwork" "web_subnet" {
name = "web-subnet"
ip_cidr_range = "10.0.1.0/24"
region = var.region
network = google_compute_network.vpc_network.id
}
resource "google_compute_subnetwork" "app_subnet" {
name = "app-subnet"
ip_cidr_range = "10.0.2.0/24"
region = var.region
network = google_compute_network.vpc_network.id
}
# Firewall rules
resource "google_compute_firewall" "web" {
name = "allow-web"
network = google_compute_network.vpc_network.name
allow {
protocol = "tcp"
ports = ["80", "443"]
}
source_ranges = ["0.0.0.0/0"]
target_tags = ["web"]
}
resource "google_compute_firewall" "ssh" {
name = "allow-ssh"
network = google_compute_network.vpc_network.name
allow {
protocol = "tcp"
ports = ["22"]
}
source_ranges = [var.admin_cidr_block]
}HCLGCP-Specific Services:
# GKE cluster
resource "google_container_cluster" "primary" {
name = "my-gke-cluster"
location = var.region
remove_default_node_pool = true
initial_node_count = 1
network = google_compute_network.vpc_network.name
subnetwork = google_compute_subnetwork.app_subnet.name
master_auth {
client_certificate_config {
issue_client_certificate = false
}
}
}
resource "google_container_node_pool" "primary_preemptible_nodes" {
name = "my-node-pool"
location = var.region
cluster = google_container_cluster.primary.name
node_count = 3
node_config {
preemptible = true
machine_type = "e2-medium"
service_account = google_service_account.gke_sa.email
oauth_scopes = [
"https://www.googleapis.com/auth/cloud-platform"
]
}
}
# Cloud SQL
resource "google_sql_database_instance" "main" {
name = "my-database-instance"
database_version = "POSTGRES_13"
region = var.region
settings {
tier = "db-f1-micro"
ip_configuration {
ipv4_enabled = false
private_network = google_compute_network.vpc_network.id
}
}
}
# Cloud Storage
resource "google_storage_bucket" "static" {
name = "static-assets-bucket"
location = "US"
force_destroy = true
uniform_bucket_level_access = true
website {
main_page_suffix = "index.html"
not_found_page = "404.html"
}
}HCLPerformance Optimization:
# Instance template for managed instance group
resource "google_compute_instance_template" "web_server" {
name_prefix = "web-server-template-"
machine_type = "e2-medium"
disk {
source_image = "debian-cloud/debian-10"
auto_delete = true
boot = true
disk_type = "pd-ssd"
disk_size_gb = 20
}
network_interface {
network = google_compute_network.vpc_network.name
subnetwork = google_compute_subnetwork.web_subnet.name
access_config {
// Ephemeral IP
}
}
metadata_startup_script = file("startup.sh")
service_account {
email = google_service_account.web_sa.email
scopes = ["cloud-platform"]
}
tags = ["web"]
lifecycle {
create_before_destroy = true
}
}
# Managed instance group
resource "google_compute_region_instance_group_manager" "web_servers" {
name = "web-server-group"
base_instance_name = "web"
region = var.region
version {
instance_template = google_compute_instance_template.web_server.id
}
target_size = 3
named_port {
name = "http"
port = 80
}
auto_healing_policies {
health_check = google_compute_health_check.web.id
initial_delay_sec = 300
}
}
# Load balancing
resource "google_compute_global_address" "default" {
name = "lb-ip-address"
}
resource "google_compute_global_forwarding_rule" "default" {
name = "global-rule"
target = google_compute_target_http_proxy.default.id
port_range = "80"
ip_address = google_compute_global_address.default.address
}
resource "google_compute_target_http_proxy" "default" {
name = "http-proxy"
url_map = google_compute_url_map.default.id
}
resource "google_compute_url_map" "default" {
name = "url-map"
default_service = google_compute_backend_service.default.id
}
resource "google_compute_backend_service" "default" {
name = "backend-service"
port_name = "http"
protocol = "HTTP"
timeout_sec = 10
health_checks = [google_compute_health_check.web.id]
backend {
group = google_compute_region_instance_group_manager.web_servers.instance_group
}
}
resource "google_compute_health_check" "web" {
name = "web-health-check"
check_interval_sec = 5
timeout_sec = 5
http_health_check {
port = 80
request_path = "/healthz"
}
}HCLChapter 7: Multi-Cloud and Hybrid Deployments
Cross-Provider Architecture:
# Configure multiple providers
provider "aws" {
region = "us-west-2"
alias = "west"
}
provider "aws" {
region = "us-east-1"
alias = "east"
}
provider "azurerm" {
features {}
alias = "primary"
}
provider "google" {
project = var.gcp_project
region = "us-central1"
alias = "gcp"
}
# Create resources across providers
module "aws_west_resources" {
source = "./modules/aws_infrastructure"
providers = {
aws = aws.west
}
vpc_cidr = "10.0.0.0/16"
environment = "production"
availability_zones = ["us-west-2a", "us-west-2b"]
}
module "aws_east_resources" {
source = "./modules/aws_infrastructure"
providers = {
aws = aws.east
}
vpc_cidr = "10.1.0.0/16"
environment = "production"
availability_zones = ["us-east-1a", "us-east-1b"]
}
module "azure_resources" {
source = "./modules/azure_infrastructure"
providers = {
azurerm = azurerm.primary
}
resource_group_location = "East US"
vnet_address_space = ["10.2.0.0/16"]
environment = "production"
}HCLManaging Multiple Providers:
# Use provider-agnostic module with provider-specific implementations
module "database" {
source = "./modules/database"
# Common parameters
name = "production-db"
environment = "production"
# Provider-specific parameters
aws_enabled = true
azure_enabled = true
gcp_enabled = false
# Provider objects
providers = {
aws = aws.west
azurerm = azurerm.primary
google = google.gcp
}
}
# Output cross-cloud information
output "database_endpoints" {
value = {
aws = module.database.aws_endpoint
azure = module.database.azure_endpoint
gcp = module.database.gcp_endpoint
}
}HCLAbstraction Strategies: Creating multi-cloud modules with conditional resource creation:
# Virtual machine module supporting multiple clouds
# main.tf
variable "aws_enabled" {
description = "Whether to create AWS resources"
type = bool
default = false
}
variable "azure_enabled" {
description = "Whether to create Azure resources"
type = bool
default = false
}
variable "name" {
description = "Name for the virtual machine"
type = string
}
# AWS implementation
resource "aws_instance" "vm" {
count = var.aws_enabled ? 1 : 0
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = {
Name = var.name
}
}
# Azure implementation
resource "azurerm_linux_virtual_machine" "vm" {
count = var.azure_enabled ? 1 : 0
name = var.name
resource_group_name = var.resource_group_name
location = var.location
size = "Standard_B1s"
admin_username = var.admin_username
network_interface_ids = [var.nic_id]
admin_ssh_key {
username = var.admin_username
public_key = var.ssh_public_key
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
}
# Provide unified outputs
output "public_ip" {
value = coalesce(
var.aws_enabled ? aws_instance.vm[0].public_ip : null,
var.azure_enabled ? azurerm_linux_virtual_machine.vm[0].public_ip_address : null
)
}HCLData Sharing Between Clouds:
# AWS S3 bucket for cross-cloud data sharing
resource "aws_s3_bucket" "shared_data" {
bucket = "cross-cloud-shared-data"
tags = {
Name = "SharedData"
}
}
# Azure Storage Account with cross-cloud access
resource "azurerm_storage_account" "sync" {
name = "crosscloudsync"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
account_tier = "Standard"
account_replication_type = "LRS"
network_rules {
default_action = "Deny"
ip_rules = ["0.0.0.0/0"] # Configure appropriate IPs
virtual_network_subnet_ids = [azurerm_subnet.sync.id]
}
}
# GCP data transfer service to sync from AWS S3
resource "google_storage_transfer_job" "s3_to_gcs" {
description = "S3 to GCS transfer job"
transfer_spec {
aws_s3_data_source {
bucket_name = aws_s3_bucket.shared_data.bucket
aws_access_key {
access_key_id = var.aws_access_key
secret_access_key = var.aws_secret_key
}
}
gcs_data_sink {
bucket_name = google_storage_bucket.gcp_sync.name
}
}
schedule {
schedule_start_date {
year = 2025
month = 1
day = 1
}
start_time_of_day {
hours = 0
minutes = 0
seconds = 0
nanos = 0
}
repeat_interval = "86400s" # Daily
}
}HCLHybrid Cloud-On-premises Solutions:
# AWS Direct Connect
resource "aws_dx_connection" "datacenter" {
name = "datacenter-connection"
bandwidth = "1Gbps"
location = "EqSe2"
}
resource "aws_dx_private_virtual_interface" "datacenter" {
connection_id = aws_dx_connection.datacenter.id
name = "datacenter-vif"
vlan = 100
address_family = "ipv4"
bgp_asn = 65000
amazon_address = "169.254.0.1/30"
customer_address = "169.254.0.2/30"
vpn_gateway_id = aws_vpn_gateway.main.id
}
# Azure ExpressRoute
resource "azurerm_express_route_circuit" "datacenter" {
name = "datacenter-expressroute"
resource_group_name = azurerm_resource_group.network.name
location = azurerm_resource_group.network.location
service_provider_name = "Equinix"
peering_location = "Silicon Valley"
bandwidth_in_mbps = 1000
sku {
tier = "Premium"
family = "MeteredData"
}
}
# Connect ExpressRoute to VNet
resource "azurerm_virtual_network_gateway_connection" "datacenter" {
name = "datacenter-connection"
location = azurerm_resource_group.network.location
resource_group_name = azurerm_resource_group.network.name
type = "ExpressRoute"
virtual_network_gateway_id = azurerm_virtual_network_gateway.main.id
express_route_circuit_id = azurerm_express_route_circuit.datacenter.id
authorization_key = var.expressroute_auth_key
}
# GCP Cloud Interconnect
resource "google_compute_interconnect_attachment" "datacenter" {
name = "datacenter-interconnect"
type = "PARTNER"
router = google_compute_router.datacenter.id
region = var.region
bandwidth = "BPS_1G"
vlan_tag8021q = 100
}
resource "google_compute_router" "datacenter" {
name = "datacenter-router"
network = google_compute_network.vpc_network.name
region = var.region
bgp {
asn = 65001
}
}HCLPart III: Production Techniques
Chapter 8: State Management
Remote State Configuration:
# S3 backend configuration
terraform {
backend "s3" {
bucket = "terraform-states"
key = "production/network/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-lock"
}
}
# Azure backend configuration
terraform {
backend "azurerm" {
resource_group_name = "terraform-states"
storage_account_name = "terraformstate"
container_name = "tfstate"
key = "production.terraform.tfstate"
}
}
# GCP backend configuration
terraform {
backend "gcs" {
bucket = "terraform-states"
prefix = "production"
}
}
# Terraform Cloud backend
terraform {
backend "remote" {
organization = "my-company"
workspaces {
name = "production"
}
}
}HCLState Locking Mechanisms:
AWS DynamoDB lock table:
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
tags = {
Name = "TerraformStateLock"
}
}HCLState File Security:
# S3 bucket for state with encryption and versioning
resource "aws_s3_bucket" "terraform_state" {
bucket = "terraform-states"
tags = {
Name = "TerraformState"
}
}
resource "aws_s3_bucket_versioning" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
# Restrict access to state bucket
resource "aws_s3_bucket_public_access_block" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
# IAM policy for state access
resource "aws_iam_policy" "terraform_state_access" {
name = "TerraformStateAccess"
description = "Policy for accessing Terraform state"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"s3:ListBucket",
"s3:GetObject",
"s3:PutObject"
]
Resource = [
aws_s3_bucket.terraform_state.arn,
"${aws_s3_bucket.terraform_state.arn}/*"
]
},
{
Effect = "Allow"
Action = [
"dynamodb:DescribeTable",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:DeleteItem"
]
Resource = aws_dynamodb_table.terraform_locks.arn
}
]
})
}HCLImport and Migration Strategies:
Import existing infrastructure:
terraform import aws_instance.web i-1234567890abcdef0BashMigration between backends:
# Export current state
terraform state pull > terraform.tfstate
# After reconfiguring backend
terraform init -migrate-stateBashState File Troubleshooting:
Common state issues and resolutions:
- State locking failures: Check permissions and lock table configuration
- State file corruption: Restore from versioned backups
- Resource drift: Use
terraform refreshandterraform planto identify - Orphaned resources: Remove with
terraform state rm - State conflicts: Resolve by merging state files
State file operations:
# List resources in state
terraform state list
# Show resource details
terraform state show aws_instance.web
# Move resources
terraform state mv aws_instance.web aws_instance.web_server
# Remove resources from state
terraform state rm aws_instance.oldBashChapter 9: Security Best Practices
Secrets Management:
# Integrate with Vault for secrets
provider "vault" {
address = "https://vault.example.com:8200"
}
data "vault_generic_secret" "db_credentials" {
path = "secret/database"
}
resource "aws_db_instance" "postgres" {
allocated_storage = 20
engine = "postgres"
engine_version = "14"
instance_class = "db.t3.micro"
db_name = "mydb"
username = data.vault_generic_secret.db_credentials.data["username"]
password = data.vault_generic_secret.db_credentials.data["password"]
parameter_group_name = "default.postgres14"
skip_final_snapshot = true
}HCLIAM Implementation Patterns:
Least privilege principle:
# Granular IAM roles with specific permissions
resource "aws_iam_role" "ec2_s3_read_only" {
name = "ec2-s3-read-only"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
}
]
})
}
resource "aws_iam_role_policy" "s3_read_only" {
name = "s3-read-only"
role = aws_iam_role.ec2_s3_read_only.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"s3:Get*",
"s3:List*"
]
Effect = "Allow"
Resource = [
"arn:aws:s3:::specific-bucket",
"arn:aws:s3:::specific-bucket/*"
]
}
]
})
}HCLNetwork Security Configurations:
# Security group with minimal access
resource "aws_security_group" "restricted" {
name = "restricted-access"
description = "Allow minimal traffic"
vpc_id = aws_vpc.main.id
# Allow inbound traffic only from internal subnet
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [aws_subnet.private.cidr_block]
}
# Allow outbound only to specific services
egress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Azure Network Security Group with detailed rules
resource "azurerm_network_security_group" "restricted" {
name = "restricted-nsg"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
security_rule {
name = "AllowHTTPSInbound"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "443"
source_address_prefix = "VirtualNetwork"
destination_address_prefix = "*"
}
security_rule {
name = "DenyAllInbound"
priority = 4096
direction = "Inbound"
access = "Deny"
protocol = "*"
source_port_range = "*"
destination_port_range = "*"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}HCLCompliance as Code:
# Using Sentinel Policy as Code (Terraform Cloud/Enterprise)
# sentinel.hcl
policy "enforce-mandatory-tags" {
enforcement_level = "hard-mandatory"
}
policy "restrict-instance-type" {
enforcement_level = "soft-mandatory"
}
# enforce-mandatory-tags.sentinel
import "tfplan"
required_tags = [
"environment",
"owner",
"application"
]
ec2_instances = filter tfplan.resource_changes as _, rc {
rc.type is "aws_instance" and
(rc.change.actions contains "create" or rc.change.actions contains "update")
}
tags_validation = rule {
all ec2_instances as _, instance {
all required_tags as rt {
instance.change.after.tags contains rt
}
}
}
main = rule {
tags_validation
}HCLSecurity Scanning Integration:
# GitHub Actions workflow for Terraform security scanning
name: Terraform Security Scan
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
tfsec:
name: Run tfsec sarif report
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- name: Clone repo
uses: actions/checkout@v3
- name: Run tfsec
uses: tfsec/tfsec-sarif-action@v0.1.0
with:
sarif_file: tfsec.sarif
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v1
with:
sarif_file: tfsec.sarifYAMLChapter 10: Testing Infrastructure Code
Unit Testing with Terraform:
# Example module to test
# modules/networking/main.tf
variable "vpc_cidr" {
type = string
}
variable "subnet_cidrs" {
type = list(string)
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
}
resource "aws_subnet" "main" {
count = length(var.subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.subnet_cidrs[count.index]
}
output "vpc_id" {
value = aws_vpc.main.id
}
output "subnet_ids" {
value = aws_subnet.main[*].id
}HCL// Test file: modules/networking/main_test.go
package test
import (
"testing"
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/assert"
)
func TestNetworkingModule(t *testing.T) {
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../examples/networking",
Vars: map[string]interface{}{
"vpc_cidr": "10.0.0.0/16",
"subnet_cidrs": []string{
"10.0.1.0/24",
"10.0.2.0/24",
},
},
})
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
vpcID := terraform.Output(t, terraformOptions, "vpc_id")
subnetIDs := terraform.OutputList(t, terraformOptions, "subnet_ids")
assert.NotEmpty(t, vpcID)
assert.Equal(t, 2, len(subnetIDs))
}GoIntegration Testing Strategies:
package test
import (
"fmt"
"testing"
"time"
"github.com/gruntwork-io/terratest/modules/http-helper"
"github.com/gruntwork-io/terratest/modules/terraform"
)
func TestWebServerDeployment(t *testing.T) {
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../examples/web-server",
})
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
publicIP := terraform.Output(t, terraformOptions, "public_ip")
url := fmt.Sprintf("http://%s", publicIP)
// Test that the web server returns a 200 OK
http_helper.HttpGetWithRetry(
t,
url,
nil,
200,
"Hello, World!",
30,
5*time.Second,
)
}GoPolicy Validation with Sentinel:
# restrict-instance-type.sentinel
import "tfplan"
allowed_types = [
"t3.micro",
"t3.small",
"t3.medium"
]
ec2_instances = filter tfplan.resource_changes as _, rc {
rc.type is "aws_instance" and
(rc.change.actions contains "create" or rc.change.actions contains "update")
}
instance_type_allowed = rule {
all ec2_instances as _, instance {
instance.change.after.instance_type in allowed_types
}
}
main = rule {
instance_type_allowed
}Power QueryAutomated Validation Workflows:
# GitLab CI workflow for Terraform validation
stages:
- validate
- test
- plan
- apply
variables:
TF_ROOT: ${CI_PROJECT_DIR}
TF_STATE_NAME: default
validate:
stage: validate
script:
- cd ${TF_ROOT}
- terraform init -backend=false
- terraform validate
- terraform fmt -check
test:
stage: test
script:
- cd ${TF_ROOT}/test
- go test -v ./...
plan:
stage: plan
script:
- cd ${TF_ROOT}
- terraform init
- terraform plan -out=plan.tfplan
artifacts:
paths:
- plan.tfplan
expire_in: 1 week
apply:
stage: apply
script:
- cd ${TF_ROOT}
- terraform init
- terraform apply plan.tfplan
dependencies:
- plan
when: manual
only:
- mainYAMLTest-Driven Infrastructure Development:
# test/fixtures/s3_bucket/main.tf
provider "aws" {
region = "us-west-2"
}
module "s3_bucket" {
source = "../../../modules/s3_bucket"
bucket_name = "test-bucket-${random_id.this.hex}"
versioning_enabled = true
encryption_enabled = true
block_public_access = true
}
resource "random_id" "this" {
byte_length = 8
}
output "bucket_id" {
value = module.s3_bucket.bucket_id
}
output "bucket_arn" {
value = module.s3_bucket.bucket_arn
}HCL# test/integration/s3_bucket/controls/s3_bucket_test.rb
control 's3-bucket' do
impact 1.0
title 'Test S3 Bucket Configuration'
bucket_id = input('bucket_id')
describe aws_s3_bucket(bucket_id) do
it { should exist }
it { should have_versioning_enabled }
it { should have_default_encryption_enabled }
its('bucket_acl.grants.count') { should eq 1 } # Only the owner has access
end
describe aws_s3_bucket_policy(bucket_id) do
it { should_not be_public }
end
endRubyPart IV: DevOps Integration
Chapter 11: CI/CD Pipeline Integration
Jenkins Pipeline Integration:
pipeline {
agent any
environment {
TF_IN_AUTOMATION = 'true'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Terraform Init') {
steps {
sh 'terraform init'
}
}
stage('Terraform Validate') {
steps {
sh 'terraform validate'
sh 'terraform fmt -check'
}
}
stage('Terraform Plan') {
steps {
sh 'terraform plan -out=tfplan'
sh 'terraform show -json tfplan > tfplan.json'
}
}
stage('Security Scan') {
steps {
sh 'tfsec .'
sh 'checkov -f tfplan.json'
}
}
stage('Approval') {
when {
branch 'main'
}
steps {
input message: 'Deploy the infrastructure?'
}
}
stage('Terraform Apply') {
when {
branch 'main'
}
steps {
sh 'terraform apply -auto-approve tfplan'
}
}
}
post {
always {
archiveArtifacts artifacts: 'tfplan.json', fingerprint: true
}
}
}GroovyGitHub Actions Example:
name: 'Terraform CI/CD'
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
terraform:
name: 'Terraform'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Terraform Format
id: fmt
run: terraform fmt -check
- name: Terraform Init
id: init
run: terraform init
- name: Terraform Validate
id: validate
run: terraform validate -no-color
- name: Terraform Plan
id: plan
if: github.event_name == 'pull_request'
run: terraform plan -no-color
continue-on-error: true
- name: Update Pull Request
uses: actions/github-script@v6
if: github.event_name == 'pull_request'
env:
PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\`
#### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
#### Terraform Validation 🤖\`${{ steps.validate.outcome }}\`
#### Terraform Plan 📖\`${{ steps.plan.outcome }}\`
<details><summary>Show Plan</summary>
\`\`\`\n
${process.env.PLAN}
\`\`\`
</details>
*Pushed by: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approveYAMLGitLab CI Example:
image:
name: hashicorp/terraform:latest
entrypoint:
- '/usr/bin/env'
- 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
variables:
TF_ROOT: ${CI_PROJECT_DIR}
TF_STATE_NAME: default
cache:
paths:
- .terraform
before_script:
- cd ${TF_ROOT}
- terraform --version
stages:
- validate
- test
- build
- deploy
- cleanup
validate:
stage: validate
script:
- terraform init -backend=false
- terraform fmt -check
- terraform validate
test:
stage: test
image: golang:latest
script:
- cd test
- go test -v ./...
plan:
stage: build
script:
- terraform init
- terraform plan -out=plan.tfplan
artifacts:
paths:
- plan.tfplan
reports:
terraform: plan.json
apply:
stage: deploy
script:
- terraform init
- terraform apply -auto-approve plan.tfplan
dependencies:image:
name: hashicorp/terraform:latest
entrypoint:
- '/usr/bin/env'
- 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
variables:
TF_ROOT: ${CI_PROJECT_DIR}
TF_STATE_NAME: default
cache:
paths:
- .terraform
before_script:
- cd ${TF_ROOT}
- terraform --version
stages:
- validate
- test
- build
- deploy
- cleanup
validate:
stage: validate
script:
- terraform init -backend=false
- terraform fmt -check
- terraform validate
test:
stage: test
image: golang:latest
script:
- cd test
- go test -v ./...
plan:
stage: build
script:
- terraform init
- terraform plan -out=plan.tfplan
artifacts:
paths:
- plan.tfplan
reports:
terraform: plan.json
apply:
stage: deploy
script:
- terraform init
- terraform apply -auto-approve plan.tfplan
dependencies:
Similar code found with 6 license types
---
# HashiCorp Terraform: Production-Grade Infrastructure Management Across Cloud Providers
## Part IV: DevOps Integration (continued)
### Chapter 11: CI/CD Pipeline Integration (continued)
**GitLab CI Example (continued):**
```yaml
# Complete GitLab CI pipeline
apply:
stage: deploy
script:
- terraform init
- terraform apply -auto-approve plan.tfplan
dependencies:
- plan
when: manual
only:
- main
destroy:
stage: cleanup
script:
- terraform init
- terraform destroy -auto-approve
when: manual
environment:
name: production
action: stopYAMLAutomated Plan and Apply Workflows:
flowchart TD
A[Code Changes] --> B[CI Trigger]
B --> C[Terraform Init]
C --> D[Terraform Validate]
D --> E[Terraform Plan]
E --> F{Review Changes}
F -->|Approved| G[Terraform Apply]
F -->|Rejected| H[Reject Changes]
G --> I[Update Documentation]
G --> J[Notify Team]Change Management Integration:
# Python script to integrate Terraform with ServiceNow
import requests
import json
import os
import subprocess
# Create change request in ServiceNow
def create_change_request(plan_summary):
snow_url = os.environ['SNOW_URL']
snow_user = os.environ['SNOW_USER']
snow_pass = os.environ['SNOW_PASS']
headers = {"Content-Type": "application/json"}
payload = {
"short_description": "Terraform infrastructure changes",
"description": plan_summary,
"type": "normal",
"risk": "moderate",
"impact": "3",
"category": "Infrastructure"
}
response = requests.post(
f"{snow_url}/api/now/table/change_request",
auth=(snow_user, snow_pass),
headers=headers,
data=json.dumps(payload)
)
if response.status_code == 201:
return response.json()['result']['sys_id']
else:
raise Exception(f"Failed to create change request: {response.text}")
# Run Terraform plan and extract summary
tf_output = subprocess.check_output(["terraform", "plan", "-no-color"]).decode("utf-8")
plan_summary = "\n".join(line for line in tf_output.split("\n") if "Plan:" in line)
# Create change request
change_id = create_change_request(plan_summary)
print(f"Created change request: {change_id}")
# Wait for approval before applying
# ...PythonApproval Processes:
# Using Terraform Cloud for approvals
terraform {
cloud {
organization = "my-company"
workspaces {
name = "production"
}
}
}HCL// Terraform Cloud workspace configuration (API)
{
"data": {
"type": "workspaces",
"attributes": {
"name": "production",
"auto-apply": false,
"terraform-version": "1.5.0",
"execution-mode": "remote",
"speculative-enabled": true,
"global-remote-state": false
}
}
}JSONRelease Automation:
#!/bin/bash
# Terraform deployment script with versioning and notifications
# Set environment
ENV=$1
VERSION=$2
if [ -z "$ENV" ] || [ -z "$VERSION" ]; then
echo "Usage: $0 <environment> <version>"
exit 1
fi
# Checkout specific version
git checkout tags/v${VERSION}
# Select workspace
terraform workspace select ${ENV} || terraform workspace new ${ENV}
# Initialize and apply
terraform init
terraform apply -auto-approve
# Tag the deployment in git
git tag -a "deployed-${ENV}-v${VERSION}" -m "Deployed version ${VERSION} to ${ENV}"
git push origin --tags
# Send notification
curl -X POST \
-H "Content-Type: application/json" \
-d "{\"text\":\"Terraform v${VERSION} successfully deployed to ${ENV}\"}" \
${SLACK_WEBHOOK_URL}BashChapter 12: Infrastructure as Code Ecosystem
Integrating with Packer for Image Management:
# First define AMI using Packer
# packer.pkr.hcl
source "amazon-ebs" "ubuntu" {
ami_name = "web-server-${local.timestamp}"
instance_type = "t2.micro"
region = "us-west-2"
source_ami_filter {
filters = {
name = "ubuntu/images/*ubuntu-focal-20.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"]
}
ssh_username = "ubuntu"
}
build {
sources = ["source.amazon-ebs.ubuntu"]
provisioner "shell" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y nginx",
"sudo systemctl enable nginx"
]
}
post-processor "manifest" {
output = "manifest.json"
strip_path = true
}
}HCL# Then reference AMI in Terraform
data "external" "ami" {
program = ["jq", "-r", ".builds[-1].artifact_id", "manifest.json"]
}
locals {
ami_id = element(split(":", data.external.ami.result.output), 1)
}
resource "aws_instance" "web" {
ami = local.ami_id
instance_type = "t3.micro"
tags = {
Name = "WebServer"
}
}HCLAnsible, Chef, and Puppet Integration:
# Using Ansible with Terraform
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
key_name = aws_key_pair.deployer.key_name
provisioner "remote-exec" {
inline = ["echo 'SSH ready'"]
connection {
type = "ssh"
user = "ubuntu"
private_key = file(var.private_key_path)
host = self.public_ip
}
}
provisioner "local-exec" {
command = "ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u ubuntu -i '${self.public_ip},' --private-key ${var.private_key_path} playbook.yml"
}
}HCL# Example Ansible playbook.yml
---
- hosts: all
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
- name: Install packages
apt:
name:
- nginx
- postgresql-client
- python3-pip
state: present
- name: Start nginx
service:
name: nginx
state: started
enabled: yesYAMLVault for Secrets Management:
# Terraform with Vault integration
provider "vault" {
address = "https://vault.example.com:8200"
token = var.vault_token
}
data "vault_generic_secret" "database" {
path = "secret/database/credentials"
}
resource "aws_db_instance" "database" {
allocated_storage = 20
engine = "mysql"
engine_version = "8.0"
instance_class = "db.t3.micro"
name = "mydb"
username = data.vault_generic_secret.database.data["username"]
password = data.vault_generic_secret.database.data["password"]
parameter_group_name = "default.mysql8.0"
skip_final_snapshot = true
}HCLConsul for Service Discovery and Configuration:
# Using Terraform to set up Consul
resource "aws_instance" "consul_server" {
count = 3
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.medium"
user_data = <<-EOF
#!/bin/bash
apt-get update
apt-get install -y unzip
wget https://releases.hashicorp.com/consul/1.13.1/consul_1.13.1_linux_amd64.zip
unzip consul_1.13.1_linux_amd64.zip
mv consul /usr/local/bin/
mkdir -p /etc/consul.d
cat > /etc/consul.d/server.json <<EOL
{
"server": true,
"bootstrap_expect": 3,
"data_dir": "/var/consul",
"retry_join": [${join(",", formatlist("\"${aws_instance.consul_server[*].private_ip}\"", range(3)))}],
"client_addr": "0.0.0.0",
"ui": true
}
EOL
systemctl enable consul
systemctl start consul
EOF
tags = {
Name = "consul-server-${count.index}"
}
}
# Consul outputs for service discovery
output "consul_ui" {
value = "http://${aws_instance.consul_server[0].public_ip}:8500"
}HCLKubernetes Deployment with Terraform:
# Setting up EKS with Terraform
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 19.0"
cluster_name = "my-cluster"
cluster_version = "1.27"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
eks_managed_node_group_defaults = {
ami_type = "AL2_x86_64"
instance_types = ["t3.medium"]
}
eks_managed_node_groups = {
main = {
min_size = 1
max_size = 3
desired_size = 2
instance_types = ["t3.medium"]
capacity_type = "ON_DEMAND"
}
}
}
# Using Terraform Kubernetes provider
provider "kubernetes" {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
command = "aws"
}
}
# Deploy an application
resource "kubernetes_deployment" "example" {
metadata {
name = "example-app"
}
spec {
replicas = 2
selector {
match_labels = {
app = "example"
}
}
template {
metadata {
labels = {
app = "example"
}
}
spec {
container {
image = "nginx:1.21"
name = "example"
port {
container_port = 80
}
}
}
}
}
}
resource "kubernetes_service" "example" {
metadata {
name = "example-service"
}
spec {
selector = {
app = "example"
}
port {
port = 80
target_port = 80
}
type = "LoadBalancer"
}
}HCLChapter 13: Monitoring and Observability
Infrastructure Drift Detection:
# Output the configuration for drift detection
resource "local_file" "config_snapshot" {
content = jsonencode({
timestamp = timestamp()
vpc_id = aws_vpc.main.id
subnet_ids = aws_subnet.main.*.id
instances = [for i in aws_instance.web : {
id = i.id
type = i.instance_type
ami = i.ami
security_groups = i.security_groups
}]
})
filename = "${path.module}/snapshots/config-${formatdate("YYYY-MM-DD-hh-mm", timestamp())}.json"
}
# Drift detection script (local-exec)
resource "null_resource" "drift_detection" {
triggers = {
always_run = timestamp()
}
provisioner "local-exec" {
command = <<-EOF
#!/bin/bash
terraform plan -detailed-exitcode
if [ $? -eq 2 ]; then
echo "Drift detected - infrastructure has changed!" | tee drift-alert.txt
# Send notification
curl -X POST -H "Content-Type: application/json" -d @drift-alert.txt ${var.notification_url}
else
echo "No drift detected"
fi
EOF
}
depends_on = [
aws_instance.web,
aws_vpc.main
]
}HCLCost Management and Optimization:
# Tagging resources for cost allocation
locals {
common_tags = {
Project = var.project_name
Environment = var.environment
Owner = var.owner
CostCenter = var.cost_center
}
}
resource "aws_instance" "app" {
ami = var.ami_id
instance_type = var.instance_type
tags = merge(
local.common_tags,
{
Name = "AppServer"
}
)
# Cost optimization: Use spot instances for non-production
dynamic "instance_market_options" {
for_each = var.environment != "production" ? [1] : []
content {
market_type = "spot"
spot_options {
max_price = var.spot_price
}
}
}
# Cost optimization: Auto-shutdown in dev environments
user_data = var.environment == "development" ? <<-EOF
#!/bin/bash
echo "0 19 * * 1-5 root /usr/sbin/shutdown -h now" > /etc/cron.d/instance-shutdown
EOF
: ""
}
# Cost management using AWS Budget
resource "aws_budgets_budget" "monthly" {
name = "${var.project_name}-monthly-budget"
budget_type = "COST"
limit_amount = var.monthly_budget_limit
limit_unit = "USD"
time_period_start = "2023-01-01_00:00"
time_unit = "MONTHLY"
notification {
comparison_operator = "GREATER_THAN"
threshold = 80
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_email_addresses = var.budget_notification_emails
}
cost_filter {
name = "TagKeyValue"
values = [
"user:Project$${var.project_name}"
]
}
}HCLPerformance Monitoring:
# AWS CloudWatch setup
resource "aws_cloudwatch_dashboard" "main" {
dashboard_name = "infrastructure-dashboard"
dashboard_body = jsonencode({
widgets = [
{
type = "metric"
x = 0
y = 0
width = 12
height = 6
properties = {
metrics = [
["AWS/EC2", "CPUUtilization", "InstanceId", aws_instance.web[0].id],
["AWS/EC2", "CPUUtilization", "InstanceId", aws_instance.web[1].id]
]
period = 300
stat = "Average"
region = var.region
title = "EC2 CPU Utilization"
}
},
{
type = "metric"
x = 12
y = 0
width = 12
height = 6
properties = {
metrics = [
["AWS/RDS", "CPUUtilization", "DBInstanceIdentifier", aws_db_instance.database.id]
]
period = 300
stat = "Average"
region = var.region
title = "RDS CPU Utilization"
}
}
]
})
}
# CloudWatch alarms
resource "aws_cloudwatch_metric_alarm" "high_cpu" {
alarm_name = "ec2-high-cpu"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 2
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
alarm_description = "This alarm monitors EC2 CPU utilization"
dimensions = {
InstanceId = aws_instance.web[0].id
}
alarm_actions = [aws_sns_topic.alerts.arn]
}HCLDisaster Recovery Strategies:
# Cross-region data replication with S3
resource "aws_s3_bucket" "primary" {
bucket = "primary-data-bucket"
}
resource "aws_s3_bucket" "replica" {
provider = aws.dr_region
bucket = "replica-data-bucket"
}
resource "aws_s3_bucket_versioning" "primary" {
bucket = aws_s3_bucket.primary.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_versioning" "replica" {
provider = aws.dr_region
bucket = aws_s3_bucket.replica.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_replication_configuration" "replication" {
bucket = aws_s3_bucket.primary.id
role = aws_iam_role.replication.arn
rule {
id = "data-replication"
status = "Enabled"
destination {
bucket = aws_s3_bucket.replica.arn
storage_class = "STANDARD"
}
}
}
# Database disaster recovery setup
resource "aws_rds_cluster" "primary" {
cluster_identifier = "aurora-primary"
engine = "aurora-mysql"
database_name = "mydb"
master_username = var.db_username
master_password = var.db_password
backup_retention_period = 7
preferred_backup_window = "07:00-09:00"
enabled_cloudwatch_logs_exports = ["audit", "error", "general"]
}
resource "aws_rds_cluster" "replica" {
provider = aws.dr_region
cluster_identifier = "aurora-replica"
engine = "aurora-mysql"
replication_source_identifier = aws_rds_cluster.primary.arn
source_region = var.primary_region
backup_retention_period = 7
depends_on = [aws_rds_cluster.primary]
}HCLComprehensive Logging:
# Centralized logging with CloudWatch Logs
resource "aws_cloudwatch_log_group" "app_logs" {
name = "/app/production"
retention_in_days = 30
tags = {
Environment = "production"
Application = "web-app"
}
}
# Log subscription filter to Lambda for processing
resource "aws_cloudwatch_log_subscription_filter" "log_processor" {
name = "log-processor-filter"
log_group_name = aws_cloudwatch_log_group.app_logs.name
filter_pattern = "ERROR"
destination_arn = aws_lambda_function.log_processor.arn
depends_on = [
aws_lambda_permission.cloudwatch_logs
]
}
resource "aws_lambda_function" "log_processor" {
function_name = "log-processor"
runtime = "python3.9"
handler = "index.handler"
filename = "lambda_function.zip"
role = aws_iam_role.lambda_role.arn
environment {
variables = {
NOTIFICATION_TOPIC = aws_sns_topic.alerts.arn
}
}
}
resource "aws_lambda_permission" "cloudwatch_logs" {
statement_id = "AllowExecutionFromCloudWatchLogs"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.log_processor.function_name
principal = "logs.amazonaws.com"
source_arn = "${aws_cloudwatch_log_group.app_logs.arn}:*"
}HCLPart V: Advanced Topics
Chapter 14: Custom Providers and Extensions
Building Custom Providers:
// Example structure for a custom provider in Go
package main
import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"
)
func main() {
plugin.Serve(&plugin.ServeOpts{
ProviderFunc: Provider,
})
}
// Provider returns a terraform.ResourceProvider
func Provider() *schema.Provider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
"api_key": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
DefaultFunc: schema.EnvDefaultFunc("CUSTOM_API_KEY", nil),
},
"api_url": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("CUSTOM_API_URL", nil),
},
},
ResourcesMap: map[string]*schema.Resource{
"custom_resource": resourceCustomResource(),
},
DataSourcesMap: map[string]*schema.Resource{
"custom_data": dataSourceCustomData(),
},
ConfigureFunc: providerConfigure,
}
}
func resourceCustomResource() *schema.Resource {
return &schema.Resource{
Create: resourceCustomResourceCreate,
Read: resourceCustomResourceRead,
Update: resourceCustomResourceUpdate,
Delete: resourceCustomResourceDelete,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"property": {
Type: schema.TypeString,
Optional: true,
},
},
}
}
// Implementation of CRUD functions
func resourceCustomResourceCreate(d *schema.ResourceData, meta interface{}) error {
// Create resource implementation
return nil
}
func resourceCustomResourceRead(d *schema.ResourceData, meta interface{}) error {
// Read resource implementation
return nil
}
func resourceCustomResourceUpdate(d *schema.ResourceData, meta interface{}) error {
// Update resource implementation
return nil
}
func resourceCustomResourceDelete(d *schema.ResourceData, meta interface{}) error {
// Delete resource implementation
return nil
}
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
// Configure API client
apiKey := d.Get("api_key").(string)
apiURL := d.Get("api_url").(string)
// Initialize and return client
return NewClient(apiKey, apiURL), nil
}GoUsing and Creating Provider Plugins:
# Using a custom provider
terraform {
required_providers {
custom = {
source = "example.com/myorg/custom"
version = "1.0.0"
}
}
}
provider "custom" {
api_key = var.api_key
api_url = var.api_url
}
resource "custom_resource" "example" {
name = "example-resource"
property = "value"
}HCL#!/bin/bash
# Build and install custom provider
# Build the provider
cd terraform-provider-custom
go build -o terraform-provider-custom
# Install the provider in a local dev environment
mkdir -p ~/.terraform.d/plugins/example.com/myorg/custom/1.0.0/linux_amd64/
cp terraform-provider-custom ~/.terraform.d/plugins/example.com/myorg/custom/1.0.0/linux_amd64/BashExtending Terraform’s Functionality:
# External data source for custom API integration
data "external" "api_data" {
program = ["python", "${path.module}/scripts/fetch_api_data.py"]
query = {
endpoint = "users"
filter = "active=true"
}
}
# Use the data
resource "aws_instance" "user_instances" {
count = length(jsondecode(data.external.api_data.result.users))
ami = var.ami_id
instance_type = "t3.micro"
tags = {
Name = "instance-for-${jsondecode(data.external.api_data.result.users)[count.index].name}"
Email = jsondecode(data.external.api_data.result.users)[count.index].email
}
}HCL#!/usr/bin/env python3
# fetch_api_data.py
import json
import sys
import requests
def main():
# Parse input from Terraform
stdin = sys.stdin.read()
query = json.loads(stdin)
# Make API request
response = requests.get(
f"https://api.example.com/{query['endpoint']}?{query['filter']}",
headers={
"Authorization": f"Bearer {os.environ['API_TOKEN']}"
}
)
if response.status_code == 200:
# Return JSON result to Terraform
print(json.dumps({"users": response.json()}))
else:
sys.exit(1)
if __name__ == "__main__":
main()PythonContributing to the Terraform Ecosystem:
# Use Terraform modules to create reusable infrastructure components
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "3.14.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
tags = {
Terraform = "true"
Environment = "production"
}
}HCLChapter 15: Enterprise Patterns and Case Studies
Financial Services Implementation:
flowchart TD
A[Core Banking Network] --> B[Secure Transit Gateway]
B --> C[Product VPC]
B --> D[Data Platform VPC]
B --> E[Security VPC]
C --> F[Application Layer]
F --> G[Database Layer]
D --> H[Data Lake]
D --> I[Analytics Cluster]
E --> J[Security Monitoring]
E --> K[Compliance Reporting]# Example of a financial services infrastructure with security controls
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "3.14.0"
name = "financial-services-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
enable_vpn_gateway = true
# Enhanced security features
enable_flow_log = true
flow_log_destination_type = "s3"
flow_log_destination_arn = aws_s3_bucket.flow_logs.arn
flow_log_traffic_type = "ALL"
flow_log_max_aggregation_interval = 60
# Additional security groups
manage_default_security_group = true
default_security_group_ingress = []
default_security_group_egress = []
tags = {
Environment = "Production"
Compliance = "PCI-DSS,SOC2"
}
}
# Security monitoring
resource "aws_securityhub_account" "main" {}
resource "aws_securityhub_standards_subscription" "pci_dss" {
standards_arn = "arn:aws:securityhub:us-east-1::standards/pci-dss/v/3.2.1"
depends_on = [aws_securityhub_account.main]
}
resource "aws_securityhub_standards_subscription" "cis" {
standards_arn = "arn:aws:securityhub:us-east-1::standards/cis-aws-foundations-benchmark/v/1.2.0"
depends_on = [aws_securityhub_account.main]
}HCLHealthcare Compliance Scenarios:
# Healthcare infrastructure with HIPAA compliance
# Network isolation for PHI data
resource "aws_vpc" "hipaa_compliant" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "hipaa-vpc"
Environment = "Production"
Compliance = "HIPAA"
}
}
# Subnet tiers with specific access controls
resource "aws_subnet" "phi_data" {
count = 3
vpc_id = aws_vpc.hipaa_compliant.id
cidr_block = "10.0.${count.index + 1}.0/24"
availability_zone = element(["us-east-1a", "us-east-1b", "us-east-1c"], count.index)
tags = {
Name = "phi-data-${count.index + 1}"
DataType = "PHI"
Environment = "Production"
}
}
# Encryption for data at rest
resource "aws_kms_key" "phi_encryption" {
description = "Key for PHI data encryption"
deletion_window_in_days = 30
enable_key_rotation = true
tags = {
Name = "phi-encryption-key"
Environment = "Production"
Compliance = "HIPAA"
}
}
# RDS database with encryption and audit logging
resource "aws_db_instance" "hipaa_database" {
allocated_storage = 100
engine = "postgres"
engine_version = "13.4"
instance_class = "db.m5.large"
name = "hipaadb"
username = var.db_username
password = var.db_password
storage_encrypted = true
kms_key_id = aws_kms_key.phi_encryption.arn
multi_az = true
backup_retention_period = 30
backup_window = "03:00-05:00"
maintenance_window = "Sun:00:00-Sun:03:00"
enabled_cloudwatch_logs_exports = [
"postgresql",
"upgrade"
]
subnet_group_name = aws_db_subnet_group.hipaa.name
parameter_group_name = aws_db_parameter_group.hipaa.name
tags = {
Name = "hipaa-database"
Environment = "Production"
Compliance = "HIPAA"
}
}
# Audit logging for compliance
resource "aws_cloudtrail" "hipaa_audit" {
name = "hipaa-audit-trail"
s3_bucket_name = aws_s3_bucket.audit_logs.id
s3_key_prefix = "trail"
include_global_service_events = true
is_multi_region_trail = true
enable_log_file_validation = true
kms_key_id = aws_kms_key.audit_logs.arn
tags = {
Name = "hipaa-audit-trail"
Environment = "Production"
Compliance = "HIPAA"
}
}HCLScaling for Large Enterprises:
# Example of a multi-account AWS setup using Organizations
provider "aws" {
region = "us-east-1"
alias = "org_master"
}
resource "aws_organizations_organization" "org" {
provider = aws.org_master
feature_set = "ALL"
aws_service_access_principals = [
"cloudtrail.amazonaws.com",
"config.amazonaws.com",
"sso.amazonaws.com"
]
enabled_policy_types = [
"SERVICE_CONTROL_POLICY",
"TAG_POLICY"
]
}
# Organizational Units structure
resource "aws_organizations_organizational_unit" "security" {
provider = aws.org_master
name = "Security"
parent_id = aws_organizations_organization.org.roots[0].id
}
resource "aws_organizations_organizational_unit" "infrastructure" {
provider = aws.org_master
name = "Infrastructure"
parent_id = aws_organizations_organization.org.roots[0].id
}
resource "aws_organizations_organizational_unit" "workloads" {
provider = aws.org_master
name = "Workloads"
parent_id = aws_organizations_organization.org.roots[0].id
}
# Service Control Policies
resource "aws_organizations_policy" "deny_root_user" {
provider = aws.org_master
name = "DenyRootUser"
content = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyRootUserAccessExceptCloudtrail",
"Effect": "Deny",
"NotAction": [
"cloudtrail:*"
],
"Resource": "*",
"Condition": {
"StringLike": {
"aws:PrincipalArn": "arn:aws:iam::*:root"
}
}
}
]
}
EOF
}
# Attach policy to OUs
resource "aws_organizations_policy_attachment" "deny_root_to_workloads" {
provider = aws.org_master
policy_id = aws_organizations_policy.deny_root_user.id
target_id = aws_organizations_organizational_unit.workloads.id
}HCLMulti-Region, Multi-Account Strategies:
flowchart TD
A[Organization] --> B[Security Account]
A --> C[Networking Account]
A --> D[Development OU]
A --> E[Production OU]
D --> F[Dev Account US]
D --> G[Dev Account EU]
E --> H[Prod Account US]
E --> I[Prod Account EU]
C --> J[Transit Gateway]
J --> F
J --> G
J --> H
J --> I# Cross-region, cross-account resource sharing
# In networking account
resource "aws_ec2_transit_gateway" "tgw" {
description = "Enterprise Transit Gateway"
auto_accept_shared_attachments = "enable"
default_route_table_association = "enable"
default_route_table_propagation = "enable"
tags = {
Name = "enterprise-tgw"
}
}
resource "aws_ram_resource_share" "tgw_share" {
name = "enterprise-tgw-share"
allow_external_principals = false
tags = {
Name = "tgw-resource-share"
}
}
resource "aws_ram_resource_association" "tgw_share_association" {
resource_share_arn = aws_ram_resource_share.tgw_share.arn
resource_arn = aws_ec2_transit_gateway.tgw.arn
}
# In workload account with different provider configuration
provider "aws" {
alias = "workload"
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::${var.workload_account_id}:role/OrganizationAccountAccessRole"
session_name = "terraform-cross-account"
}
}
resource "aws_ec2_transit_gateway_vpc_attachment" "workload_attachment" {
provider = aws.workload
subnet_ids = var.workload_subnet_ids
transit_gateway_id = aws_ec2_transit_gateway.tgw.id
vpc_id = var.workload_vpc_id
tags = {
Name = "workload-tgw-attachment"
}
}HCLChapter 16: Future Trends in Infrastructure Management
Terraform Cloud and Terraform Enterprise:
# Using Terraform Cloud remote operations
terraform {
cloud {
organization = "acme-corp"
workspaces {
name = "production-infrastructure"
}
}
}
# Environment-specific variables managed in Terraform Cloud
variable "environment" {
description = "Environment name"
type = string
}
# Remote state data sources for cross-workspace references
data "terraform_remote_state" "network" {
backend = "remote"
config = {
organization = "acme-corp"
workspaces = {
name = "network-infrastructure"
}
}
}
# Use outputs from network workspace
resource "aws_security_group" "app" {
vpc_id = data.terraform_remote_state.network.outputs.vpc_id
# Security group rules
}HCLPolicy as Code Evolution:
# OPA (Open Policy Agent) policies as Terraform artifacts
resource "aws_s3_bucket_object" "policy" {
bucket = aws_s3_bucket.policies.id
key = "terraform/aws_instance_policy.rego"
content = <<EOF
package terraform.aws_instance
import input.tfplan as tfplan
allowed_instance_types = ["t3.micro", "t3.small", "t3.medium"]
deny[msg] {
r := tfplan.resource_changes[_]
r.type == "aws_instance"
not contains(allowed_instance_types, r.change.after.instance_type)
msg := sprintf("Instance type '%s' is not allowed", [r.change.after.instance_type])
}
EOF
}
# CI/CD integration for policy enforcement
resource "null_resource" "policy_check" {
triggers = {
policy_hash = filemd5("${path.module}/policies/aws_instance_policy.rego")
}
provisioner "local-exec" {
command = <<EOF
conftest test terraform.plan.json \
--policy ./policies/ \
--namespace terraform \
--no-color
EOF
}
}HCLGitOps Workflows:
# GitHub workflow for GitOps with Terraform
name: 'Terraform GitOps'
on:
push:
branches:
- main
paths:
- 'environments/**'
pull_request:
branches:
- main
paths:
- 'environments/**'
jobs:
detect-environments:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v3
- name: Find changed environments
id: set-matrix
run: |
CHANGED_DIRS=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep "^environments/" | cut -d/ -f2 | sort -u | jq -R -s -c 'split("\n") | map(select(length > 0))')
echo "matrix=${CHANGED_DIRS}" >> $GITHUB_OUTPUT
terraform:
needs: detect-environments
runs-on: ubuntu-latest
strategy:
matrix:
environment: ${{ fromJson(needs.detect-environments.outputs.matrix) }}
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Terraform Init
run: |
cd environments/${{ matrix.environment }}
terraform init
- name: Terraform Plan
id: plan
run: |
cd environments/${{ matrix.environment }}
terraform plan -no-color
continue-on-error: true
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: |
cd environments/${{ matrix.environment }}
terraform apply -auto-approveYAMLAI and ML in Infrastructure Optimization:
# Using AI/ML-optimized instance types
resource "aws_instance" "ml_workload" {
ami = data.aws_ami.ubuntu.id
instance_type = "g4dn.xlarge" # GPU-optimized
root_block_device {
volume_size = 100
volume_type = "gp3"
iops = 3000
}
tags = {
Name = "ml-training-instance"
}
}
# Integrating with AI services
resource "aws_sagemaker_notebook_instance" "ml_notebook" {
name = "ml-notebook"
role_arn = aws_iam_role.sagemaker.arn
instance_type = "ml.t3.medium"
}
resource "aws_sagemaker_endpoint_configuration" "model_endpoint" {
name = "model-endpoint-config"
production_variants {
variant_name = "variant-1"
model_name = aws_sagemaker_model.model.name
initial_instance_count = 1
instance_type = "ml.m5.large"
}
}
resource "aws_sagemaker_endpoint" "model_endpoint" {
name = "model-endpoint"
endpoint_config_name = aws_sagemaker_endpoint_configuration.model_endpoint.name
}
# Automated scaling based on ML predictions
resource "aws_appautoscaling_target" "ecs_target" {
max_capacity = 10
min_capacity = 1
resource_id = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.main.name}"
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"
}
resource "aws_appautoscaling_scheduled_action" "scale_up_prediction" {
name = "scale-up-prediction"
service_namespace = aws_appautoscaling_target.ecs_target.service_namespace
resource_id = aws_appautoscaling_target.ecs_target.resource_id
scalable_dimension = aws_appautoscaling_target.ecs_target.scalable_dimension
schedule = "cron(0 8 * * ? *)" # Based on ML-predicted peak times
scalable_target_action {
min_capacity = 5
max_capacity = 10
}
}HCLAs infrastructure continues to evolve, Terraform remains a critical tool for creating, managing, and maintaining cloud infrastructure across diverse environments. By implementing modern practices like infrastructure as code, automated testing, and integrating with the broader DevOps ecosystem, organizations can achieve significant improvements in deployment speed, security posture, and operational efficiency.
The future of infrastructure management is heading toward more automated, intelligent, and policy-driven approaches that can adapt to changing business needs while maintaining security and compliance. As Terraform and its ecosystem continue to grow, organizations that embrace these tools and practices will be well-positioned to thrive in an increasingly complex cloud landscape.
Discover more from Altgr Blog
Subscribe to get the latest posts sent to your email.
