/** * Well-Architected Framework Module * Implements all five pillars: Cost, Operations, Performance, Reliability, Security * Cloud for Sovereignty compliant */ terraform { required_version = ">= 1.5.0" required_providers { azurerm = { source = "hashicorp/azurerm" version = "~> 3.0" } } } # Data sources data "azurerm_client_config" "current" {} data "azurerm_subscription" "current" {} # Local values locals { name_prefix = var.name_prefix != "" ? var.name_prefix : "the-order" env_short = var.environment == "production" ? "prod" : var.environment == "staging" ? "stg" : "dev" # Standard tags for cost optimization common_tags = merge(var.tags, { Environment = var.environment Project = "the-order" CostCenter = var.cost_center Owner = var.owner DataClassification = var.data_classification Sovereignty = "required" ManagedBy = "terraform" WellArchitected = "true" }) # Regions for sovereignty allowed_regions = var.allowed_regions != [] ? var.allowed_regions : [ "westeurope", "northeurope", "uksouth", "switzerlandnorth", "norwayeast", "francecentral", "germanywestcentral" ] } # ============================================================================ # COST OPTIMIZATION # ============================================================================ # Budget and cost management resource "azurerm_consumption_budget_subscription" "main" { count = var.enable_cost_management ? 1 : 0 name = "${local.name_prefix}-budget-${local.env_short}" subscription_id = data.azurerm_subscription.current.id amount = var.monthly_budget_amount time_grain = "Monthly" time_period { start_date = formatdate("YYYY-MM-01T00:00:00Z", timestamp()) end_date = timeadd(formatdate("YYYY-MM-01T00:00:00Z", timestamp()), "1y") } notification { enabled = true threshold = 50 operator = "GreaterThan" threshold_type = "Actual" contact_emails = var.budget_alert_emails } notification { enabled = true threshold = 75 operator = "GreaterThan" threshold_type = "Actual" contact_emails = var.budget_alert_emails } notification { enabled = true threshold = 90 operator = "GreaterThan" threshold_type = "Actual" contact_emails = var.budget_alert_emails } notification { enabled = true threshold = 100 operator = "GreaterThan" threshold_type = "Actual" contact_emails = var.budget_alert_emails } } # Cost Management export resource "azurerm_cost_management_export_resource_group" "main" { count = var.enable_cost_management ? 1 : 0 name = "${local.name_prefix}-cost-export-${local.env_short}" resource_group_id = var.resource_group_id recurrence_type = "Monthly" recurrence_period_start_date = formatdate("YYYY-MM-01T00:00:00Z", timestamp()) recurrence_period_end_date = timeadd(formatdate("YYYY-MM-01T00:00:00Z", timestamp()), "1y") export_data_storage_location { container_id = var.cost_export_storage_container_id root_folder_path = "cost-exports" } export_data_options { type = "Usage" time_frame = "MonthToDate" } } # ============================================================================ # OPERATIONAL EXCELLENCE # ============================================================================ # Log Analytics Workspace for centralized logging resource "azurerm_log_analytics_workspace" "main" { name = "${local.name_prefix}-logs-${local.env_short}-${substr(var.region, 0, 6)}" location = var.region resource_group_name = var.resource_group_name sku = "PerGB2018" retention_in_days = var.environment == "production" ? 90 : 30 tags = local.common_tags } # Application Insights for APM resource "azurerm_application_insights" "main" { name = "${local.name_prefix}-appinsights-${local.env_short}-${substr(var.region, 0, 6)}" location = var.region resource_group_name = var.resource_group_name application_type = "web" workspace_id = azurerm_log_analytics_workspace.main.id tags = local.common_tags } # Automation Account for runbooks resource "azurerm_automation_account" "main" { count = var.enable_automation ? 1 : 0 name = "${local.name_prefix}-automation-${local.env_short}-${substr(var.region, 0, 6)}" location = var.region resource_group_name = var.resource_group_name sku_name = "Basic" identity { type = "SystemAssigned" } tags = local.common_tags } # ============================================================================ # PERFORMANCE EFFICIENCY # ============================================================================ # Azure Front Door for global load balancing and CDN resource "azurerm_front_door" "main" { count = var.enable_front_door ? 1 : 0 name = "${local.name_prefix}-fd-${local.env_short}" resource_group_name = var.resource_group_name location = "Global" routing_rule { name = "default-rule" accepted_protocols = ["Https"] patterns_to_match = ["/*"] frontend_endpoints = ["${local.name_prefix}-fd-${local.env_short}"] forwarding_configuration { forwarding_protocol = "HttpsOnly" backend_pool_name = "default-backend" } } backend_pool_load_balancing { name = "default-load-balancer" } backend_pool_health_probe { name = "default-health-probe" } backend_pool { name = "default-backend" backend { host_header = var.backend_host_header address = var.backend_address http_port = 80 https_port = 443 } load_balancing_name = "default-load-balancer" health_probe_name = "default-health-probe" } frontend_endpoint { name = "${local.name_prefix}-fd-${local.env_short}" host_name = "${local.name_prefix}-fd-${local.env_short}.azurefd.net" } tags = local.common_tags } # Redis Cache for application caching resource "azurerm_redis_cache" "main" { count = var.enable_redis_cache ? 1 : 0 name = "${local.name_prefix}-redis-${local.env_short}-${substr(var.region, 0, 6)}" location = var.region resource_group_name = var.resource_group_name capacity = var.redis_capacity family = var.redis_family sku_name = "${var.redis_family}${var.redis_capacity}" enable_non_ssl_port = false minimum_tls_version = "1.2" redis_configuration { maxmemory_reserved = 2 maxmemory_delta = 2 maxmemory_policy = "allkeys-lru" } tags = local.common_tags } # ============================================================================ # RELIABILITY # ============================================================================ # Recovery Services Vault for backups resource "azurerm_recovery_services_vault" "main" { count = var.enable_backup ? 1 : 0 name = "${local.name_prefix}-rsv-${local.env_short}-${substr(var.region, 0, 6)}" location = var.region resource_group_name = var.resource_group_name sku = "Standard" soft_delete_enabled = true identity { type = "SystemAssigned" } tags = local.common_tags } # Backup policy resource "azurerm_backup_policy_vm" "main" { count = var.enable_backup ? 1 : 0 name = "${local.name_prefix}-backup-policy-${local.env_short}" resource_group_name = var.resource_group_name recovery_vault_name = azurerm_recovery_services_vault.main[0].name timezone = "UTC" backup { frequency = "Daily" time = "23:00" } retention_daily { count = var.environment == "production" ? 30 : 7 } retention_weekly { count = var.environment == "production" ? 12 : 4 weekdays = ["Sunday"] } retention_monthly { count = var.environment == "production" ? 12 : 3 months = ["January", "July"] weekdays = ["Sunday"] weeks = ["First"] } } # ============================================================================ # SECURITY # ============================================================================ # Key Vault for secrets management (if not already created) resource "azurerm_key_vault" "main" { count = var.create_key_vault ? 1 : 0 name = "${local.name_prefix}-kv-${local.env_short}-${substr(var.region, 0, 6)}" location = var.region resource_group_name = var.resource_group_name tenant_id = data.azurerm_client_config.current.tenant_id sku_name = "premium" # Network ACLs - Private endpoint only network_acls { default_action = "Deny" bypass = "AzureServices" } # Enable soft delete and purge protection soft_delete_retention_days = 90 purge_protection_enabled = var.environment == "production" tags = merge(local.common_tags, { Purpose = "SecretsManagement" }) } # Microsoft Defender for Cloud resource "azurerm_security_center_subscription_pricing" "main" { count = var.enable_defender ? 1 : 0 tier = "Standard" subplan = "P2" resource_type = "VirtualMachines" } # DDoS Protection Plan resource "azurerm_network_ddos_protection_plan" "main" { count = var.enable_ddos_protection ? 1 : 0 name = "${local.name_prefix}-ddos-${local.env_short}-${substr(var.region, 0, 6)}" location = var.region resource_group_name = var.resource_group_name tags = local.common_tags } # ============================================================================ # CLOUD FOR SOVEREIGNTY # ============================================================================ # Azure Policy for data residency enforcement resource "azurerm_policy_definition" "data_residency" { count = var.enable_sovereignty_policies ? 1 : 0 name = "${local.name_prefix}-data-residency-${local.env_short}" policy_type = "Custom" mode = "All" display_name = "Enforce Data Residency - ${var.environment}" policy_rule = jsonencode({ if = { allOf = [ { field = "location" notIn = local.allowed_regions } ] } then = { effect = "deny" } }) metadata = jsonencode({ category = "Sovereignty" }) } # Policy assignment resource "azurerm_policy_assignment" "data_residency" { count = var.enable_sovereignty_policies ? 1 : 0 name = "${local.name_prefix}-data-residency-assignment-${local.env_short}" scope = var.management_group_id != "" ? var.management_group_id : data.azurerm_subscription.current.id policy_definition_id = azurerm_policy_definition.data_residency[0].id display_name = "Enforce Data Residency - ${var.environment}" identity { type = "SystemAssigned" } } # Outputs output "log_analytics_workspace_id" { value = azurerm_log_analytics_workspace.main.id description = "Log Analytics Workspace ID" } output "application_insights_instrumentation_key" { value = azurerm_application_insights.main.instrumentation_key sensitive = true description = "Application Insights Instrumentation Key" } output "redis_cache_hostname" { value = var.enable_redis_cache ? azurerm_redis_cache.main[0].hostname : null description = "Redis Cache Hostname" } output "key_vault_uri" { value = var.create_key_vault ? azurerm_key_vault.main[0].vault_uri : null description = "Key Vault URI" }