Azure Scenarios
This guide provides practical deployment scenarios for Azure using Terraform, incorporating modern best practices and patterns.
Landing Zone Deployment
A secure, scalable Azure landing zone implementation:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.75.0"
}
}
backend "azurerm" {}
}
module "landing_zone" {
source = "./modules/landing-zone"
tenant_id = var.tenant_id
subscription_id = var.subscription_id
location = var.primary_location
network_config = {
hub_vnet_cidr = "10.0.0.0/16"
spoke_vnet_cidr = "10.1.0.0/16"
enable_vwan = true
enable_firewall = true
enable_bastion = true
}
security_config = {
enable_defender = true
enable_sentinel = true
enable_private_links = true
enable_policy = true
}
governance_config = {
resource_tags = local.common_tags
enable_cost_management = true
enable_resource_locks = true
}
}
Multi-Region Active-Active Architecture
Deploy highly available services across multiple Azure regions:
locals {
regions = {
primary = {
location = "westeurope"
cidr = "10.1.0.0/16"
}
secondary = {
location = "northeurope"
cidr = "10.2.0.0/16"
}
}
}
module "traffic_manager" {
source = "./modules/traffic-manager"
profile_name = "app-tm-profile"
endpoints = [
{
name = "primary"
target = module.primary_region.app_service_fqdn
priority = 1
},
{
name = "secondary"
target = module.secondary_region.app_service_fqdn
priority = 2
}
]
}
module "primary_region" {
source = "./modules/region"
location = local.regions.primary.location
vnet_cidr = local.regions.primary.cidr
app_service_config = {
sku = "P1v3"
zone_redundant = true
auto_scale = true
}
}
module "secondary_region" {
source = "./modules/region"
location = local.regions.secondary.location
vnet_cidr = local.regions.secondary.cidr
app_service_config = {
sku = "P1v3"
zone_redundant = true
auto_scale = true
}
}
Secure AKS Deployment
Deploy a production-ready AKS cluster with security best practices:
module "aks_cluster" {
source = "./modules/aks"
cluster_name = "prod-aks"
location = var.location
network_config = {
vnet_cidr = "10.0.0.0/16"
pod_cidr = "10.244.0.0/16"
service_cidr = "10.245.0.0/16"
enable_network_policy = true
}
security_config = {
enable_azure_policy = true
enable_pod_security = true
enable_workload_identity = true
enable_defender = true
}
node_pools = {
system = {
vm_size = "Standard_D4s_v5"
node_count = 3
zones = [1, 2, 3]
}
user = {
vm_size = "Standard_D8s_v5"
node_count = 5
zones = [1, 2, 3]
}
}
addons = {
azure_policy = true
azure_key_vault_secrets_provider = true
open_service_mesh = true
}
}
# Private ACR with Managed Identity access
module "container_registry" {
source = "./modules/acr"
name = "prodacr"
sku = "Premium"
enable_private_link = true
allowed_subnets = [module.aks_cluster.subnet_id]
}
# Key Vault for secrets management
module "key_vault" {
source = "./modules/key-vault"
name = "prod-kv"
enable_private_link = true
allowed_subnets = [module.aks_cluster.subnet_id]
access_policies = {
aks = {
object_id = module.aks_cluster.kubelet_identity_object_id
key_permissions = ["Get", "List"]
secret_permissions = ["Get", "List"]
}
}
}
Azure Front Door with Web Apps
Deploy globally distributed web applications:
module "front_door" {
source = "./modules/front-door"
name = "global-web-app"
frontend_endpoints = {
default = {
host_name = "app.example.com"
waf_policy_id = module.waf_policy.id
}
}
routing_rules = {
default = {
accepted_protocols = ["Https"]
patterns_to_match = ["/*"]
backend_pool_name = "app-backend"
}
}
backend_pools = {
app-backend = {
backends = [
{
address = module.webapp_eu.default_site_hostname
weight = 100
enabled = true
},
{
address = module.webapp_us.default_site_hostname
weight = 100
enabled = true
}
]
health_probe_settings = {
protocol = "Https"
path = "/health"
}
}
}
}
module "waf_policy" {
source = "./modules/waf-policy"
name = "global-waf"
mode = "Prevention"
managed_rules = {
enable_core_ruleset = true
enable_php_ruleset = true
}
custom_rules = {
rate_limiting = {
priority = 1
rule_type = "RateLimiting"
match_conditions = {
match_variables = [{
variable_name = "RemoteAddr"
}]
}
rate_limit_duration = "MINUTE"
rate_limit_threshold = 100
}
}
}
Azure Database Deployment
Deploy a highly available database with geo-replication:
module "database" {
source = "./modules/azure-sql"
name = "prod-sql"
location = var.primary_location
dr_location = var.secondary_location
networking = {
enable_private_endpoint = true
allowed_subnets = var.app_subnet_ids
}
high_availability = {
enable_zone_redundancy = true
enable_geo_replication = true
failover_group_name = "prod-sql-fog"
}
security = {
enable_auditing = true
enable_threat_detection = true
enable_data_encryption = true
}
performance = {
sku_name = "GP_Gen5_8"
max_size_gb = 256
auto_pause_delay = 60
min_capacity = 4
}
maintenance = {
window_start_hour = 2
window_duration_hrs = 4
}
}
Best Practices for Azure Deployments
1. Resource Naming and Tagging
locals {
required_tags = {
Environment = var.environment
Project = var.project_name
Owner = var.team_name
CostCenter = var.cost_center
CreatedBy = "Terraform"
}
}
resource "azurerm_resource_group" "example" {
name = format("%s-%s-%s-rg", var.prefix, var.environment, var.purpose)
location = var.location
tags = local.required_tags
}
2. Network Security
module "network_security" {
source = "./modules/network-security"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
network_watcher_enabled = true
ddos_protection_enabled = true
flow_logs_enabled = true
flow_logs_retention = 30
nsg_rules = {
deny_all_inbound = {
priority = 4096
direction = "Inbound"
access = "Deny"
protocol = "*"
source_port_range = "*"
destination_port_range = "*"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
}
3. Monitoring and Alerting
module "monitoring" {
source = "./modules/monitoring"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
log_analytics_workspace = {
sku = "PerGB2018"
retention_in_days = 30
}
action_groups = {
critical = {
short_name = "critical"
email_receivers = [{
name = "ops-team"
email_address = "ops@example.com"
}]
}
}
metric_alerts = {
high_cpu = {
name = "high-cpu-usage"
description = "Alert when CPU usage is high"
metric_namespace = "Microsoft.Compute/virtualMachines"
metric_name = "Percentage CPU"
aggregation = "Average"
operator = "GreaterThan"
threshold = 90
window_size = "PT5M"
frequency = "PT1M"
severity = 1
action_group_id = module.monitoring.action_group_ids["critical"]
}
}
}
CI/CD Pipeline Integration
Azure DevOps Pipeline
trigger:
branches:
include:
- main
paths:
include:
- terraform/**
variables:
- group: terraform-variables
pool:
vmImage: 'ubuntu-latest'
stages:
- stage: Validate
jobs:
- job: ValidateAndPlan
steps:
- task: TerraformInstaller@1
inputs:
terraformVersion: 'latest'
- task: TerraformTaskV4@4
inputs:
provider: 'azurerm'
command: 'init'
backendServiceArm: 'Azure-Service-Connection'
backendAzureRmResourceGroupName: 'terraform-state-rg'
backendAzureRmStorageAccountName: 'tfstate'
backendAzureRmContainerName: 'tfstate'
backendAzureRmKey: '$(Environment).tfstate'
- task: TerraformTaskV4@4
inputs:
provider: 'azurerm'
command: 'plan'
environmentServiceNameAzureRM: 'Azure-Service-Connection'
- stage: Apply
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- job: ApplyChanges
steps:
- task: TerraformTaskV4@4
inputs:
provider: 'azurerm'
command: 'apply'
environmentServiceNameAzureRM: 'Azure-Service-Connection'
commandOptions: '-auto-approve'
Testing and Validation
Policy Testing
resource "azurerm_policy_definition" "require_tags" {
name = "require-resource-tags"
policy_type = "Custom"
mode = "All"
display_name = "Require specified tags on resources"
metadata = jsonencode({
version = "1.0.0"
category = "Tags"
})
policy_rule = jsonencode({
if = {
allOf = [
{
field = "tags['Environment']"
exists = "false"
},
{
field = "tags['CostCenter']"
exists = "false"
}
]
}
then = {
effect = "deny"
}
})
}
resource "azurerm_policy_assignment" "require_tags" {
name = "require-resource-tags"
scope = data.azurerm_subscription.current.id
policy_definition_id = azurerm_policy_definition.require_tags.id
description = "Requires specified tags on all resources"
display_name = "Require Resource Tags"
parameters = jsonencode({
tagNames = {
value = ["Environment", "CostCenter"]
}
})
}
Last updated