diff --git a/.gitignore b/.gitignore index 9da6ed31..8598e5e0 100644 --- a/.gitignore +++ b/.gitignore @@ -393,3 +393,5 @@ override.tf.json # CodeRush personal settings .DS_Store + +tfplan \ No newline at end of file diff --git a/scenarios/aca-internal/bicep/modules/01-hub/modules/azureFirewall.bicep b/scenarios/aca-internal/bicep/modules/01-hub/modules/azureFirewall.bicep index f463d14b..ae5692f2 100644 --- a/scenarios/aca-internal/bicep/modules/01-hub/modules/azureFirewall.bicep +++ b/scenarios/aca-internal/bicep/modules/01-hub/modules/azureFirewall.bicep @@ -24,7 +24,7 @@ param tags object = {} @description('CIDR of the spoke infrastructure subnet.') param spokeInfraSubnetAddressPrefix string -param azureFirewallSubnetManagementAddressPrefix string +param azureFirewallSubnetManagementAddressPrefix string var applicationRuleCollections = [ { @@ -68,9 +68,9 @@ var applicationRuleCollections = [ spokeInfraSubnetAddressPrefix ] targetFqdns: [ - '*.blob.${environment().suffixes.storage}' + '*.blob.${environment().suffixes.storage}' 'login.microsoft.com' - '*.azurecr.io' //NOTE: for less permisive environment replace wildcard with actual(s) Container Registries + '*.azurecr.io' //NOTE: for less permisive environment replace wildcard with actual(s) Container Registries 'hub.docker.com' 'registry-1.docker.io' 'production.cloudflare.docker.com' @@ -89,9 +89,7 @@ var applicationRuleCollections = [ ] targetFqdns: [ '*.identity.azure.net' - #disable-next-line no-hardcoded-env-urls 'login.microsoftonline.com' - #disable-next-line no-hardcoded-env-urls '*.login.microsoftonline.com' '*.login.microsoft.com' ] @@ -108,8 +106,8 @@ var applicationRuleCollections = [ spokeInfraSubnetAddressPrefix ] targetFqdns: [ - '*${environment().suffixes.keyvaultDns}' //NOTE: for less permisive environment replace wildcard with actual(s) KeyVault - #disable-next-line no-hardcoded-env-urls + '*${environment().suffixes.keyvaultDns}' //NOTE: for less permisive environment replace wildcard with actual(s) KeyVault + #disable-next-line no-hardcoded-env-urls 'login.microsoft.com' ] } @@ -123,9 +121,9 @@ var applicationRuleCollections = [ type: 'allow' } priority: 120 - rules: [ + rules: [ { - fqdnTags: [ ] + fqdnTags: [] targetFqdns: [ 'dc.applicationinsights.azure.com' 'dc.applicationinsights.microsoft.com' @@ -141,7 +139,7 @@ var applicationRuleCollections = [ '*.monitor.azure.com' ] name: 'allow-azure-monitor' - protocols: [ + protocols: [ { port: '443' protocolType: 'HTTPS' @@ -161,19 +159,19 @@ var applicationRuleCollections = [ type: 'allow' } priority: 130 - rules: [ - { + rules: [ + { name: 'allow-developer-services' - fqdnTags: [ ] + fqdnTags: [] targetFqdns: [ 'github.com' '*.github.com' 'ghcr.io' '*.ghcr.io' '*.nuget.org' - '*.blob.${environment().suffixes.storage}' // might replace wildcard with specific FQDN + '*.blob.${environment().suffixes.storage}' // might replace wildcard with specific FQDN '*.table.${environment().suffixes.storage}' // might replace wildcard with specific FQDN - '*.servicebus.windows.net' // might replace wildcard with specific FQDN + '*.servicebus.windows.net' // might replace wildcard with specific FQDN 'githubusercontent.com' '*.githubusercontent.com' 'dev.azure.com' @@ -183,7 +181,7 @@ var applicationRuleCollections = [ 'appservice.azureedge.net' '*.azurewebsites.net' ] - protocols: [ + protocols: [ { port: '443' protocolType: 'HTTPS' @@ -193,11 +191,11 @@ var applicationRuleCollections = [ spokeInfraSubnetAddressPrefix ] } - { + { name: 'allow-certificate-dependencies' - fqdnTags: [ ] + fqdnTags: [] targetFqdns: [ - '*.delivery.mp.microsoft.com' + '*.delivery.mp.microsoft.com' 'ctldl.windowsupdate.com' 'ocsp.msocsp.com' 'oneocsp.microsoft.com' @@ -208,11 +206,11 @@ var applicationRuleCollections = [ '*.symcb.com' '*.d-trust.net' ] - protocols: [ + protocols: [ { port: '80' protocolType: 'HTTP' - } + } { port: '443' protocolType: 'HTTPS' @@ -227,90 +225,89 @@ var applicationRuleCollections = [ } ] -var networkRules = [ - { - name: 'ace-allow-rules' - properties: { - action: { - type: 'allow' - } - priority: 100 - // For more Azure resources (than KeyVault, ACR etc which we use here) you are using with Azure Firewall, - // please refer to the service tags documentation: https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags - rules: [ - { - name: 'ace-general-allow-rule' - protocols: [ - 'Any' - ] - sourceAddresses: [ - spokeInfraSubnetAddressPrefix - ] - destinationAddresses: [ - 'MicrosoftContainerRegistry' //For even less permisive environment, you can point to a specific MCR region, i.e. 'MicrosoftContainerRegistry.Westeurope' - 'AzureFrontDoor.FirstParty' - ] - destinationPorts: [ - '443' - ] - } - { - name: 'ace-acr-allow-rule' - protocols: [ - 'Any' - ] - sourceAddresses: [ - spokeInfraSubnetAddressPrefix - ] - destinationAddresses: [ - 'AzureContainerRegistry' //For even less permisive environment, you can point to a specific ACR region, i.e. 'MicrosoftContainerRegistry.Westeurope' - 'AzureActiveDirectory' - ] - destinationPorts: [ - '443' - ] - } - { - name: 'ace-keyvault-allow-rule' - protocols: [ - 'Any' - ] - sourceAddresses: [ - spokeInfraSubnetAddressPrefix - ] - destinationAddresses: [ - 'AzureKeyVault' //For even less permisive environment, you can point to a specific keyvault region, i.e. 'MicrosoftContainerRegistry.Westeurope' - 'AzureActiveDirectory' - ] - destinationPorts: [ - '443' - ] - } - { - name: 'ace-managedIdentity-allow-rule' - protocols: [ - 'Any' - ] - sourceAddresses: [ - spokeInfraSubnetAddressPrefix - ] - destinationAddresses: [ - 'AzureActiveDirectory' - ] - destinationPorts: [ - '443' - ] - } +var networkRules = [ + { + name: 'ace-allow-rules' + properties: { + action: { + type: 'allow' + } + priority: 100 + // For more Azure resources (than KeyVault, ACR etc which we use here) you are using with Azure Firewall, + // please refer to the service tags documentation: https://learn.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags + rules: [ + { + name: 'ace-general-allow-rule' + protocols: [ + 'Any' + ] + sourceAddresses: [ + spokeInfraSubnetAddressPrefix + ] + destinationAddresses: [ + 'MicrosoftContainerRegistry' //For even less permisive environment, you can point to a specific MCR region, i.e. 'MicrosoftContainerRegistry.Westeurope' + 'AzureFrontDoor.FirstParty' + ] + destinationPorts: [ + '443' ] } - } - ] + { + name: 'ace-acr-allow-rule' + protocols: [ + 'Any' + ] + sourceAddresses: [ + spokeInfraSubnetAddressPrefix + ] + destinationAddresses: [ + 'AzureContainerRegistry' //For even less permisive environment, you can point to a specific ACR region, i.e. 'MicrosoftContainerRegistry.Westeurope' + 'AzureActiveDirectory' + ] + destinationPorts: [ + '443' + ] + } + { + name: 'ace-keyvault-allow-rule' + protocols: [ + 'Any' + ] + sourceAddresses: [ + spokeInfraSubnetAddressPrefix + ] + destinationAddresses: [ + 'AzureKeyVault' //For even less permisive environment, you can point to a specific keyvault region, i.e. 'MicrosoftContainerRegistry.Westeurope' + 'AzureActiveDirectory' + ] + destinationPorts: [ + '443' + ] + } + { + name: 'ace-managedIdentity-allow-rule' + protocols: [ + 'Any' + ] + sourceAddresses: [ + spokeInfraSubnetAddressPrefix + ] + destinationAddresses: [ + 'AzureActiveDirectory' + ] + destinationPorts: [ + '443' + ] + } + ] + } + } +] resource hubVnet 'Microsoft.Network/virtualNetworks@2022-11-01' existing = { name: afwVNetName } - resource fwManagementSubnet 'Microsoft.Network/virtualNetworks/subnets@2020-11-01' = { parent: hubVnet name: 'AzureFirewallManagementSubnet' @@ -340,6 +337,5 @@ module afw '../../../../../shared/bicep/azureFirewalls/main.bicep' = { } } - output afwPrivateIp string = afw.outputs.privateIp output afwId string = afw.outputs.resourceId diff --git a/scenarios/aca-internal/terraform/main.tf b/scenarios/aca-internal/terraform/main.tf index d0a5da03..ecd73267 100644 --- a/scenarios/aca-internal/terraform/main.tf +++ b/scenarios/aca-internal/terraform/main.tf @@ -1,15 +1,17 @@ module "hub" { - source = "./modules/01-hub" - workloadName = var.workloadName - environment = var.environment - hubResourceGroupName = var.hubResourceGroupName - location = var.location - vnetAddressPrefixes = var.hubVnetAddressPrefixes - enableBastion = var.enableBastion - bastionSubnetAddressPrefixes = var.bastionSubnetAddressPrefixes - gatewaySubnetAddressPrefix = var.gatewaySubnetAddressPrefix - azureFirewallSubnetAddressPrefix = var.azureFirewallSubnetAddressPrefix - tags = var.tags + source = "./modules/01-hub" + workloadName = var.workloadName + environment = var.environment + hubResourceGroupName = var.hubResourceGroupName + location = var.location + vnetAddressPrefixes = var.hubVnetAddressPrefixes + enableBastion = var.enableBastion + bastionSubnetAddressPrefixes = var.bastionSubnetAddressPrefixes + gatewaySubnetAddressPrefix = var.gatewaySubnetAddressPrefix + azureFirewallSubnetAddressPrefix = var.azureFirewallSubnetAddressPrefix + azureFirewallSubnetManagementAddressPrefix = var.azureFirewallSubnetManagementAddressPrefix + infraSubnetAddressPrefix = var.infraSubnetAddressPrefix + tags = var.tags } module "spoke" { @@ -30,6 +32,7 @@ module "spoke" { vmLinuxSshAuthorizedKeys = var.vmLinuxSshAuthorizedKeys vmJumpboxOSType = var.vmJumpboxOSType jumpboxSubnetAddressPrefix = var.vmJumpBoxSubnetAddressPrefix + firewallPrivateIp = module.hub.firewallPrivateIp tags = var.tags } @@ -48,6 +51,8 @@ module "supportingServices" { keyVaultPullRoleAssignment = var.keyVaultPullRoleAssignment clientIP = var.clientIP logAnalyticsWorkspaceId = module.spoke.logAnalyticsWorkspaceId + supportingResourceGroupName = var.supportingResourceGroupName + vnetLinks = [ { "name" = module.spoke.spokeVNetName @@ -65,31 +70,33 @@ module "supportingServices" { } module "containerAppsEnvironment" { - source = "./modules/04-container-apps-environment" - workloadName = var.workloadName - environment = var.environment - location = var.location - spokeResourceGroupName = module.spoke.spokeResourceGroupName - hubResourceGroupName = module.hub.hubResourceGroupName - appInsightsName = var.appInsightsName - hubVnetId = module.hub.hubVnetId - spokeVnetId = module.spoke.spokeVNetId - spokeInfraSubnetId = module.spoke.spokeInfraSubnetId + source = "./modules/04-container-apps-environment" + workloadName = var.workloadName + environment = var.environment + location = var.location + spokeResourceGroupName = module.spoke.spokeResourceGroupName + hubResourceGroupName = module.hub.hubResourceGroupName + appInsightsName = var.appInsightsName + hubVnetId = module.hub.hubVnetId + spokeVnetId = module.spoke.spokeVNetId + spokeInfraSubnetId = module.spoke.spokeInfraSubnetId logAnalyticsWorkspaceId = module.spoke.logAnalyticsWorkspaceId + workloadProfiles = var.workloadProfiles + tags = var.tags + vnetLinks = [ { - "name" = module.spoke.spokeVNetName - "vnetId" = module.spoke.spokeVNetId - "resourceGroupName" = module.spoke.spokeResourceGroupName - "registrationEnabled" = false + name = module.spoke.spokeVNetName + vnetId = module.spoke.spokeVNetId + resourceGroupName = module.spoke.spokeResourceGroupName + registrationEnabled = false }, { - "name" = module.hub.hubVnetName - "vnetId" = module.hub.hubVnetId - "resourceGroupName" = module.hub.hubResourceGroupName - "registrationEnabled" = false + name = module.hub.hubVnetName + vnetId = module.hub.hubVnetId + resourceGroupName = module.hub.hubResourceGroupName + registrationEnabled = false }] - tags = var.tags } module "helloWorldApp" { @@ -100,10 +107,10 @@ module "helloWorldApp" { helloWorldContainerAppName = var.helloWorldContainerAppName containerAppsEnvironmentId = module.containerAppsEnvironment.containerAppsEnvironmentId containerRegistryUserAssignedIdentityId = module.supportingServices.containerRegistryUserAssignedIdentityId + workloadProfileName = var.workloadProfiles != [] ? var.workloadProfiles.0.name : "Consumption" tags = var.tags } - # If you would like to deploy an Application Gateway and have provided your IP address for KeyVault access, leave this module uncommented # If you would like to keep your KeyVault private, comment out this module module "applicationGateway" { diff --git a/scenarios/aca-internal/terraform/modules/01-hub/locals.tf b/scenarios/aca-internal/terraform/modules/01-hub/locals.tf new file mode 100644 index 00000000..89e30f5e --- /dev/null +++ b/scenarios/aca-internal/terraform/modules/01-hub/locals.tf @@ -0,0 +1,143 @@ +locals { + firewallPolicyRuleCollectionGroups = [ + { + name = "policy-rules-collection" + priority = "1000" + + application_rule_collections = [ + { + name = "ace-general-allow-rules" + priority = 110 + action = "Allow" + rules = [ + { + name = "ace-general-allow-rules" + source_addresses = ["${var.infraSubnetAddressPrefix}"] + source_ip_groups = [] + destination_fqdns = ["mcr.microsoft.com", "*.data.mcr.microsoft.com", "*.blob.core.windows.net"] //NOTE: If you use ACR the endpoint must be added as well. + protocols = [{ port = "80", type = "Http" }, { port = "443", type = "Https" }] + destination_addresses = [] + }, + { + name = "ace-acr-and-docker-allow-rules" + source_addresses = ["${var.infraSubnetAddressPrefix}"] + source_ip_groups = [] + destination_fqdns = ["*.blob.core.windows.net", "login.microsoft.com", "*.azurecr.io", "hub.docker.com", "registry-1.docker.io", "production.cloudflare.docker.com", "index.docker.io", "auth.docker.io"] + protocols = [{ port = "443", type = "Https" }] + destination_addresses = [] + }, + { + name = "ace-managed-identity-allow-rules" + source_addresses = ["${var.infraSubnetAddressPrefix}"] + source_ip_groups = [] + destination_fqdns = ["*.identity.azure.net", "login.microsoftonline.com", "*.login.microsoftonline.com", "*.login.microsoft.com"] + protocols = [{ port = "443", type = "Https" }] + destination_addresses = [] + }, + { + name = "ace-keyvault-allow-rules" + source_addresses = ["${var.infraSubnetAddressPrefix}"] + source_ip_groups = [] + destination_fqdns = ["*.vault.azure.net", "login.microsoft.com"] + protocols = [{ port = "443", type = "Https" }] + destination_addresses = [] + } + ] + }, + { + name = "allow-azure-monitor" + priority = 120 + action = "Allow" + + rules = [ + { + name = "allow-azure-monitor" + source_addresses = ["${var.infraSubnetAddressPrefix}"] + source_ip_groups = [] + destination_fqdns = ["dc.applicationinsights.azure.com", "dc.applicationinsights.microsoft.com", "dc.services.visualstudio.com", "*.in.applicationinsights.azure.com", "live.applicationinsights.azure.com", "rt.applicationinsights.microsoft.com", "rt.services.visualstudio.com", "*.livediagnostics.monitor.azure.com", "*.monitoring.azure.com", "agent.azureserviceprofiler.net", "*.agent.azureserviceprofiler.net", "*.monitor.azure.com"] + protocols = [{ port = "443", type = "Https" }] + destination_addresses = [] + } + ] + }, + { + name = "allow-core-dev-fqdn" + priority = 130 + action = "Allow" + + rules = [ + { + name = "allow-developer-services" + source_addresses = ["${var.infraSubnetAddressPrefix}"] + source_ip_groups = [] + destination_fqdns = ["github.com", "*.github.com", "ghcr.io", "*.ghcr.io", "*.nuget.org", "*.blob.core.windows.net", "*.table.core.windows.net", "*.servicebus.windows.net", "githubusercontent.com", "*.githubusercontent.com", "dev.azure.com", "portal.azure.com", "*.portal.azure.com", "*.portal.azure.net", "appservice.azureedge.net", "*.azurewebsites.net"] + protocols = [{ port = "443", type = "Https" }] + destination_addresses = [] + }, + { + name = "allow-certificate-dependencies" + source_addresses = ["${var.infraSubnetAddressPrefix}"] + source_ip_groups = [] + destination_fqdns = ["*.delivery.mp.microsoft.com", "ctldl.windowsupdate.com", "ocsp.msocsp.com", "oneocsp.microsoft.com", "crl.microsoft.com", "www.microsoft.com", "*.digicert.com", "*.symantec.com", "*.symcb.com", "*.d-trust.net"] + protocols = [{ port = "80", type = "Http" }, { port = "443", type = "Https" }] + destination_addresses = [] + } + ] + } + ] + + network_rule_collections = [ + { + name = "ace-allow-rules" + priority = 100 + action = "Allow" + + rules = [ + { + name = "ace-general-allow-rule" + source_addresses = ["${var.infraSubnetAddressPrefix}"] + source_ip_groups = [] + destination_ports = ["443"] + destination_addresses = ["MicrosoftContainerRegistry", "AzureFrontDoor.FirstParty"] + destination_ip_groups = [] + destination_fqdns = [] + protocols = ["Any"] + }, + { + name = "ace-acr-allow-rule" + source_addresses = ["${var.infraSubnetAddressPrefix}"] + source_ip_groups = [] + destination_ports = ["443"] + destination_addresses = ["AzureContainerRegistry", "AzureActiveDirectory"] + destination_ip_groups = [] + destination_fqdns = [] + protocols = ["Any"] + }, + { + name = "ace-keyvault-allow-rule" + source_addresses = ["${var.infraSubnetAddressPrefix}"] + source_ip_groups = [] + destination_ports = ["443"] + destination_addresses = ["AzureKeyVault", "AzureActiveDirectory"] + destination_ip_groups = [] + destination_fqdns = [] + protocols = ["Any"] + }, + { + name = "ace-managedIdentity-allow-rule" + source_addresses = ["${var.infraSubnetAddressPrefix}"] + source_ip_groups = [] + destination_ports = ["443"] + destination_addresses = ["AzureActiveDirectory"] + destination_ip_groups = [] + destination_fqdns = [] + protocols = ["Any"] + } + ] + } + ] + + nat_rule_collections = [] + } + ] +} diff --git a/scenarios/aca-internal/terraform/modules/01-hub/main.tf b/scenarios/aca-internal/terraform/modules/01-hub/main.tf index 52e417f9..46d613e1 100644 --- a/scenarios/aca-internal/terraform/modules/01-hub/main.tf +++ b/scenarios/aca-internal/terraform/modules/01-hub/main.tf @@ -26,18 +26,36 @@ module "vnet" { addressSpace = var.vnetAddressPrefixes tags = var.tags ddosProtectionPlanId = var.ddosProtectionPlanId - subnets = [ + subnets = [ { - "name" = var.gatewaySubnetName - "addressPrefixes" = [var.gatewaySubnetAddressPrefix] + name = var.gatewaySubnetName + addressPrefixes = [var.gatewaySubnetAddressPrefix] }, { - "name" = var.azureFirewallSubnetName - "addressPrefixes" = [var.azureFirewallSubnetAddressPrefix] + name = var.azureFirewallSubnetName + addressPrefixes = [var.azureFirewallSubnetAddressPrefix] + }, + { + name = var.azureFirewallSubnetManagementName + addressPrefixes = [var.azureFirewallSubnetManagementAddressPrefix] } ] } +module "firewall" { + source = "../../../../shared/terraform/modules/firewall" + firewallName = module.naming.resourceNames["firewall"] + location = var.location + hubResourceGroupName = azurerm_resource_group.hubResourceGroup.name + subnetFirewallId = module.vnet.subnetIds[var.azureFirewallSubnetName] + subnetFirewallManagementId = module.vnet.subnetIds[var.azureFirewallSubnetManagementName] + publicIpFirewallName = module.naming.resourceNames["firewallPip"] + publicIpFirewallManagementName = module.naming.resourceNames["firewallManagementPip"] + firewallPolicyName = module.naming.resourceNames["firewallPolicy"] + firewallPolicyRuleCollectionGroups = local.firewallPolicyRuleCollectionGroups + tags = var.tags +} + module "bastion" { source = "../../../../shared/terraform/modules/bastion" vnetName = module.vnet.vnetName @@ -49,3 +67,30 @@ module "bastion" { tags = var.tags bastionHostName = module.naming.resourceNames["bastion"] } + +module "logAnalyticsWorkspace" { + source = "../../../../shared/terraform/modules/monitoring/log-analytics" + resourceGroupName = azurerm_resource_group.hubResourceGroup.name + location = var.location + workspaceName = module.naming.resourceNames["logAnalyticsWorkspace"] + tags = var.tags +} + +module "diagnostics" { + source = "../../../../shared/terraform/modules/diagnostics" + logAnalyticsWorkspaceId = module.logAnalyticsWorkspace.workspaceId + resources = [ + { + type = "firewall-hub" + id = module.firewall.firewallId + }, + { + type = "vnet-hub" + id = module.vnet.vnetId + }, + { + type = "bastion" + id = module.bastion.bastionHostId + } + ] +} diff --git a/scenarios/aca-internal/terraform/modules/01-hub/outputs.tf b/scenarios/aca-internal/terraform/modules/01-hub/outputs.tf index 1bb404de..eaee0ee7 100644 --- a/scenarios/aca-internal/terraform/modules/01-hub/outputs.tf +++ b/scenarios/aca-internal/terraform/modules/01-hub/outputs.tf @@ -14,4 +14,9 @@ output "hubVnetName" { output "hubResourceGroupName" { description = "The name of the Hub resource group." value = azurerm_resource_group.hubResourceGroup.name +} + +output "firewallPrivateIp" { + description = "The private IP address of the firewall." + value = module.firewall.firewallPrivateIp } \ No newline at end of file diff --git a/scenarios/aca-internal/terraform/modules/01-hub/providers.tf b/scenarios/aca-internal/terraform/modules/01-hub/providers.tf index b4f31ae0..75043546 100644 --- a/scenarios/aca-internal/terraform/modules/01-hub/providers.tf +++ b/scenarios/aca-internal/terraform/modules/01-hub/providers.tf @@ -3,7 +3,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "~> 3.71.0" + version = ">= 3.90.0" } } required_version = ">= 1.3.4" diff --git a/scenarios/aca-internal/terraform/modules/01-hub/terraform.tfvars b/scenarios/aca-internal/terraform/modules/01-hub/terraform.tfvars index 84be3af1..17652a77 100644 --- a/scenarios/aca-internal/terraform/modules/01-hub/terraform.tfvars +++ b/scenarios/aca-internal/terraform/modules/01-hub/terraform.tfvars @@ -8,4 +8,3 @@ hubResourceGroupName = "" vnetAddressPrefixes = ["10.0.0.0/24"] enableBastion = true bastionSubnetAddressPrefixes = ["10.0.0.128/26"] - diff --git a/scenarios/aca-internal/terraform/modules/01-hub/variables.tf b/scenarios/aca-internal/terraform/modules/01-hub/variables.tf index 1e70d6f2..e13d4c93 100644 --- a/scenarios/aca-internal/terraform/modules/01-hub/variables.tf +++ b/scenarios/aca-internal/terraform/modules/01-hub/variables.tf @@ -45,12 +45,21 @@ variable "gatewaySubnetName" { default = "GatewaySubnet" type = string } - + variable "gatewaySubnetAddressPrefix" {} variable "azureFirewallSubnetName" { default = "AzureFirewallSubnet" - type = string + type = string } variable "azureFirewallSubnetAddressPrefix" {} + +variable "azureFirewallSubnetManagementName" { + default = "AzureFirewallManagementSubnet" # must use this name for Firewall Basic SKU + type = string +} + +variable "azureFirewallSubnetManagementAddressPrefix" {} + +variable "infraSubnetAddressPrefix" {} diff --git a/scenarios/aca-internal/terraform/modules/02-spoke/locals.tf b/scenarios/aca-internal/terraform/modules/02-spoke/locals.tf index 57a0f0ba..957af950 100644 --- a/scenarios/aca-internal/terraform/modules/02-spoke/locals.tf +++ b/scenarios/aca-internal/terraform/modules/02-spoke/locals.tf @@ -5,18 +5,40 @@ locals { hubVnetName = local.hubTokens[8] defaultSubnets = [ - { "name" = var.infraSubnetName - "addressPrefixes" = tolist([var.infraSubnetAddressPrefix]) + { + name = var.infraSubnetName + addressPrefixes = tolist([var.infraSubnetAddressPrefix]) }, { - "name" = var.privateEndpointsSubnetName - "addressPrefixes" = tolist([var.privateEndpointsSubnetAddressPrefix]) + name = var.privateEndpointsSubnetName + addressPrefixes = tolist([var.privateEndpointsSubnetAddressPrefix]) } ] - appGatewayandDefaultSubnets = var.applicationGatewaySubnetAddressPrefix != "" ? concat(local.defaultSubnets, [{ "name" = var.applicationGatewaySubnetName - "addressPrefixes" = tolist([var.applicationGatewaySubnetAddressPrefix]) }]) : local.defaultSubnets + appGatewayandDefaultSubnets = var.applicationGatewaySubnetAddressPrefix != "" ? concat( + local.defaultSubnets, + [{ + name = var.applicationGatewaySubnetName + addressPrefixes = tolist([var.applicationGatewaySubnetAddressPrefix]) + }] + ) : local.defaultSubnets + + spokeSubnets = var.vmJumpboxOSType != "none" ? concat( + local.appGatewayandDefaultSubnets, + [{ + name = var.jumpboxSubnetName + addressPrefixes = tolist([var.jumpboxSubnetAddressPrefix]) + }] + ) : local.appGatewayandDefaultSubnets - spokeSubnets = var.vmJumpboxOSType != "none" ? concat(local.appGatewayandDefaultSubnets, [{ "name" = var.jumpboxSubnetName - "addressPrefixes" = tolist([var.jumpboxSubnetAddressPrefix]) }]) : local.appGatewayandDefaultSubnets -} \ No newline at end of file + subnetDelegations = { + "${var.infraSubnetName}" = { + "Microsoft.App/environments" = { + service_name = "Microsoft.App/environments" + service_actions = [ + "Microsoft.Network/virtualNetworks/subnets/join/action" + ] + } + } + } +} diff --git a/scenarios/aca-internal/terraform/modules/02-spoke/main.tf b/scenarios/aca-internal/terraform/modules/02-spoke/main.tf index e84e9771..7fbe42a9 100644 --- a/scenarios/aca-internal/terraform/modules/02-spoke/main.tf +++ b/scenarios/aca-internal/terraform/modules/02-spoke/main.tf @@ -26,6 +26,7 @@ module "vnet" { addressSpace = var.vnetAddressPrefixes tags = var.tags subnets = local.spokeSubnets + subnetDelegations = local.subnetDelegations } module "nsgContainerAppsEnvironmentNsg" { @@ -33,7 +34,7 @@ module "nsgContainerAppsEnvironmentNsg" { nsgName = module.naming.resourceNames["containerAppsEnvironmentNsg"] location = var.location resourceGroupName = azurerm_resource_group.spokeResourceGroup.name - securityRules = var.containerAppsSecurityRules.default + securityRules = var.containerAppsSecurityRules tags = var.tags } @@ -60,12 +61,12 @@ module "nsgAppGateway" { nsgName = module.naming.resourceNames["applicationGatewayNsg"] location = var.location resourceGroupName = azurerm_resource_group.spokeResourceGroup.name - securityRules = var.appGatewaySecurityRules.default + securityRules = var.appGatewaySecurityRules tags = var.tags } resource "azurerm_subnet_network_security_group_association" "agwSecurityGroupAssociation" { - count = var.applicationGatewaySubnetAddressPrefix != "" ? 1 : 0 + count = var.applicationGatewaySubnetAddressPrefix != "" ? 1 : 0 subnet_id = data.azurerm_subnet.appGatewaySubnet[0].id network_security_group_id = module.nsgAppGateway.nsgId } @@ -79,7 +80,7 @@ module "nsgJumpbox" { } resource "azurerm_subnet_network_security_group_association" "jumpBoxSecurityGroupAssociation" { - count = var.jumpboxSubnetAddressPrefix != "" ? 1 : 0 + count = var.jumpboxSubnetAddressPrefix != "" ? 1 : 0 subnet_id = data.azurerm_subnet.jumpboxSubnet[0].id network_security_group_id = module.nsgJumpbox.nsgId } @@ -102,18 +103,18 @@ module "peeringHubToSpoke" { } module "vm" { - source = "../../../../shared/terraform/modules/vms" - osType = "Linux" - location = var.location - tags = var.tags - nicName = module.naming.resourceNames["vmJumpBoxNic"] - vmName = module.naming.resourceNames["vmJumpBox"] - adminUsername = var.vmAdminUsername - adminPassword = var.vmAdminPassword - resourceGroupName = azurerm_resource_group.spokeResourceGroup.name - size = var.vmSize + source = "../../../../shared/terraform/modules/vms" + osType = "Linux" + location = var.location + tags = var.tags + nicName = module.naming.resourceNames["vmJumpBoxNic"] + vmName = module.naming.resourceNames["vmJumpBox"] + adminUsername = var.vmAdminUsername + adminPassword = var.vmAdminPassword + resourceGroupName = azurerm_resource_group.spokeResourceGroup.name + size = var.vmSize vnetResourceGroupName = azurerm_resource_group.spokeResourceGroup.name - subnetId = data.azurerm_subnet.jumpboxSubnet[0].id + subnetId = data.azurerm_subnet.jumpboxSubnet[0].id } module "logAnalyticsWorkspace" { @@ -125,16 +126,16 @@ module "logAnalyticsWorkspace" { } module "diagnostics" { - source = "../../../../shared/terraform/modules/diagnostics" + source = "../../../../shared/terraform/modules/diagnostics" logAnalyticsWorkspaceId = module.logAnalyticsWorkspace.workspaceId - resources = [ + resources = [ { - "type" = "vnet-spoke" - "id" = module.vnet.vnetId + type = "vnet-spoke" + id = module.vnet.vnetId }, { - "type" = "vm-jumpbox" - "id" = module.vm.vmId + type = "vm-jumpbox" + id = module.vm.vmId } ] } @@ -176,4 +177,21 @@ data "azurerm_subnet" "jumpboxSubnet" { name = var.jumpboxSubnetName resource_group_name = azurerm_resource_group.spokeResourceGroup.name virtual_network_name = module.vnet.vnetName -} \ No newline at end of file +} + +module "routeTable" { + source = "../../../../shared/terraform/modules/networking/route-table" + routeTableName = module.naming.resourceNames["routeTable"] + location = var.location + resourceGroupName = azurerm_resource_group.spokeResourceGroup.name + subnetId = data.azurerm_subnet.infraSubnet.id + tags = var.tags + + routes = [{ + name = "defaultEgressLockdown" + addressPrefix = "0.0.0.0/0" + nextHopType = "VirtualAppliance" + nextHopIpAddress = var.firewallPrivateIp + } + ] +} diff --git a/scenarios/aca-internal/terraform/modules/02-spoke/outputs.tf b/scenarios/aca-internal/terraform/modules/02-spoke/outputs.tf index 356ad65e..12368f15 100644 --- a/scenarios/aca-internal/terraform/modules/02-spoke/outputs.tf +++ b/scenarios/aca-internal/terraform/modules/02-spoke/outputs.tf @@ -36,4 +36,4 @@ output "spokeApplicationGatewaySubnetName" { output "logAnalyticsWorkspaceId" { value = module.logAnalyticsWorkspace.workspaceId -} +} \ No newline at end of file diff --git a/scenarios/aca-internal/terraform/modules/02-spoke/providers.tf b/scenarios/aca-internal/terraform/modules/02-spoke/providers.tf index b4f31ae0..75043546 100644 --- a/scenarios/aca-internal/terraform/modules/02-spoke/providers.tf +++ b/scenarios/aca-internal/terraform/modules/02-spoke/providers.tf @@ -3,7 +3,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "~> 3.71.0" + version = ">= 3.90.0" } } required_version = ">= 1.3.4" diff --git a/scenarios/aca-internal/terraform/modules/02-spoke/variables.tf b/scenarios/aca-internal/terraform/modules/02-spoke/variables.tf index 8b491697..d353ac46 100644 --- a/scenarios/aca-internal/terraform/modules/02-spoke/variables.tf +++ b/scenarios/aca-internal/terraform/modules/02-spoke/variables.tf @@ -65,7 +65,7 @@ variable "applicationGatewaySubnetAddressPrefix" { variable "jumpboxSubnetName" { default = "snet-jumpbox" } - + variable "jumpboxSubnetAddressPrefix" { default = "" } @@ -98,133 +98,137 @@ variable "vmSubnetName" { default = "snet-jumpbox" type = string } - + variable "containerAppsSecurityRules" { default = [ - { - "name" : "Allow_Internal_AKS_Connection_Between_Nodes_And_Control_Plane_UDP", - "description" : "internal AKS secure connection between underlying nodes and control plane..", - "protocol" : "Udp", - "sourceAddressPrefix" : "VirtualNetwork", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "AzureCloud.eastus", - "destinationPortRanges" : ["1194"], - "access" : "Allow", - "priority" : 100, - "direction" : "Outbound" - }, - { - "name" : "Allow_Internal_AKS_Connection_Between_Nodes_And_Control_Plane_TCP", - "description" : "internal AKS secure connection between underlying nodes and control plane..", - "protocol" : "Tcp", - "sourceAddressPrefix" : "VirtualNetwork", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "AzureCloud.eastus", - "destinationPortRanges" : ["9000"], - "access" : "Allow", - "priority" : 110, - "direction" : "Outbound" - }, - { - "name" : "Allow_Azure_Monitor", - "description" : "Allows outbound calls to Azure Monitor.", - "protocol" : "Tcp", - "sourceAddressPrefix" : "VirtualNetwork", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "AzureCloud.eastus", - "destinationPortRanges" : ["443"], - "access" : "Allow", - "priority" : 120, - "direction" : "Outbound" - }, - { - "name" : "Allow_Outbound_443", - "description" : "Allowing all outbound on port 443 provides a way to allow all FQDN based outbound dependencies that don't have a static IP", - "protocol" : "Tcp", - "sourceAddressPrefix" : "VirtualNetwork", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["443"], - "access" : "Allow", - "priority" : 130, - "direction" : "Outbound" - }, - { - "name" : "Allow_NTP_Server", - "description" : "NTP server", - "protocol" : "Udp", - "sourceAddressPrefix" : "VirtualNetwork", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["123"], - "access" : "Allow", - "priority" : 140, - "direction" : "Outbound" - }, - { - "name" : "Allow_Container_Apps_control_plane", - "description" : "Container Apps control plane", - "protocol" : "Tcp", - "sourceAddressPrefix" : "VirtualNetwork", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["5671", "5672"], - "access" : "Allow", - "priority" : 150, - "direction" : "Outbound" - } -] + { + "name" : "Allow_Internal_AKS_Connection_Between_Nodes_And_Control_Plane_UDP", + "description" : "internal AKS secure connection between underlying nodes and control plane..", + "protocol" : "Udp", + "sourceAddressPrefix" : "VirtualNetwork", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "AzureCloud.eastus", + "destinationPortRanges" : ["1194"], + "access" : "Allow", + "priority" : 100, + "direction" : "Outbound" + }, + { + "name" : "Allow_Internal_AKS_Connection_Between_Nodes_And_Control_Plane_TCP", + "description" : "internal AKS secure connection between underlying nodes and control plane..", + "protocol" : "Tcp", + "sourceAddressPrefix" : "VirtualNetwork", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "AzureCloud.eastus", + "destinationPortRanges" : ["9000"], + "access" : "Allow", + "priority" : 110, + "direction" : "Outbound" + }, + { + "name" : "Allow_Azure_Monitor", + "description" : "Allows outbound calls to Azure Monitor.", + "protocol" : "Tcp", + "sourceAddressPrefix" : "VirtualNetwork", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "AzureCloud.eastus", + "destinationPortRanges" : ["443"], + "access" : "Allow", + "priority" : 120, + "direction" : "Outbound" + }, + { + "name" : "Allow_Outbound_443", + "description" : "Allowing all outbound on port 443 provides a way to allow all FQDN based outbound dependencies that don't have a static IP", + "protocol" : "Tcp", + "sourceAddressPrefix" : "VirtualNetwork", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["443"], + "access" : "Allow", + "priority" : 130, + "direction" : "Outbound" + }, + { + "name" : "Allow_NTP_Server", + "description" : "NTP server", + "protocol" : "Udp", + "sourceAddressPrefix" : "VirtualNetwork", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["123"], + "access" : "Allow", + "priority" : 140, + "direction" : "Outbound" + }, + { + "name" : "Allow_Container_Apps_control_plane", + "description" : "Container Apps control plane", + "protocol" : "Tcp", + "sourceAddressPrefix" : "VirtualNetwork", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["5671", "5672"], + "access" : "Allow", + "priority" : 150, + "direction" : "Outbound" + } + ] } variable "appGatewaySecurityRules" { default = [ - { - "name" : "HealthProbes", - "description" : "Allow HealthProbes from gateway Manager.", - "protocol" : "*", - "sourceAddressPrefix" : "GatewayManager", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["65200-65535"], - "access" : "Allow", - "priority" : 100, - "direction" : "Inbound" - }, - { - "name" : "Allow_TLS", - "description" : "allow https incoming connections", - "protocol" : "*", - "sourceAddressPrefix" : "*", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["443"], - "access" : "Allow", - "priority" : 110, - "direction" : "Inbound" - }, - { - "name" : "Allow_HTTP", - "description" : "allow http incoming connections", - "protocol" : "*", - "sourceAddressPrefix" : "*", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["80"], - "access" : "Allow", - "priority" : 120, - "direction" : "Inbound" - }, - { - "name" : "Allow_AzureLoadBalancer", - "description" : "allow AzureLoadBalancer incoming connections", - "protocol" : "*", - "sourceAddressPrefix" : "AzureLoadBalancer", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["80"], - "access" : "Allow", - "priority" : 130, - "direction" : "Inbound" - } -] -} + { + "name" : "HealthProbes", + "description" : "Allow HealthProbes from gateway Manager.", + "protocol" : "*", + "sourceAddressPrefix" : "GatewayManager", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["65200-65535"], + "access" : "Allow", + "priority" : 100, + "direction" : "Inbound" + }, + { + "name" : "Allow_TLS", + "description" : "allow https incoming connections", + "protocol" : "*", + "sourceAddressPrefix" : "*", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["443"], + "access" : "Allow", + "priority" : 110, + "direction" : "Inbound" + }, + { + "name" : "Allow_HTTP", + "description" : "allow http incoming connections", + "protocol" : "*", + "sourceAddressPrefix" : "*", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["80"], + "access" : "Allow", + "priority" : 120, + "direction" : "Inbound" + }, + { + "name" : "Allow_AzureLoadBalancer", + "description" : "allow AzureLoadBalancer incoming connections", + "protocol" : "*", + "sourceAddressPrefix" : "AzureLoadBalancer", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["80"], + "access" : "Allow", + "priority" : 130, + "direction" : "Inbound" + } + ] +} + +variable "firewallPrivateIp" { + type = string +} \ No newline at end of file diff --git a/scenarios/aca-internal/terraform/modules/03-supporting-services/main.tf b/scenarios/aca-internal/terraform/modules/03-supporting-services/main.tf index 9dbe03a6..c03e8c99 100644 --- a/scenarios/aca-internal/terraform/modules/03-supporting-services/main.tf +++ b/scenarios/aca-internal/terraform/modules/03-supporting-services/main.tf @@ -45,16 +45,16 @@ module "keyVault" { } module "diagnostics" { - source = "../../../../shared/terraform/modules/diagnostics" + source = "../../../../shared/terraform/modules/diagnostics" logAnalyticsWorkspaceId = var.logAnalyticsWorkspaceId resources = [ { - "type" = "keyvault" - "id" = module.keyVault.keyVaultId + type = "keyvault" + id = module.keyVault.keyVaultId }, { - "type" = "acr" - "id" = module.containerRegistry.acrId + type = "acr" + id = module.containerRegistry.acrId } ] } \ No newline at end of file diff --git a/scenarios/aca-internal/terraform/modules/03-supporting-services/providers.tf b/scenarios/aca-internal/terraform/modules/03-supporting-services/providers.tf index b4f31ae0..75043546 100644 --- a/scenarios/aca-internal/terraform/modules/03-supporting-services/providers.tf +++ b/scenarios/aca-internal/terraform/modules/03-supporting-services/providers.tf @@ -3,7 +3,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "~> 3.71.0" + version = ">= 3.90.0" } } required_version = ">= 1.3.4" diff --git a/scenarios/aca-internal/terraform/modules/03-supporting-services/terraform.tfvars b/scenarios/aca-internal/terraform/modules/03-supporting-services/terraform.tfvars index 1a7b92c2..2e86c504 100644 --- a/scenarios/aca-internal/terraform/modules/03-supporting-services/terraform.tfvars +++ b/scenarios/aca-internal/terraform/modules/03-supporting-services/terraform.tfvars @@ -9,5 +9,5 @@ spokeVnetId = "" spokePrivateEndpointSubnetId = "" containerRegistryPullRoleAssignment = "acrRoleAssignment" keyVaultPullRoleAssignment = "keyVaultRoleAssignment" -clientIP = "" +clientIP = "" tags = {} diff --git a/scenarios/aca-internal/terraform/modules/04-container-apps-environment/main.tf b/scenarios/aca-internal/terraform/modules/04-container-apps-environment/main.tf index d4168cc4..dd3f1741 100644 --- a/scenarios/aca-internal/terraform/modules/04-container-apps-environment/main.tf +++ b/scenarios/aca-internal/terraform/modules/04-container-apps-environment/main.tf @@ -24,10 +24,11 @@ module "applicationInsights" { module "containerAppsEnvironment" { source = "../../../../shared/terraform/modules/aca-environment" environmentName = module.naming.resourceNames["containerAppsEnvironment"] - resourceGroupName = var.spokeResourceGroupName + resourceGroupName = var.spokeResourceGroupName location = var.location logAnalyticsWorkspaceId = var.logAnalyticsWorkspaceId subnetId = var.spokeInfraSubnetId + workloadProfiles = var.workloadProfiles } module "containerAppsEnvironmentPrivateDnsZone" { @@ -36,9 +37,10 @@ module "containerAppsEnvironmentPrivateDnsZone" { zoneName = module.containerAppsEnvironment.containerAppsEnvironmentDefaultDomain vnetLinks = var.vnetLinks != [] ? var.vnetLinks : local.vnetLinks records = [ - { "name" = "*" + { + "name" = "*" "ipv4Address" = [module.containerAppsEnvironment.containerAppsEnvironmentLoadBalancerIP] - }] + } + ] tags = var.tags } - diff --git a/scenarios/aca-internal/terraform/modules/04-container-apps-environment/providers.tf b/scenarios/aca-internal/terraform/modules/04-container-apps-environment/providers.tf index 999dc23f..eb2fbd8e 100644 --- a/scenarios/aca-internal/terraform/modules/04-container-apps-environment/providers.tf +++ b/scenarios/aca-internal/terraform/modules/04-container-apps-environment/providers.tf @@ -3,7 +3,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "~> 3.71.0" + version = ">= 3.90.0" } } required_version = ">= 1.3.4" diff --git a/scenarios/aca-internal/terraform/modules/04-container-apps-environment/terraform.tfvars b/scenarios/aca-internal/terraform/modules/04-container-apps-environment/terraform.tfvars index b33122cf..0690d45b 100644 --- a/scenarios/aca-internal/terraform/modules/04-container-apps-environment/terraform.tfvars +++ b/scenarios/aca-internal/terraform/modules/04-container-apps-environment/terraform.tfvars @@ -1,10 +1,10 @@ // The name of the workloard that is being deployed. Up to 10 characters long. This wil be used as part of the naming convention (i.e. as defined here: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming) workloadName = "lzaaca" //The name of the environment (e.g. "dev", "test", "prod", "preprod", "staging", "uat", "dr", "qa"). Up to 8 characters long. -environment = "dev" -spokeResourceGroupName = "rg-lzaaca-spoke-dev-eus" -appInsightsName = "appInsightsAca" -hubVnetId = "" -spokeVnetId = "" -spokeInfraSubnetId = "" -tags = {} \ No newline at end of file +environment = "dev" +spokeResourceGroupName = "rg-lzaaca-spoke-dev-eus" +appInsightsName = "appInsightsAca" +hubVnetId = "" +spokeVnetId = "" +spokeInfraSubnetId = "" +tags = {} diff --git a/scenarios/aca-internal/terraform/modules/04-container-apps-environment/variables.tf b/scenarios/aca-internal/terraform/modules/04-container-apps-environment/variables.tf index 3d4949e7..6ee933a8 100644 --- a/scenarios/aca-internal/terraform/modules/04-container-apps-environment/variables.tf +++ b/scenarios/aca-internal/terraform/modules/04-container-apps-environment/variables.tf @@ -55,4 +55,15 @@ variable "enableTelemetry" { variable "vnetLinks" {} -variable "logAnalyticsWorkspaceId" {} \ No newline at end of file +variable "logAnalyticsWorkspaceId" {} + +variable "workloadProfiles" { + description = "Optional, the workload profiles required by the end user. The default is 'Consumption', and is automatically added whether workload profiles are specified or not." + type = list(object({ + name = string + workload_profile_type = string + minimum_count = number + maximum_count = number + })) + default = [] +} \ No newline at end of file diff --git a/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/main.tf b/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/main.tf index 2f6a243f..e4c1109e 100644 --- a/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/main.tf +++ b/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/main.tf @@ -1,9 +1,11 @@ resource "azurerm_container_app" "helloWorld" { - count = var.deployApp ? 1:0 + count = var.deployApp ? 1 : 0 name = var.helloWorldContainerAppName resource_group_name = var.resourceGroupName container_app_environment_id = var.containerAppsEnvironmentId tags = var.tags + workload_profile_name = var.workloadProfileName + identity { type = "UserAssigned" identity_ids = [var.containerRegistryUserAssignedIdentityId] @@ -34,4 +36,4 @@ resource "azurerm_container_app" "helloWorld" { min_replicas = 1 max_replicas = 10 } -} \ No newline at end of file +} diff --git a/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/providers.tf b/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/providers.tf index b4f31ae0..75043546 100644 --- a/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/providers.tf +++ b/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/providers.tf @@ -3,7 +3,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "~> 3.71.0" + version = ">= 3.90.0" } } required_version = ">= 1.3.4" diff --git a/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/terraform.tfvars b/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/terraform.tfvars index 630b0bba..c066b399 100644 --- a/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/terraform.tfvars +++ b/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/terraform.tfvars @@ -2,4 +2,5 @@ resourceGroupName = "rg-lzaaca-spoke-dev-eus" helloWorldContainerAppName = "ca-hello-world" containerAppsEnvironmentId = "" containerRegistryUserAssignedIdentityId = "" -tags = {} \ No newline at end of file +tags = {} +workloadProfileName = "Consumption" diff --git a/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/variables.tf b/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/variables.tf index dc642548..ee2518f1 100644 --- a/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/variables.tf +++ b/scenarios/aca-internal/terraform/modules/05-hello-world-sample-app/variables.tf @@ -17,4 +17,8 @@ variable "containerAppsEnvironmentId" {} variable "resourceGroupName" {} -variable "deployApp" {} \ No newline at end of file +variable "deployApp" {} + +variable "workloadProfileName" { + type = string +} \ No newline at end of file diff --git a/scenarios/aca-internal/terraform/modules/06-application-gateway/main.tf b/scenarios/aca-internal/terraform/modules/06-application-gateway/main.tf index cd4ea38b..aef9ec35 100644 --- a/scenarios/aca-internal/terraform/modules/06-application-gateway/main.tf +++ b/scenarios/aca-internal/terraform/modules/06-application-gateway/main.tf @@ -25,14 +25,14 @@ resource "azurerm_public_ip" "appGatewayPip" { resource_group_name = var.resourceGroupName sku = "Standard" sku_tier = "Regional" - zones = var.makeZoneRedundant == true? [ + zones = var.makeZoneRedundant == true ? [ "1", "2", "3" - ]: [] - allocation_method = "Static" + ] : [] + allocation_method = "Static" ddos_protection_mode = var.ddosProtectionEnabled - tags = var.tags + tags = var.tags } module "appGatewayAddCertificates" { @@ -45,38 +45,38 @@ module "appGatewayAddCertificates" { } module "appGatewayConfiguration" { - source = "../../../../shared/terraform/modules/application-gateway/" - appGatewayName = module.naming.resourceNames["applicationGateway"] - resourceGroupName = var.resourceGroupName - location = var.location - diagnosticSettingName = "agw-diagnostics" - skuName = "WAF_v2" - skuTier = "WAF_v2" + source = "../../../../shared/terraform/modules/application-gateway/" + appGatewayName = module.naming.resourceNames["applicationGateway"] + resourceGroupName = var.resourceGroupName + location = var.location + diagnosticSettingName = "agw-diagnostics" + skuName = "WAF_v2" + skuTier = "WAF_v2" gatewayIPConfigurations = [ { name = "appGatewayIpConfig" subnet_id = var.appGatewaySubnetId - }] - backendAddressPools = [ + }] + backendAddressPools = [ { name = "acaServiceBackend" fqdns = [var.appGatewayPrimaryBackendEndFQDN] } ] - sslCertificates = [ + sslCertificates = [ { name = var.appGatewayFQDN key_vault_secret_id = module.appGatewayAddCertificates.SecretUri } ] - frontendIPConfigurations = [ + frontendIPConfigurations = [ { name = "appGwPublicFrontendIp" private_ip_address_allocation = "Dynamic" public_ip_address_id = azurerm_public_ip.appGatewayPip.id } ] - frontendPorts = var.enableAppGatewayCertificate? [ + frontendPorts = var.enableAppGatewayCertificate ? [ { name = "port_443" port = 443 @@ -85,7 +85,7 @@ module "appGatewayConfiguration" { name = "port_80" port = 80 } - ]: [ + ] : [ { name = "port_80" port = 80 @@ -93,16 +93,16 @@ module "appGatewayConfiguration" { ] backendHttpSettings = [ { - name = "https" - cookie_based_affinity = "Disabled" - port = 443 - protocol = "Https" - request_timeout = 20 + name = "https" + cookie_based_affinity = "Disabled" + port = 443 + protocol = "Https" + request_timeout = 20 pick_host_name_from_backend_address = true - probe_name = "webProbe" + probe_name = "webProbe" } ] - httpListeners = !var.enableAppGatewayCertificate? [ + httpListeners = !var.enableAppGatewayCertificate ? [ { name = "httpListener" frontend_ip_configuration_name = "appGwPublicFrontendIp" @@ -110,7 +110,7 @@ module "appGatewayConfiguration" { protocol = "Http" require_sni = false } - ]: [ + ] : [ { name = "httpListener" frontend_ip_configuration_name = "appGwPublicFrontendIp" @@ -132,36 +132,36 @@ module "appGatewayConfiguration" { ] probes = [ { - name = "webProbe" - protocol = "Https" - host = var.appGatewayPrimaryBackendEndFQDN - path = "/" # verify this - interval = 30 - timeout = 30 - unhealthy_threshold = 3 + name = "webProbe" + protocol = "Https" + host = var.appGatewayPrimaryBackendEndFQDN + path = "/" # verify this + interval = 30 + timeout = 30 + unhealthy_threshold = 3 pick_host_name_from_backend_http_settings = false - minimum_servers = 0 + minimum_servers = 0 match = { status_code = "200-499" } } ] - zones = var.makeZoneRedundant == true? [ + zones = var.makeZoneRedundant == true ? [ "1", "2", "3" - ]: [] + ] : [] firewallConfiguration = { - enabled = true - mode = "Prevention" - rule_set_type = "OWASP" - rule_set_version = "3.0" - request_body_check = true + enabled = true + mode = "Prevention" + rule_set_type = "OWASP" + rule_set_version = "3.0" + request_body_check = true max_request_body_size_in_kb = 128 - file_upload_limit_mb = 100 + file_upload_limit_mb = 100 } - sslPolicyName = "AppGwSslPolicy20220101" - sslPolicyType = "Predefined" + sslPolicyName = "AppGwSslPolicy20220101" + sslPolicyType = "Predefined" appGatewayFQDN = var.appGatewayFQDN appGatewayPrimaryBackendEndFQDN = var.appGatewayPrimaryBackendEndFQDN appGatewayPublicIpName = module.naming.resourceNames["applicationGatewayPip"] @@ -173,12 +173,12 @@ module "appGatewayConfiguration" { } module "diagnostics" { - source = "../../../../shared/terraform/modules/diagnostics" + source = "../../../../shared/terraform/modules/diagnostics" logAnalyticsWorkspaceId = var.logAnalyticsWorkspaceId resources = [ { - "type" = "agw" - "id" = module.appGatewayConfiguration.applicationGatewayId + type = "agw" + id = module.appGatewayConfiguration.applicationGatewayId } ] } \ No newline at end of file diff --git a/scenarios/aca-internal/terraform/modules/06-application-gateway/providers.tf b/scenarios/aca-internal/terraform/modules/06-application-gateway/providers.tf index b4f31ae0..75043546 100644 --- a/scenarios/aca-internal/terraform/modules/06-application-gateway/providers.tf +++ b/scenarios/aca-internal/terraform/modules/06-application-gateway/providers.tf @@ -3,7 +3,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "~> 3.71.0" + version = ">= 3.90.0" } } required_version = ">= 1.3.4" diff --git a/scenarios/aca-internal/terraform/modules/06-application-gateway/variables.tf b/scenarios/aca-internal/terraform/modules/06-application-gateway/variables.tf index cdef0cf9..e5bad3f3 100644 --- a/scenarios/aca-internal/terraform/modules/06-application-gateway/variables.tf +++ b/scenarios/aca-internal/terraform/modules/06-application-gateway/variables.tf @@ -24,7 +24,7 @@ variable "appGatewayCertificatePath" {} variable "logAnalyticsWorkspaceId" {} variable "ddosProtectionEnabled" { - default = "Enabled" + default = "Enabled" } variable "enableAppGatewayCertificate" { diff --git a/scenarios/aca-internal/terraform/modules/06-front-door/main.tf b/scenarios/aca-internal/terraform/modules/06-front-door/main.tf index 2e7388b6..b49c7954 100644 --- a/scenarios/aca-internal/terraform/modules/06-front-door/main.tf +++ b/scenarios/aca-internal/terraform/modules/06-front-door/main.tf @@ -28,12 +28,12 @@ module "frontDoor" { } module "diagnostics" { - source = "../../../../shared/terraform/modules/diagnostics" + source = "../../../../shared/terraform/modules/diagnostics" logAnalyticsWorkspaceId = var.logAnalyticsWorkspaceId resources = [ { - "type" = "fd" - "id" = module.frontDoor.frontDoorId + type = "fd" + id = module.frontDoor.frontDoorId } ] } \ No newline at end of file diff --git a/scenarios/aca-internal/terraform/outputs.tf b/scenarios/aca-internal/terraform/outputs.tf index 2969c289..21c26453 100644 --- a/scenarios/aca-internal/terraform/outputs.tf +++ b/scenarios/aca-internal/terraform/outputs.tf @@ -1,87 +1,11 @@ -// Hub -output "hubVnetId" { - value = module.hub.hubVnetId +output "applicationGatewayPublicIp" { + value = module.applicationGateway.applicationGatewayPublicIp } output "hubResourceGroupName" { value = module.hub.hubResourceGroupName } -# // Spoke -# output "spokeVnetId" { -# value = module.spoke.spokeVNetId -# } - -# output "spokeResourceGroupName" { -# value = module.spoke.spokeResourceGroupName -# } - -# output "spokeVnetName" { -# value = module.spoke.spokeVNetName -# } - -# output "spokeInfraSubnetId" { -# value = module.spoke.spokeInfraSubnetId -# } - -# output "spokeInfraSubnetName" { -# value = module.spoke.spokeInfraSubnetName -# } - -# output "spokePrivateEndpointsSubnetId" { -# value = module.spoke.spokePrivateEndpointsSubnetId -# } - -# output "spokePrivateEndpointsSubnetName" { -# value = module.spoke.spokePrivateEndpointsSubnetName -# } - -# output "spokeApplicationGatewaySubnetId" { -# value = module.spoke.spokeApplicationGatewaySubnetId -# } - -# output "spokeApplicationGatewaySubnetName" { -# value = module.spoke.spokeApplicationGatewaySubnetName -# } - -# // Supporting Services -# output "containerRegistryId" { -# value = module.supportingServices.containerRegistryId -# } - -# output "containerRegistryName" { -# value = module.supportingServices.containerRegistryName -# } - -# output "containerRegistryUserAssignedIdentityId" { -# value = module.supportingServices.containerRegistryUserAssignedIdentityId -# } - -# output "keyVaultId" { -# value = module.supportingServices.keyVaultId -# } - -# output "keyVaultName" { -# value = module.supportingServices.keyVaultName -# } - -# output "keyVaultUserAssignedIdentityId" { -# value = module.supportingServices.keyVaultUserAssignedIdentityId -# } - -# // Container Apps Environment -# output "containerAppsEnvironmentId" { -# value = module.containerAppsEnvironment.containerAppsEnvironmentId -# } - -# output "containerAppsEnvironmentName" { -# value = module.containerAppsEnvironment.containerAppsEnvironmentName -# } - -# output "logAnalyticsWorkspaceId" { -# value = module.containerAppsEnvironment.logAnalyticsWorkspaceId -# } - -# output "logAnalyticsWorkspaceCustomerId" { -# value = module.containerAppsEnvironment.logAnalyticsWorkspaceId -# } \ No newline at end of file +output "spokeResourceGroupName" { + value = module.spoke.spokeResourceGroupName +} \ No newline at end of file diff --git a/scenarios/aca-internal/terraform/providers.tf b/scenarios/aca-internal/terraform/providers.tf index 39c1d0ef..47562b1c 100644 --- a/scenarios/aca-internal/terraform/providers.tf +++ b/scenarios/aca-internal/terraform/providers.tf @@ -3,11 +3,12 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "~> 3.71.0" + version = ">= 3.90.0" } } required_version = ">= 1.3.4" + # uncomment if you want to save state file into remote storae account backend "azurerm" { } } diff --git a/scenarios/aca-internal/terraform/terraform.tfvars b/scenarios/aca-internal/terraform/terraform.tfvars index e3ea3812..023cd771 100644 --- a/scenarios/aca-internal/terraform/terraform.tfvars +++ b/scenarios/aca-internal/terraform/terraform.tfvars @@ -1,27 +1,32 @@ // The name of the workloard that is being deployed. Up to 10 characters long. This wil be used as part of the naming convention (i.e. as defined here: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming) workloadName = "lzaaca" //The name of the environment (e.g. "dev", "test", "prod", "preprod", "staging", "uat", "dr", "qa"). Up to 8 characters long. -environment = "dev" -tags = {} -location = "northeurope" -hubVnetAddressPrefixes = ["10.0.0.0/24"] -enableBastion = true -bastionSubnetAddressPrefixes = ["10.0.0.128/26"] -vmSize = "Standard_B2ms" -vmAdminUsername = "vmadmin" -vmAdminPassword = "@Aa123456789" # change this to a strong password -vmLinuxSshAuthorizedKeys = "" -vmJumpboxOSType = "Linux" -vmJumpBoxSubnetAddressPrefix = "10.1.2.32/27" +environment = "dev" +tags = {} +location = "northeurope" + +hubVnetAddressPrefixes = ["10.0.0.0/24"] +gatewaySubnetAddressPrefix = "10.0.0.0/27" +azureFirewallSubnetAddressPrefix = "10.0.0.64/26" +bastionSubnetAddressPrefixes = ["10.0.0.128/26"] +azureFirewallSubnetManagementAddressPrefix = "10.0.0.192/26" + spokeVnetAddressPrefixes = ["10.1.0.0/22"] -infraSubnetAddressPrefix = "10.1.0.0/23" -infraSubnetName = "snet-infra" +vmJumpBoxSubnetAddressPrefix = "10.1.2.32/27" +infraSubnetAddressPrefix = "10.1.0.0/27" privateEndpointsSubnetAddressPrefix = "10.1.2.0/27" applicationGatewaySubnetAddressPrefix = "10.1.3.0/24" -azureFirewallSubnetAddressPrefix = "10.0.0.64/26" -gatewaySubnetAddressPrefix = "10.0.0.0/27" -deployHelloWorldSample = true -clientIP = "" + +enableBastion = true +vmSize = "Standard_B2ms" # "Standard_B2als_v2" not supported in north europe +vmAdminUsername = "vmadmin" +vmAdminPassword = "@Aa123456789" # change this to a strong password +vmLinuxSshAuthorizedKeys = "" +vmJumpboxOSType = "Linux" +infraSubnetName = "snet-infra" + +deployHelloWorldSample = true +clientIP = "" supportingResourceGroupName = "supporting-services" aRecords = [] containerRegistryPullRoleAssignment = "acrRoleAssignment" @@ -29,4 +34,11 @@ keyVaultPullRoleAssignment = "keyVaultRoleAssignment" appInsightsName = "appInsightsAca" helloWorldContainerAppName = "ca-hello-world" appGatewayCertificateKeyName = "agwcert" -appGatewayFQDN = "acahello.demoapp.com" \ No newline at end of file +appGatewayFQDN = "acahello.demoapp.com" + +workloadProfiles = [{ + name = "general-purpose" + workload_profile_type = "D4" + minimum_count = 1 + maximum_count = 3 +}] diff --git a/scenarios/aca-internal/terraform/tfplan b/scenarios/aca-internal/terraform/tfplan new file mode 100644 index 00000000..c2f12223 Binary files /dev/null and b/scenarios/aca-internal/terraform/tfplan differ diff --git a/scenarios/aca-internal/terraform/variables.tf b/scenarios/aca-internal/terraform/variables.tf index 7ca8f17e..999f7307 100644 --- a/scenarios/aca-internal/terraform/variables.tf +++ b/scenarios/aca-internal/terraform/variables.tf @@ -74,132 +74,132 @@ variable "ddosProtectionPlanId" { variable "containerAppsSecurityRules" { default = [ - { - "name" : "Allow_Internal_AKS_Connection_Between_Nodes_And_Control_Plane_UDP", - "description" : "internal AKS secure connection between underlying nodes and control plane..", - "protocol" : "Udp", - "sourceAddressPrefix" : "VirtualNetwork", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "AzureCloud.eastus", - "destinationPortRanges" : ["1194"], - "access" : "Allow", - "priority" : 100, - "direction" : "Outbound" - }, - { - "name" : "Allow_Internal_AKS_Connection_Between_Nodes_And_Control_Plane_TCP", - "description" : "internal AKS secure connection between underlying nodes and control plane..", - "protocol" : "Tcp", - "sourceAddressPrefix" : "VirtualNetwork", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "AzureCloud.eastus", - "destinationPortRanges" : ["9000"], - "access" : "Allow", - "priority" : 110, - "direction" : "Outbound" - }, - { - "name" : "Allow_Azure_Monitor", - "description" : "Allows outbound calls to Azure Monitor.", - "protocol" : "Tcp", - "sourceAddressPrefix" : "VirtualNetwork", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "AzureCloud.eastus", - "destinationPortRanges" : ["443"], - "access" : "Allow", - "priority" : 120, - "direction" : "Outbound" - }, - { - "name" : "Allow_Outbound_443", - "description" : "Allowing all outbound on port 443 provides a way to allow all FQDN based outbound dependencies that don't have a static IP", - "protocol" : "Tcp", - "sourceAddressPrefix" : "VirtualNetwork", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["443"], - "access" : "Allow", - "priority" : 130, - "direction" : "Outbound" - }, - { - "name" : "Allow_NTP_Server", - "description" : "NTP server", - "protocol" : "Udp", - "sourceAddressPrefix" : "VirtualNetwork", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["123"], - "access" : "Allow", - "priority" : 140, - "direction" : "Outbound" - }, - { - "name" : "Allow_Container_Apps_control_plane", - "description" : "Container Apps control plane", - "protocol" : "Tcp", - "sourceAddressPrefix" : "VirtualNetwork", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["5671", "5672"], - "access" : "Allow", - "priority" : 150, - "direction" : "Outbound" - } -] + { + "name" : "Allow_Internal_AKS_Connection_Between_Nodes_And_Control_Plane_UDP", + "description" : "internal AKS secure connection between underlying nodes and control plane..", + "protocol" : "Udp", + "sourceAddressPrefix" : "VirtualNetwork", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "AzureCloud.eastus", + "destinationPortRanges" : ["1194"], + "access" : "Allow", + "priority" : 100, + "direction" : "Outbound" + }, + { + "name" : "Allow_Internal_AKS_Connection_Between_Nodes_And_Control_Plane_TCP", + "description" : "internal AKS secure connection between underlying nodes and control plane..", + "protocol" : "Tcp", + "sourceAddressPrefix" : "VirtualNetwork", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "AzureCloud.eastus", + "destinationPortRanges" : ["9000"], + "access" : "Allow", + "priority" : 110, + "direction" : "Outbound" + }, + { + "name" : "Allow_Azure_Monitor", + "description" : "Allows outbound calls to Azure Monitor.", + "protocol" : "Tcp", + "sourceAddressPrefix" : "VirtualNetwork", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "AzureCloud.eastus", + "destinationPortRanges" : ["443"], + "access" : "Allow", + "priority" : 120, + "direction" : "Outbound" + }, + { + "name" : "Allow_Outbound_443", + "description" : "Allowing all outbound on port 443 provides a way to allow all FQDN based outbound dependencies that don't have a static IP", + "protocol" : "Tcp", + "sourceAddressPrefix" : "VirtualNetwork", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["443"], + "access" : "Allow", + "priority" : 130, + "direction" : "Outbound" + }, + { + "name" : "Allow_NTP_Server", + "description" : "NTP server", + "protocol" : "Udp", + "sourceAddressPrefix" : "VirtualNetwork", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["123"], + "access" : "Allow", + "priority" : 140, + "direction" : "Outbound" + }, + { + "name" : "Allow_Container_Apps_control_plane", + "description" : "Container Apps control plane", + "protocol" : "Tcp", + "sourceAddressPrefix" : "VirtualNetwork", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["5671", "5672"], + "access" : "Allow", + "priority" : 150, + "direction" : "Outbound" + } + ] } variable "appGatewaySecurityRules" { default = [ - { - "name" : "HealthProbes", - "description" : "Sllow HealthProbes from gateway Manager.", - "protocol" : "*", - "sourceAddressPrefix" : "GatewayManager", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["65200-65535"], - "access" : "Allow", - "priority" : 100, - "direction" : "Inbound" - }, - { - "name" : "Allow_TLS", - "description" : "allow https incoming connections", - "protocol" : "*", - "sourceAddressPrefix" : "*", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["443"], - "access" : "Allow", - "priority" : 110, - "direction" : "Inbound" - }, - { - "name" : "Allow_HTTP", - "description" : "allow http incoming connections", - "protocol" : "*", - "sourceAddressPrefix" : "*", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["80"], - "access" : "Allow", - "priority" : 120, - "direction" : "Inbound" - }, - { - "name" : "Allow_AzureLoadBalancer", - "description" : "allow AzureLoadBalancer incoming connections", - "protocol" : "*", - "sourceAddressPrefix" : "AzureLoadBalancer", - "sourcePortRange" : "*", - "destinationAddressPrefix" : "*", - "destinationPortRanges" : ["80"], - "access" : "Allow", - "priority" : 130, - "direction" : "Inbound" - } -] + { + "name" : "HealthProbes", + "description" : "Sllow HealthProbes from gateway Manager.", + "protocol" : "*", + "sourceAddressPrefix" : "GatewayManager", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["65200-65535"], + "access" : "Allow", + "priority" : 100, + "direction" : "Inbound" + }, + { + "name" : "Allow_TLS", + "description" : "allow https incoming connections", + "protocol" : "*", + "sourceAddressPrefix" : "*", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["443"], + "access" : "Allow", + "priority" : 110, + "direction" : "Inbound" + }, + { + "name" : "Allow_HTTP", + "description" : "allow http incoming connections", + "protocol" : "*", + "sourceAddressPrefix" : "*", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["80"], + "access" : "Allow", + "priority" : 120, + "direction" : "Inbound" + }, + { + "name" : "Allow_AzureLoadBalancer", + "description" : "allow AzureLoadBalancer incoming connections", + "protocol" : "*", + "sourceAddressPrefix" : "AzureLoadBalancer", + "sourcePortRange" : "*", + "destinationAddressPrefix" : "*", + "destinationPortRanges" : ["80"], + "access" : "Allow", + "priority" : 130, + "direction" : "Inbound" + } + ] } @@ -246,6 +246,8 @@ variable "azureFirewallSubnetName" { type = string } +variable "azureFirewallSubnetManagementAddressPrefix" {} + variable "azureFirewallSubnetAddressPrefix" {} variable "supportingResourceGroupName" {} @@ -281,3 +283,13 @@ variable "deployHelloWorldSample" { variable "clientIP" { default = "" } + +variable "workloadProfiles" { + description = "Optional, the workload profiles required by the end user. The default is 'Consumption', and is automatically added whether workload profiles are specified or not." + type = list(object({ + name = string + workload_profile_type = string + minimum_count = number + maximum_count = number + })) +} \ No newline at end of file diff --git a/scenarios/shared/terraform/modules/aca-environment/main.tf b/scenarios/shared/terraform/modules/aca-environment/main.tf index 45ed8d25..fdbd2c52 100644 --- a/scenarios/shared/terraform/modules/aca-environment/main.tf +++ b/scenarios/shared/terraform/modules/aca-environment/main.tf @@ -5,6 +5,17 @@ resource "azurerm_container_app_environment" "environment" { log_analytics_workspace_id = var.logAnalyticsWorkspaceId infrastructure_subnet_id = var.subnetId internal_load_balancer_enabled = true + + dynamic "workload_profile" { + for_each = var.workloadProfiles + + content { + name = workload_profile.value.name + workload_profile_type = workload_profile.value.workload_profile_type + minimum_count = workload_profile.value.minimum_count + maximum_count = workload_profile.value.maximum_count + } + } } # resource "azurerm_container_app_environment_dapr_component" "daprComponent" { @@ -12,4 +23,4 @@ resource "azurerm_container_app_environment" "environment" { # name = var.daprName # type = "" # version = "" -# } \ No newline at end of file +# } diff --git a/scenarios/shared/terraform/modules/aca-environment/variables.tf b/scenarios/shared/terraform/modules/aca-environment/variables.tf index 8732e229..15dc69ff 100644 --- a/scenarios/shared/terraform/modules/aca-environment/variables.tf +++ b/scenarios/shared/terraform/modules/aca-environment/variables.tf @@ -21,3 +21,12 @@ variable "subnetId" { variable "resourceGroupName" {} +variable "workloadProfiles" { + description = "Optional, the workload profiles required by the end user. The default is 'Consumption', and is automatically added whether workload profiles are specified or not." + type = list(object({ + name = string + workload_profile_type = string + minimum_count = number + maximum_count = number + })) +} \ No newline at end of file diff --git a/scenarios/shared/terraform/modules/acr/provider.tf b/scenarios/shared/terraform/modules/acr/provider.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/scenarios/shared/terraform/modules/application-gateway/certificate-config/main.tf b/scenarios/shared/terraform/modules/application-gateway/certificate-config/main.tf index 1b3c327b..27367993 100644 --- a/scenarios/shared/terraform/modules/application-gateway/certificate-config/main.tf +++ b/scenarios/shared/terraform/modules/application-gateway/certificate-config/main.tf @@ -4,13 +4,13 @@ data "azurerm_key_vault" "keyVault" { } resource "azurerm_role_assignment" "keyvaultSecretUserRoleAssignment" { - scope = data.azurerm_key_vault.keyVault.id + scope = data.azurerm_key_vault.keyVault.id principal_id = var.appGatewayUserAssignedIdentityPrincipalId role_definition_name = "Key Vault Secrets User" } resource "azurerm_key_vault_secret" "sslCertSecret" { - depends_on = [ azurerm_role_assignment.keyvaultSecretUserRoleAssignment ] + depends_on = [azurerm_role_assignment.keyvaultSecretUserRoleAssignment] name = var.appGatewayCertificateKeyName key_vault_id = data.azurerm_key_vault.keyVault.id value = var.appGatewayCertificateData diff --git a/scenarios/shared/terraform/modules/application-gateway/certificate-config/provider.tf b/scenarios/shared/terraform/modules/application-gateway/certificate-config/provider.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/scenarios/shared/terraform/modules/application-gateway/main.tf b/scenarios/shared/terraform/modules/application-gateway/main.tf index a246d938..0181bf89 100644 --- a/scenarios/shared/terraform/modules/application-gateway/main.tf +++ b/scenarios/shared/terraform/modules/application-gateway/main.tf @@ -8,8 +8,8 @@ resource "azurerm_application_gateway" "appGateway" { } sku { - name = var.skuName - tier = var.skuTier + name = var.skuName + tier = var.skuTier capacity = var.capacity } @@ -28,7 +28,7 @@ resource "azurerm_application_gateway" "appGateway" { fqdns = backend_address_pool.value.fqdns } } - + dynamic "ssl_certificate" { for_each = var.sslCertificates content { @@ -57,13 +57,13 @@ resource "azurerm_application_gateway" "appGateway" { dynamic "backend_http_settings" { for_each = var.backendHttpSettings content { - name = backend_http_settings.value.name - port = backend_http_settings.value.port - protocol = backend_http_settings.value.protocol - cookie_based_affinity = backend_http_settings.value.cookie_based_affinity + name = backend_http_settings.value.name + port = backend_http_settings.value.port + protocol = backend_http_settings.value.protocol + cookie_based_affinity = backend_http_settings.value.cookie_based_affinity pick_host_name_from_backend_address = backend_http_settings.value.pick_host_name_from_backend_address - request_timeout = backend_http_settings.value.request_timeout - probe_name = backend_http_settings.value.probe_name + request_timeout = backend_http_settings.value.request_timeout + probe_name = backend_http_settings.value.probe_name } } @@ -123,10 +123,10 @@ resource "azurerm_application_gateway" "appGateway" { dynamic "autoscale_configuration" { for_each = var.autoScaleSettings content { - min_capacity = var.autoscaleMinCapacity == -1? null: var.autoscaleMinCapacity - max_capacity = var.autoscaleMaxCapacity == -1? null: var.autoscaleMaxCapacity + min_capacity = var.autoscaleMinCapacity == -1 ? null : var.autoscaleMinCapacity + max_capacity = var.autoscaleMaxCapacity == -1 ? null : var.autoscaleMaxCapacity } } - zones = var.makeZoneRedundant == true? var.zones: [] + zones = var.makeZoneRedundant == true ? var.zones : [] } diff --git a/scenarios/shared/terraform/modules/application-gateway/outputs.tf b/scenarios/shared/terraform/modules/application-gateway/outputs.tf index 335f7e8d..7bcb1629 100644 --- a/scenarios/shared/terraform/modules/application-gateway/outputs.tf +++ b/scenarios/shared/terraform/modules/application-gateway/outputs.tf @@ -1,3 +1,3 @@ output "applicationGatewayId" { - value = azurerm_application_gateway.appGateway.id + value = azurerm_application_gateway.appGateway.id } \ No newline at end of file diff --git a/scenarios/shared/terraform/modules/application-gateway/provider.tf b/scenarios/shared/terraform/modules/application-gateway/provider.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/scenarios/shared/terraform/modules/application-gateway/variables.tf b/scenarios/shared/terraform/modules/application-gateway/variables.tf index abf04017..fcba9631 100644 --- a/scenarios/shared/terraform/modules/application-gateway/variables.tf +++ b/scenarios/shared/terraform/modules/application-gateway/variables.tf @@ -31,7 +31,7 @@ variable "diagnosticSettingName" { variable "skuName" { default = "WAF_Medium" validation { - condition = var.skuName == "Standard_Small" || var.skuName == "Standard_Medium" || var.skuName == "Standard_Large" || var.skuName == "WAF_Medium" || var.skuName == "WAF_Large" || var.skuName == "Standard_v2" || var.skuName == "WAF_v2" + condition = var.skuName == "Standard_Small" || var.skuName == "Standard_Medium" || var.skuName == "Standard_Large" || var.skuName == "WAF_Medium" || var.skuName == "WAF_Large" || var.skuName == "Standard_v2" || var.skuName == "WAF_v2" error_message = "The sku value needs to be one of the following: Standard_Small, Standard_Medium, Standard_Large, WAF_Medium, WAF_Large, Standard_v2, WAF_v2" } } @@ -39,7 +39,7 @@ variable "skuName" { variable "skuTier" { default = "WAF" validation { - condition = var.skuTier == "WAF" || var.skuTier == "Standard" || var.skuTier == "Standard_v2" || var.skuTier == "WAF_v2" + condition = var.skuTier == "WAF" || var.skuTier == "Standard" || var.skuTier == "Standard_v2" || var.skuTier == "WAF_v2" error_message = "The sku tier needs to be one of the following: WAF, Standard, Standard_v2, WAF_v2" } } @@ -47,15 +47,15 @@ variable "skuTier" { variable "capacity" { default = 1 validation { - condition = var.capacity >= 1 && var.capacity <= 10 + condition = var.capacity >= 1 && var.capacity <= 10 error_message = "The capacity needs to be between 1 and 10" } } variable "sslPolicyCipherSuites" { - default = ["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"] + default = ["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"] validation { - condition = length(var.sslPolicyCipherSuites) > 0 + condition = length(var.sslPolicyCipherSuites) > 0 error_message = "The sslPolicyCipherSuites needs to be a list of cipher suites" } } @@ -63,7 +63,7 @@ variable "sslPolicyCipherSuites" { variable "sslProtocolEnums" { default = "TLSv1_2" validation { - condition = var.sslProtocolEnums == "TLSv1_0" || var.sslProtocolEnums == "TLSv1_1" || var.sslProtocolEnums == "TLSv1_2" || var.sslProtocolEnums == "TLSv1_3" + condition = var.sslProtocolEnums == "TLSv1_0" || var.sslProtocolEnums == "TLSv1_1" || var.sslProtocolEnums == "TLSv1_2" || var.sslProtocolEnums == "TLSv1_3" error_message = "SSL protocol must be one of the following: TLSv1_0, TLSv1_1, TLSv1_2, TLSv1_3" } } @@ -71,7 +71,7 @@ variable "sslProtocolEnums" { variable "sslPolicyName" { default = null validation { - condition = var.sslPolicyName == "AppGwSslPolicy20150501" || var.sslPolicyName == "AppGwSslPolicy20170401" || var.sslPolicyName == "AppGwSslPolicy20170401S" || var.sslPolicyName == "AppGwSslPolicy20220101" || var.sslPolicyName == "AppGwSslPolicy20220101S" + condition = var.sslPolicyName == "AppGwSslPolicy20150501" || var.sslPolicyName == "AppGwSslPolicy20170401" || var.sslPolicyName == "AppGwSslPolicy20170401S" || var.sslPolicyName == "AppGwSslPolicy20220101" || var.sslPolicyName == "AppGwSslPolicy20220101S" error_message = "The SSL policy must be one of the following: AppGwSslPolicy20150501, AppGwSslPolicy20170401, AppGwSslPolicy20170401S, AppGwSslPolicy20220101, AppGwSslPolicy20220101S" } } @@ -79,7 +79,7 @@ variable "sslPolicyName" { variable "sslPolicyType" { default = "Custom" validation { - condition = var.sslPolicyType == "Custom" || var.sslPolicyType == "Predefined" || var.sslPolicyType == "CustomV2" + condition = var.sslPolicyType == "Custom" || var.sslPolicyType == "Predefined" || var.sslPolicyType == "CustomV2" error_message = "The SSL policy must be one of the following: Custom, Predefined, CustomV2" } } @@ -102,7 +102,7 @@ variable "makeZoneRedundant" { variable "ddosProtectionEnabled" { default = "Disabled" validation { - condition = var.ddosProtectionEnabled == "Enabled" || var.ddosProtectionEnabled == "Disabled" || var.ddosProtectionEnabled == "VirtualNetworkInherited" + condition = var.ddosProtectionEnabled == "Enabled" || var.ddosProtectionEnabled == "Disabled" || var.ddosProtectionEnabled == "VirtualNetworkInherited" error_message = "The DDOS protection must be set to Enabled, Disabled or VirtualNetworkInherited" } } diff --git a/scenarios/shared/terraform/modules/bastion/main.tf b/scenarios/shared/terraform/modules/bastion/main.tf index 09e75cbd..92c636c7 100644 --- a/scenarios/shared/terraform/modules/bastion/main.tf +++ b/scenarios/shared/terraform/modules/bastion/main.tf @@ -3,7 +3,7 @@ module "nsg" { nsgName = var.bastionNsgName location = var.location resourceGroupName = var.vnetResourceGroupName - securityRules = var.securityRules.default + securityRules = var.securityRules tags = var.tags } @@ -36,6 +36,7 @@ resource "azurerm_bastion_host" "bastionHost" { name = var.bastionHostName location = var.location resource_group_name = var.vnetResourceGroupName + ip_configuration { name = "ipconf" subnet_id = azurerm_subnet.bastionSubnet.id diff --git a/scenarios/shared/terraform/modules/bastion/outputs.tf b/scenarios/shared/terraform/modules/bastion/outputs.tf index e69de29b..338130b9 100644 --- a/scenarios/shared/terraform/modules/bastion/outputs.tf +++ b/scenarios/shared/terraform/modules/bastion/outputs.tf @@ -0,0 +1,3 @@ +output "bastionHostId" { + value = azurerm_bastion_host.bastionHost.id +} \ No newline at end of file diff --git a/scenarios/shared/terraform/modules/diagnostics/main.tf b/scenarios/shared/terraform/modules/diagnostics/main.tf index a180e79e..03fc74a8 100644 --- a/scenarios/shared/terraform/modules/diagnostics/main.tf +++ b/scenarios/shared/terraform/modules/diagnostics/main.tf @@ -1,14 +1,14 @@ # Diagnostic Settings data "azurerm_monitor_diagnostic_categories" "resources" { for_each = { for resource in var.resources : resource.type => resource } - + resource_id = each.value.id } resource "azurerm_monitor_diagnostic_setting" "rule" { - for_each = { for resource in var.resources : resource.type => resource } + for_each = { for resource in var.resources : resource.type => resource } - name = "${each.key}-diagnostic-settings" + name = "${each.key}-diagnostic-setting" target_resource_id = each.value.id log_analytics_workspace_id = var.logAnalyticsWorkspaceId log_analytics_destination_type = "AzureDiagnostics" @@ -19,10 +19,6 @@ resource "azurerm_monitor_diagnostic_setting" "rule" { content { category = entry.value - - retention_policy { - enabled = true - } } } @@ -33,10 +29,6 @@ resource "azurerm_monitor_diagnostic_setting" "rule" { content { category = entry.value enabled = true - - retention_policy { - enabled = true - } } } } diff --git a/scenarios/shared/terraform/modules/diagnostics/providers.tf b/scenarios/shared/terraform/modules/diagnostics/providers.tf deleted file mode 100644 index b4f31ae0..00000000 --- a/scenarios/shared/terraform/modules/diagnostics/providers.tf +++ /dev/null @@ -1,16 +0,0 @@ -# Configure the Azure provider -terraform { - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = "~> 3.71.0" - } - } - required_version = ">= 1.3.4" - - # backend "azurerm" { - # } -} -provider "azurerm" { - features {} -} \ No newline at end of file diff --git a/scenarios/shared/terraform/modules/firewall/main.tf b/scenarios/shared/terraform/modules/firewall/main.tf new file mode 100644 index 00000000..203c1487 --- /dev/null +++ b/scenarios/shared/terraform/modules/firewall/main.tf @@ -0,0 +1,137 @@ +resource "azurerm_public_ip" "publicIpFirewall" { + name = var.publicIpFirewallName + resource_group_name = var.hubResourceGroupName + location = var.location + allocation_method = "Static" + sku = "Standard" + zones = var.firewallAvailabilityZones + tags = var.tags +} + +resource "azurerm_public_ip" "publicIpFirewallManagement" { + name = var.publicIpFirewallManagementName + resource_group_name = var.hubResourceGroupName + location = var.location + allocation_method = "Static" + sku = "Standard" + zones = var.firewallAvailabilityZones + tags = var.tags +} + +resource "azurerm_firewall" "firewall" { + name = var.firewallName + resource_group_name = var.hubResourceGroupName + location = var.location + sku_name = var.firewallSkuName + sku_tier = var.firewallSkuTier + firewall_policy_id = azurerm_firewall_policy.firewallPolicy.id + zones = var.firewallAvailabilityZones + tags = var.tags + + ip_configuration { + name = "configuration" + subnet_id = var.subnetFirewallId + public_ip_address_id = azurerm_public_ip.publicIpFirewall.id + } + + management_ip_configuration { # Firewall with Basic SKU must have Management Ip configuration + name = "mgmtconfig" + subnet_id = var.subnetFirewallManagementId + public_ip_address_id = azurerm_public_ip.publicIpFirewallManagement.id + } +} + +resource "azurerm_firewall_policy" "firewallPolicy" { + name = var.firewallPolicyName + resource_group_name = var.hubResourceGroupName + location = var.location + sku = var.firewallSkuTier +} + +resource "azurerm_firewall_policy_rule_collection_group" "policyGroup" { + for_each = try({ for group in var.firewallPolicyRuleCollectionGroups : group.name => group }, toset([])) + + name = each.value.name + priority = each.value.priority + firewall_policy_id = azurerm_firewall_policy.firewallPolicy.id + + dynamic "application_rule_collection" { + for_each = each.value.application_rule_collections + + content { + name = application_rule_collection.value.name + priority = application_rule_collection.value.priority + action = application_rule_collection.value.action + + dynamic "rule" { + for_each = application_rule_collection.value.rules + + content { + name = rule.value.name + source_addresses = rule.value.source_addresses + source_ip_groups = rule.value.source_ip_groups + destination_addresses = rule.value.destination_addresses + destination_fqdns = rule.value.destination_fqdns + + dynamic "protocols" { + for_each = rule.value.protocols + + content { + port = protocols.value.port + type = protocols.value.type + } + } + } + } + } + } + + dynamic "network_rule_collection" { + for_each = each.value.network_rule_collections + + content { + name = network_rule_collection.value.name + priority = network_rule_collection.value.priority + action = network_rule_collection.value.action + + dynamic "rule" { + for_each = network_rule_collection.value.rules + + content { + name = rule.value.name + source_addresses = rule.value.source_addresses + source_ip_groups = rule.value.source_ip_groups + destination_ports = rule.value.destination_ports + destination_addresses = rule.value.destination_addresses + destination_ip_groups = rule.value.destination_ip_groups + destination_fqdns = rule.value.destination_fqdns + protocols = rule.value.protocols + } + } + } + } + + dynamic "nat_rule_collection" { + for_each = each.value.nat_rule_collections + content { + name = nat_rule_collection.value.name + priority = nat_rule_collection.value.priority + action = nat_rule_collection.value.action + + dynamic "rule" { + for_each = nat_rule_collection.value.rules + + content { + name = rule.value.name + source_addresses = rule.value.source_addresses + source_ip_groups = rule.value.source_ip_groups + destination_ports = rule.value.destination_ports + translated_address = rule.value.translated_address + translated_port = rule.value.translated_port + protocols = rule.value.protocols + } + } + } + + } +} diff --git a/scenarios/shared/terraform/modules/firewall/outputs.tf b/scenarios/shared/terraform/modules/firewall/outputs.tf new file mode 100644 index 00000000..5018f273 --- /dev/null +++ b/scenarios/shared/terraform/modules/firewall/outputs.tf @@ -0,0 +1,7 @@ +output "firewallId" { + value = azurerm_firewall.firewall.id +} + +output "firewallPrivateIp" { + value = azurerm_firewall.firewall.ip_configuration.0.private_ip_address +} diff --git a/scenarios/shared/terraform/modules/firewall/variables.tf b/scenarios/shared/terraform/modules/firewall/variables.tf new file mode 100644 index 00000000..95c73e0a --- /dev/null +++ b/scenarios/shared/terraform/modules/firewall/variables.tf @@ -0,0 +1,106 @@ +variable "location" { + type = string +} + +variable "tags" { + default = {} +} + +variable "hubResourceGroupName" {} + +variable "firewallName" { + type = string +} + +variable "publicIpFirewallName" { + type = string +} + +variable "publicIpFirewallManagementName" { + type = string +} + +variable "subnetFirewallId" { + type = string +} + +variable "subnetFirewallManagementId" { + type = string +} + +variable "firewallPolicyName" { + type = string +} + +variable "firewallSkuName" { + type = string + default = "AZFW_VNet" # "AZFW_Hub" +} + +variable "firewallSkuTier" { + type = string + default = "Basic" # "Standard" "Premium" "Basic" +} + +variable "firewallAvailabilityZones" { + type = list(number) + default = [1] # [1, 2, 3] +} + +variable "firewallPolicyRuleCollectionGroups" { + description = "Firewall policy rule collection group configuration" + type = list(object({ + name = string + priority = number + + application_rule_collections = list(object({ + name = string, + priority = number, + action = string, + rules = list(object({ + name = string, + source_addresses = list(string), + source_ip_groups = list(string), + destination_fqdns = list(string), + destination_addresses = list(string), + protocols = list(object({ + port = string, + type = string + })) + })) + })) + + network_rule_collections = list(object({ + name = string, + priority = number, + action = string, + rules = list(object({ + name = string, + source_addresses = list(string), + source_ip_groups = list(string), + destination_ports = list(string), + destination_addresses = list(string), + destination_ip_groups = list(string), + destination_fqdns = list(string), + protocols = list(string) + })) + })) + + nat_rule_collections = list(object({ + name = string, + priority = number, + action = string, + rules = list(object({ + name = string, + source_addresses = list(string), + destination_address = string, + destination_ports = list(string), + translated_port = number, + translated_address = string, + protocols = list(string) + })) + })) + } + ) + ) +} diff --git a/scenarios/shared/terraform/modules/frontdoor/provider.tf b/scenarios/shared/terraform/modules/frontdoor/provider.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/scenarios/shared/terraform/modules/identity/managed-identity/provider.tf b/scenarios/shared/terraform/modules/identity/managed-identity/provider.tf deleted file mode 100644 index b4f31ae0..00000000 --- a/scenarios/shared/terraform/modules/identity/managed-identity/provider.tf +++ /dev/null @@ -1,16 +0,0 @@ -# Configure the Azure provider -terraform { - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = "~> 3.71.0" - } - } - required_version = ">= 1.3.4" - - # backend "azurerm" { - # } -} -provider "azurerm" { - features {} -} \ No newline at end of file diff --git a/scenarios/shared/terraform/modules/keyvault/main.tf b/scenarios/shared/terraform/modules/keyvault/main.tf index 1e2885b2..22f61f5a 100644 --- a/scenarios/shared/terraform/modules/keyvault/main.tf +++ b/scenarios/shared/terraform/modules/keyvault/main.tf @@ -8,7 +8,7 @@ resource "azurerm_key_vault" "keyvault" { tenant_id = data.azurerm_client_config.current.tenant_id soft_delete_retention_days = 7 purge_protection_enabled = false - public_network_access_enabled = (var.clientIP == "" || var.clientIP == null)? false : true + public_network_access_enabled = (var.clientIP == "" || var.clientIP == null) ? false : true enable_rbac_authorization = true enabled_for_template_deployment = true tags = var.tags @@ -16,18 +16,18 @@ resource "azurerm_key_vault" "keyvault" { network_acls { default_action = "Deny" bypass = "AzureServices" - ip_rules = (var.clientIP == "" || var.clientIP == null)? null : [var.clientIP] + ip_rules = (var.clientIP == "" || var.clientIP == null) ? null : [var.clientIP] virtual_network_subnet_ids = null } } module "keyVaultPrivateZones" { - source = "../networking/private-zones" - resourceGroupName = var.hubResourceGroupName - vnetLinks = var.vnetLinks - zoneName = local.privateDnsZoneNames - records = var.aRecords - tags = var.tags + source = "../networking/private-zones" + resourceGroupName = var.hubResourceGroupName + vnetLinks = var.vnetLinks + zoneName = local.privateDnsZoneNames + records = var.aRecords + tags = var.tags } module "keyVaultPrivateEndpoints" { diff --git a/scenarios/shared/terraform/modules/keyvault/provider.tf b/scenarios/shared/terraform/modules/keyvault/provider.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/scenarios/shared/terraform/modules/naming/local.tf b/scenarios/shared/terraform/modules/naming/local.tf index 573fa4d3..02fbd342 100644 --- a/scenarios/shared/terraform/modules/naming/local.tf +++ b/scenarios/shared/terraform/modules/naming/local.tf @@ -21,6 +21,10 @@ locals { containerRegistryUserAssignedIdentity = "${var.resourceTypeAbbreviations.managedIdentity}-${lower(replace(replace(local.namingBaseUnique, var.resourceTypeToken, var.resourceTypeAbbreviations.containerRegistry), "-", ""))}-AcrPull" cosmosDbNoSql = lower(substr(replace(local.namingBaseUnique, var.resourceTypeToken, var.resourceTypeAbbreviations.cosmosDbNoSql), 0, 44)) cosmosDbNoSqlPep = "${var.resourceTypeAbbreviations.privateEndpoint}-${lower(substr(replace(local.namingBaseUnique, var.resourceTypeToken, var.resourceTypeAbbreviations.cosmosDbNoSql), 0, 44))}" + firewall = replace(local.namingBaseNoWorkloadName, var.resourceTypeToken, var.resourceTypeAbbreviations.firewall) + firewallPip = "${var.resourceTypeAbbreviations.publicIpAddress}-${replace(local.namingBaseNoWorkloadName, var.resourceTypeToken, var.resourceTypeAbbreviations.firewall)}" + firewallManagementPip = "${var.resourceTypeAbbreviations.publicIpAddress}-${replace(local.namingBaseNoWorkloadName, var.resourceTypeToken, var.resourceTypeAbbreviations.firewall)}-management" + firewallPolicy = replace(local.namingBaseNoWorkloadName, var.resourceTypeToken, var.resourceTypeAbbreviations.firewallPolicy) frontDoorProfile = replace(local.namingBase, var.resourceTypeToken, var.resourceTypeAbbreviations.frontDoor) keyVault = substr(replace(local.namingBaseUnique, var.resourceTypeToken, var.resourceTypeAbbreviations.keyVault), 0, 24) keyVaultPep = "${var.resourceTypeAbbreviations.privateEndpoint}-${replace(local.namingBaseUnique, var.resourceTypeToken, var.resourceTypeAbbreviations.keyVault)}" @@ -30,6 +34,7 @@ locals { privateLinkServiceName = "${var.resourceTypeAbbreviations.privateLinkService}-${replace(local.namingBase, var.resourceTypeToken, var.resourceTypeAbbreviations.frontDoor)}" rgHubName = "${var.resourceTypeAbbreviations.resourceGroup}-${var.workloadName}-hub-${var.environment}-${var.regionAbbreviations[lower(var.location)]}" rgSpokeName = "${var.resourceTypeAbbreviations.resourceGroup}-${var.workloadName}-spoke-${var.environment}-${var.regionAbbreviations[lower(var.location)]}" + routeTable = "${var.resourceTypeAbbreviations.routeTable}-${var.workloadName}-${var.environment}-${var.regionAbbreviations[lower(var.location)]}" serviceBus = replace(local.namingBaseUnique, var.resourceTypeToken, var.resourceTypeAbbreviations.serviceBus) serviceBusPep = "${var.resourceTypeAbbreviations.privateEndpoint}-${replace(local.namingBaseUnique, var.resourceTypeToken, var.resourceTypeAbbreviations.serviceBus)}" vmJumpBox = replace(local.namingBaseNoWorkloadName, var.resourceTypeToken, var.resourceTypeAbbreviations.virtualMachine) diff --git a/scenarios/shared/terraform/modules/naming/variables.tf b/scenarios/shared/terraform/modules/naming/variables.tf index 9b8017d3..ef86d437 100644 --- a/scenarios/shared/terraform/modules/naming/variables.tf +++ b/scenarios/shared/terraform/modules/naming/variables.tf @@ -8,6 +8,8 @@ variable "resourceTypeAbbreviations" { containerAppsEnvironment = "cae" containerRegistry = "cr" cosmosDbNoSql = "cosno" + firewall = "fw" + firewallPolicy = "fwp" frontDoor = "afd" frontDoorEndpoint = "fde" frontDoorWaf = "fdfp" @@ -20,6 +22,7 @@ variable "resourceTypeAbbreviations" { privateLinkService = "pls" publicIpAddress = "pip" resourceGroup = "rg" + routeTable = "rt" serviceBus = "sb" serviceBusQueue = "sbq" serviceBusTopic = "sbt" diff --git a/scenarios/shared/terraform/modules/networking/private-endpoints/main.tf b/scenarios/shared/terraform/modules/networking/private-endpoints/main.tf index 5e7bcab9..a37a30d1 100644 --- a/scenarios/shared/terraform/modules/networking/private-endpoints/main.tf +++ b/scenarios/shared/terraform/modules/networking/private-endpoints/main.tf @@ -1,4 +1,3 @@ - resource "azurerm_private_endpoint" "pe" { name = var.endpointName location = var.location diff --git a/scenarios/shared/terraform/modules/networking/route-table/main.tf b/scenarios/shared/terraform/modules/networking/route-table/main.tf new file mode 100644 index 00000000..4764834a --- /dev/null +++ b/scenarios/shared/terraform/modules/networking/route-table/main.tf @@ -0,0 +1,22 @@ +resource "azurerm_route_table" "rt" { + name = var.routeTableName + resource_group_name = var.resourceGroupName + location = var.location + disable_bgp_route_propagation = true + tags = var.tags +} + +resource "azurerm_route" "routeToFirewall" { + for_each = { for route in var.routes : route.name => route } + name = each.value.name + resource_group_name = azurerm_route_table.rt.resource_group_name + route_table_name = azurerm_route_table.rt.name + address_prefix = each.value.addressPrefix + next_hop_type = each.value.nextHopType + next_hop_in_ip_address = each.value.nextHopIpAddress +} + +resource "azurerm_subnet_route_table_association" "associationRtSubnetInfra" { + subnet_id = var.subnetId + route_table_id = azurerm_route_table.rt.id +} diff --git a/scenarios/shared/terraform/modules/aca-environment/provider.tf b/scenarios/shared/terraform/modules/networking/route-table/outputs.tf similarity index 100% rename from scenarios/shared/terraform/modules/aca-environment/provider.tf rename to scenarios/shared/terraform/modules/networking/route-table/outputs.tf diff --git a/scenarios/shared/terraform/modules/networking/route-table/variables.tf b/scenarios/shared/terraform/modules/networking/route-table/variables.tf new file mode 100644 index 00000000..674ca038 --- /dev/null +++ b/scenarios/shared/terraform/modules/networking/route-table/variables.tf @@ -0,0 +1,32 @@ +variable "routeTableName" { + default = "routeTableSpoke" + type = string + validation { + condition = length(var.routeTableName) >= 2 && length(var.routeTableName) <= 32 + error_message = "Name must be at least 2 characters long and not longer than 32." + + } +} + +variable "location" { + type = string +} + +variable "resourceGroupName" { + type = string +} + +variable "subnetId" { + type = string +} + +variable "tags" {} + +variable "routes" { + type = list(object({ + name = string + addressPrefix = string + nextHopType = string + nextHopIpAddress = string + })) +} diff --git a/scenarios/shared/terraform/modules/networking/vnet/main.tf b/scenarios/shared/terraform/modules/networking/vnet/main.tf index 39cf8df7..0bc1c736 100644 --- a/scenarios/shared/terraform/modules/networking/vnet/main.tf +++ b/scenarios/shared/terraform/modules/networking/vnet/main.tf @@ -1,19 +1,9 @@ -## Virtual Network - resource "azurerm_virtual_network" "vnet" { name = var.networkName location = var.location resource_group_name = var.resourceGroupName address_space = var.addressSpace - - - # var.ddosProtectionPlanId != "" ? ddos_protection_plan { - # enable = var.ddosProtectionPlanId != ""? true: false - # id = var.ddosProtectionPlanId != ""? var.ddosProtectionPlanId: null - # } - - - tags = var.tags + tags = var.tags } resource "azurerm_subnet" "subnets" { @@ -22,6 +12,18 @@ resource "azurerm_subnet" "subnets" { name = each.key virtual_network_name = azurerm_virtual_network.vnet.name resource_group_name = azurerm_virtual_network.vnet.resource_group_name + address_prefixes = each.value.addressPrefixes + + dynamic "delegation" { + for_each = lookup(var.subnetDelegations, each.key, {}) - address_prefixes = each.value.addressPrefixes -} \ No newline at end of file + content { + name = delegation.key + + service_delegation { + name = delegation.value.service_name + actions = delegation.value.service_actions + } + } + } +} diff --git a/scenarios/shared/terraform/modules/networking/vnet/outputs.tf b/scenarios/shared/terraform/modules/networking/vnet/outputs.tf index 71a9cdd1..b84cc0c0 100644 --- a/scenarios/shared/terraform/modules/networking/vnet/outputs.tf +++ b/scenarios/shared/terraform/modules/networking/vnet/outputs.tf @@ -8,4 +8,8 @@ output "vnetId" { output "vnetName" { value = azurerm_virtual_network.vnet.name -} \ No newline at end of file +} + +output "subnetIds" { + value = tomap({ for subnet in azurerm_subnet.subnets : subnet.name => subnet.id }) +} diff --git a/scenarios/shared/terraform/modules/networking/vnet/variables.tf b/scenarios/shared/terraform/modules/networking/vnet/variables.tf index 836e749b..0a89db5e 100644 --- a/scenarios/shared/terraform/modules/networking/vnet/variables.tf +++ b/scenarios/shared/terraform/modules/networking/vnet/variables.tf @@ -30,4 +30,8 @@ variable "ddosProtectionPlanId" { } variable "subnets" { +} + +variable "subnetDelegations" { + default = {} } \ No newline at end of file diff --git a/scenarios/shared/terraform/modules/vms/main.tf b/scenarios/shared/terraform/modules/vms/main.tf index ee20ea62..348e1928 100644 --- a/scenarios/shared/terraform/modules/vms/main.tf +++ b/scenarios/shared/terraform/modules/vms/main.tf @@ -95,7 +95,7 @@ resource "azurerm_virtual_machine_extension" "vm_extension_windows" { publisher = "Microsoft.Azure.Extensions" type = "CustomScript" type_handler_version = "2.1" - settings = <