diff --git a/scenarios/aca-internal/azure-resource-manager/build-arm-json.azcli b/scenarios/aca-internal/azure-resource-manager/build-arm-json.azcli index 16f9ef63..e79513e8 100644 --- a/scenarios/aca-internal/azure-resource-manager/build-arm-json.azcli +++ b/scenarios/aca-internal/azure-resource-manager/build-arm-json.azcli @@ -4,7 +4,7 @@ cd scenarios/aca-internal/azure-resource-manager/ # Compile bicep to ARM - az bicep build --file ../bicep/main.bicep --outfile ../azure-resource-manager/main-del.json + az bicep build --file ../bicep/main.bicep --outfile ../azure-resource-manager/main.json # copy parameters file, and edit it if needed cp ../bicep/main.parameters.jsonc ../azure-resource-manager/main.parameters.jsonc diff --git a/scenarios/aca-internal/azure-resource-manager/main-portal-ux.json b/scenarios/aca-internal/azure-resource-manager/main-portal-ux.json index 698ccf76..181181fd 100644 --- a/scenarios/aca-internal/azure-resource-manager/main-portal-ux.json +++ b/scenarios/aca-internal/azure-resource-manager/main-portal-ux.json @@ -80,6 +80,54 @@ "infoMessages": [], "visible": true }, + { + "name": "deployZoneRedundantResources", + "type": "Microsoft.Common.DropDown", + "label": "Deploy Zone Redundant Resources", + "subLabel": "", + "defaultValue": "true", + "toolTip": "If true, any resources that support AZ will be deployed in all three AZ. However if the selected region is not supporting AZ, this parameter needs to be set to false", + "constraints": { + "required": true, + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "validations": [] + }, + "infoMessages": [], + "visible": true + }, + { + "name": "deployAzurePolicies", + "type": "Microsoft.Common.DropDown", + "label": "Deploy Azure Policies for Azure Container Apps", + "subLabel": "", + "defaultValue": "true", + "toolTip": "If true, built-in and custom Azure Policies for Azure Container Apps will be deployed in the spoke Resource Group. If false, no Azure Policies will be deployed.", + "constraints": { + "required": true, + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "validations": [] + }, + "infoMessages": [], + "visible": true + }, { "name": "location", "type": "Microsoft.Common.TextBox", @@ -193,12 +241,12 @@ "visible": true }, { - "name": "bastionSubnetAddressPrefix", + "name": "gatewaySubnetAddressPrefix", "type": "Microsoft.Common.TextBox", - "label": "Bastion Subnet Address Prefix", + "label": "Gateway Subnet Address Prefix", "subLabel": "", - "defaultValue": "10.0.0.128/26", - "toolTip": "CIDR to use for the Azure Bastion subnet.", + "defaultValue": "10.0.0.0/27", + "toolTip": "CIDR to use for the Gateway Subnet.", "constraints": { "required": true, "regex": "", @@ -209,12 +257,12 @@ "visible": true }, { - "name": "vmJumpBoxSubnetAddressPrefix", + "name": "azureFirewallSubnetAddressPrefix", "type": "Microsoft.Common.TextBox", - "label": "VM Jump Box Subnet Address Prefix", + "label": "Azure Firewall Subnet Address Prefix", "subLabel": "", - "defaultValue": "10.1.2.32/27", - "toolTip": "CIDR to use for the virtual machine subnet.", + "defaultValue": "10.0.0.64/26", + "toolTip": "CIDR to use for the Azure Firewall subnet.", "constraints": { "required": true, "regex": "", @@ -224,6 +272,22 @@ "infoMessages": [], "visible": true }, + { + "name": "bastionSubnetAddressPrefix", + "type": "Microsoft.Common.TextBox", + "label": "Bastion Subnet Address Prefix", + "subLabel": "", + "defaultValue": "10.0.0.128/26", + "toolTip": "CIDR to use for the Azure Bastion subnet.", + "constraints": { + "required": true, + "regex": "", + "validationMessage": "", + "validations": [] + }, + "infoMessages": [], + "visible": true + }, { "name": "sectionSpoke", "type": "Microsoft.Common.Section", @@ -293,6 +357,22 @@ "infoMessages": [], "visible": true }, + { + "name": "vmJumpBoxSubnetAddressPrefix", + "type": "Microsoft.Common.TextBox", + "label": "VM Jump Box Subnet Address Prefix", + "subLabel": "", + "defaultValue": "10.1.2.32/27", + "toolTip": "CIDR to use for the virtual machine subnet.", + "constraints": { + "required": true, + "regex": "", + "validationMessage": "", + "validations": [] + }, + "infoMessages": [], + "visible": true + }, { "name": "spokeApplicationGatewaySubnetAddressPrefix", "type": "Microsoft.Common.TextBox", @@ -562,7 +642,34 @@ "infoMessages": [], "visible": true }, - + { + "name": "ddosProtectionMode", + "type": "Microsoft.Common.DropDown", + "label": "Enable DDoS Protection", + "subLabel": "", + "defaultValue": "Enabled", + "toolTip": "DDoS protection mode for the Public IP of the Application Gateway. Allowed values are 'VirtualNetworkInherited', 'Enabled' and 'Disabled'", + "constraints": { + "required": true, + "allowedValues": [ + { + "label": "Enabled", + "value": "Enabled" + }, + { + "label": "VirtualNetworkInherited", + "value": "VirtualNetworkInherited" + }, + { + "label": "Disabled", + "value": "Disabled" + } + ], + "validations": [] + }, + "infoMessages": [], + "visible": true + }, { "name": "enableTelemetry", @@ -652,11 +759,15 @@ "parameters": { "workloadName": "[steps('basics').workloadName]", "environment": "[steps('basics').environment]", + "deployZoneRedundantResources": "[steps('basics').deployZoneRedundantResources]", + "deployAzurePolicies": "[steps('basics').deployAzurePolicies]", "location": "[steps('basics').location]", "hubResourceGroupName": "[steps('basics').hubResourceGroupName]", "spokeResourceGroupName": "[steps('basics').spokeResourceGroupName]", "vnetAddressPrefixes": "[steps('networking').vnetAddressPrefixes]", "vmJumpBoxSubnetAddressPrefix": "[steps('networking').vmJumpBoxSubnetAddressPrefix]", + "gatewaySubnetAddressPrefix": "[steps('networking').gatewaySubnetAddressPrefix]", + "azureFirewallSubnetAddressPrefix": "[steps('networking').azureFirewallSubnetAddressPrefix]", "bastionSubnetAddressPrefix": "[steps('networking').bastionSubnetAddressPrefix]", "spokeVNetAddressPrefixes": "[steps('networking').spokeVNetAddressPrefixes]", "spokeInfraSubnetAddressPrefix": "[steps('networking').spokeInfraSubnetAddressPrefix]", @@ -666,16 +777,17 @@ "vmAdminUsername": "[if( not( equals(steps('vmsettings').vmJumpboxOSType, 'none') ), steps('vmsettings').vmAdminUsername, 'azureuser')]", "vmAdminPassword": "[if( not( equals(steps('vmsettings').vmJumpboxOSType, 'none') ), steps('vmsettings').vmAdminPassword.password, 'Pass@word123$' )]", "vmLinuxSshAuthorizedKeys": "[if ( equals ( steps('vmsettings').vmJumpboxOSType, 'linux'), steps('vmsettings').vmLinuxSshAuthorizedKeys, 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDpNpoh248rsraL3uejAwKlla+pHaDLbp4DM7bKFoc3Rt1DeXPs0XTutJcNtq4iRq+ooRQ1T7WaK42MfQQxt3qkXwjyv8lPJ4v7aElWkAbxZIRYVYmQVxxwfw+zyB1rFdaCQD/kISg/zXxCWw+gdds4rEy7eq23/bXFM0l7pNvbAULIB6ZY7MRpC304lIAJusuZC59iwvjT3dWsDNWifA1SJtgr39yaxB9Fb01UdacwJNuvfGC35GNYH0VJ56c+iCFeAnMXIT00cYuHf0FCRTP0WvTKl+PQmeD1pwxefdFvKCVpidU2hOARb4ooapT0SDM1SODqjaZ/qwWP18y/qQ/v imported-openssh-key'])", - "vmJumpboxOSType": "[steps('vmsettings').vmJumpboxOSType]", - "enableBastion": "[steps('flags').enableBastion]", - "enableApplicationInsights": "[steps('flags').enableApplicationInsights]", - "enableDaprInstrumentation": "[steps('flags').enableDaprInstrumentation]", - "deployHelloWorldSample": "[steps('flags').deployHelloWorldSample]", + "vmJumpboxOSType": "[steps('vmsettings').vmJumpboxOSType]", "applicationGatewayFqdn": "acahello.demoapp.com", "enableApplicationGatewayCertificate": "true", "applicationGatewayCertificateKeyName": "agwcert", + "enableBastion": "[steps('flags').enableBastion]", + "enableApplicationInsights": "[steps('flags').enableApplicationInsights]", + "enableDaprInstrumentation": "[steps('flags').enableDaprInstrumentation]", + "deployHelloWorldSample": "[steps('flags').deployHelloWorldSample]", "enableTelemetry": "[steps('flags').enableTelemetry]", - "deployRedisCache": "[steps('flags').deployRedisCache]" + "deployRedisCache": "[steps('flags').deployRedisCache]", + "ddosProtectionMode": "[steps('flags').ddosProtectionMode]" }, "kind": "Subscription", "location": "[steps('basics').resourceScope.location.name]", diff --git a/scenarios/aca-internal/azure-resource-manager/main.json b/scenarios/aca-internal/azure-resource-manager/main.json index 0bbe381b..6f5a665e 100644 --- a/scenarios/aca-internal/azure-resource-manager/main.json +++ b/scenarios/aca-internal/azure-resource-manager/main.json @@ -4,16 +4,16 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "14308216302892243410" + "version": "0.20.4.51522", + "templateHash": "14914323878058747757" } }, "parameters": { "workloadName": { "type": "string", "defaultValue": "aca-lza", - "maxLength": 10, "minLength": 2, + "maxLength": 10, "metadata": { "description": "The name of the workload that is being deployed. Up to 10 characters long." } @@ -65,6 +65,18 @@ "description": "CIDR to use for the Azure Bastion subnet." } }, + "gatewaySubnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "CIDR to use for the gatewaySubnet." + } + }, + "azureFirewallSubnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "CIDR to use for the azureFirewallSubnet." + } + }, "vmSize": { "type": "string", "metadata": { @@ -161,7 +173,6 @@ }, "enableApplicationGatewayCertificate": { "type": "bool", - "defaultValue": true, "metadata": { "description": "Enable or disable Application Gateway Certificate (PFX)." } @@ -185,10 +196,36 @@ "metadata": { "description": "Optional, default value is false. If true, Azure Cache for Redis (Premium SKU), together with Private Endpoint and the relavant Private DNS Zone will be deployed" } + }, + "deployZoneRedundantResources": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional, default value is true. If true, any resources that support AZ will be deployed in all three AZ. However if the selected region is not supporting AZ, this parameter needs to be set to false." + } + }, + "deployAzurePolicies": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional, default value is true. If true, Azure Policies will be deployed" + } + }, + "ddosProtectionMode": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled", + "VirtualNetworkInherited" + ], + "metadata": { + "description": "Optional. DDoS protection mode. see https://learn.microsoft.com/azure/ddos-protection/ddos-protection-sku-comparison#skus" + } } }, "variables": { - "$fxv#0": "{\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\n \"resourceTypeAbbreviations\" : {\n \"applicationGateway\": \"agw\",\n \"applicationInsights\": \"appi\",\n \"appService\": \"app\",\n \"bastion\": \"bas\",\n \"containerAppsEnvironment\": \"cae\",\n \"containerRegistry\": \"cr\",\n \"cosmosDbNoSql\": \"cosno\",\n \"frontDoor\": \"afd\",\n \"frontDoorEndpoint\": \"fde\",\n \"frontDoorWaf\": \"fdfp\",\n \"keyVault\": \"kv\",\n \"logAnalyticsWorkspace\": \"log\",\n \"managedIdentity\": \"id\",\n \"networkInterface\": \"nic\",\n \"networkSecurityGroup\": \"nsg\",\n \"privateEndpoint\": \"pep\",\n \"privateLinkService\": \"pls\",\n \"publicIpAddress\": \"pip\",\n \"resourceGroup\": \"rg\",\n \"serviceBus\": \"sb\",\n \"serviceBusQueue\": \"sbq\",\n \"serviceBusTopic\": \"sbt\",\n \"storageAccount\": \"st\",\n \"virtualMachine\": \"vm\",\n \"virtualNetwork\": \"vnet\",\n \"redisCache\": \"redis\"\n },\n\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\n \"regionAbbreviations\" : {\n \"australiacentral\": \"auc\",\n \"australiacentral2\": \"auc2\",\n \"australiaeast\": \"aue\",\n \"australiasoutheast\": \"ause\",\n \"brazilsouth\": \"brs\",\n \"brazilsoutheast\": \"brse\",\n \"canadacentral\": \"canc\",\n \"canadaeast\": \"cane\",\n \"centralindia\": \"cin\",\n \"centralus\": \"cus\",\n \"centraluseuap\": \"cuseuap\",\n \"eastasia\": \"ea\",\n \"eastus\": \"eus\",\n \"eastus2\": \"eus2\",\n \"eastus2euap\": \"eus2euap\",\n \"francecentral\": \"frc\",\n \"francesouth\": \"frs\",\n \"germanynorth\": \"gern\",\n \"germanywestcentral\": \"gerwc\",\n \"japaneast\": \"jae\",\n \"japanwest\": \"jaw\",\n \"jioindiacentral\": \"jioinc\",\n \"jioindiawest\": \"jioinw\",\n \"koreacentral\": \"koc\",\n \"koreasouth\": \"kors\",\n \"northcentralus\": \"ncus\",\n \"northeurope\": \"neu\",\n \"norwayeast\": \"nore\",\n \"norwaywest\": \"norw\",\n \"southafricanorth\": \"san\",\n \"southafricawest\": \"saw\",\n \"southcentralus\": \"scus\",\n \"southeastasia\": \"sea\",\n \"southindia\": \"sin\",\n \"swedencentral\": \"swc\",\n \"switzerlandnorth\": \"swn\",\n \"switzerlandwest\": \"sww\",\n \"uaecentral\": \"uaec\",\n \"uaenorth\": \"uaen\",\n \"uksouth\": \"uks\",\n \"ukwest\": \"ukw\",\n \"westcentralus\": \"wcus\",\n \"westeurope\": \"weu\",\n \"westindia\": \"win\",\n \"westus\": \"wus\",\n \"westus2\": \"wus2\",\n \"westus3\": \"wus3\"\n }\n}", + "$fxv#0": "{\r\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\r\n \"resourceTypeAbbreviations\" : {\r\n \"applicationGateway\": \"agw\",\r\n \"applicationInsights\": \"appi\",\r\n \"appService\": \"app\",\r\n \"bastion\": \"bas\",\r\n \"containerAppsEnvironment\": \"cae\",\r\n \"containerRegistry\": \"cr\",\r\n \"cosmosDbNoSql\": \"cosno\",\r\n \"frontDoor\": \"afd\",\r\n \"frontDoorEndpoint\": \"fde\",\r\n \"frontDoorWaf\": \"fdfp\",\r\n \"keyVault\": \"kv\",\r\n \"logAnalyticsWorkspace\": \"log\",\r\n \"managedIdentity\": \"id\",\r\n \"networkInterface\": \"nic\",\r\n \"networkSecurityGroup\": \"nsg\",\r\n \"privateEndpoint\": \"pep\",\r\n \"privateLinkService\": \"pls\",\r\n \"publicIpAddress\": \"pip\",\r\n \"resourceGroup\": \"rg\",\r\n \"serviceBus\": \"sb\",\r\n \"serviceBusQueue\": \"sbq\",\r\n \"serviceBusTopic\": \"sbt\",\r\n \"storageAccount\": \"st\",\r\n \"virtualMachine\": \"vm\",\r\n \"virtualNetwork\": \"vnet\",\r\n \"redisCache\": \"redis\"\r\n },\r\n\r\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\r\n \"regionAbbreviations\" : {\r\n \"australiacentral\": \"auc\",\r\n \"australiacentral2\": \"auc2\",\r\n \"australiaeast\": \"aue\",\r\n \"australiasoutheast\": \"ause\",\r\n \"brazilsouth\": \"brs\",\r\n \"brazilsoutheast\": \"brse\",\r\n \"canadacentral\": \"canc\",\r\n \"canadaeast\": \"cane\",\r\n \"centralindia\": \"cin\",\r\n \"centralus\": \"cus\",\r\n \"centraluseuap\": \"cuseuap\",\r\n \"eastasia\": \"ea\",\r\n \"eastus\": \"eus\",\r\n \"eastus2\": \"eus2\",\r\n \"eastus2euap\": \"eus2euap\",\r\n \"francecentral\": \"frc\",\r\n \"francesouth\": \"frs\",\r\n \"germanynorth\": \"gern\",\r\n \"germanywestcentral\": \"gerwc\",\r\n \"japaneast\": \"jae\",\r\n \"japanwest\": \"jaw\",\r\n \"jioindiacentral\": \"jioinc\",\r\n \"jioindiawest\": \"jioinw\",\r\n \"koreacentral\": \"koc\",\r\n \"koreasouth\": \"kors\",\r\n \"northcentralus\": \"ncus\",\r\n \"northeurope\": \"neu\",\r\n \"norwayeast\": \"nore\",\r\n \"norwaywest\": \"norw\",\r\n \"southafricanorth\": \"san\",\r\n \"southafricawest\": \"saw\",\r\n \"southcentralus\": \"scus\",\r\n \"southeastasia\": \"sea\",\r\n \"southindia\": \"sin\",\r\n \"swedencentral\": \"swc\",\r\n \"switzerlandnorth\": \"swn\",\r\n \"switzerlandwest\": \"sww\",\r\n \"uaecentral\": \"uaec\",\r\n \"uaenorth\": \"uaen\",\r\n \"uksouth\": \"uks\",\r\n \"ukwest\": \"ukw\",\r\n \"westcentralus\": \"wcus\",\r\n \"westeurope\": \"weu\",\r\n \"westindia\": \"win\",\r\n \"westus\": \"wus\",\r\n \"westus2\": \"wus2\",\r\n \"westus3\": \"wus3\"\r\n }\r\n}", "namingRules": "[json(variables('$fxv#0'))]", "rgHubName": "[if(not(empty(parameters('hubResourceGroupName'))), parameters('hubResourceGroupName'), format('{0}-{1}-hub-{2}-{3}', variables('namingRules').resourceTypeAbbreviations.resourceGroup, parameters('workloadName'), parameters('environment'), variables('namingRules').regionAbbreviations[toLower(parameters('location'))]))]", "rgSpokeName": "[if(not(empty(parameters('spokeResourceGroupName'))), parameters('spokeResourceGroupName'), format('{0}-{1}-spoke-{2}-{3}', variables('namingRules').resourceTypeAbbreviations.resourceGroup, parameters('workloadName'), parameters('environment'), variables('namingRules').regionAbbreviations[toLower(parameters('location'))]))]" @@ -236,23 +273,11 @@ "bastionSubnetAddressPrefix": { "value": "[parameters('bastionSubnetAddressPrefix')]" }, - "vmSize": { - "value": "[parameters('vmSize')]" - }, - "vmAdminUsername": { - "value": "[parameters('vmAdminUsername')]" - }, - "vmAdminPassword": { - "value": "[parameters('vmAdminPassword')]" - }, - "vmLinuxSshAuthorizedKeys": { - "value": "[parameters('vmLinuxSshAuthorizedKeys')]" - }, - "vmJumpboxOSType": { - "value": "[parameters('vmJumpboxOSType')]" + "azureFirewallSubnetAddressPrefix": { + "value": "[parameters('azureFirewallSubnetAddressPrefix')]" }, - "vmJumpBoxSubnetAddressPrefix": { - "value": "[parameters('vmJumpBoxSubnetAddressPrefix')]" + "gatewaySubnetAddressPrefix": { + "value": "[parameters('gatewaySubnetAddressPrefix')]" } }, "template": { @@ -261,15 +286,15 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "15798059479114563505" + "version": "0.20.4.51522", + "templateHash": "4874053915765506288" } }, "parameters": { "workloadName": { "type": "string", - "maxLength": 10, "minLength": 2, + "maxLength": 10, "metadata": { "description": "The name of the workload that is being deployed. Up to 10 characters long." } @@ -320,62 +345,39 @@ "description": "CIDR to use for the Azure Bastion subnet." } }, - "vmSize": { - "type": "string", - "metadata": { - "description": "The size of the jump box virtual machine to create. See https://learn.microsoft.com/azure/virtual-machines/sizes for more information." - } - }, - "vmAdminUsername": { - "type": "string", - "metadata": { - "description": "The username to use for the jump box." - } - }, - "vmAdminPassword": { - "type": "securestring", - "metadata": { - "description": "The password to use for the jump box." - } - }, - "vmLinuxSshAuthorizedKeys": { - "type": "securestring", - "metadata": { - "description": "The SSH public key to use for the jump box. Only relevant for Linux." - } - }, - "vmJumpboxOSType": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "linux", - "windows", - "none" - ], - "metadata": { - "description": "The OS of the jump box virtual machine to create. If set to \"none\", no jump box will be created." - } - }, - "vmSubnetName": { + "gatewaySubnetAddressPrefix": { "type": "string", - "defaultValue": "snet-jumpbox", "metadata": { - "description": "Optional. The name of the subnet to create for the jump box. If set, it overrides the name generated by the template." + "description": "CIDR to use for the gatewaySubnet." } }, - "vmJumpBoxSubnetAddressPrefix": { + "azureFirewallSubnetAddressPrefix": { "type": "string", "metadata": { - "description": "CIDR to use for the jump box subnet." + "description": "CIDR to use for the azureFirewallSubnet." } } }, "variables": { - "$fxv#0": "{\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\n \"resourceTypeAbbreviations\" : {\n \"applicationGateway\": \"agw\",\n \"applicationInsights\": \"appi\",\n \"appService\": \"app\",\n \"bastion\": \"bas\",\n \"containerAppsEnvironment\": \"cae\",\n \"containerRegistry\": \"cr\",\n \"cosmosDbNoSql\": \"cosno\",\n \"frontDoor\": \"afd\",\n \"frontDoorEndpoint\": \"fde\",\n \"frontDoorWaf\": \"fdfp\",\n \"keyVault\": \"kv\",\n \"logAnalyticsWorkspace\": \"log\",\n \"managedIdentity\": \"id\",\n \"networkInterface\": \"nic\",\n \"networkSecurityGroup\": \"nsg\",\n \"privateEndpoint\": \"pep\",\n \"privateLinkService\": \"pls\",\n \"publicIpAddress\": \"pip\",\n \"resourceGroup\": \"rg\",\n \"serviceBus\": \"sb\",\n \"serviceBusQueue\": \"sbq\",\n \"serviceBusTopic\": \"sbt\",\n \"storageAccount\": \"st\",\n \"virtualMachine\": \"vm\",\n \"virtualNetwork\": \"vnet\",\n \"redisCache\": \"redis\"\n },\n\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\n \"regionAbbreviations\" : {\n \"australiacentral\": \"auc\",\n \"australiacentral2\": \"auc2\",\n \"australiaeast\": \"aue\",\n \"australiasoutheast\": \"ause\",\n \"brazilsouth\": \"brs\",\n \"brazilsoutheast\": \"brse\",\n \"canadacentral\": \"canc\",\n \"canadaeast\": \"cane\",\n \"centralindia\": \"cin\",\n \"centralus\": \"cus\",\n \"centraluseuap\": \"cuseuap\",\n \"eastasia\": \"ea\",\n \"eastus\": \"eus\",\n \"eastus2\": \"eus2\",\n \"eastus2euap\": \"eus2euap\",\n \"francecentral\": \"frc\",\n \"francesouth\": \"frs\",\n \"germanynorth\": \"gern\",\n \"germanywestcentral\": \"gerwc\",\n \"japaneast\": \"jae\",\n \"japanwest\": \"jaw\",\n \"jioindiacentral\": \"jioinc\",\n \"jioindiawest\": \"jioinw\",\n \"koreacentral\": \"koc\",\n \"koreasouth\": \"kors\",\n \"northcentralus\": \"ncus\",\n \"northeurope\": \"neu\",\n \"norwayeast\": \"nore\",\n \"norwaywest\": \"norw\",\n \"southafricanorth\": \"san\",\n \"southafricawest\": \"saw\",\n \"southcentralus\": \"scus\",\n \"southeastasia\": \"sea\",\n \"southindia\": \"sin\",\n \"swedencentral\": \"swc\",\n \"switzerlandnorth\": \"swn\",\n \"switzerlandwest\": \"sww\",\n \"uaecentral\": \"uaec\",\n \"uaenorth\": \"uaen\",\n \"uksouth\": \"uks\",\n \"ukwest\": \"ukw\",\n \"westcentralus\": \"wcus\",\n \"westeurope\": \"weu\",\n \"westindia\": \"win\",\n \"westus\": \"wus\",\n \"westus2\": \"wus2\",\n \"westus3\": \"wus3\"\n }\n}", - "defaultSubnets": [], + "$fxv#0": "{\r\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\r\n \"resourceTypeAbbreviations\" : {\r\n \"applicationGateway\": \"agw\",\r\n \"applicationInsights\": \"appi\",\r\n \"appService\": \"app\",\r\n \"bastion\": \"bas\",\r\n \"containerAppsEnvironment\": \"cae\",\r\n \"containerRegistry\": \"cr\",\r\n \"cosmosDbNoSql\": \"cosno\",\r\n \"frontDoor\": \"afd\",\r\n \"frontDoorEndpoint\": \"fde\",\r\n \"frontDoorWaf\": \"fdfp\",\r\n \"keyVault\": \"kv\",\r\n \"logAnalyticsWorkspace\": \"log\",\r\n \"managedIdentity\": \"id\",\r\n \"networkInterface\": \"nic\",\r\n \"networkSecurityGroup\": \"nsg\",\r\n \"privateEndpoint\": \"pep\",\r\n \"privateLinkService\": \"pls\",\r\n \"publicIpAddress\": \"pip\",\r\n \"resourceGroup\": \"rg\",\r\n \"serviceBus\": \"sb\",\r\n \"serviceBusQueue\": \"sbq\",\r\n \"serviceBusTopic\": \"sbt\",\r\n \"storageAccount\": \"st\",\r\n \"virtualMachine\": \"vm\",\r\n \"virtualNetwork\": \"vnet\",\r\n \"redisCache\": \"redis\"\r\n },\r\n\r\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\r\n \"regionAbbreviations\" : {\r\n \"australiacentral\": \"auc\",\r\n \"australiacentral2\": \"auc2\",\r\n \"australiaeast\": \"aue\",\r\n \"australiasoutheast\": \"ause\",\r\n \"brazilsouth\": \"brs\",\r\n \"brazilsoutheast\": \"brse\",\r\n \"canadacentral\": \"canc\",\r\n \"canadaeast\": \"cane\",\r\n \"centralindia\": \"cin\",\r\n \"centralus\": \"cus\",\r\n \"centraluseuap\": \"cuseuap\",\r\n \"eastasia\": \"ea\",\r\n \"eastus\": \"eus\",\r\n \"eastus2\": \"eus2\",\r\n \"eastus2euap\": \"eus2euap\",\r\n \"francecentral\": \"frc\",\r\n \"francesouth\": \"frs\",\r\n \"germanynorth\": \"gern\",\r\n \"germanywestcentral\": \"gerwc\",\r\n \"japaneast\": \"jae\",\r\n \"japanwest\": \"jaw\",\r\n \"jioindiacentral\": \"jioinc\",\r\n \"jioindiawest\": \"jioinw\",\r\n \"koreacentral\": \"koc\",\r\n \"koreasouth\": \"kors\",\r\n \"northcentralus\": \"ncus\",\r\n \"northeurope\": \"neu\",\r\n \"norwayeast\": \"nore\",\r\n \"norwaywest\": \"norw\",\r\n \"southafricanorth\": \"san\",\r\n \"southafricawest\": \"saw\",\r\n \"southcentralus\": \"scus\",\r\n \"southeastasia\": \"sea\",\r\n \"southindia\": \"sin\",\r\n \"swedencentral\": \"swc\",\r\n \"switzerlandnorth\": \"swn\",\r\n \"switzerlandwest\": \"sww\",\r\n \"uaecentral\": \"uaec\",\r\n \"uaenorth\": \"uaen\",\r\n \"uksouth\": \"uks\",\r\n \"ukwest\": \"ukw\",\r\n \"westcentralus\": \"wcus\",\r\n \"westeurope\": \"weu\",\r\n \"westindia\": \"win\",\r\n \"westus\": \"wus\",\r\n \"westus2\": \"wus2\",\r\n \"westus3\": \"wus3\"\r\n }\r\n}", + "gatewaySubnetName": "GatewaySubnet", + "azureFirewallSubnetName": "AzureFirewallSubnet", + "defaultSubnets": [ + { + "name": "[variables('gatewaySubnetName')]", + "properties": { + "addressPrefix": "[parameters('gatewaySubnetAddressPrefix')]" + } + }, + { + "name": "[variables('azureFirewallSubnetName')]", + "properties": { + "addressPrefix": "[parameters('azureFirewallSubnetAddressPrefix')]" + } + } + ], "bastionSubnetName": "AzureBastionSubnet", - "subnets": "[if(parameters('enableBastion'), concat(variables('defaultSubnets'), createArray(createObject('name', variables('bastionSubnetName'), 'properties', createObject('addressPrefix', parameters('bastionSubnetAddressPrefix'))))), variables('defaultSubnets'))]", - "vnetSubnets": "[if(not(equals(parameters('vmJumpboxOSType'), 'none')), concat(variables('subnets'), createArray(createObject('name', parameters('vmSubnetName'), 'properties', createObject('addressPrefix', parameters('vmJumpBoxSubnetAddressPrefix'))))), variables('subnets'))]", + "vnetSubnets": "[if(parameters('enableBastion'), concat(variables('defaultSubnets'), createArray(createObject('name', variables('bastionSubnetName'), 'properties', createObject('addressPrefix', parameters('bastionSubnetAddressPrefix'))))), variables('defaultSubnets'))]", "namingRules": "[json(variables('$fxv#0'))]", "rgHubName": "[if(not(empty(parameters('hubResourceGroupName'))), parameters('hubResourceGroupName'), format('{0}-{1}-hub-{2}-{3}', variables('namingRules').resourceTypeAbbreviations.resourceGroup, parameters('workloadName'), parameters('environment'), variables('namingRules').regionAbbreviations[toLower(parameters('location'))]))]" }, @@ -420,18 +422,18 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "14985913302549051532" + "version": "0.20.4.51522", + "templateHash": "6817832201461302860" } }, "parameters": { "workloadName": { "type": "string", + "minLength": 2, + "maxLength": 10, "metadata": { "description": "The name of the workloard that is being deployed. Up to 10 characters long." - }, - "maxLength": 10, - "minLength": 2 + } }, "environment": { "type": "string", @@ -454,7 +456,7 @@ } }, "variables": { - "$fxv#0": "{\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\n \"resourceTypeAbbreviations\" : {\n \"applicationGateway\": \"agw\",\n \"applicationInsights\": \"appi\",\n \"appService\": \"app\",\n \"bastion\": \"bas\",\n \"containerAppsEnvironment\": \"cae\",\n \"containerRegistry\": \"cr\",\n \"cosmosDbNoSql\": \"cosno\",\n \"frontDoor\": \"afd\",\n \"frontDoorEndpoint\": \"fde\",\n \"frontDoorWaf\": \"fdfp\",\n \"keyVault\": \"kv\",\n \"logAnalyticsWorkspace\": \"log\",\n \"managedIdentity\": \"id\",\n \"networkInterface\": \"nic\",\n \"networkSecurityGroup\": \"nsg\",\n \"privateEndpoint\": \"pep\",\n \"privateLinkService\": \"pls\",\n \"publicIpAddress\": \"pip\",\n \"resourceGroup\": \"rg\",\n \"serviceBus\": \"sb\",\n \"serviceBusQueue\": \"sbq\",\n \"serviceBusTopic\": \"sbt\",\n \"storageAccount\": \"st\",\n \"virtualMachine\": \"vm\",\n \"virtualNetwork\": \"vnet\",\n \"redisCache\": \"redis\"\n },\n\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\n \"regionAbbreviations\" : {\n \"australiacentral\": \"auc\",\n \"australiacentral2\": \"auc2\",\n \"australiaeast\": \"aue\",\n \"australiasoutheast\": \"ause\",\n \"brazilsouth\": \"brs\",\n \"brazilsoutheast\": \"brse\",\n \"canadacentral\": \"canc\",\n \"canadaeast\": \"cane\",\n \"centralindia\": \"cin\",\n \"centralus\": \"cus\",\n \"centraluseuap\": \"cuseuap\",\n \"eastasia\": \"ea\",\n \"eastus\": \"eus\",\n \"eastus2\": \"eus2\",\n \"eastus2euap\": \"eus2euap\",\n \"francecentral\": \"frc\",\n \"francesouth\": \"frs\",\n \"germanynorth\": \"gern\",\n \"germanywestcentral\": \"gerwc\",\n \"japaneast\": \"jae\",\n \"japanwest\": \"jaw\",\n \"jioindiacentral\": \"jioinc\",\n \"jioindiawest\": \"jioinw\",\n \"koreacentral\": \"koc\",\n \"koreasouth\": \"kors\",\n \"northcentralus\": \"ncus\",\n \"northeurope\": \"neu\",\n \"norwayeast\": \"nore\",\n \"norwaywest\": \"norw\",\n \"southafricanorth\": \"san\",\n \"southafricawest\": \"saw\",\n \"southcentralus\": \"scus\",\n \"southeastasia\": \"sea\",\n \"southindia\": \"sin\",\n \"swedencentral\": \"swc\",\n \"switzerlandnorth\": \"swn\",\n \"switzerlandwest\": \"sww\",\n \"uaecentral\": \"uaec\",\n \"uaenorth\": \"uaen\",\n \"uksouth\": \"uks\",\n \"ukwest\": \"ukw\",\n \"westcentralus\": \"wcus\",\n \"westeurope\": \"weu\",\n \"westindia\": \"win\",\n \"westus\": \"wus\",\n \"westus2\": \"wus2\",\n \"westus3\": \"wus3\"\n }\n}", + "$fxv#0": "{\r\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\r\n \"resourceTypeAbbreviations\" : {\r\n \"applicationGateway\": \"agw\",\r\n \"applicationInsights\": \"appi\",\r\n \"appService\": \"app\",\r\n \"bastion\": \"bas\",\r\n \"containerAppsEnvironment\": \"cae\",\r\n \"containerRegistry\": \"cr\",\r\n \"cosmosDbNoSql\": \"cosno\",\r\n \"frontDoor\": \"afd\",\r\n \"frontDoorEndpoint\": \"fde\",\r\n \"frontDoorWaf\": \"fdfp\",\r\n \"keyVault\": \"kv\",\r\n \"logAnalyticsWorkspace\": \"log\",\r\n \"managedIdentity\": \"id\",\r\n \"networkInterface\": \"nic\",\r\n \"networkSecurityGroup\": \"nsg\",\r\n \"privateEndpoint\": \"pep\",\r\n \"privateLinkService\": \"pls\",\r\n \"publicIpAddress\": \"pip\",\r\n \"resourceGroup\": \"rg\",\r\n \"serviceBus\": \"sb\",\r\n \"serviceBusQueue\": \"sbq\",\r\n \"serviceBusTopic\": \"sbt\",\r\n \"storageAccount\": \"st\",\r\n \"virtualMachine\": \"vm\",\r\n \"virtualNetwork\": \"vnet\",\r\n \"redisCache\": \"redis\"\r\n },\r\n\r\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\r\n \"regionAbbreviations\" : {\r\n \"australiacentral\": \"auc\",\r\n \"australiacentral2\": \"auc2\",\r\n \"australiaeast\": \"aue\",\r\n \"australiasoutheast\": \"ause\",\r\n \"brazilsouth\": \"brs\",\r\n \"brazilsoutheast\": \"brse\",\r\n \"canadacentral\": \"canc\",\r\n \"canadaeast\": \"cane\",\r\n \"centralindia\": \"cin\",\r\n \"centralus\": \"cus\",\r\n \"centraluseuap\": \"cuseuap\",\r\n \"eastasia\": \"ea\",\r\n \"eastus\": \"eus\",\r\n \"eastus2\": \"eus2\",\r\n \"eastus2euap\": \"eus2euap\",\r\n \"francecentral\": \"frc\",\r\n \"francesouth\": \"frs\",\r\n \"germanynorth\": \"gern\",\r\n \"germanywestcentral\": \"gerwc\",\r\n \"japaneast\": \"jae\",\r\n \"japanwest\": \"jaw\",\r\n \"jioindiacentral\": \"jioinc\",\r\n \"jioindiawest\": \"jioinw\",\r\n \"koreacentral\": \"koc\",\r\n \"koreasouth\": \"kors\",\r\n \"northcentralus\": \"ncus\",\r\n \"northeurope\": \"neu\",\r\n \"norwayeast\": \"nore\",\r\n \"norwaywest\": \"norw\",\r\n \"southafricanorth\": \"san\",\r\n \"southafricawest\": \"saw\",\r\n \"southcentralus\": \"scus\",\r\n \"southeastasia\": \"sea\",\r\n \"southindia\": \"sin\",\r\n \"swedencentral\": \"swc\",\r\n \"switzerlandnorth\": \"swn\",\r\n \"switzerlandwest\": \"sww\",\r\n \"uaecentral\": \"uaec\",\r\n \"uaenorth\": \"uaen\",\r\n \"uksouth\": \"uks\",\r\n \"ukwest\": \"ukw\",\r\n \"westcentralus\": \"wcus\",\r\n \"westeurope\": \"weu\",\r\n \"westindia\": \"win\",\r\n \"westus\": \"wus\",\r\n \"westus2\": \"wus2\",\r\n \"westus3\": \"wus3\"\r\n }\r\n}", "naming": "[json(variables('$fxv#0'))]", "uniqueIdShort": "[substring(parameters('uniqueId'), 0, 5)]", "resourceTypeToken": "RES_TYPE", @@ -470,6 +472,7 @@ "applicationGatewayPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", "applicationGatewayUserAssignedIdentity": "[format('{0}-{1}-KeyVaultSecretUser', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", "applicationGatewayNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", + "pepNsg": "[format('{0}-pep', variables('naming').resourceTypeAbbreviations.networkSecurityGroup)]", "applicationInsights": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationInsights)]", "bastion": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion)]", "bastionNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", @@ -486,7 +489,6 @@ "frontDoorProfile": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]", "keyVault": "[if(endsWith(variables('keyVaultName'), '-'), take(variables('keyVaultName'), 23), variables('keyVaultName'))]", "keyVaultPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", - "keyVaultUserAssignedIdentity": "[format('{0}-{1}-KeyVaultReader', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", "logAnalyticsWorkspace": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.logAnalyticsWorkspace)]", "serviceBus": "[replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus)]", "serviceBusPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus))]", @@ -551,15 +553,15 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "10750814407079155041" + "version": "0.20.4.51522", + "templateHash": "16217514057343077749" } }, "parameters": { "name": { "type": "string", - "maxLength": 80, "minLength": 2, + "maxLength": 80, "metadata": { "description": "Name of the resource Virtual Network (The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens)" } @@ -703,8 +705,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "11089184817356857131" + "version": "0.20.4.51522", + "templateHash": "10067602788727268258" } }, "parameters": { @@ -950,518 +952,107 @@ "metadata": { "description": "An optional Azure Bastion deployment for jump box access. This would normally be already provisioned by your platform team." } + } + ], + "outputs": { + "hubVNetId": { + "type": "string", + "metadata": { + "description": "The resource ID of hub virtual network." + }, + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('vnetHub-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetId.value]" }, - { - "condition": "[equals(parameters('vmJumpboxOSType'), 'linux')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('vm-linux-{0}', deployment().name), 64)]", - "resourceGroup": "[variables('rgHubName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "vmName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('01-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.vmJumpBox]" - }, - "vmAdminUsername": { - "value": "[parameters('vmAdminUsername')]" - }, - "vmAdminPassword": { - "value": "[parameters('vmAdminPassword')]" - }, - "vmSshPublicKey": { - "value": "[parameters('vmLinuxSshAuthorizedKeys')]" - }, - "vmSize": { - "value": "[parameters('vmSize')]" - }, - "vmVnetName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('vnetHub-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value]" - }, - "vmSubnetName": { - "value": "[parameters('vmSubnetName')]" - }, - "vmSubnetAddressPrefix": { - "value": "[parameters('vmJumpBoxSubnetAddressPrefix')]" - }, - "vmNetworkInterfaceName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('01-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.vmJumpBoxNic]" - }, - "vmNetworkSecurityGroupName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('01-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.vmJumpBoxNsg]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "11874839089691230966" - } - }, - "parameters": { - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - }, - "vmVnetName": { - "type": "string" - }, - "vmSubnetName": { - "type": "string" - }, - "vmSubnetAddressPrefix": { - "type": "string" - }, - "vmNetworkSecurityGroupName": { - "type": "string" - }, - "vmNetworkInterfaceName": { - "type": "string" - }, - "vmAdminUsername": { - "type": "string" - }, - "vmAdminPassword": { - "type": "securestring" - }, - "vmSshPublicKey": { - "type": "securestring" - }, - "vmAuthenticationType": { - "type": "string", - "defaultValue": "password", - "allowedValues": [ - "sshPublicKey", - "password" - ], - "metadata": { - "description": "Type of authentication to use on the Virtual Machine. SSH key is recommended." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The tags to be assigned to the created resources." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]" - } - }, - "variables": { - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "path": "[format('/home/{0}/.ssh/authorized_keys', parameters('vmAdminUsername'))]", - "keyData": "[parameters('vmSshPublicKey')]" - } - ] - } - } - }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2020-06-01", - "name": "[parameters('vmNetworkSecurityGroupName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "securityRules": [] - } - }, - { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2020-11-01", - "name": "[format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName'))]", - "properties": { - "addressPrefix": "[parameters('vmSubnetAddressPrefix')]", - "networkSecurityGroup": { - "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('vmNetworkSecurityGroupName'))]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('vmNetworkSecurityGroupName'))]" - ] - }, - { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2021-02-01", - "name": "[parameters('vmNetworkInterfaceName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "subnet": { - "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[0], split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[1])]" - }, - "privateIPAllocationMethod": "Dynamic" - } - } - ] - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/virtualNetworks/subnets', split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[0], split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[1])]" - ] - }, - { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2021-03-01", - "name": "[parameters('vmName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "osProfile": { - "computerName": "[parameters('vmName')]", - "adminUsername": "[parameters('vmAdminUsername')]", - "adminPassword": "[parameters('vmAdminPassword')]", - "linuxConfiguration": "[if(equals(parameters('vmAuthenticationType'), 'password'), null(), variables('linuxConfiguration'))]" - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "storageProfile": { - "osDisk": { - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "Standard_LRS" - } - }, - "imageReference": { - "publisher": "Canonical", - "offer": "UbuntuServer", - "sku": "18.04-LTS", - "version": "latest" - } - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('vmNetworkInterfaceName'))]" - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkInterfaces', parameters('vmNetworkInterfaceName'))]" - ] - } - ] - } + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the hub resource group." }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgHubName'))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('01-sharedNamingDeployment-{0}', deployment().name), 64))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('vnetHub-{0}', deployment().name), 64))]" - ], + "value": "[variables('rgHubName')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('spoke-{0}-deployment', deployment().name), 64)]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "spokeResourceGroupName": { + "value": "[variables('rgSpokeName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "environment": { + "value": "[parameters('environment')]" + }, + "workloadName": { + "value": "[parameters('workloadName')]" + }, + "hubVNetId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('hub-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.hubVNetId.value]" + }, + "spokeApplicationGatewaySubnetAddressPrefix": { + "value": "[parameters('spokeApplicationGatewaySubnetAddressPrefix')]" + }, + "spokeInfraSubnetAddressPrefix": { + "value": "[parameters('spokeInfraSubnetAddressPrefix')]" + }, + "spokePrivateEndpointsSubnetAddressPrefix": { + "value": "[parameters('spokePrivateEndpointsSubnetAddressPrefix')]" + }, + "spokeVNetAddressPrefixes": { + "value": "[parameters('spokeVNetAddressPrefixes')]" + }, + "vmSize": { + "value": "[parameters('vmSize')]" + }, + "vmAdminUsername": { + "value": "[parameters('vmAdminUsername')]" + }, + "vmAdminPassword": { + "value": "[parameters('vmAdminPassword')]" + }, + "vmLinuxSshAuthorizedKeys": { + "value": "[parameters('vmLinuxSshAuthorizedKeys')]" + }, + "vmJumpboxOSType": { + "value": "[parameters('vmJumpboxOSType')]" + }, + "vmJumpBoxSubnetAddressPrefix": { + "value": "[parameters('vmJumpBoxSubnetAddressPrefix')]" + }, + "deployAzurePolicies": { + "value": "[parameters('deployAzurePolicies')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "5087634839071873859" + } + }, + "parameters": { + "workloadName": { + "type": "string", + "minLength": 2, + "maxLength": 10, "metadata": { - "description": "An optional Linux virtual machine deployment to act as a jump box." - } - }, - { - "condition": "[equals(parameters('vmJumpboxOSType'), 'windows')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('vm-windows-{0}', deployment().name), 64)]", - "resourceGroup": "[variables('rgHubName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "vmName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('01-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.vmJumpBox]" - }, - "vmAdminUsername": { - "value": "[parameters('vmAdminUsername')]" - }, - "vmAdminPassword": { - "value": "[parameters('vmAdminPassword')]" - }, - "vmSize": { - "value": "[parameters('vmSize')]" - }, - "vmVnetName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('vnetHub-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value]" - }, - "vmSubnetName": { - "value": "[parameters('vmSubnetName')]" - }, - "vmSubnetAddressPrefix": { - "value": "[parameters('vmJumpBoxSubnetAddressPrefix')]" - }, - "vmNetworkInterfaceName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('01-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.vmJumpBoxNic]" - }, - "vmNetworkSecurityGroupName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('01-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.vmJumpBoxNsg]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "13764422953123404114" - } - }, - "parameters": { - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - }, - "vmWindowsOSVersion": { - "type": "string", - "defaultValue": "2016-Datacenter" - }, - "vmVnetName": { - "type": "string" - }, - "vmSubnetName": { - "type": "string" - }, - "vmSubnetAddressPrefix": { - "type": "string" - }, - "vmNetworkSecurityGroupName": { - "type": "string" - }, - "vmNetworkInterfaceName": { - "type": "string" - }, - "vmAdminUsername": { - "type": "string" - }, - "vmAdminPassword": { - "type": "securestring" - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The tags to be assigned to the created resources." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]" - } - }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2020-06-01", - "name": "[parameters('vmNetworkSecurityGroupName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "securityRules": [] - } - }, - { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2020-11-01", - "name": "[format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName'))]", - "properties": { - "addressPrefix": "[parameters('vmSubnetAddressPrefix')]", - "networkSecurityGroup": { - "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('vmNetworkSecurityGroupName'))]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('vmNetworkSecurityGroupName'))]" - ] - }, - { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2021-02-01", - "name": "[parameters('vmNetworkInterfaceName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "subnet": { - "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[0], split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[1])]" - }, - "privateIPAllocationMethod": "Dynamic" - } - } - ] - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/virtualNetworks/subnets', split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[0], split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[1])]" - ] - }, - { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2021-04-01", - "name": "[parameters('vmName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "zones": [ - "1" - ], - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "storageProfile": { - "osDisk": { - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "Standard_LRS" - } - }, - "imageReference": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "[parameters('vmWindowsOSVersion')]", - "version": "latest" - } - }, - "osProfile": { - "computerName": "[parameters('vmName')]", - "adminUsername": "[parameters('vmAdminUsername')]", - "adminPassword": "[parameters('vmAdminPassword')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('vmNetworkInterfaceName'))]" - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkInterfaces', parameters('vmNetworkInterfaceName'))]" - ] - } - ] - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgHubName'))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('01-sharedNamingDeployment-{0}', deployment().name), 64))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('vnetHub-{0}', deployment().name), 64))]" - ], - "metadata": { - "description": "An optional Windows virtual machine deployment to act as a jump box." - } - } - ], - "outputs": { - "hubVNetId": { - "type": "string", - "metadata": { - "description": "The resource ID of hub virtual network." - }, - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgHubName')), 'Microsoft.Resources/deployments', take(format('vnetHub-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetId.value]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the hub resource group." - }, - "value": "[variables('rgHubName')]" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('spoke-{0}-deployment', deployment().name), 64)]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "spokeResourceGroupName": { - "value": "[variables('rgSpokeName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "environment": { - "value": "[parameters('environment')]" - }, - "workloadName": { - "value": "[parameters('workloadName')]" - }, - "hubVNetId": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('hub-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.hubVNetId.value]" - }, - "spokeApplicationGatewaySubnetAddressPrefix": { - "value": "[parameters('spokeApplicationGatewaySubnetAddressPrefix')]" - }, - "spokeInfraSubnetAddressPrefix": { - "value": "[parameters('spokeInfraSubnetAddressPrefix')]" - }, - "spokePrivateEndpointsSubnetAddressPrefix": { - "value": "[parameters('spokePrivateEndpointsSubnetAddressPrefix')]" - }, - "spokeVNetAddressPrefixes": { - "value": "[parameters('spokeVNetAddressPrefixes')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "449241502517533227" - } - }, - "parameters": { - "workloadName": { - "type": "string", - "maxLength": 10, - "minLength": 2, - "metadata": { - "description": "The name of the workload that is being deployed. Up to 10 characters long." + "description": "The name of the workload that is being deployed. Up to 10 characters long." } }, "environment": { @@ -1541,6 +1132,62 @@ "metadata": { "description": "CIDR of the spoke Application Gateway subnet. If the value is empty, this subnet will not be created." } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "The size of the jump box virtual machine to create. See https://learn.microsoft.com/azure/virtual-machines/sizes for more information." + } + }, + "vmAdminUsername": { + "type": "string", + "metadata": { + "description": "The username to use for the jump box." + } + }, + "vmAdminPassword": { + "type": "securestring", + "metadata": { + "description": "The password to use for the jump box." + } + }, + "vmLinuxSshAuthorizedKeys": { + "type": "securestring", + "metadata": { + "description": "The SSH public key to use for the jump box. Only relevant for Linux." + } + }, + "vmJumpboxOSType": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "linux", + "windows", + "none" + ], + "metadata": { + "description": "The OS of the jump box virtual machine to create. If set to \"none\", no jump box will be created." + } + }, + "vmSubnetName": { + "type": "string", + "defaultValue": "snet-jumpbox", + "metadata": { + "description": "Optional. The name of the subnet to create for the jump box. If set, it overrides the name generated by the template." + } + }, + "vmJumpBoxSubnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "CIDR to use for the jump box subnet." + } + }, + "deployAzurePolicies": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional, default value is true. If true, Azure Policies will be deployed" + } } }, "variables": { @@ -1603,7 +1250,7 @@ } } ], - "$fxv#2": "{\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\n \"resourceTypeAbbreviations\" : {\n \"applicationGateway\": \"agw\",\n \"applicationInsights\": \"appi\",\n \"appService\": \"app\",\n \"bastion\": \"bas\",\n \"containerAppsEnvironment\": \"cae\",\n \"containerRegistry\": \"cr\",\n \"cosmosDbNoSql\": \"cosno\",\n \"frontDoor\": \"afd\",\n \"frontDoorEndpoint\": \"fde\",\n \"frontDoorWaf\": \"fdfp\",\n \"keyVault\": \"kv\",\n \"logAnalyticsWorkspace\": \"log\",\n \"managedIdentity\": \"id\",\n \"networkInterface\": \"nic\",\n \"networkSecurityGroup\": \"nsg\",\n \"privateEndpoint\": \"pep\",\n \"privateLinkService\": \"pls\",\n \"publicIpAddress\": \"pip\",\n \"resourceGroup\": \"rg\",\n \"serviceBus\": \"sb\",\n \"serviceBusQueue\": \"sbq\",\n \"serviceBusTopic\": \"sbt\",\n \"storageAccount\": \"st\",\n \"virtualMachine\": \"vm\",\n \"virtualNetwork\": \"vnet\",\n \"redisCache\": \"redis\"\n },\n\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\n \"regionAbbreviations\" : {\n \"australiacentral\": \"auc\",\n \"australiacentral2\": \"auc2\",\n \"australiaeast\": \"aue\",\n \"australiasoutheast\": \"ause\",\n \"brazilsouth\": \"brs\",\n \"brazilsoutheast\": \"brse\",\n \"canadacentral\": \"canc\",\n \"canadaeast\": \"cane\",\n \"centralindia\": \"cin\",\n \"centralus\": \"cus\",\n \"centraluseuap\": \"cuseuap\",\n \"eastasia\": \"ea\",\n \"eastus\": \"eus\",\n \"eastus2\": \"eus2\",\n \"eastus2euap\": \"eus2euap\",\n \"francecentral\": \"frc\",\n \"francesouth\": \"frs\",\n \"germanynorth\": \"gern\",\n \"germanywestcentral\": \"gerwc\",\n \"japaneast\": \"jae\",\n \"japanwest\": \"jaw\",\n \"jioindiacentral\": \"jioinc\",\n \"jioindiawest\": \"jioinw\",\n \"koreacentral\": \"koc\",\n \"koreasouth\": \"kors\",\n \"northcentralus\": \"ncus\",\n \"northeurope\": \"neu\",\n \"norwayeast\": \"nore\",\n \"norwaywest\": \"norw\",\n \"southafricanorth\": \"san\",\n \"southafricawest\": \"saw\",\n \"southcentralus\": \"scus\",\n \"southeastasia\": \"sea\",\n \"southindia\": \"sin\",\n \"swedencentral\": \"swc\",\n \"switzerlandnorth\": \"swn\",\n \"switzerlandwest\": \"sww\",\n \"uaecentral\": \"uaec\",\n \"uaenorth\": \"uaen\",\n \"uksouth\": \"uks\",\n \"ukwest\": \"ukw\",\n \"westcentralus\": \"wcus\",\n \"westeurope\": \"weu\",\n \"westindia\": \"win\",\n \"westus\": \"wus\",\n \"westus2\": \"wus2\",\n \"westus3\": \"wus3\"\n }\n}", + "$fxv#2": "{\r\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\r\n \"resourceTypeAbbreviations\" : {\r\n \"applicationGateway\": \"agw\",\r\n \"applicationInsights\": \"appi\",\r\n \"appService\": \"app\",\r\n \"bastion\": \"bas\",\r\n \"containerAppsEnvironment\": \"cae\",\r\n \"containerRegistry\": \"cr\",\r\n \"cosmosDbNoSql\": \"cosno\",\r\n \"frontDoor\": \"afd\",\r\n \"frontDoorEndpoint\": \"fde\",\r\n \"frontDoorWaf\": \"fdfp\",\r\n \"keyVault\": \"kv\",\r\n \"logAnalyticsWorkspace\": \"log\",\r\n \"managedIdentity\": \"id\",\r\n \"networkInterface\": \"nic\",\r\n \"networkSecurityGroup\": \"nsg\",\r\n \"privateEndpoint\": \"pep\",\r\n \"privateLinkService\": \"pls\",\r\n \"publicIpAddress\": \"pip\",\r\n \"resourceGroup\": \"rg\",\r\n \"serviceBus\": \"sb\",\r\n \"serviceBusQueue\": \"sbq\",\r\n \"serviceBusTopic\": \"sbt\",\r\n \"storageAccount\": \"st\",\r\n \"virtualMachine\": \"vm\",\r\n \"virtualNetwork\": \"vnet\",\r\n \"redisCache\": \"redis\"\r\n },\r\n\r\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\r\n \"regionAbbreviations\" : {\r\n \"australiacentral\": \"auc\",\r\n \"australiacentral2\": \"auc2\",\r\n \"australiaeast\": \"aue\",\r\n \"australiasoutheast\": \"ause\",\r\n \"brazilsouth\": \"brs\",\r\n \"brazilsoutheast\": \"brse\",\r\n \"canadacentral\": \"canc\",\r\n \"canadaeast\": \"cane\",\r\n \"centralindia\": \"cin\",\r\n \"centralus\": \"cus\",\r\n \"centraluseuap\": \"cuseuap\",\r\n \"eastasia\": \"ea\",\r\n \"eastus\": \"eus\",\r\n \"eastus2\": \"eus2\",\r\n \"eastus2euap\": \"eus2euap\",\r\n \"francecentral\": \"frc\",\r\n \"francesouth\": \"frs\",\r\n \"germanynorth\": \"gern\",\r\n \"germanywestcentral\": \"gerwc\",\r\n \"japaneast\": \"jae\",\r\n \"japanwest\": \"jaw\",\r\n \"jioindiacentral\": \"jioinc\",\r\n \"jioindiawest\": \"jioinw\",\r\n \"koreacentral\": \"koc\",\r\n \"koreasouth\": \"kors\",\r\n \"northcentralus\": \"ncus\",\r\n \"northeurope\": \"neu\",\r\n \"norwayeast\": \"nore\",\r\n \"norwaywest\": \"norw\",\r\n \"southafricanorth\": \"san\",\r\n \"southafricawest\": \"saw\",\r\n \"southcentralus\": \"scus\",\r\n \"southeastasia\": \"sea\",\r\n \"southindia\": \"sin\",\r\n \"swedencentral\": \"swc\",\r\n \"switzerlandnorth\": \"swn\",\r\n \"switzerlandwest\": \"sww\",\r\n \"uaecentral\": \"uaec\",\r\n \"uaenorth\": \"uaen\",\r\n \"uksouth\": \"uks\",\r\n \"ukwest\": \"ukw\",\r\n \"westcentralus\": \"wcus\",\r\n \"westeurope\": \"weu\",\r\n \"westindia\": \"win\",\r\n \"westus\": \"wus\",\r\n \"westus2\": \"wus2\",\r\n \"westus3\": \"wus3\"\r\n }\r\n}", "nsgCaeRules": "[json(replace(variables('$fxv#0'), '', parameters('location')))]", "nsgAppGwRules": "[variables('$fxv#1')]", "namingRules": "[json(variables('$fxv#2'))]", @@ -1654,18 +1301,18 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "14985913302549051532" + "version": "0.20.4.51522", + "templateHash": "6817832201461302860" } }, "parameters": { "workloadName": { "type": "string", + "minLength": 2, + "maxLength": 10, "metadata": { "description": "The name of the workloard that is being deployed. Up to 10 characters long." - }, - "maxLength": 10, - "minLength": 2 + } }, "environment": { "type": "string", @@ -1688,7 +1335,7 @@ } }, "variables": { - "$fxv#0": "{\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\n \"resourceTypeAbbreviations\" : {\n \"applicationGateway\": \"agw\",\n \"applicationInsights\": \"appi\",\n \"appService\": \"app\",\n \"bastion\": \"bas\",\n \"containerAppsEnvironment\": \"cae\",\n \"containerRegistry\": \"cr\",\n \"cosmosDbNoSql\": \"cosno\",\n \"frontDoor\": \"afd\",\n \"frontDoorEndpoint\": \"fde\",\n \"frontDoorWaf\": \"fdfp\",\n \"keyVault\": \"kv\",\n \"logAnalyticsWorkspace\": \"log\",\n \"managedIdentity\": \"id\",\n \"networkInterface\": \"nic\",\n \"networkSecurityGroup\": \"nsg\",\n \"privateEndpoint\": \"pep\",\n \"privateLinkService\": \"pls\",\n \"publicIpAddress\": \"pip\",\n \"resourceGroup\": \"rg\",\n \"serviceBus\": \"sb\",\n \"serviceBusQueue\": \"sbq\",\n \"serviceBusTopic\": \"sbt\",\n \"storageAccount\": \"st\",\n \"virtualMachine\": \"vm\",\n \"virtualNetwork\": \"vnet\",\n \"redisCache\": \"redis\"\n },\n\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\n \"regionAbbreviations\" : {\n \"australiacentral\": \"auc\",\n \"australiacentral2\": \"auc2\",\n \"australiaeast\": \"aue\",\n \"australiasoutheast\": \"ause\",\n \"brazilsouth\": \"brs\",\n \"brazilsoutheast\": \"brse\",\n \"canadacentral\": \"canc\",\n \"canadaeast\": \"cane\",\n \"centralindia\": \"cin\",\n \"centralus\": \"cus\",\n \"centraluseuap\": \"cuseuap\",\n \"eastasia\": \"ea\",\n \"eastus\": \"eus\",\n \"eastus2\": \"eus2\",\n \"eastus2euap\": \"eus2euap\",\n \"francecentral\": \"frc\",\n \"francesouth\": \"frs\",\n \"germanynorth\": \"gern\",\n \"germanywestcentral\": \"gerwc\",\n \"japaneast\": \"jae\",\n \"japanwest\": \"jaw\",\n \"jioindiacentral\": \"jioinc\",\n \"jioindiawest\": \"jioinw\",\n \"koreacentral\": \"koc\",\n \"koreasouth\": \"kors\",\n \"northcentralus\": \"ncus\",\n \"northeurope\": \"neu\",\n \"norwayeast\": \"nore\",\n \"norwaywest\": \"norw\",\n \"southafricanorth\": \"san\",\n \"southafricawest\": \"saw\",\n \"southcentralus\": \"scus\",\n \"southeastasia\": \"sea\",\n \"southindia\": \"sin\",\n \"swedencentral\": \"swc\",\n \"switzerlandnorth\": \"swn\",\n \"switzerlandwest\": \"sww\",\n \"uaecentral\": \"uaec\",\n \"uaenorth\": \"uaen\",\n \"uksouth\": \"uks\",\n \"ukwest\": \"ukw\",\n \"westcentralus\": \"wcus\",\n \"westeurope\": \"weu\",\n \"westindia\": \"win\",\n \"westus\": \"wus\",\n \"westus2\": \"wus2\",\n \"westus3\": \"wus3\"\n }\n}", + "$fxv#0": "{\r\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\r\n \"resourceTypeAbbreviations\" : {\r\n \"applicationGateway\": \"agw\",\r\n \"applicationInsights\": \"appi\",\r\n \"appService\": \"app\",\r\n \"bastion\": \"bas\",\r\n \"containerAppsEnvironment\": \"cae\",\r\n \"containerRegistry\": \"cr\",\r\n \"cosmosDbNoSql\": \"cosno\",\r\n \"frontDoor\": \"afd\",\r\n \"frontDoorEndpoint\": \"fde\",\r\n \"frontDoorWaf\": \"fdfp\",\r\n \"keyVault\": \"kv\",\r\n \"logAnalyticsWorkspace\": \"log\",\r\n \"managedIdentity\": \"id\",\r\n \"networkInterface\": \"nic\",\r\n \"networkSecurityGroup\": \"nsg\",\r\n \"privateEndpoint\": \"pep\",\r\n \"privateLinkService\": \"pls\",\r\n \"publicIpAddress\": \"pip\",\r\n \"resourceGroup\": \"rg\",\r\n \"serviceBus\": \"sb\",\r\n \"serviceBusQueue\": \"sbq\",\r\n \"serviceBusTopic\": \"sbt\",\r\n \"storageAccount\": \"st\",\r\n \"virtualMachine\": \"vm\",\r\n \"virtualNetwork\": \"vnet\",\r\n \"redisCache\": \"redis\"\r\n },\r\n\r\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\r\n \"regionAbbreviations\" : {\r\n \"australiacentral\": \"auc\",\r\n \"australiacentral2\": \"auc2\",\r\n \"australiaeast\": \"aue\",\r\n \"australiasoutheast\": \"ause\",\r\n \"brazilsouth\": \"brs\",\r\n \"brazilsoutheast\": \"brse\",\r\n \"canadacentral\": \"canc\",\r\n \"canadaeast\": \"cane\",\r\n \"centralindia\": \"cin\",\r\n \"centralus\": \"cus\",\r\n \"centraluseuap\": \"cuseuap\",\r\n \"eastasia\": \"ea\",\r\n \"eastus\": \"eus\",\r\n \"eastus2\": \"eus2\",\r\n \"eastus2euap\": \"eus2euap\",\r\n \"francecentral\": \"frc\",\r\n \"francesouth\": \"frs\",\r\n \"germanynorth\": \"gern\",\r\n \"germanywestcentral\": \"gerwc\",\r\n \"japaneast\": \"jae\",\r\n \"japanwest\": \"jaw\",\r\n \"jioindiacentral\": \"jioinc\",\r\n \"jioindiawest\": \"jioinw\",\r\n \"koreacentral\": \"koc\",\r\n \"koreasouth\": \"kors\",\r\n \"northcentralus\": \"ncus\",\r\n \"northeurope\": \"neu\",\r\n \"norwayeast\": \"nore\",\r\n \"norwaywest\": \"norw\",\r\n \"southafricanorth\": \"san\",\r\n \"southafricawest\": \"saw\",\r\n \"southcentralus\": \"scus\",\r\n \"southeastasia\": \"sea\",\r\n \"southindia\": \"sin\",\r\n \"swedencentral\": \"swc\",\r\n \"switzerlandnorth\": \"swn\",\r\n \"switzerlandwest\": \"sww\",\r\n \"uaecentral\": \"uaec\",\r\n \"uaenorth\": \"uaen\",\r\n \"uksouth\": \"uks\",\r\n \"ukwest\": \"ukw\",\r\n \"westcentralus\": \"wcus\",\r\n \"westeurope\": \"weu\",\r\n \"westindia\": \"win\",\r\n \"westus\": \"wus\",\r\n \"westus2\": \"wus2\",\r\n \"westus3\": \"wus3\"\r\n }\r\n}", "naming": "[json(variables('$fxv#0'))]", "uniqueIdShort": "[substring(parameters('uniqueId'), 0, 5)]", "resourceTypeToken": "RES_TYPE", @@ -1704,6 +1351,7 @@ "applicationGatewayPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", "applicationGatewayUserAssignedIdentity": "[format('{0}-{1}-KeyVaultSecretUser', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", "applicationGatewayNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", + "pepNsg": "[format('{0}-pep', variables('naming').resourceTypeAbbreviations.networkSecurityGroup)]", "applicationInsights": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationInsights)]", "bastion": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion)]", "bastionNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", @@ -1720,7 +1368,6 @@ "frontDoorProfile": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]", "keyVault": "[if(endsWith(variables('keyVaultName'), '-'), take(variables('keyVaultName'), 23), variables('keyVaultName'))]", "keyVaultPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", - "keyVaultUserAssignedIdentity": "[format('{0}-{1}-KeyVaultReader', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", "logAnalyticsWorkspace": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.logAnalyticsWorkspace)]", "serviceBus": "[replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus)]", "serviceBusPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus))]", @@ -1772,7 +1419,7 @@ "tags": { "value": "[parameters('tags')]" }, - "subnets": "[if(not(empty(parameters('spokeApplicationGatewaySubnetAddressPrefix'))), createObject('value', concat(createArray(createObject('name', parameters('spokeInfraSubnetName'), 'properties', createObject('addressPrefix', parameters('spokeInfraSubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgContainerAppsEnvironment-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value))), createObject('name', parameters('spokePrivateEndpointsSubnetName'), 'properties', createObject('addressPrefix', parameters('spokePrivateEndpointsSubnetAddressPrefix')))), createArray(createObject('name', parameters('spokeApplicationGatewaySubnetName'), 'properties', createObject('addressPrefix', parameters('spokeApplicationGatewaySubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgAppGw-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value)))))), createObject('value', createArray(createObject('name', parameters('spokeInfraSubnetName'), 'properties', createObject('addressPrefix', parameters('spokeInfraSubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgContainerAppsEnvironment-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value))), createObject('name', parameters('spokePrivateEndpointsSubnetName'), 'properties', createObject('addressPrefix', parameters('spokePrivateEndpointsSubnetAddressPrefix'))))))]", + "subnets": "[if(not(equals(parameters('vmJumpboxOSType'), 'none')), createObject('value', concat(if(not(empty(parameters('spokeApplicationGatewaySubnetAddressPrefix'))), concat(createArray(createObject('name', parameters('spokeInfraSubnetName'), 'properties', createObject('addressPrefix', parameters('spokeInfraSubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgContainerAppsEnvironment-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value))), createObject('name', parameters('spokePrivateEndpointsSubnetName'), 'properties', createObject('addressPrefix', parameters('spokePrivateEndpointsSubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgPep-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value)))), createArray(createObject('name', parameters('spokeApplicationGatewaySubnetName'), 'properties', createObject('addressPrefix', parameters('spokeApplicationGatewaySubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgAppGw-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value))))), createArray(createObject('name', parameters('spokeInfraSubnetName'), 'properties', createObject('addressPrefix', parameters('spokeInfraSubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgContainerAppsEnvironment-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value))), createObject('name', parameters('spokePrivateEndpointsSubnetName'), 'properties', createObject('addressPrefix', parameters('spokePrivateEndpointsSubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgPep-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value))))), createArray(createObject('name', parameters('vmSubnetName'), 'properties', createObject('addressPrefix', parameters('vmJumpBoxSubnetAddressPrefix')))))), if(not(empty(parameters('spokeApplicationGatewaySubnetAddressPrefix'))), createObject('value', concat(createArray(createObject('name', parameters('spokeInfraSubnetName'), 'properties', createObject('addressPrefix', parameters('spokeInfraSubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgContainerAppsEnvironment-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value))), createObject('name', parameters('spokePrivateEndpointsSubnetName'), 'properties', createObject('addressPrefix', parameters('spokePrivateEndpointsSubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgPep-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value)))), createArray(createObject('name', parameters('spokeApplicationGatewaySubnetName'), 'properties', createObject('addressPrefix', parameters('spokeApplicationGatewaySubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgAppGw-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value)))))), createObject('value', createArray(createObject('name', parameters('spokeInfraSubnetName'), 'properties', createObject('addressPrefix', parameters('spokeInfraSubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgContainerAppsEnvironment-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value))), createObject('name', parameters('spokePrivateEndpointsSubnetName'), 'properties', createObject('addressPrefix', parameters('spokePrivateEndpointsSubnetAddressPrefix'), 'networkSecurityGroup', createObject('id', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgPep-{0}', deployment().name), 64)), '2022-09-01').outputs.nsgId.value)))))))]", "vnetAddressPrefixes": { "value": "[parameters('spokeVNetAddressPrefixes')]" } @@ -1783,15 +1430,15 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "10750814407079155041" + "version": "0.20.4.51522", + "templateHash": "16217514057343077749" } }, "parameters": { "name": { "type": "string", - "maxLength": 80, "minLength": 2, + "maxLength": 80, "metadata": { "description": "Name of the resource Virtual Network (The name must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens)" } @@ -1888,6 +1535,7 @@ "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgAppGw-{0}', deployment().name), 64))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgContainerAppsEnvironment-{0}', deployment().name), 64))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('nsgPep-{0}', deployment().name), 64))]", "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]" ], "metadata": { @@ -1897,7 +1545,7 @@ { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('nsgContainerAppsEnvironment-{0}', deployment().name), 64)]", + "name": "[take(format('logAnalyticsWs-{0}', uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName')))), 64)]", "resourceGroup": "[variables('rgSpokeName')]", "properties": { "expressionEvaluationOptions": { @@ -1905,17 +1553,11 @@ }, "mode": "Incremental", "parameters": { - "name": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.containerAppsEnvironmentNsg]" - }, "location": { "value": "[parameters('location')]" }, - "tags": { - "value": "[parameters('tags')]" - }, - "securityRules": { - "value": "[variables('nsgCaeRules').securityRules]" + "name": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.logAnalyticsWorkspace]" } }, "template": { @@ -1924,63 +1566,127 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "18411287820228882012" + "version": "0.20.4.51522", + "templateHash": "18168190213647109808" } }, "parameters": { "name": { "type": "string", - "maxLength": 80, + "minLength": 4, + "maxLength": 63, "metadata": { - "description": "Name of the Network Security Group. Alphanumerics, underscores, periods, and hyphens. Start with alphanumeric. End alphanumeric or underscore. " + "description": "Required. Name of the Log Analytics Workspace Service. It must be between 4 and 63 characters and can contain only letters, numbers and \"-\". The \"-\" should not be the first or the last symbol" } }, "location": { "type": "string", "metadata": { - "description": "Azure Region where the resource will be deployed in" + "description": "Azure region where the resources will be deployed in" } }, "tags": { "type": "object", + "defaultValue": {} + }, + "serviceTier": { + "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "Free", + "Standalone", + "PerNode", + "PerGB2018" + ], "metadata": { - "description": "key-value pairs as tags, to identify the resource" + "description": "Optional. Service Tier: PerGB2018, Free, Standalone, PerGB or PerNode." } }, - "securityRules": { - "type": "array", + "dataRetention": { + "type": "int", + "defaultValue": 90, + "minValue": 0, + "maxValue": 730, + "metadata": { + "description": "Optional, default 90. Number of days data will be retained for." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics ingestion." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics query." + } + }, + "useResourcePermissions": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "An array of network security rules. " + "description": "Optional. Set to 'true' to use resource or workspace permissions and 'false' (or leave empty) to require workspace permissions." } } }, + "variables": { + "lawsMaxLength": 63, + "lawsNameSantized": "[replace(replace(parameters('name'), '_', '-'), '.', '-')]", + "lawsName": "[if(greater(length(variables('lawsNameSantized')), variables('lawsMaxLength')), substring(variables('lawsNameSantized'), 0, variables('lawsMaxLength')), variables('lawsNameSantized'))]" + }, "resources": [ { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2022-09-01", - "name": "[parameters('name')]", + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[variables('lawsName')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "properties": { - "securityRules": "[parameters('securityRules')]" + "retentionInDays": "[parameters('dataRetention')]", + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "sku": { + "name": "[parameters('serviceTier')]" + }, + "features": { + "enableLogAccessUsingOnlyResourcePermissions": "[parameters('useResourcePermissions')]" + } } } ], "outputs": { - "nsgId": { + "logAnalyticsWsName": { "type": "string", "metadata": { - "description": "Resource id of the newly created Network Security Group" + "description": "The name of the resource." }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + "value": "[variables('lawsName')]" }, - "nsgName": { + "logAnalyticsWsId": { "type": "string", "metadata": { - "description": "Resource name of the newly created Network Security Group" + "description": "The resource ID of the resource." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', variables('lawsName'))]" + }, + "customerId": { + "type": "string", + "metadata": { + "description": "The customer id of the log analytics workspace." + }, + "value": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', variables('lawsName')), '2022-10-01').customerId]" } } } @@ -1990,14 +1696,13 @@ "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]" ], "metadata": { - "description": "Network security group rules for the Container Apps cluster." + "description": "The log sink for Azure Diagnostics" } }, { - "condition": "[not(empty(parameters('spokeApplicationGatewaySubnetAddressPrefix')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('nsgAppGw-{0}', deployment().name), 64)]", + "name": "[take(format('nsgContainerAppsEnvironment-{0}', deployment().name), 64)]", "resourceGroup": "[variables('rgSpokeName')]", "properties": { "expressionEvaluationOptions": { @@ -2006,7 +1711,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGatewayNsg]" + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.containerAppsEnvironmentNsg]" }, "location": { "value": "[parameters('location')]" @@ -2015,7 +1720,10 @@ "value": "[parameters('tags')]" }, "securityRules": { - "value": "[variables('nsgAppGwRules')]" + "value": "[variables('nsgCaeRules').securityRules]" + }, + "diagnosticWorkspaceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('logAnalyticsWs-{0}', uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName')))), 64)), '2022-09-01').outputs.logAnalyticsWsId.value]" } }, "template": { @@ -2024,8 +1732,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "18411287820228882012" + "version": "0.20.4.51522", + "templateHash": "141603598488449882" } }, "parameters": { @@ -2050,21 +1758,122 @@ }, "securityRules": { "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." + } + }, + "flushConnection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + } + }, + "diagnosticStorageAccountId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account." + } + }, + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + }, + "diagnosticWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace." + } + }, + "diagnosticEventHubAuthorizationRuleId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "diagnosticEventHubName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category." + } + }, + "diagnosticLogCategoriesToEnable": { + "type": "array", + "defaultValue": [ + "allLogs" + ], + "allowedValues": [ + "allLogs", + "NetworkSecurityGroupEvent", + "NetworkSecurityGroupRuleCounter" + ], + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource." + } + }, + "diagnosticSettingsName": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "An array of network security rules. " + "description": "Optional. The name of the diagnostic setting, if deployed. If left empty, it defaults to \"-diagnosticSettings\"." } } }, + "variables": { + "copy": [ + { + "name": "diagnosticsLogsSpecified", + "count": "[length(filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs')))))]", + "input": { + "category": "[filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs'))))[copyIndex('diagnosticsLogsSpecified')]]", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + } + ], + "diagnosticsLogs": "[if(contains(parameters('diagnosticLogCategoriesToEnable'), 'allLogs'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true(), 'retentionPolicy', createObject('enabled', true(), 'days', parameters('diagnosticLogsRetentionInDays')))), variables('diagnosticsLogsSpecified'))]" + }, "resources": [ { "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2022-09-01", + "apiVersion": "2022-07-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "properties": { + "flushConnection": "[parameters('flushConnection')]", "securityRules": "[parameters('securityRules')]" } + }, + { + "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[if(not(empty(parameters('diagnosticSettingsName'))), parameters('diagnosticSettingsName'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", + "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", + "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", + "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", + "logs": "[variables('diagnosticsLogs')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + ] } ], "outputs": { @@ -2086,18 +1895,19 @@ } }, "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('logAnalyticsWs-{0}', uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName')))), 64))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64))]", "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]" ], "metadata": { - "description": "NSG Rules for the Application Gateway." + "description": "Network security group rules for the Container Apps cluster." } }, { - "condition": "[not(empty(parameters('hubVNetId')))]", + "condition": "[not(empty(parameters('spokeApplicationGatewaySubnetAddressPrefix')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('{0}-peerSpokeToHubDeployment', deployment().name), 64)]", + "name": "[take(format('nsgAppGw-{0}', deployment().name), 64)]", "resourceGroup": "[variables('rgSpokeName')]", "properties": { "expressionEvaluationOptions": { @@ -2105,17 +1915,20 @@ }, "mode": "Incremental", "parameters": { - "localVnetName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value]" + "name": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGatewayNsg]" }, - "remoteSubscriptionId": { - "value": "[variables('hubSubscriptionId')]" + "location": { + "value": "[parameters('location')]" }, - "remoteRgName": { - "value": "[variables('hubResourceGroupName')]" + "tags": { + "value": "[parameters('tags')]" }, - "remoteVnetName": { - "value": "[variables('hubVNetName')]" + "securityRules": { + "value": "[variables('nsgAppGwRules')]" + }, + "diagnosticWorkspaceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('logAnalyticsWs-{0}', uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName')))), 64)), '2022-09-01').outputs.logAnalyticsWsId.value]" } }, "template": { @@ -2124,69 +1937,387 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "13181302078385014318" + "version": "0.20.4.51522", + "templateHash": "141603598488449882" } }, "parameters": { - "localVnetName": { + "name": { "type": "string", + "maxLength": 80, "metadata": { - "description": "The name of the local Virtual Network" + "description": "Name of the Network Security Group. Alphanumerics, underscores, periods, and hyphens. Start with alphanumeric. End alphanumeric or underscore. " } }, - "remoteVnetName": { + "location": { "type": "string", "metadata": { - "description": "The name of the remote Virtual Network" + "description": "Azure Region where the resource will be deployed in" } }, - "remoteRgName": { + "tags": { + "type": "object", + "metadata": { + "description": "key-value pairs as tags, to identify the resource" + } + }, + "securityRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." + } + }, + "flushConnection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + } + }, + "diagnosticStorageAccountId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The name of the resource group of the remote virtual netowrk" + "description": "Optional. Resource ID of the diagnostic storage account." } }, - "remoteSubscriptionId": { + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + }, + "diagnosticWorkspaceId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The id of the subscription of the remote virtual netowrk" + "description": "Optional. Resource ID of the diagnostic log analytics workspace." + } + }, + "diagnosticEventHubAuthorizationRuleId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "diagnosticEventHubName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category." + } + }, + "diagnosticLogCategoriesToEnable": { + "type": "array", + "defaultValue": [ + "allLogs" + ], + "allowedValues": [ + "allLogs", + "NetworkSecurityGroupEvent", + "NetworkSecurityGroupRuleCounter" + ], + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource." + } + }, + "diagnosticSettingsName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the diagnostic setting, if deployed. If left empty, it defaults to \"-diagnosticSettings\"." } } }, + "variables": { + "copy": [ + { + "name": "diagnosticsLogsSpecified", + "count": "[length(filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs')))))]", + "input": { + "category": "[filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs'))))[copyIndex('diagnosticsLogsSpecified')]]", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + } + ], + "diagnosticsLogs": "[if(contains(parameters('diagnosticLogCategoriesToEnable'), 'allLogs'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true(), 'retentionPolicy', createObject('enabled', true(), 'days', parameters('diagnosticLogsRetentionInDays')))), variables('diagnosticsLogsSpecified'))]" + }, "resources": [ { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2021-08-01", - "name": "[format('{0}/peerTo-{1}', parameters('localVnetName'), parameters('remoteVnetName'))]", + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "allowVirtualNetworkAccess": true, - "allowGatewayTransit": false, - "allowForwardedTraffic": false, - "useRemoteGateways": false, - "remoteVirtualNetwork": { - "id": "[resourceId(parameters('remoteSubscriptionId'), parameters('remoteRgName'), 'Microsoft.Network/virtualNetworks', parameters('remoteVnetName'))]" + "flushConnection": "[parameters('flushConnection')]", + "securityRules": "[parameters('securityRules')]" + } + }, + { + "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[if(not(empty(parameters('diagnosticSettingsName'))), parameters('diagnosticSettingsName'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", + "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", + "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", + "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", + "logs": "[variables('diagnosticsLogs')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + ] + } + ], + "outputs": { + "nsgId": { + "type": "string", + "metadata": { + "description": "Resource id of the newly created Network Security Group" + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "nsgName": { + "type": "string", + "metadata": { + "description": "Resource name of the newly created Network Security Group" + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('logAnalyticsWs-{0}', uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName')))), 64))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64))]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]" + ], + "metadata": { + "description": "NSG Rules for the Application Gateway." + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('nsgPep-{0}', deployment().name), 64)]", + "resourceGroup": "[variables('rgSpokeName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.pepNsg]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "securityRules": { + "value": [] + }, + "diagnosticWorkspaceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('logAnalyticsWs-{0}', uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName')))), 64)), '2022-09-01').outputs.logAnalyticsWsId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "141603598488449882" + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 80, + "metadata": { + "description": "Name of the Network Security Group. Alphanumerics, underscores, periods, and hyphens. Start with alphanumeric. End alphanumeric or underscore. " + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure Region where the resource will be deployed in" + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "key-value pairs as tags, to identify the resource" + } + }, + "securityRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." + } + }, + "flushConnection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + } + }, + "diagnosticStorageAccountId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account." + } + }, + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + }, + "diagnosticWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace." + } + }, + "diagnosticEventHubAuthorizationRuleId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "diagnosticEventHubName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category." + } + }, + "diagnosticLogCategoriesToEnable": { + "type": "array", + "defaultValue": [ + "allLogs" + ], + "allowedValues": [ + "allLogs", + "NetworkSecurityGroupEvent", + "NetworkSecurityGroupRuleCounter" + ], + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource." + } + }, + "diagnosticSettingsName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the diagnostic setting, if deployed. If left empty, it defaults to \"-diagnosticSettings\"." + } + } + }, + "variables": { + "copy": [ + { + "name": "diagnosticsLogsSpecified", + "count": "[length(filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs')))))]", + "input": { + "category": "[filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs'))))[copyIndex('diagnosticsLogsSpecified')]]", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } } } + ], + "diagnosticsLogs": "[if(contains(parameters('diagnosticLogCategoriesToEnable'), 'allLogs'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true(), 'retentionPolicy', createObject('enabled', true(), 'days', parameters('diagnosticLogsRetentionInDays')))), variables('diagnosticsLogsSpecified'))]" + }, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "flushConnection": "[parameters('flushConnection')]", + "securityRules": "[parameters('securityRules')]" + } + }, + { + "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[if(not(empty(parameters('diagnosticSettingsName'))), parameters('diagnosticSettingsName'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", + "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", + "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", + "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", + "logs": "[variables('diagnosticsLogs')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + ] } - ] + ], + "outputs": { + "nsgId": { + "type": "string", + "metadata": { + "description": "Resource id of the newly created Network Security Group" + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "nsgName": { + "type": "string", + "metadata": { + "description": "Resource name of the newly created Network Security Group" + }, + "value": "[parameters('name')]" + } + } } }, "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64))]" + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('logAnalyticsWs-{0}', uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName')))), 64))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64))]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]" ], "metadata": { - "description": "Spoke peering to regional hub network. This peering would normally already be provisioned by your subscription vending process." + "description": "NSG Rules for the private enpoint subnet." } }, { "condition": "[not(empty(parameters('hubVNetId')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('{0}-peerHubToSpokeDeployment', deployment().name), 64)]", - "subscriptionId": "[variables('hubSubscriptionId')]", - "resourceGroup": "[variables('hubResourceGroupName')]", + "name": "[take(format('{0}-peerSpokeToHubDeployment', deployment().name), 64)]", + "resourceGroup": "[variables('rgSpokeName')]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -2194,16 +2325,16 @@ "mode": "Incremental", "parameters": { "localVnetName": { - "value": "[variables('hubVNetName')]" + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value]" }, "remoteSubscriptionId": { - "value": "[last(split(subscription().id, '/'))]" + "value": "[variables('hubSubscriptionId')]" }, "remoteRgName": { - "value": "[variables('rgSpokeName')]" + "value": "[variables('hubResourceGroupName')]" }, "remoteVnetName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value]" + "value": "[variables('hubVNetName')]" } }, "template": { @@ -2212,8 +2343,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "13181302078385014318" + "version": "0.20.4.51522", + "templateHash": "9683203958437324298" } }, "parameters": { @@ -2265,206 +2396,33 @@ "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64))]" ], "metadata": { - "description": "Regional hub peering to this spoke network. This peering would normally already be provisioned by your subscription vending process." + "description": "Spoke peering to regional hub network. This peering would normally already be provisioned by your subscription vending process." } - } - ], - "outputs": { - "spokeResourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the spoke resource group." - }, - "value": "[variables('rgSpokeName')]" - }, - "spokeVNetId": { - "type": "string", - "metadata": { - "description": "The resource ID of the spoke virtual network." - }, - "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Network/virtualNetworks', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value)]" - }, - "spokeVNetName": { - "type": "string", - "metadata": { - "description": "The name of the spoke virtual network." - }, - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value]" - }, - "spokeInfraSubnetId": { - "type": "string", - "metadata": { - "description": "The resource ID of the spoke infrastructure subnet." - }, - "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Network/virtualNetworks/subnets', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value, parameters('spokeInfraSubnetName'))]" - }, - "spokeInfraSubnetName": { - "type": "string", - "metadata": { - "description": "The name of the spoke infrastructure subnet." - }, - "value": "[parameters('spokeInfraSubnetName')]" - }, - "spokePrivateEndpointsSubnetId": { - "type": "string", - "metadata": { - "description": "The resource ID of the spoke private endpoints subnet." - }, - "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Network/virtualNetworks/subnets', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value, parameters('spokePrivateEndpointsSubnetName'))]" }, - "spokePrivateEndpointsSubnetName": { - "type": "string", - "metadata": { - "description": "The name of the spoke private endpoints subnet." - }, - "value": "[parameters('spokePrivateEndpointsSubnetName')]" - }, - "spokeApplicationGatewaySubnetId": { - "type": "string", - "metadata": { - "description": "The resource ID of the spoke Application Gateway subnet. This is '' if the subnet was not created." - }, - "value": "[if(not(empty(parameters('spokeApplicationGatewaySubnetAddressPrefix'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Network/virtualNetworks/subnets', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value, parameters('spokeApplicationGatewaySubnetName')), '')]" - }, - "spokeApplicationGatewaySubnetName": { - "type": "string", - "metadata": { - "description": "The name of the spoke Application Gateway subnet. This is '' if the subnet was not created." - }, - "value": "[if(not(empty(parameters('spokeApplicationGatewaySubnetAddressPrefix'))), parameters('spokeApplicationGatewaySubnetName'), '')]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/deployments', take(format('hub-{0}-deployment', deployment().name), 64))]", - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('supportingServices-{0}-deployment', deployment().name), 64)]", - "resourceGroup": "[variables('rgSpokeName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "spokePrivateEndpointSubnetName": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.spokePrivateEndpointsSubnetName.value]" - }, - "environment": { - "value": "[parameters('environment')]" - }, - "workloadName": { - "value": "[parameters('workloadName')]" - }, - "spokeVNetId": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.spokeVNetId.value]" - }, - "hubVNetId": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('hub-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.hubVNetId.value]" - }, - "deployRedisCache": { - "value": "[parameters('deployRedisCache')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "15346428229640726738" - } - }, - "parameters": { - "workloadName": { - "type": "string", - "maxLength": 10, - "minLength": 2, - "metadata": { - "description": "The name of the workload that is being deployed. Up to 10 characters long." - } - }, - "environment": { - "type": "string", - "maxLength": 8, - "metadata": { - "description": "The name of the environment (e.g. \"dev\", \"test\", \"prod\", \"uat\", \"dr\", \"qa\"). Up to 8 characters long." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "The location where the resources will be created. This needs to be the same region as the spoke." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The tags to be assigned to the created resources." - } - }, - "hubVNetId": { - "type": "string", - "metadata": { - "description": "The resource ID of the existing hub virtual network." - } - }, - "spokeVNetId": { - "type": "string", - "metadata": { - "description": "The resource ID of the existing spoke virtual network to which the private endpoint will be connected." - } - }, - "spokePrivateEndpointSubnetName": { - "type": "string", - "metadata": { - "description": "The name of the existing subnet in the spoke virtual to which the private endpoint will be connected." - } - }, - "deployRedisCache": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Deploy Redis cache premium SKU" - } - } - }, - "resources": [ { + "condition": "[not(empty(parameters('hubVNetId')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('03-sharedNamingDeployment-{0}', deployment().name), 64)]", + "name": "[take(format('{0}-peerHubToSpokeDeployment', deployment().name), 64)]", + "subscriptionId": "[variables('hubSubscriptionId')]", + "resourceGroup": "[variables('hubResourceGroupName')]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "uniqueId": { - "value": "[uniqueString(resourceGroup().id)]" + "localVnetName": { + "value": "[variables('hubVNetName')]" }, - "environment": { - "value": "[parameters('environment')]" + "remoteSubscriptionId": { + "value": "[last(split(subscription().id, '/'))]" }, - "workloadName": { - "value": "[parameters('workloadName')]" + "remoteRgName": { + "value": "[variables('rgSpokeName')]" }, - "location": { - "value": "[parameters('location')]" + "remoteVnetName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value]" } }, "template": { @@ -2473,134 +2431,109 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "14985913302549051532" + "version": "0.20.4.51522", + "templateHash": "9683203958437324298" } }, "parameters": { - "workloadName": { + "localVnetName": { "type": "string", "metadata": { - "description": "The name of the workloard that is being deployed. Up to 10 characters long." - }, - "maxLength": 10, - "minLength": 2 + "description": "The name of the local Virtual Network" + } }, - "environment": { + "remoteVnetName": { "type": "string", - "maxLength": 8, "metadata": { - "description": "The name of the environment (e.g. \"dev\", \"test\", \"prod\", \"uat\", \"dr\", \"qa\") Up to 8 characters long." + "description": "The name of the remote Virtual Network" } }, - "location": { + "remoteRgName": { "type": "string", "metadata": { - "description": "Location for all Resources." + "description": "The name of the resource group of the remote virtual netowrk" } }, - "uniqueId": { + "remoteSubscriptionId": { "type": "string", "metadata": { - "description": "a unique ID that can be appended (or prepended) in azure resource names that require some kind of uniqueness" + "description": "The id of the subscription of the remote virtual netowrk" } } }, - "variables": { - "$fxv#0": "{\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\n \"resourceTypeAbbreviations\" : {\n \"applicationGateway\": \"agw\",\n \"applicationInsights\": \"appi\",\n \"appService\": \"app\",\n \"bastion\": \"bas\",\n \"containerAppsEnvironment\": \"cae\",\n \"containerRegistry\": \"cr\",\n \"cosmosDbNoSql\": \"cosno\",\n \"frontDoor\": \"afd\",\n \"frontDoorEndpoint\": \"fde\",\n \"frontDoorWaf\": \"fdfp\",\n \"keyVault\": \"kv\",\n \"logAnalyticsWorkspace\": \"log\",\n \"managedIdentity\": \"id\",\n \"networkInterface\": \"nic\",\n \"networkSecurityGroup\": \"nsg\",\n \"privateEndpoint\": \"pep\",\n \"privateLinkService\": \"pls\",\n \"publicIpAddress\": \"pip\",\n \"resourceGroup\": \"rg\",\n \"serviceBus\": \"sb\",\n \"serviceBusQueue\": \"sbq\",\n \"serviceBusTopic\": \"sbt\",\n \"storageAccount\": \"st\",\n \"virtualMachine\": \"vm\",\n \"virtualNetwork\": \"vnet\",\n \"redisCache\": \"redis\"\n },\n\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\n \"regionAbbreviations\" : {\n \"australiacentral\": \"auc\",\n \"australiacentral2\": \"auc2\",\n \"australiaeast\": \"aue\",\n \"australiasoutheast\": \"ause\",\n \"brazilsouth\": \"brs\",\n \"brazilsoutheast\": \"brse\",\n \"canadacentral\": \"canc\",\n \"canadaeast\": \"cane\",\n \"centralindia\": \"cin\",\n \"centralus\": \"cus\",\n \"centraluseuap\": \"cuseuap\",\n \"eastasia\": \"ea\",\n \"eastus\": \"eus\",\n \"eastus2\": \"eus2\",\n \"eastus2euap\": \"eus2euap\",\n \"francecentral\": \"frc\",\n \"francesouth\": \"frs\",\n \"germanynorth\": \"gern\",\n \"germanywestcentral\": \"gerwc\",\n \"japaneast\": \"jae\",\n \"japanwest\": \"jaw\",\n \"jioindiacentral\": \"jioinc\",\n \"jioindiawest\": \"jioinw\",\n \"koreacentral\": \"koc\",\n \"koreasouth\": \"kors\",\n \"northcentralus\": \"ncus\",\n \"northeurope\": \"neu\",\n \"norwayeast\": \"nore\",\n \"norwaywest\": \"norw\",\n \"southafricanorth\": \"san\",\n \"southafricawest\": \"saw\",\n \"southcentralus\": \"scus\",\n \"southeastasia\": \"sea\",\n \"southindia\": \"sin\",\n \"swedencentral\": \"swc\",\n \"switzerlandnorth\": \"swn\",\n \"switzerlandwest\": \"sww\",\n \"uaecentral\": \"uaec\",\n \"uaenorth\": \"uaen\",\n \"uksouth\": \"uks\",\n \"ukwest\": \"ukw\",\n \"westcentralus\": \"wcus\",\n \"westeurope\": \"weu\",\n \"westindia\": \"win\",\n \"westus\": \"wus\",\n \"westus2\": \"wus2\",\n \"westus3\": \"wus3\"\n }\n}", - "naming": "[json(variables('$fxv#0'))]", - "uniqueIdShort": "[substring(parameters('uniqueId'), 0, 5)]", - "resourceTypeToken": "RES_TYPE", - "namingBase": "[format('{0}-{1}-{2}-{3}', variables('resourceTypeToken'), parameters('workloadName'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", - "namingBaseUnique": "[format('{0}-{1}-{2}-{3}-{4}', variables('resourceTypeToken'), parameters('workloadName'), variables('uniqueIdShort'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", - "namingBaseNoWorkloadName": "[format('{0}-{1}-{2}', variables('resourceTypeToken'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", - "resourceTypeAbbreviations": "[variables('naming').resourceTypeAbbreviations]", - "keyVaultName": "[take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault), 24)]", - "resourceNames": { - "vnetSpoke": "[format('{0}-spoke', replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualNetwork))]", - "vnetHub": "[format('{0}-hub', replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualNetwork))]", - "applicationGateway": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway)]", - "applicationGatewayPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", - "applicationGatewayUserAssignedIdentity": "[format('{0}-{1}-KeyVaultSecretUser', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", - "applicationGatewayNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", - "applicationInsights": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationInsights)]", - "bastion": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion)]", - "bastionNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", - "bastionPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", - "containerAppsEnvironment": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerAppsEnvironment)]", - "containerAppsEnvironmentNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerAppsEnvironment))]", - "containerRegistry": "[take(toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')), 50)]", - "containerRegistryPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')))]", - "containerRegistryUserAssignedIdentity": "[format('{0}-{1}-AcrPull', variables('naming').resourceTypeAbbreviations.managedIdentity, toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')))]", - "redisCache": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.redisCache)]", - "redisCachePep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.redisCache))]", - "cosmosDbNoSql": "[toLower(take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.cosmosDbNoSql), 44))]", - "cosmosDbNoSqlPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.cosmosDbNoSql), 44)))]", - "frontDoorProfile": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]", - "keyVault": "[if(endsWith(variables('keyVaultName'), '-'), take(variables('keyVaultName'), 23), variables('keyVaultName'))]", - "keyVaultPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", - "keyVaultUserAssignedIdentity": "[format('{0}-{1}-KeyVaultReader', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", - "logAnalyticsWorkspace": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.logAnalyticsWorkspace)]", - "serviceBus": "[replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus)]", - "serviceBusPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus))]", - "storageAccount": "[toLower(take(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.storageAccount), '-', ''), 24))]", - "storageAccountPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.storageAccount)))]", - "vmJumpBox": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine)]", - "vmJumpBoxNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine))]", - "vmJumpBoxNic": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkInterface, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine))]", - "frontDoor": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]" - } - }, - "resources": [], - "outputs": { - "resourcesNames": { - "type": "object", - "value": "[variables('resourceNames')]" - }, - "resourceTypeAbbreviations": { - "type": "object", - "value": "[variables('resourceTypeAbbreviations')]" + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2021-08-01", + "name": "[format('{0}/peerTo-{1}', parameters('localVnetName'), parameters('remoteVnetName'))]", + "properties": { + "allowVirtualNetworkAccess": true, + "allowGatewayTransit": false, + "allowForwardedTraffic": false, + "useRemoteGateways": false, + "remoteVirtualNetwork": { + "id": "[resourceId(parameters('remoteSubscriptionId'), parameters('remoteRgName'), 'Microsoft.Network/virtualNetworks', parameters('remoteVnetName'))]" + } + } } - } + ] } }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64))]" + ], "metadata": { - "description": "User-configured naming rules" + "description": "Regional hub peering to this spoke network. This peering would normally already be provisioned by your subscription vending process." } }, { + "condition": "[equals(parameters('vmJumpboxOSType'), 'linux')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('containerRegistry-{0}', uniqueString(resourceGroup().id))]", + "name": "[take(format('vm-linux-{0}', deployment().name), 64)]", + "resourceGroup": "[variables('rgSpokeName')]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerRegistryName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('03-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.containerRegistry]" - }, "location": { "value": "[parameters('location')]" }, "tags": { "value": "[parameters('tags')]" }, - "spokeVNetId": { - "value": "[parameters('spokeVNetId')]" - }, - "hubVNetId": { - "value": "[parameters('hubVNetId')]" + "vmName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.vmJumpBox]" }, - "spokePrivateEndpointSubnetName": { - "value": "[parameters('spokePrivateEndpointSubnetName')]" + "vmAdminUsername": { + "value": "[parameters('vmAdminUsername')]" }, - "containerRegistryPrivateEndpointName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('03-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.containerRegistryPep]" + "vmAdminPassword": { + "value": "[parameters('vmAdminPassword')]" }, - "containerRegistryUserAssignedIdentityName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('03-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.containerRegistryUserAssignedIdentity]" + "vmSshPublicKey": { + "value": "[parameters('vmLinuxSshAuthorizedKeys')]" + }, + "vmSize": { + "value": "[parameters('vmSize')]" + }, + "vmVnetName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value]" + }, + "vmSubnetName": { + "value": "[parameters('vmSubnetName')]" + }, + "vmSubnetAddressPrefix": { + "value": "[parameters('vmJumpBoxSubnetAddressPrefix')]" + }, + "vmNetworkInterfaceName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.vmJumpBoxNic]" + }, + "vmNetworkSecurityGroupName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.vmJumpBoxNsg]" } }, "template": { @@ -2609,129 +2542,1826 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "10545735030084056426" + "version": "0.20.4.51522", + "templateHash": "4630758869167449489" } }, "parameters": { - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "The location where the resources will be created." - } + "vmName": { + "type": "string" }, - "containerRegistryName": { - "type": "string", - "metadata": { - "description": "The name of the container registry." - } + "vmSize": { + "type": "string" }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The tags to be assigned to the created resources." - } + "vmVnetName": { + "type": "string" }, - "hubVNetId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Hub Virtual Network." - } + "vmSubnetName": { + "type": "string" }, - "spokeVNetId": { - "type": "string", - "metadata": { - "description": "The resource ID of the VNet to which the private endpoint will be connected." - } + "vmSubnetAddressPrefix": { + "type": "string" }, - "spokePrivateEndpointSubnetName": { + "vmNetworkSecurityGroupName": { + "type": "string" + }, + "vmNetworkInterfaceName": { + "type": "string" + }, + "vmAdminUsername": { + "type": "string" + }, + "vmAdminPassword": { + "type": "securestring" + }, + "vmSshPublicKey": { + "type": "securestring" + }, + "vmAuthenticationType": { "type": "string", + "defaultValue": "password", + "allowedValues": [ + "sshPublicKey", + "password" + ], "metadata": { - "description": "The name of the subnet in the VNet to which the private endpoint will be connected." + "description": "Type of authentication to use on the Virtual Machine. SSH key is recommended." } }, - "containerRegistryPrivateEndpointName": { - "type": "string", + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "The name of the private endpoint to be created for Azure Container Registry." + "description": "Optional. The tags to be assigned to the created resources." } }, - "containerRegistryUserAssignedIdentityName": { + "location": { "type": "string", - "metadata": { - "description": "The name of the user assigned identity to be created to pull image from Azure Container Registry." - } + "defaultValue": "[resourceGroup().location]" } }, "variables": { - "privateDnsZoneNames": "privatelink.azurecr.io", - "containerRegistryResourceName": "registry", - "hubVNetIdTokens": "[split(parameters('hubVNetId'), '/')]", - "hubSubscriptionId": "[variables('hubVNetIdTokens')[2]]", - "hubResourceGroupName": "[variables('hubVNetIdTokens')[4]]", - "hubVNetName": "[variables('hubVNetIdTokens')[8]]", - "spokeVNetIdTokens": "[split(parameters('spokeVNetId'), '/')]", - "spokeSubscriptionId": "[variables('spokeVNetIdTokens')[2]]", - "spokeResourceGroupName": "[variables('spokeVNetIdTokens')[4]]", - "spokeVNetName": "[variables('spokeVNetIdTokens')[8]]", - "containerRegistryPullRoleGuid": "7f951dda-4ed3-4680-a7ca-43fe172d538d", - "spokeVNetLinks": [ - { - "vnetName": "[variables('spokeVNetName')]", - "vnetId": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('spokeSubscriptionId'), variables('spokeResourceGroupName')), 'Microsoft.Network/virtualNetworks', variables('spokeVNetName'))]", - "registrationEnabled": false - }, - { - "vnetName": "[variables('hubVNetName')]", - "vnetId": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('hubSubscriptionId'), variables('hubResourceGroupName')), 'Microsoft.Network/virtualNetworks', variables('hubVNetName'))]", - "registrationEnabled": false + "linuxConfiguration": { + "disablePasswordAuthentication": true, + "ssh": { + "publicKeys": [ + { + "path": "[format('/home/{0}/.ssh/authorized_keys', parameters('vmAdminUsername'))]", + "keyData": "[parameters('vmSshPublicKey')]" + } + ] } - ] + } }, "resources": [ { - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2022-12-01", - "name": "[parameters('containerRegistryName')]", + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2020-06-01", + "name": "[parameters('vmNetworkSecurityGroupName')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "sku": { - "name": "Premium" + "properties": { + "securityRules": [] + } + }, + { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2020-11-01", + "name": "[format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName'))]", + "properties": { + "addressPrefix": "[parameters('vmSubnetAddressPrefix')]", + "networkSecurityGroup": { + "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('vmNetworkSecurityGroupName'))]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('vmNetworkSecurityGroupName'))]" + ] + }, + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2021-02-01", + "name": "[parameters('vmNetworkInterfaceName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "subnet": { + "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[0], split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[1])]" + }, + "privateIPAllocationMethod": "Dynamic" + } + } + ] }, + "dependsOn": [ + "[resourceId('Microsoft.Network/virtualNetworks/subnets', split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[0], split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[1])]" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2021-03-01", + "name": "[parameters('vmName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "adminUserEnabled": false, - "publicNetworkAccess": "Disabled", - "networkRuleBypassOptions": "AzureServices" + "osProfile": { + "computerName": "[parameters('vmName')]", + "adminUsername": "[parameters('vmAdminUsername')]", + "adminPassword": "[parameters('vmAdminPassword')]", + "linuxConfiguration": "[if(equals(parameters('vmAuthenticationType'), 'password'), null(), variables('linuxConfiguration'))]" + }, + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "storageProfile": { + "osDisk": { + "createOption": "FromImage", + "managedDisk": { + "storageAccountType": "Standard_LRS" + } + }, + "imageReference": { + "publisher": "Canonical", + "offer": "UbuntuServer", + "sku": "18.04-LTS", + "version": "latest" + } + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('vmNetworkInterfaceName'))]" + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkInterfaces', parameters('vmNetworkInterfaceName'))]" + ] + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64))]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64))]" + ], + "metadata": { + "description": "An optional Linux virtual machine deployment to act as a jump box." + } + }, + { + "condition": "[equals(parameters('vmJumpboxOSType'), 'windows')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('vm-windows-{0}', deployment().name), 64)]", + "resourceGroup": "[variables('rgSpokeName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "vmName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.vmJumpBox]" + }, + "vmAdminUsername": { + "value": "[parameters('vmAdminUsername')]" + }, + "vmAdminPassword": { + "value": "[parameters('vmAdminPassword')]" + }, + "vmSize": { + "value": "[parameters('vmSize')]" + }, + "vmVnetName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value]" + }, + "vmSubnetName": { + "value": "[parameters('vmSubnetName')]" + }, + "vmSubnetAddressPrefix": { + "value": "[parameters('vmJumpBoxSubnetAddressPrefix')]" + }, + "vmNetworkInterfaceName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.vmJumpBoxNic]" + }, + "vmNetworkSecurityGroupName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.vmJumpBoxNsg]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "13300298721636255698" + } + }, + "parameters": { + "vmName": { + "type": "string" + }, + "vmSize": { + "type": "string" + }, + "vmWindowsOSVersion": { + "type": "string", + "defaultValue": "2016-Datacenter" + }, + "vmVnetName": { + "type": "string" + }, + "vmSubnetName": { + "type": "string" + }, + "vmSubnetAddressPrefix": { + "type": "string" + }, + "vmNetworkSecurityGroupName": { + "type": "string" + }, + "vmNetworkInterfaceName": { + "type": "string" + }, + "vmAdminUsername": { + "type": "string" + }, + "vmAdminPassword": { + "type": "securestring" + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The tags to be assigned to the created resources." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2020-06-01", + "name": "[parameters('vmNetworkSecurityGroupName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "securityRules": [] + } + }, + { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2020-11-01", + "name": "[format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName'))]", + "properties": { + "addressPrefix": "[parameters('vmSubnetAddressPrefix')]", + "networkSecurityGroup": { + "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('vmNetworkSecurityGroupName'))]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('vmNetworkSecurityGroupName'))]" + ] + }, + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2021-02-01", + "name": "[parameters('vmNetworkInterfaceName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "subnet": { + "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[0], split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[1])]" + }, + "privateIPAllocationMethod": "Dynamic" + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/virtualNetworks/subnets', split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[0], split(format('{0}/{1}', parameters('vmVnetName'), parameters('vmSubnetName')), '/')[1])]" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2021-04-01", + "name": "[parameters('vmName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "zones": [ + "1" + ], + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "storageProfile": { + "osDisk": { + "createOption": "FromImage", + "managedDisk": { + "storageAccountType": "Standard_LRS" + } + }, + "imageReference": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "[parameters('vmWindowsOSVersion')]", + "version": "latest" + } + }, + "osProfile": { + "computerName": "[parameters('vmName')]", + "adminUsername": "[parameters('vmAdminUsername')]", + "adminPassword": "[parameters('vmAdminPassword')]" + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('vmNetworkInterfaceName'))]" + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkInterfaces', parameters('vmNetworkInterfaceName'))]" + ] + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64))]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64))]" + ], + "metadata": { + "description": "An optional Windows virtual machine deployment to act as a jump box." + } + }, + { + "condition": "[parameters('deployAzurePolicies')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('policyAssignments-{0}', deployment().name), 64)]", + "resourceGroup": "[variables('rgSpokeName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "containerRegistryName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.containerRegistry]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "15284178452562695596" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "The location where the resources will be created." + } + }, + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "The name of the Container Registry that will be allow-listed by the policy." + } + } + }, + "variables": { + "$fxv#0": "{\r\n \"properties\": {\r\n \"displayName\": \"Azure Container Apps allowed container registries\",\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"description\": \"This policy enables you to restrict the list of container registries for Azure Container Apps.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Azure Container Apps\"\r\n },\r\n \"parameters\": {\r\n \"listOfAllowedContainerRegistries\": {\r\n \"type\": \"Array\",\r\n \"metadata\": {\r\n \"displayName\": \"Allowed container registries\",\r\n \"description\": \"The list of container registries that can be specified when deploying resources.\"\r\n },\r\n \"defaultValue\": [\r\n \"mcr.microsoft.com\"\r\n ]\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n },\r\n \"allowedValues\": [\r\n \"Audit\",\r\n \"Deny\",\r\n \"Disabled\"\r\n ],\r\n \"defaultValue\": \"Audit\"\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"allOf\": [{\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.App/containerApps\"\r\n },\r\n {\r\n \"count\": {\r\n \"field\": \"Microsoft.App/containerApps/template.containers[*]\",\r\n \"where\": {\r\n \"value\": \"[split(first(field('Microsoft.App/containerApps/template.containers[*].image')), '/')[0]]\",\r\n \"notIn\": \"[parameters('listOfAllowedContainerRegistries')]\"\r\n }\r\n },\r\n \"greater\": 0\r\n }\r\n ]\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\"\r\n }\r\n }\r\n }\r\n}", + "$fxv#1": "{\r\n \"properties\": {\r\n \"displayName\": \"Azure Container Apps container replica count limits\",\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"description\": \"This policy enforces limits for the minimum and maximum number of replicas for Azure Container Apps.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Azure Container Apps\"\r\n },\r\n \"parameters\": {\r\n \"minReplicas\": {\r\n \"type\": \"integer\",\r\n \"metadata\": {\r\n \"displayName\": \"Min allowed replicas\",\r\n \"description\": \"Specifies the minimum number of container replicas for the Azure Container App\"\r\n },\r\n \"defaultValue\": 0\r\n },\r\n \"maxReplicas\": {\r\n \"type\": \"integer\",\r\n \"metadata\": {\r\n \"displayName\": \"Max allowed replicas\",\r\n \"description\": \"Specifies the maximum number of container replicas for the Azure Container App\"\r\n },\r\n \"defaultValue\": 30\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n },\r\n \"allowedValues\": [\r\n \"Audit\",\r\n \"Deny\",\r\n \"Disabled\"\r\n ],\r\n \"defaultValue\": \"Audit\"\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"allOf\": [{\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.App/containerApps\"\r\n },\r\n {\r\n \"anyOf\": [{\r\n \"field\": \"Microsoft.App/containerApps/template.scale.minReplicas\",\r\n \"less\": \"[parameters('MinReplicas')]\"\r\n }, {\r\n \"field\": \"Microsoft.App/containerApps/template.scale.maxReplicas\",\r\n \"greater\": \"[parameters('MaxReplicas')]\"\r\n }]\r\n }\r\n ]\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\"\r\n }\r\n }\r\n }\r\n}", + "$fxv#2": "{\r\n \"properties\": {\r\n \"displayName\": \"Azure Container Apps no container liveness probes\",\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"description\": \"This policy enforces that all the containers of Azure Containers Apps have liveness probes configured.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Azure Container Apps\"\r\n },\r\n \"parameters\": {\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n },\r\n \"allowedValues\": [\r\n \"Audit\",\r\n \"Deny\",\r\n \"Disabled\"\r\n ],\r\n \"defaultValue\": \"Audit\"\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"allOf\": [{\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.App/containerApps\"\r\n },\r\n {\r\n \"count\": {\r\n \"field\": \"Microsoft.App/containerApps/template.containers[*].probes[*]\",\r\n \"where\": {\r\n \"field\": \"Microsoft.App/containerApps/template.containers[*].probes[*].type\",\r\n \"equals\": \"Liveness\"\r\n }\r\n },\r\n \"equals\": 0\r\n }\r\n ]\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\"\r\n }\r\n }\r\n }\r\n}", + "$fxv#3": "{\r\n \"properties\": {\r\n \"displayName\": \"Azure Container Apps no container readiness probes\",\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"description\": \"This policy enforces that all the containers of Azure Containers Apps have readiness probes configured.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Azure Container Apps\"\r\n },\r\n \"parameters\": {\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n },\r\n \"allowedValues\": [\r\n \"Audit\",\r\n \"Deny\",\r\n \"Disabled\"\r\n ],\r\n \"defaultValue\": \"Audit\"\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"allOf\": [{\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.App/containerApps\"\r\n },\r\n {\r\n \"count\": {\r\n \"field\": \"Microsoft.App/containerApps/template.containers[*].probes[*]\",\r\n \"where\": {\r\n \"field\": \"Microsoft.App/containerApps/template.containers[*].probes[*].type\",\r\n \"equals\": \"Readiness\"\r\n }\r\n },\r\n \"equals\": 0\r\n }\r\n ]\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\"\r\n }\r\n }\r\n }\r\n}", + "$fxv#4": "{\r\n \"properties\": {\r\n \"displayName\": \"Azure Container Apps no container startup probes\",\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"description\": \"This policy enforces that all the containers of Azure Containers Apps have startup probes configured.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Azure Container Apps\"\r\n },\r\n \"parameters\": {\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n },\r\n \"allowedValues\": [\r\n \"Audit\",\r\n \"Deny\",\r\n \"Disabled\"\r\n ],\r\n \"defaultValue\": \"Audit\"\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"allOf\": [{\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.App/containerApps\"\r\n },\r\n {\r\n \"count\": {\r\n \"field\": \"Microsoft.App/containerApps/template.containers[*].probes[*]\",\r\n \"where\": {\r\n \"field\": \"Microsoft.App/containerApps/template.containers[*].probes[*].type\",\r\n \"equals\": \"Startup\"\r\n }\r\n },\r\n \"equals\": 0\r\n }\r\n ]\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\"\r\n }\r\n }\r\n }\r\n}", + "$fxv#5": "{\r\n \"properties\": {\r\n \"displayName\": \"Azure Container Apps container required CPU and memory\",\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"description\": \"This policy enforces limits for container CPU and memory requests in an AZure Container App.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Azure Container Apps\"\r\n },\r\n \"parameters\": {\r\n \"maxCpu\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Max allowed CPU cores\",\r\n \"description\": \"Specifies the maximum CPU cores allowed for a container. E.g. 1.25.\"\r\n },\r\n \"defaultValue\": \"2.0\"\r\n },\r\n \"maxMemory\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Max allowed memory in Gi\",\r\n \"description\": \"Specifies the maximum memory in Gi allowed for a container. E.g. 2.5\"\r\n },\r\n \"defaultValue\": \"4.0\"\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n },\r\n \"allowedValues\": [\r\n \"Audit\",\r\n \"Deny\",\r\n \"Disabled\"\r\n ],\r\n \"defaultValue\": \"Audit\"\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"allOf\": [{\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.App/containerApps\"\r\n },\r\n {\r\n \"anyOf\": [{\r\n \"count\": {\r\n \"field\": \"Microsoft.App/containerApps/template.containers[*]\",\r\n \"where\": {\r\n \"field\": \"Microsoft.App/containerApps/template.containers[*].resources.cpu\",\r\n \"greater\": \"[float(parameters('maxCpu'))]\"\r\n }\r\n },\r\n \"greater\": 0\r\n },\r\n {\r\n \"count\": {\r\n \"field\": \"Microsoft.App/containerApps/template.containers[*]\",\r\n \"where\": {\r\n \"value\": \"[float(substring(first(field('Microsoft.App/containerApps/template.containers[*].resources.memory')), 0, sub(length(first(field('Microsoft.App/containerApps/template.containers[*].resources.memory'))), 2)))]\",\r\n \"greater\": \"[float(parameters('maxMemory'))]\"\r\n }\r\n },\r\n \"greater\": 0\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\"\r\n }\r\n }\r\n }\r\n}", + "$fxv#6": "{\r\n \"properties\": {\r\n \"displayName\": \"Azure Container Apps no monitoring configured\",\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"All\",\r\n \"description\": \"This policy enforces that monitoring is configured for Azure Container Apps environments.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Azure Container Apps\"\r\n },\r\n \"parameters\": {\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n },\r\n \"allowedValues\": [\r\n \"Audit\",\r\n \"Deny\",\r\n \"Disabled\"\r\n ],\r\n \"defaultValue\": \"Audit\"\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"allOf\": [{\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.App/managedEnvironments\"\r\n },\r\n {\r\n \"field\": \"Microsoft.App/managedEnvironments/appLogsConfiguration.destination\",\r\n \"exists\": false\r\n }\r\n ]\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\"\r\n }\r\n }\r\n }\r\n}", + "builtInPolicies": [ + { + "name": "authentication-should-be-enabled-on-container-apps", + "definition": { + "properties": { + "displayName": "Authentication should be enabled on container apps", + "description": "Container Apps Authentication is a feature that can prevent anonymous HTTP requests from reaching the Container App, or authenticate those that have tokens before they reach the Container App" + } + }, + "parameters": { + "effect": { + "value": "AuditIfNotExists" + } + }, + "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/2b585559-a78e-4cc4-b1aa-fb169d2f6b96" + }, + { + "name": "container-app-environments-should-use-network-injection", + "definition": { + "properties": { + "displayName": "Container App environments should use network injection", + "description": "Container Apps environments should use virtual network injection to: 1.Isolate Container Apps from the public internet 2.Enable network integration with resources on-premises or in other Azure virtual networks 3.Achieve more granular control over network traffic flowing to and from the environment" + } + }, + "parameters": { + "effect": { + "value": "Audit" + } + }, + "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/8b346db6-85af-419b-8557-92cee2c0f9bb" + }, + { + "name": "container-app-should-configure-with-volume-mount", + "definition": { + "properties": { + "displayName": "Container App should configure with volume mount", + "description": "Enforce the use of volume mounts for Container Apps to ensure availability of persistent storage capacity" + } + }, + "parameters": { + "effect": { + "value": "Audit" + } + }, + "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/7c9f3fbb-739d-4844-8e42-97e3be6450e0" + }, + { + "name": "container-app-should-disable-public-network-access", + "definition": { + "properties": { + "displayName": "Container Apps environment should disable public network access", + "description": "Disable public network access to improve security by exposing the Container Apps environment through an internal load balancer. This removes the need for a public IP address and prevents internet access to all Container Apps within the environment." + } + }, + "parameters": { + "effect": { + "value": "Audit" + } + }, + "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/d074ddf8-01a5-4b5e-a2b8-964aed452c0a" + }, + { + "name": "container-apps-should-disable-external-network-access", + "definition": { + "properties": { + "displayName": "Container Apps should disable external network access", + "description": "Disable external network access to your Container Apps by enforcing internal-only ingress. This will ensure inbound communication for Container Apps is limited to callers within the Container Apps environment" + } + }, + "parameters": { + "effect": { + "value": "Audit" + } + }, + "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/783ea2a8-b8fd-46be-896a-9ae79643a0b1" + }, + { + "name": "containerapps-should-only-be-accessible-over-HTTPS", + "definition": { + "properties": { + "displayName": "Container Apps should only be accessible over HTTPS", + "description": "Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks. Disabling \"allowInsecur\" will result in the automatic redirection of requests from HTTP to HTTPS connections for container apps." + } + }, + "parameters": { + "effect": { + "value": "Audit" + } + }, + "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/0e80e269-43a4-4ae9-b5bc-178126b8a5cb" + }, + { + "name": "managed-identity-should-be-enabled", + "definition": { + "properties": { + "displayName": "Managed Identity should be enabled for Container Apps", + "description": "Enforcing managed identity ensures Container Apps can securely authenticate to any resource that supports Azure AD authentication" + } + }, + "parameters": { + "effect": { + "value": "Audit" + } + }, + "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/b874ab2d-72dd-47f1-8cb5-4a306478a4e7" + } + ], + "customPolicies": [ + { + "name": "aca-allowed-container-registries", + "definition": "[json(variables('$fxv#0'))]", + "parameters": { + "listOfAllowedContainerRegistries": { + "value": [ + "mcr.microsoft.com", + "docker.io", + "ghcr.io", + "[format('{0}.azurecr.io', parameters('containerRegistryName'))]" + ] + }, + "effect": { + "value": "Audit" + } + } + }, + { + "name": "aca-replica-count", + "definition": "[json(variables('$fxv#1'))]", + "parameters": { + "minReplicas": { + "value": 0 + }, + "maxReplicas": { + "value": 30 + }, + "effect": { + "value": "Audit" + } + }, + "identity": false + }, + { + "name": "aca-no-liveness-probes", + "definition": "[json(variables('$fxv#2'))]", + "parameters": { + "effect": { + "value": "Audit" + } + }, + "identity": false + }, + { + "name": "aca-no-readiness-probes", + "definition": "[json(variables('$fxv#3'))]", + "parameters": { + "effect": { + "value": "Audit" + } + }, + "identity": false + }, + { + "name": "aca-no-startup-probes", + "definition": "[json(variables('$fxv#4'))]", + "parameters": { + "effect": { + "value": "Audit" + } + }, + "identity": false + }, + { + "name": "aca-required-cpu-and-memory", + "definition": "[json(variables('$fxv#5'))]", + "parameters": { + "maxCpu": { + "value": "1.0" + }, + "maxMemory": { + "value": "2.5" + }, + "effect": { + "value": "Audit" + } + }, + "identity": false + }, + { + "name": "aca-no-monitoring", + "definition": "[json(variables('$fxv#6'))]", + "parameters": { + "effect": { + "value": "Audit" + } + }, + "identity": false + } + ] + }, + "resources": [ + { + "copy": { + "name": "builtInPolicyAssignment", + "count": "[length(variables('builtInPolicies'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('poAssign_{0}', take(variables('builtInPolicies')[copyIndex()].name, 40))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "policy": { + "value": "[variables('builtInPolicies')[copyIndex()]]" + }, + "policyDefinitionId": { + "value": "[variables('builtInPolicies')[copyIndex()].policyDefinitionId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "13451226014402037925" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Specifies the location of the deployment." + } + }, + "policy": { + "type": "object", + "metadata": { + "description": "Specifies the policy definition to assign." + } + }, + "policyDefinitionId": { + "type": "string", + "metadata": { + "description": "Specifies the resource id of the policy definition to assign." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2022-06-01", + "name": "[uniqueString(format('{0}', parameters('policy').name))]", + "location": "[parameters('location')]", + "properties": { + "description": "[parameters('policy').definition.properties.description]", + "displayName": "[parameters('policy').definition.properties.displayName]", + "policyDefinitionId": "[parameters('policyDefinitionId')]", + "parameters": "[parameters('policy').parameters]" + } + } + ], + "outputs": { + "policyAssignmentId": { + "type": "string", + "value": "[resourceId('Microsoft.Authorization/policyAssignments', uniqueString(format('{0}', parameters('policy').name)))]" + } + } + } + } + }, + { + "copy": { + "name": "policyDefinition", + "count": "[length(variables('customPolicies'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('poDef_{0}', guid(variables('customPolicies')[copyIndex()].name))]", + "subscriptionId": "[subscription().subscriptionId]", + "location": "[resourceGroup().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "policy": { + "value": "[variables('customPolicies')[copyIndex()]]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "1948385689214915540" + } + }, + "parameters": { + "policy": { + "type": "object", + "metadata": { + "description": "Specifies the policy definition to assign." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyDefinitions", + "apiVersion": "2021-06-01", + "name": "[guid(parameters('policy').name)]", + "properties": { + "description": "[parameters('policy').definition.properties.description]", + "displayName": "[parameters('policy').definition.properties.displayName]", + "metadata": "[parameters('policy').definition.properties.metadata]", + "mode": "[parameters('policy').definition.properties.mode]", + "parameters": "[parameters('policy').definition.properties.parameters]", + "policyType": "[parameters('policy').definition.properties.policyType]", + "policyRule": "[parameters('policy').definition.properties.policyRule]" + } + } + ], + "outputs": { + "policyDefinitionId": { + "type": "string", + "value": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(parameters('policy').name))]" + } + } + } + } + }, + { + "copy": { + "name": "customPolicyAssignment", + "count": "[length(variables('customPolicies'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('poAssign_{0}', take(variables('customPolicies')[copyIndex()].name, 40))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "policy": { + "value": "[variables('customPolicies')[copyIndex()]]" + }, + "policyDefinitionId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', format('poDef_{0}', guid(variables('customPolicies')[copyIndex()].name))), '2022-09-01').outputs.policyDefinitionId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "13451226014402037925" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Specifies the location of the deployment." + } + }, + "policy": { + "type": "object", + "metadata": { + "description": "Specifies the policy definition to assign." + } + }, + "policyDefinitionId": { + "type": "string", + "metadata": { + "description": "Specifies the resource id of the policy definition to assign." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2022-06-01", + "name": "[uniqueString(format('{0}', parameters('policy').name))]", + "location": "[parameters('location')]", + "properties": { + "description": "[parameters('policy').definition.properties.description]", + "displayName": "[parameters('policy').definition.properties.displayName]", + "policyDefinitionId": "[parameters('policyDefinitionId')]", + "parameters": "[parameters('policy').parameters]" + } + } + ], + "outputs": { + "policyAssignmentId": { + "type": "string", + "value": "[resourceId('Microsoft.Authorization/policyAssignments', uniqueString(format('{0}', parameters('policy').name)))]" + } + } + } + }, + "dependsOn": [ + "policyDefinition" + ] + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('02-sharedNamingDeployment-{0}', deployment().name), 64))]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]" + ], + "metadata": { + "description": "Assign built-in and custom (container-apps related) policies to the spoke subscription." + } + } + ], + "outputs": { + "spokeResourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the spoke resource group." + }, + "value": "[variables('rgSpokeName')]" + }, + "spokeVNetId": { + "type": "string", + "metadata": { + "description": "The resource ID of the spoke virtual network." + }, + "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Network/virtualNetworks', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value)]" + }, + "spokeVNetName": { + "type": "string", + "metadata": { + "description": "The name of the spoke virtual network." + }, + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value]" + }, + "spokeInfraSubnetId": { + "type": "string", + "metadata": { + "description": "The resource ID of the spoke infrastructure subnet." + }, + "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Network/virtualNetworks/subnets', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value, parameters('spokeInfraSubnetName'))]" + }, + "spokeInfraSubnetName": { + "type": "string", + "metadata": { + "description": "The name of the spoke infrastructure subnet." + }, + "value": "[parameters('spokeInfraSubnetName')]" + }, + "spokePrivateEndpointsSubnetName": { + "type": "string", + "metadata": { + "description": "The name of the spoke private endpoints subnet." + }, + "value": "[parameters('spokePrivateEndpointsSubnetName')]" + }, + "spokeApplicationGatewaySubnetId": { + "type": "string", + "metadata": { + "description": "The resource ID of the spoke Application Gateway subnet. This is '' if the subnet was not created." + }, + "value": "[if(not(empty(parameters('spokeApplicationGatewaySubnetAddressPrefix'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Network/virtualNetworks/subnets', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('vnetSpoke-{0}', deployment().name), 64)), '2022-09-01').outputs.vnetName.value, parameters('spokeApplicationGatewaySubnetName')), '')]" + }, + "spokeApplicationGatewaySubnetName": { + "type": "string", + "metadata": { + "description": "The name of the spoke Application Gateway subnet. This is '' if the subnet was not created." + }, + "value": "[if(not(empty(parameters('spokeApplicationGatewaySubnetAddressPrefix'))), parameters('spokeApplicationGatewaySubnetName'), '')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure Log Analytics Workspace." + }, + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('logAnalyticsWs-{0}', uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName')))), 64)), '2022-09-01').outputs.logAnalyticsWsId.value]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/deployments', take(format('hub-{0}-deployment', deployment().name), 64))]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('supportingServices-{0}-deployment', deployment().name), 64)]", + "resourceGroup": "[variables('rgSpokeName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "spokePrivateEndpointSubnetName": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.spokePrivateEndpointsSubnetName.value]" + }, + "environment": { + "value": "[parameters('environment')]" + }, + "workloadName": { + "value": "[parameters('workloadName')]" + }, + "spokeVNetId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.spokeVNetId.value]" + }, + "hubVNetId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('hub-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.hubVNetId.value]" + }, + "deployRedisCache": { + "value": "[parameters('deployRedisCache')]" + }, + "logAnalyticsWorkspaceId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.logAnalyticsWorkspaceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "17570437521361084825" + } + }, + "parameters": { + "workloadName": { + "type": "string", + "minLength": 2, + "maxLength": 10, + "metadata": { + "description": "The name of the workload that is being deployed. Up to 10 characters long." + } + }, + "environment": { + "type": "string", + "maxLength": 8, + "metadata": { + "description": "The name of the environment (e.g. \"dev\", \"test\", \"prod\", \"uat\", \"dr\", \"qa\"). Up to 8 characters long." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The location where the resources will be created. This needs to be the same region as the spoke." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The tags to be assigned to the created resources." + } + }, + "hubVNetId": { + "type": "string", + "metadata": { + "description": "The resource ID of the existing hub virtual network." + } + }, + "spokeVNetId": { + "type": "string", + "metadata": { + "description": "The resource ID of the existing spoke virtual network to which the private endpoint will be connected." + } + }, + "spokePrivateEndpointSubnetName": { + "type": "string", + "metadata": { + "description": "The name of the existing subnet in the spoke virtual to which the private endpoint will be connected." + } + }, + "deployRedisCache": { + "type": "bool", + "metadata": { + "description": "Deploy Redis cache premium SKU" + } + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. If left empty, no diagnostics settings will be defined." + } + }, + "deployZoneRedundantResources": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional, default value is true. If true, any resources that support AZ will be deployed in all three AZ. However if the selected region is not supporting AZ, this parameter needs to be set to false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('03-sharedNamingDeployment-{0}', deployment().name), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "uniqueId": { + "value": "[uniqueString(resourceGroup().id)]" + }, + "environment": { + "value": "[parameters('environment')]" + }, + "workloadName": { + "value": "[parameters('workloadName')]" + }, + "location": { + "value": "[parameters('location')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "6817832201461302860" + } + }, + "parameters": { + "workloadName": { + "type": "string", + "minLength": 2, + "maxLength": 10, + "metadata": { + "description": "The name of the workloard that is being deployed. Up to 10 characters long." + } + }, + "environment": { + "type": "string", + "maxLength": 8, + "metadata": { + "description": "The name of the environment (e.g. \"dev\", \"test\", \"prod\", \"uat\", \"dr\", \"qa\") Up to 8 characters long." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location for all Resources." + } + }, + "uniqueId": { + "type": "string", + "metadata": { + "description": "a unique ID that can be appended (or prepended) in azure resource names that require some kind of uniqueness" + } + } + }, + "variables": { + "$fxv#0": "{\r\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\r\n \"resourceTypeAbbreviations\" : {\r\n \"applicationGateway\": \"agw\",\r\n \"applicationInsights\": \"appi\",\r\n \"appService\": \"app\",\r\n \"bastion\": \"bas\",\r\n \"containerAppsEnvironment\": \"cae\",\r\n \"containerRegistry\": \"cr\",\r\n \"cosmosDbNoSql\": \"cosno\",\r\n \"frontDoor\": \"afd\",\r\n \"frontDoorEndpoint\": \"fde\",\r\n \"frontDoorWaf\": \"fdfp\",\r\n \"keyVault\": \"kv\",\r\n \"logAnalyticsWorkspace\": \"log\",\r\n \"managedIdentity\": \"id\",\r\n \"networkInterface\": \"nic\",\r\n \"networkSecurityGroup\": \"nsg\",\r\n \"privateEndpoint\": \"pep\",\r\n \"privateLinkService\": \"pls\",\r\n \"publicIpAddress\": \"pip\",\r\n \"resourceGroup\": \"rg\",\r\n \"serviceBus\": \"sb\",\r\n \"serviceBusQueue\": \"sbq\",\r\n \"serviceBusTopic\": \"sbt\",\r\n \"storageAccount\": \"st\",\r\n \"virtualMachine\": \"vm\",\r\n \"virtualNetwork\": \"vnet\",\r\n \"redisCache\": \"redis\"\r\n },\r\n\r\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\r\n \"regionAbbreviations\" : {\r\n \"australiacentral\": \"auc\",\r\n \"australiacentral2\": \"auc2\",\r\n \"australiaeast\": \"aue\",\r\n \"australiasoutheast\": \"ause\",\r\n \"brazilsouth\": \"brs\",\r\n \"brazilsoutheast\": \"brse\",\r\n \"canadacentral\": \"canc\",\r\n \"canadaeast\": \"cane\",\r\n \"centralindia\": \"cin\",\r\n \"centralus\": \"cus\",\r\n \"centraluseuap\": \"cuseuap\",\r\n \"eastasia\": \"ea\",\r\n \"eastus\": \"eus\",\r\n \"eastus2\": \"eus2\",\r\n \"eastus2euap\": \"eus2euap\",\r\n \"francecentral\": \"frc\",\r\n \"francesouth\": \"frs\",\r\n \"germanynorth\": \"gern\",\r\n \"germanywestcentral\": \"gerwc\",\r\n \"japaneast\": \"jae\",\r\n \"japanwest\": \"jaw\",\r\n \"jioindiacentral\": \"jioinc\",\r\n \"jioindiawest\": \"jioinw\",\r\n \"koreacentral\": \"koc\",\r\n \"koreasouth\": \"kors\",\r\n \"northcentralus\": \"ncus\",\r\n \"northeurope\": \"neu\",\r\n \"norwayeast\": \"nore\",\r\n \"norwaywest\": \"norw\",\r\n \"southafricanorth\": \"san\",\r\n \"southafricawest\": \"saw\",\r\n \"southcentralus\": \"scus\",\r\n \"southeastasia\": \"sea\",\r\n \"southindia\": \"sin\",\r\n \"swedencentral\": \"swc\",\r\n \"switzerlandnorth\": \"swn\",\r\n \"switzerlandwest\": \"sww\",\r\n \"uaecentral\": \"uaec\",\r\n \"uaenorth\": \"uaen\",\r\n \"uksouth\": \"uks\",\r\n \"ukwest\": \"ukw\",\r\n \"westcentralus\": \"wcus\",\r\n \"westeurope\": \"weu\",\r\n \"westindia\": \"win\",\r\n \"westus\": \"wus\",\r\n \"westus2\": \"wus2\",\r\n \"westus3\": \"wus3\"\r\n }\r\n}", + "naming": "[json(variables('$fxv#0'))]", + "uniqueIdShort": "[substring(parameters('uniqueId'), 0, 5)]", + "resourceTypeToken": "RES_TYPE", + "namingBase": "[format('{0}-{1}-{2}-{3}', variables('resourceTypeToken'), parameters('workloadName'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", + "namingBaseUnique": "[format('{0}-{1}-{2}-{3}-{4}', variables('resourceTypeToken'), parameters('workloadName'), variables('uniqueIdShort'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", + "namingBaseNoWorkloadName": "[format('{0}-{1}-{2}', variables('resourceTypeToken'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", + "resourceTypeAbbreviations": "[variables('naming').resourceTypeAbbreviations]", + "keyVaultName": "[take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault), 24)]", + "resourceNames": { + "vnetSpoke": "[format('{0}-spoke', replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualNetwork))]", + "vnetHub": "[format('{0}-hub', replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualNetwork))]", + "applicationGateway": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway)]", + "applicationGatewayPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", + "applicationGatewayUserAssignedIdentity": "[format('{0}-{1}-KeyVaultSecretUser', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", + "applicationGatewayNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", + "pepNsg": "[format('{0}-pep', variables('naming').resourceTypeAbbreviations.networkSecurityGroup)]", + "applicationInsights": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationInsights)]", + "bastion": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion)]", + "bastionNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", + "bastionPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", + "containerAppsEnvironment": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerAppsEnvironment)]", + "containerAppsEnvironmentNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerAppsEnvironment))]", + "containerRegistry": "[take(toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')), 50)]", + "containerRegistryPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')))]", + "containerRegistryUserAssignedIdentity": "[format('{0}-{1}-AcrPull', variables('naming').resourceTypeAbbreviations.managedIdentity, toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')))]", + "redisCache": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.redisCache)]", + "redisCachePep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.redisCache))]", + "cosmosDbNoSql": "[toLower(take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.cosmosDbNoSql), 44))]", + "cosmosDbNoSqlPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.cosmosDbNoSql), 44)))]", + "frontDoorProfile": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]", + "keyVault": "[if(endsWith(variables('keyVaultName'), '-'), take(variables('keyVaultName'), 23), variables('keyVaultName'))]", + "keyVaultPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", + "logAnalyticsWorkspace": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.logAnalyticsWorkspace)]", + "serviceBus": "[replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus)]", + "serviceBusPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus))]", + "storageAccount": "[toLower(take(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.storageAccount), '-', ''), 24))]", + "storageAccountPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.storageAccount)))]", + "vmJumpBox": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine)]", + "vmJumpBoxNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine))]", + "vmJumpBoxNic": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkInterface, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine))]", + "frontDoor": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]" + } + }, + "resources": [], + "outputs": { + "resourcesNames": { + "type": "object", + "value": "[variables('resourceNames')]" + }, + "resourceTypeAbbreviations": { + "type": "object", + "value": "[variables('resourceTypeAbbreviations')]" + } + } + } + }, + "metadata": { + "description": "User-configured naming rules" + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('containerRegistry-{0}', uniqueString(resourceGroup().id))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerRegistryName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('03-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.containerRegistry]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "spokeVNetId": { + "value": "[parameters('spokeVNetId')]" + }, + "hubVNetId": { + "value": "[parameters('hubVNetId')]" + }, + "spokePrivateEndpointSubnetName": { + "value": "[parameters('spokePrivateEndpointSubnetName')]" + }, + "containerRegistryPrivateEndpointName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('03-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.containerRegistryPep]" + }, + "containerRegistryUserAssignedIdentityName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('03-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.containerRegistryUserAssignedIdentity]" + }, + "diagnosticWorkspaceId": { + "value": "[parameters('logAnalyticsWorkspaceId')]" + }, + "deployZoneRedundantResources": { + "value": "[parameters('deployZoneRedundantResources')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "3859020996589006509" + } + }, + "parameters": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The location where the resources will be created." + } + }, + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The tags to be assigned to the created resources." + } + }, + "hubVNetId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Hub Virtual Network." + } + }, + "spokeVNetId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VNet to which the private endpoint will be connected." + } + }, + "spokePrivateEndpointSubnetName": { + "type": "string", + "metadata": { + "description": "The name of the subnet in the VNet to which the private endpoint will be connected." + } + }, + "containerRegistryPrivateEndpointName": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint to be created for Azure Container Registry." + } + }, + "containerRegistryUserAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity to be created to pull image from Azure Container Registry." + } + }, + "diagnosticWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace." + } + }, + "deployZoneRedundantResources": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional, default value is true. If true, any resources that support AZ will be deployed in all three AZ. However if the selected region is not supporting AZ, this parameter needs to be set to false." + } + } + }, + "variables": { + "privateDnsZoneNames": "privatelink.azurecr.io", + "containerRegistryResourceName": "registry", + "hubVNetIdTokens": "[split(parameters('hubVNetId'), '/')]", + "hubSubscriptionId": "[variables('hubVNetIdTokens')[2]]", + "hubResourceGroupName": "[variables('hubVNetIdTokens')[4]]", + "hubVNetName": "[variables('hubVNetIdTokens')[8]]", + "spokeVNetIdTokens": "[split(parameters('spokeVNetId'), '/')]", + "spokeSubscriptionId": "[variables('spokeVNetIdTokens')[2]]", + "spokeResourceGroupName": "[variables('spokeVNetIdTokens')[4]]", + "spokeVNetName": "[variables('spokeVNetIdTokens')[8]]", + "containerRegistryPullRoleGuid": "7f951dda-4ed3-4680-a7ca-43fe172d538d", + "spokeVNetLinks": [ + { + "vnetName": "[variables('spokeVNetName')]", + "vnetId": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('spokeSubscriptionId'), variables('spokeResourceGroupName')), 'Microsoft.Network/virtualNetworks', variables('spokeVNetName'))]", + "registrationEnabled": false + }, + { + "vnetName": "[variables('hubVNetName')]", + "vnetId": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('hubSubscriptionId'), variables('hubResourceGroupName')), 'Microsoft.Network/virtualNetworks', variables('hubVNetName'))]", + "registrationEnabled": false + } + ] + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2018-11-30", + "name": "[parameters('containerRegistryUserAssignedIdentityName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('containerRegistryNameDeployment-{0}', deployment().name), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "name": { + "value": "[parameters('containerRegistryName')]" + }, + "acrSku": { + "value": "Premium" + }, + "zoneRedundancy": "[if(parameters('deployZoneRedundantResources'), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", + "acrAdminUserEnabled": { + "value": false + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "networkRuleBypassOptions": { + "value": "AzureServices" + }, + "diagnosticWorkspaceId": { + "value": "[parameters('diagnosticWorkspaceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "18103636292400817846" + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. Name of your Azure container registry." + } + }, + "acrAdminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable admin user that have push / pull permission to the registry." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the export policy is enabled or not." + } + }, + "quarantinePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not." + } + }, + "trustPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the trust policy is enabled or not." + } + }, + "retentionPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the retention policy is enabled or not." + } + }, + "retentionPolicyDays": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + } + }, + "azureADAuthenticationAsArmPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registr is enabled or not. Default is enabled." + } + }, + "softDeletePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. Soft Delete policy status. Default is disabled." + } + }, + "softDeletePolicyDays": { + "type": "int", + "defaultValue": 7, + "metadata": { + "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + } + }, + "dataEndpointEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "networkRuleBypassOptions": { + "type": "string", + "defaultValue": "AzureServices", + "allowedValues": [ + "AzureServices", + "None" + ], + "metadata": { + "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + } + }, + "networkRuleSetDefaultAction": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. The default action of allow or deny when no other rules match." + } + }, + "networkRuleSetIpRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "privateEndpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "systemAssignedIdentity": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The ID(s) to assign to the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticLogCategoriesToEnable": { + "type": "array", + "defaultValue": [ + "allLogs" + ], + "allowedValues": [ + "allLogs", + "ContainerRegistryRepositoryEvents", + "ContainerRegistryLoginEvents" + ], + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource." + } + }, + "diagnosticMetricsToEnable": { + "type": "array", + "defaultValue": [ + "AllMetrics" + ], + "allowedValues": [ + "AllMetrics" + ], + "metadata": { + "description": "Optional. The name of metrics that will be streamed." + } + }, + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + }, + "diagnosticStorageAccountId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account." + } + }, + "diagnosticWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace." + } + }, + "diagnosticEventHubAuthorizationRuleId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "diagnosticEventHubName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category." + } + }, + "diagnosticSettingsName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the diagnostic setting, if deployed. If left empty, it defaults to \"-diagnosticSettings\"." + } + }, + "anonymousPullEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." + } + }, + "cMKKeyVaultResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of a key vault to reference a customer managed key for encryption from. Note, CMK requires the 'acrSku' to be 'Premium'." + } + }, + "cMKKeyName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the customer managed key to use for encryption. Note, CMK requires the 'acrSku' to be 'Premium'." + } + }, + "cMKKeyVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the latest key version is used." + } + }, + "cMKUserAssignedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. User assigned identity to use when fetching the customer managed key. Note, CMK requires the 'acrSku' to be 'Premium'. Required if 'cMKKeyName' is not empty." + } + } + }, + "variables": { + "copy": [ + { + "name": "diagnosticsLogsSpecified", + "count": "[length(filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs')))))]", + "input": { + "category": "[filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs'))))[copyIndex('diagnosticsLogsSpecified')]]", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + }, + { + "name": "diagnosticsMetrics", + "count": "[length(parameters('diagnosticMetricsToEnable'))]", + "input": { + "category": "[parameters('diagnosticMetricsToEnable')[copyIndex('diagnosticsMetrics')]]", + "timeGrain": null, + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + } + ], + "diagnosticsLogs": "[if(contains(parameters('diagnosticLogCategoriesToEnable'), 'allLogs'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true(), 'retentionPolicy', createObject('enabled', true(), 'days', parameters('diagnosticLogsRetentionInDays')))), variables('diagnosticsLogsSpecified'))]", + "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", + "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), null())]" + }, + "resources": [ + { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2022-02-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('acrSku')]" + }, + "properties": { + "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", + "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", + "encryption": "[if(not(empty(parameters('cMKKeyName'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('cMKUserAssignedIdentityResourceId'), '/')[2], split(parameters('cMKUserAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(parameters('cMKUserAssignedIdentityResourceId'), '/'))), '2018-11-30').clientId, 'keyIdentifier', if(not(empty(parameters('cMKKeyVersion'))), format('{0}/{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('cMKKeyVaultResourceId'), '/')[2], split(parameters('cMKKeyVaultResourceId'), '/')[4]), 'Microsoft.KeyVault/vaults/keys', split(format('{0}/{1}', last(split(parameters('cMKKeyVaultResourceId'), '/')), parameters('cMKKeyName')), '/')[0], split(format('{0}/{1}', last(split(parameters('cMKKeyVaultResourceId'), '/')), parameters('cMKKeyName')), '/')[1]), '2021-10-01').keyUri, parameters('cMKKeyVersion')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('cMKKeyVaultResourceId'), '/')[2], split(parameters('cMKKeyVaultResourceId'), '/')[4]), 'Microsoft.KeyVault/vaults/keys', split(format('{0}/{1}', last(split(parameters('cMKKeyVaultResourceId'), '/')), parameters('cMKKeyName')), '/')[0], split(format('{0}/{1}', last(split(parameters('cMKKeyVaultResourceId'), '/')), parameters('cMKKeyName')), '/')[1]), '2021-10-01').keyUriWithVersion))), null())]", + "policies": { + "azureADAuthenticationAsArmPolicy": { + "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + }, + "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", + "quarantinePolicy": { + "status": "[parameters('quarantinePolicyStatus')]" + }, + "trustPolicy": { + "type": "Notary", + "status": "[parameters('trustPolicyStatus')]" + }, + "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", + "softDeletePolicy": { + "retentionDays": "[parameters('softDeletePolicyDays')]", + "status": "[parameters('softDeletePolicyStatus')]" + } + }, + "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", + "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", + "networkRuleSet": "[if(not(empty(parameters('networkRuleSetIpRules'))), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', parameters('networkRuleSetIpRules')), null())]", + "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" + } + }, + { + "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.ContainerRegistry/registries/{0}', parameters('name'))]", + "name": "[if(not(empty(parameters('diagnosticSettingsName'))), parameters('diagnosticSettingsName'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", + "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", + "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", + "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", + "metrics": "[variables('diagnosticsMetrics')]", + "logs": "[variables('diagnosticsLogs')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Azure container registry." + }, + "value": "[parameters('name')]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The reference to the Azure container registry." + }, + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2019-05-01').loginServer]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + }, + "systemAssignedPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2022-02-01-preview', 'full').identity, 'principalId')), reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2022-02-01-preview', 'full').identity.principalId, '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2022-02-01-preview', 'full').location]" + } + } + } } }, - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2018-11-30", - "name": "[parameters('containerRegistryUserAssignedIdentityName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ContainerRegistry/registries/{0}', parameters('containerRegistryName'))]", - "name": "[guid(subscription().id, resourceId('Microsoft.ContainerRegistry/registries', parameters('containerRegistryName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('containerRegistryUserAssignedIdentityName')))]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('containerRegistryUserAssignedIdentityName')), '2018-11-30').principalId]", - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('containerRegistryPullRoleGuid'))]", - "principalType": "ServicePrincipal" - }, - "dependsOn": [ - "[resourceId('Microsoft.ContainerRegistry/registries', parameters('containerRegistryName'))]", - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('containerRegistryUserAssignedIdentityName'))]" - ] - }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('containerRegistryNetwork-{0}', uniqueString(resourceId('Microsoft.ContainerRegistry/registries', parameters('containerRegistryName'))))]", + "name": "[take(format('containerRegistryNetworkDeployment-{0}', deployment().name), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -2745,7 +4375,7 @@ "value": "[variables('privateDnsZoneNames')]" }, "azServiceId": { - "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('containerRegistryName'))]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('containerRegistryNameDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourceId.value]" }, "privateEndpointName": { "value": "[parameters('containerRegistryPrivateEndpointName')]" @@ -2758,6 +4388,9 @@ }, "subnetId": { "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('spokeSubscriptionId'), variables('spokeResourceGroupName')), 'Microsoft.Network/virtualNetworks/subnets', variables('spokeVNetName'), parameters('spokePrivateEndpointSubnetName'))]" + }, + "vnetHubResourceId": { + "value": "[parameters('hubVNetId')]" } }, "template": { @@ -2766,8 +4399,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "15478438910397268748" + "version": "0.20.4.51522", + "templateHash": "1892554050389365289" } }, "parameters": { @@ -2778,6 +4411,12 @@ "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain vnetName, vnetId, registrationEnabled" } }, + "vnetHubResourceId": { + "type": "string", + "metadata": { + "description": "if empty, private dns zone will be deployed in the current RG scope" + } + }, "subnetId": { "type": "string", "metadata": { @@ -2816,11 +4455,16 @@ } } }, + "variables": { + "vnetHubSplitTokens": "[if(not(empty(parameters('vnetHubResourceId'))), split(parameters('vnetHubResourceId'), '/'), array(''))]" + }, "resources": [ { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName')))]", + "subscriptionId": "[variables('vnetHubSplitTokens')[2]]", + "resourceGroup": "[variables('vnetHubSplitTokens')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -2840,8 +4484,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "8461334250568869203" + "version": "0.20.4.51522", + "templateHash": "16481873424741287744" } }, "parameters": { @@ -2947,7 +4591,7 @@ "value": "[parameters('location')]" }, "privateDnsZonesId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName')))), '2022-09-01').outputs.privateDnsZonesId.value]" + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('vnetHubSplitTokens')[2], variables('vnetHubSplitTokens')[4]), 'Microsoft.Resources/deployments', format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName')))), '2022-09-01').outputs.privateDnsZonesId.value]" }, "privateLinkServiceId": { "value": "[parameters('azServiceId')]" @@ -2965,15 +4609,15 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "17714688339806767068" + "version": "0.20.4.51522", + "templateHash": "9790261476800825323" } }, "parameters": { "name": { "type": "string", - "maxLength": 64, "minLength": 2, + "maxLength": 64, "metadata": { "description": "Required. Name of your Private Endpoint. Must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens." } @@ -3062,14 +4706,140 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName'))))]" + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('vnetHubSplitTokens')[2], variables('vnetHubSplitTokens')[4]), 'Microsoft.Resources/deployments', format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName'))))]" ] } ] } }, "dependsOn": [ - "[resourceId('Microsoft.ContainerRegistry/registries', parameters('containerRegistryName'))]" + "[resourceId('Microsoft.Resources/deployments', take(format('containerRegistryNameDeployment-{0}', deployment().name), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('containerRegistryPullRoleAssignmentDeployment-{0}', deployment().name), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "ra-containerRegistryPullRoleAssignment" + }, + "principalId": { + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('containerRegistryUserAssignedIdentityName')), '2018-11-30').principalId]" + }, + "resourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('containerRegistryNameDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourceId.value]" + }, + "roleDefinitionId": { + "value": "[variables('containerRegistryPullRoleGuid')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "190817844660563497" + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "The name of the RoleAssignment. Can be found by running: az role assignment list --output json" + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The type of resource you wish to assign the role to. Can be found by running: az resource list --output json" + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "The GUID of the RoleDefinition you wish to assign. Can be found by running: az role definition list --output json" + } + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "defaultValue": "ServicePrincipal", + "allowedValues": [ + "ServicePrincipal", + "Device", + "ForeignGroup", + "Group", + "User" + ], + "metadata": { + "description": "Optional, default ServicePrincipal" + } + }, + "roledescription": { + "type": "string", + "defaultValue": "" + } + }, + "variables": { + "$fxv#0": "{\r\n \"$schema\": \"https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"scope\": {\r\n \"type\": \"string\"\r\n },\r\n \"name\": {\r\n \"type\": \"string\"\r\n },\r\n \"roleDefinitionId\": {\r\n \"type\": \"string\"\r\n },\r\n \"principalId\": {\r\n \"type\": \"string\"\r\n },\r\n \"principalType\": {\r\n \"type\": \"string\"\r\n }\r\n },\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.Authorization/roleAssignments\",\r\n \"apiVersion\": \"2020-08-01-preview\",\r\n \"scope\": \"[parameters('scope')]\",\r\n \"name\": \"[parameters('name')]\",\r\n \"properties\": {\r\n \"roleDefinitionId\": \"[resourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))]\",\r\n \"principalId\": \"[parameters('principalId')]\",\r\n \"principalType\": \"[parameters('principalType')]\"\r\n }\r\n }\r\n ],\r\n \"outputs\": {\r\n \"roleAssignmentId\": {\r\n \"type\": \"string\",\r\n \"value\": \"[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]\"\r\n }\r\n }\r\n}" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2021-04-01", + "name": "[parameters('name')]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[json(variables('$fxv#0'))]", + "parameters": { + "scope": { + "value": "[parameters('resourceId')]" + }, + "name": { + "value": "[guid(parameters('principalId'), parameters('roleDefinitionId'), parameters('resourceId'))]" + }, + "roleDefinitionId": { + "value": "[parameters('roleDefinitionId')]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "principalType": { + "value": "[parameters('principalType')]" + } + } + } + } + ], + "outputs": { + "resourceid": { + "type": "string", + "value": "[parameters('resourceId')]" + }, + "roleAssignmentId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', parameters('name')), '2021-04-01').outputs.roleAssignmentId.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('containerRegistryNameDeployment-{0}', deployment().name), 64))]", + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('containerRegistryUserAssignedIdentityName'))]" ] } ], @@ -3079,14 +4849,14 @@ "metadata": { "description": "The resource ID of the container registry." }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('containerRegistryName'))]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('containerRegistryNameDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourceId.value]" }, "containerRegistryName": { "type": "string", "metadata": { "description": "The name of the container registry." }, - "value": "[parameters('containerRegistryName')]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('containerRegistryNameDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.name.value]" }, "containerRegistryUserAssignedIdentityId": { "type": "string", @@ -3136,8 +4906,8 @@ "keyVaultPrivateEndpointName": { "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('03-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.keyVaultPep]" }, - "keyVaultUserAssignedIdentityName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('03-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.keyVaultUserAssignedIdentity]" + "diagnosticWorkspaceId": { + "value": "[parameters('logAnalyticsWorkspaceId')]" } }, "template": { @@ -3146,8 +4916,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "1667118111542117352" + "version": "0.20.4.51522", + "templateHash": "15958183020623658616" } }, "parameters": { @@ -3195,14 +4965,105 @@ "description": "The name of the private endpoint to be created for Key Vault." } }, - "keyVaultUserAssignedIdentityName": { + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + }, + "diagnosticStorageAccountId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "diagnosticWorkspaceId": { "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "diagnosticEventHubAuthorizationRuleId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "diagnosticEventHubName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "diagnosticLogCategoriesToEnable": { + "type": "array", + "defaultValue": [ + "allLogs" + ], + "allowedValues": [ + "allLogs", + "AuditEvent", + "AzurePolicyEvaluationDetails" + ], + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource." + } + }, + "diagnosticMetricsToEnable": { + "type": "array", + "defaultValue": [ + "AllMetrics" + ], + "allowedValues": [ + "AllMetrics" + ], + "metadata": { + "description": "Optional. The name of metrics that will be streamed." + } + }, + "diagnosticSettingsName": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "The name of the user assigned identity with Key Vault reader role." + "description": "Optional. The name of the diagnostic setting, if deployed. If left empty, it defaults to \"-diagnosticSettings\"." } } }, "variables": { + "copy": [ + { + "name": "diagnosticsLogsSpecified", + "count": "[length(filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs')))))]", + "input": { + "category": "[filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs'))))[copyIndex('diagnosticsLogsSpecified')]]", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + }, + { + "name": "diagnosticsMetrics", + "count": "[length(parameters('diagnosticMetricsToEnable'))]", + "input": { + "category": "[parameters('diagnosticMetricsToEnable')[copyIndex('diagnosticsMetrics')]]", + "timeGrain": null, + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + } + ], "privateDnsZoneNames": "privatelink.vaultcore.azure.net", "keyVaultResourceName": "vault", "hubVNetIdTokens": "[split(parameters('hubVNetId'), '/')]", @@ -3213,7 +5074,6 @@ "spokeSubscriptionId": "[variables('spokeVNetIdTokens')[2]]", "spokeResourceGroupName": "[variables('spokeVNetIdTokens')[4]]", "spokeVNetName": "[variables('spokeVNetIdTokens')[8]]", - "keyvaultReaderRoleGuid": "21090545-7ca7-4776-b22c-e363652d74d2", "spokeVNetLinks": [ { "vnetName": "[variables('spokeVNetName')]", @@ -3225,7 +5085,8 @@ "vnetId": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('hubSubscriptionId'), variables('hubResourceGroupName')), 'Microsoft.Network/virtualNetworks', variables('hubVNetName'))]", "registrationEnabled": false } - ] + ], + "diagnosticsLogs": "[if(contains(parameters('diagnosticLogCategoriesToEnable'), 'allLogs'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true(), 'retentionPolicy', createObject('enabled', true(), 'days', parameters('diagnosticLogsRetentionInDays')))), variables('diagnosticsLogsSpecified'))]" }, "resources": [ { @@ -3253,25 +5114,21 @@ } }, { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2018-11-30", - "name": "[parameters('keyVaultUserAssignedIdentityName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", + "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('keyVaultName'))]", - "name": "[guid(subscription().id, resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('keyVaultUserAssignedIdentityName')))]", + "name": "[if(not(empty(parameters('diagnosticSettingsName'))), parameters('diagnosticSettingsName'), format('{0}-diagnosticSettings', parameters('keyVaultName')))]", "properties": { - "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('keyVaultUserAssignedIdentityName')), '2018-11-30').principalId]", - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('keyvaultReaderRoleGuid'))]", - "principalType": "ServicePrincipal" + "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", + "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", + "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", + "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", + "metrics": "[variables('diagnosticsMetrics')]", + "logs": "[variables('diagnosticsLogs')]" }, "dependsOn": [ - "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]", - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('keyVaultUserAssignedIdentityName'))]" + "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" ] }, { @@ -3304,6 +5161,9 @@ }, "subnetId": { "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('spokeSubscriptionId'), variables('spokeResourceGroupName')), 'Microsoft.Network/virtualNetworks/subnets', variables('spokeVNetName'), parameters('spokePrivateEndpointSubnetName'))]" + }, + "vnetHubResourceId": { + "value": "[parameters('hubVNetId')]" } }, "template": { @@ -3312,8 +5172,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "15478438910397268748" + "version": "0.20.4.51522", + "templateHash": "1892554050389365289" } }, "parameters": { @@ -3324,6 +5184,12 @@ "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain vnetName, vnetId, registrationEnabled" } }, + "vnetHubResourceId": { + "type": "string", + "metadata": { + "description": "if empty, private dns zone will be deployed in the current RG scope" + } + }, "subnetId": { "type": "string", "metadata": { @@ -3362,11 +5228,16 @@ } } }, + "variables": { + "vnetHubSplitTokens": "[if(not(empty(parameters('vnetHubResourceId'))), split(parameters('vnetHubResourceId'), '/'), array(''))]" + }, "resources": [ { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName')))]", + "subscriptionId": "[variables('vnetHubSplitTokens')[2]]", + "resourceGroup": "[variables('vnetHubSplitTokens')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -3386,8 +5257,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "8461334250568869203" + "version": "0.20.4.51522", + "templateHash": "16481873424741287744" } }, "parameters": { @@ -3493,7 +5364,7 @@ "value": "[parameters('location')]" }, "privateDnsZonesId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName')))), '2022-09-01').outputs.privateDnsZonesId.value]" + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('vnetHubSplitTokens')[2], variables('vnetHubSplitTokens')[4]), 'Microsoft.Resources/deployments', format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName')))), '2022-09-01').outputs.privateDnsZonesId.value]" }, "privateLinkServiceId": { "value": "[parameters('azServiceId')]" @@ -3511,15 +5382,15 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "17714688339806767068" + "version": "0.20.4.51522", + "templateHash": "9790261476800825323" } }, "parameters": { "name": { "type": "string", - "maxLength": 64, "minLength": 2, + "maxLength": 64, "metadata": { "description": "Required. Name of your Private Endpoint. Must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens." } @@ -3608,7 +5479,7 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName'))))]" + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('vnetHubSplitTokens')[2], variables('vnetHubSplitTokens')[4]), 'Microsoft.Resources/deployments', format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName'))))]" ] } ] @@ -3633,13 +5504,6 @@ "description": "The name of the key vault." }, "value": "[parameters('keyVaultName')]" - }, - "keyVaultUserAssignedIdentityId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user assigned managed identity to access the key vault." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('keyVaultUserAssignedIdentityName'))]" } } } @@ -3651,161 +5515,6 @@ "description": "Azure Key Vault used to hold items like TLS certs and application secrets that your workload will need." } }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('logAnalyticsWs-{0}', uniqueString(resourceGroup().id)), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "name": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('03-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.logAnalyticsWorkspace]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "3888572269456304541" - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 63, - "minLength": 4, - "metadata": { - "description": "Required. Name of the Log Analytics Workspace Service. It must be between 4 and 63 characters and can contain only letters, numbers and \"-\". The \"-\" should not be the first or the last symbol" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Azure region where the resources will be deployed in" - } - }, - "tags": { - "type": "object", - "defaultValue": {} - }, - "serviceTier": { - "type": "string", - "defaultValue": "PerGB2018", - "allowedValues": [ - "Free", - "Standalone", - "PerNode", - "PerGB2018" - ], - "metadata": { - "description": "Optional. Service Tier: PerGB2018, Free, Standalone, PerGB or PerNode." - } - }, - "dataRetention": { - "type": "int", - "defaultValue": 90, - "maxValue": 730, - "minValue": 0, - "metadata": { - "description": "Optional, default 90. Number of days data will be retained for." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics ingestion." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics query." - } - }, - "useResourcePermissions": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Set to 'true' to use resource or workspace permissions and 'false' (or leave empty) to require workspace permissions." - } - } - }, - "variables": { - "lawsMaxLength": 63, - "lawsNameSantized": "[replace(replace(parameters('name'), '_', '-'), '.', '-')]", - "lawsName": "[if(greater(length(variables('lawsNameSantized')), variables('lawsMaxLength')), substring(variables('lawsNameSantized'), 0, variables('lawsMaxLength')), variables('lawsNameSantized'))]" - }, - "resources": [ - { - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2022-10-01", - "name": "[variables('lawsName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "retentionInDays": "[parameters('dataRetention')]", - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "sku": { - "name": "[parameters('serviceTier')]" - }, - "features": { - "enableLogAccessUsingOnlyResourcePermissions": "[parameters('useResourcePermissions')]" - } - } - } - ], - "outputs": { - "logAnalyticsWsName": { - "type": "string", - "metadata": { - "description": "The name of the resource." - }, - "value": "[variables('lawsName')]" - }, - "logAnalyticsWsId": { - "type": "string", - "metadata": { - "description": "The resource ID of the resource." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces', variables('lawsName'))]" - }, - "customerId": { - "type": "string", - "metadata": { - "description": "The customer id of the log analytics workspace." - }, - "value": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', variables('lawsName')), '2022-10-01').customerId]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('03-sharedNamingDeployment-{0}', deployment().name), 64))]" - ], - "metadata": { - "description": "The log sink for Azure Diagnostics" - } - }, { "condition": "[parameters('deployRedisCache')]", "type": "Microsoft.Resources/deployments", @@ -3824,7 +5533,7 @@ "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('03-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.redisCache]" }, "logAnalyticsWsId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('logAnalyticsWs-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.logAnalyticsWsId.value]" + "value": "[parameters('logAnalyticsWorkspaceId')]" }, "keyVaultName": { "value": "[reference(resourceId('Microsoft.Resources/deployments', format('keyVault-{0}', uniqueString(resourceGroup().id))), '2022-09-01').outputs.keyVaultName.value]" @@ -3848,8 +5557,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "604222685683593390" + "version": "0.20.4.51522", + "templateHash": "16754067833539512780" } }, "parameters": { @@ -3976,8 +5685,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "9375885309875252836" + "version": "0.20.4.51522", + "templateHash": "4084240094989273702" } }, "parameters": { @@ -4026,33 +5735,30 @@ "replicasPerMaster": { "type": "int", "defaultValue": 1, + "minValue": 1, "metadata": { "description": "Optional. The number of replicas to be created per primary." - }, - "minValue": 1 + } }, "replicasPerPrimary": { "type": "int", "defaultValue": 1, + "minValue": 1, "metadata": { "description": "Optional. The number of replicas to be created per primary." - }, - "minValue": 1 + } }, "shardCount": { "type": "int", "defaultValue": 1, + "minValue": 1, "metadata": { "description": "Optional. The number of shards to be created on a Premium Cluster Cache." - }, - "minValue": 1 + } }, "capacity": { "type": "int", "defaultValue": 2, - "metadata": { - "description": "Optional. The size of the Redis cache to deploy. Valid values: for C (Basic/Standard) family (0, 1, 2, 3, 4, 5, 6), for P (Premium) family (1, 2, 3, 4)." - }, "allowedValues": [ 0, 1, @@ -4061,19 +5767,22 @@ 4, 5, 6 - ] + ], + "metadata": { + "description": "Optional. The size of the Redis cache to deploy. Valid values: for C (Basic/Standard) family (0, 1, 2, 3, 4, 5, 6), for P (Premium) family (1, 2, 3, 4)." + } }, "skuName": { "type": "string", "defaultValue": "Standard", - "metadata": { - "description": "Optional, default is Standard. The type of Redis cache to deploy." - }, "allowedValues": [ "Basic", "Premium", "Standard" - ] + ], + "metadata": { + "description": "Optional, default is Standard. The type of Redis cache to deploy." + } }, "subnetId": { "type": "string", @@ -4092,8 +5801,8 @@ "diagnosticLogsRetentionInDays": { "type": "int", "defaultValue": 365, - "maxValue": 365, "minValue": 0, + "maxValue": 365, "metadata": { "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." } @@ -4317,6 +6026,9 @@ }, "subnetId": { "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('spokeSubscriptionId'), variables('spokeResourceGroupName')), 'Microsoft.Network/virtualNetworks/subnets', variables('spokeVNetName'), parameters('spokePrivateEndpointSubnetName'))]" + }, + "vnetHubResourceId": { + "value": "[parameters('hubVNetId')]" } }, "template": { @@ -4325,8 +6037,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "15478438910397268748" + "version": "0.20.4.51522", + "templateHash": "1892554050389365289" } }, "parameters": { @@ -4337,6 +6049,12 @@ "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain vnetName, vnetId, registrationEnabled" } }, + "vnetHubResourceId": { + "type": "string", + "metadata": { + "description": "if empty, private dns zone will be deployed in the current RG scope" + } + }, "subnetId": { "type": "string", "metadata": { @@ -4375,11 +6093,16 @@ } } }, + "variables": { + "vnetHubSplitTokens": "[if(not(empty(parameters('vnetHubResourceId'))), split(parameters('vnetHubResourceId'), '/'), array(''))]" + }, "resources": [ { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName')))]", + "subscriptionId": "[variables('vnetHubSplitTokens')[2]]", + "resourceGroup": "[variables('vnetHubSplitTokens')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -4399,8 +6122,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "8461334250568869203" + "version": "0.20.4.51522", + "templateHash": "16481873424741287744" } }, "parameters": { @@ -4506,7 +6229,7 @@ "value": "[parameters('location')]" }, "privateDnsZonesId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName')))), '2022-09-01').outputs.privateDnsZonesId.value]" + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('vnetHubSplitTokens')[2], variables('vnetHubSplitTokens')[4]), 'Microsoft.Resources/deployments', format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName')))), '2022-09-01').outputs.privateDnsZonesId.value]" }, "privateLinkServiceId": { "value": "[parameters('azServiceId')]" @@ -4524,15 +6247,15 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "17714688339806767068" + "version": "0.20.4.51522", + "templateHash": "9790261476800825323" } }, "parameters": { "name": { "type": "string", - "maxLength": 64, "minLength": 2, + "maxLength": 64, "metadata": { "description": "Required. Name of your Private Endpoint. Must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens." } @@ -4621,7 +6344,7 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName'))))]" + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('vnetHubSplitTokens')[2], variables('vnetHubSplitTokens')[4]), 'Microsoft.Resources/deployments', format('privateDnsZoneDeployment-{0}', uniqueString(parameters('azServiceId'), parameters('privateEndpointSubResourceName'))))]" ] } ] @@ -4645,7 +6368,6 @@ }, "dependsOn": [ "[resourceId('Microsoft.Resources/deployments', format('keyVault-{0}', uniqueString(resourceGroup().id)))]", - "[resourceId('Microsoft.Resources/deployments', take(format('logAnalyticsWs-{0}', uniqueString(resourceGroup().id)), 64))]", "[resourceId('Microsoft.Resources/deployments', take(format('03-sharedNamingDeployment-{0}', deployment().name), 64))]" ] } @@ -4686,20 +6408,6 @@ }, "value": "[reference(resourceId('Microsoft.Resources/deployments', format('keyVault-{0}', uniqueString(resourceGroup().id))), '2022-09-01').outputs.keyVaultName.value]" }, - "keyVaultUserAssignedIdentityId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user-assigned managed identity to read from Azure Key Vault." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('keyVault-{0}', uniqueString(resourceGroup().id))), '2022-09-01').outputs.keyVaultUserAssignedIdentityId.value]" - }, - "logAnalyticsWorkspaceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Azure Log Analytics Workspace." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('logAnalyticsWs-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.logAnalyticsWsId.value]" - }, "redisCacheSecretKey": { "type": "string", "metadata": { @@ -4758,7 +6466,7 @@ "value": "[parameters('enableTelemetry')]" }, "logAnalyticsWorkspaceId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('supportingServices-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.logAnalyticsWorkspaceId.value]" + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.logAnalyticsWorkspaceId.value]" } }, "template": { @@ -4767,15 +6475,15 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "18441024042217970394" + "version": "0.20.4.51522", + "templateHash": "10870903567140957099" } }, "parameters": { "workloadName": { "type": "string", - "maxLength": 10, "minLength": 2, + "maxLength": 10, "metadata": { "description": "The name of the workload that is being deployed. Up to 10 characters long." } @@ -4835,62 +6543,396 @@ "type": "bool", "defaultValue": true, "metadata": { - "description": "Enable sending usage and telemetry feedback to Microsoft." + "description": "Enable sending usage and telemetry feedback to Microsoft." + } + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "The resource id of an existing Azure Log Analytics Workspace." + } + }, + "deployZoneRedundantResources": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional, default value is true. If true, any resources that support AZ will be deployed in all three AZ. However if the selected region is not supporting AZ, this parameter needs to be set to false." + } + } + }, + "variables": { + "hubVNetResourceIdTokens": "[if(not(empty(parameters('hubVNetId'))), split(parameters('hubVNetId'), '/'), array(''))]", + "hubSubscriptionId": "[variables('hubVNetResourceIdTokens')[2]]", + "hubResourceGroupName": "[variables('hubVNetResourceIdTokens')[4]]", + "hubVNetName": "[variables('hubVNetResourceIdTokens')[8]]", + "telemetryId": "[format('9b4433d6-924a-4c07-b47c-7478619759c7-{0}-acasb', parameters('location'))]" + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2021-04-01", + "name": "[variables('telemetryId')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "resources": {} + } + }, + "metadata": { + "description": "Microsoft telemetry deployment." + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('04-sharedNamingDeployment-{0}', deployment().name), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "uniqueId": { + "value": "[uniqueString(resourceGroup().id)]" + }, + "environment": { + "value": "[parameters('environment')]" + }, + "workloadName": { + "value": "[parameters('workloadName')]" + }, + "location": { + "value": "[parameters('location')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "6817832201461302860" + } + }, + "parameters": { + "workloadName": { + "type": "string", + "minLength": 2, + "maxLength": 10, + "metadata": { + "description": "The name of the workloard that is being deployed. Up to 10 characters long." + } + }, + "environment": { + "type": "string", + "maxLength": 8, + "metadata": { + "description": "The name of the environment (e.g. \"dev\", \"test\", \"prod\", \"uat\", \"dr\", \"qa\") Up to 8 characters long." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location for all Resources." + } + }, + "uniqueId": { + "type": "string", + "metadata": { + "description": "a unique ID that can be appended (or prepended) in azure resource names that require some kind of uniqueness" + } + } + }, + "variables": { + "$fxv#0": "{\r\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\r\n \"resourceTypeAbbreviations\" : {\r\n \"applicationGateway\": \"agw\",\r\n \"applicationInsights\": \"appi\",\r\n \"appService\": \"app\",\r\n \"bastion\": \"bas\",\r\n \"containerAppsEnvironment\": \"cae\",\r\n \"containerRegistry\": \"cr\",\r\n \"cosmosDbNoSql\": \"cosno\",\r\n \"frontDoor\": \"afd\",\r\n \"frontDoorEndpoint\": \"fde\",\r\n \"frontDoorWaf\": \"fdfp\",\r\n \"keyVault\": \"kv\",\r\n \"logAnalyticsWorkspace\": \"log\",\r\n \"managedIdentity\": \"id\",\r\n \"networkInterface\": \"nic\",\r\n \"networkSecurityGroup\": \"nsg\",\r\n \"privateEndpoint\": \"pep\",\r\n \"privateLinkService\": \"pls\",\r\n \"publicIpAddress\": \"pip\",\r\n \"resourceGroup\": \"rg\",\r\n \"serviceBus\": \"sb\",\r\n \"serviceBusQueue\": \"sbq\",\r\n \"serviceBusTopic\": \"sbt\",\r\n \"storageAccount\": \"st\",\r\n \"virtualMachine\": \"vm\",\r\n \"virtualNetwork\": \"vnet\",\r\n \"redisCache\": \"redis\"\r\n },\r\n\r\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\r\n \"regionAbbreviations\" : {\r\n \"australiacentral\": \"auc\",\r\n \"australiacentral2\": \"auc2\",\r\n \"australiaeast\": \"aue\",\r\n \"australiasoutheast\": \"ause\",\r\n \"brazilsouth\": \"brs\",\r\n \"brazilsoutheast\": \"brse\",\r\n \"canadacentral\": \"canc\",\r\n \"canadaeast\": \"cane\",\r\n \"centralindia\": \"cin\",\r\n \"centralus\": \"cus\",\r\n \"centraluseuap\": \"cuseuap\",\r\n \"eastasia\": \"ea\",\r\n \"eastus\": \"eus\",\r\n \"eastus2\": \"eus2\",\r\n \"eastus2euap\": \"eus2euap\",\r\n \"francecentral\": \"frc\",\r\n \"francesouth\": \"frs\",\r\n \"germanynorth\": \"gern\",\r\n \"germanywestcentral\": \"gerwc\",\r\n \"japaneast\": \"jae\",\r\n \"japanwest\": \"jaw\",\r\n \"jioindiacentral\": \"jioinc\",\r\n \"jioindiawest\": \"jioinw\",\r\n \"koreacentral\": \"koc\",\r\n \"koreasouth\": \"kors\",\r\n \"northcentralus\": \"ncus\",\r\n \"northeurope\": \"neu\",\r\n \"norwayeast\": \"nore\",\r\n \"norwaywest\": \"norw\",\r\n \"southafricanorth\": \"san\",\r\n \"southafricawest\": \"saw\",\r\n \"southcentralus\": \"scus\",\r\n \"southeastasia\": \"sea\",\r\n \"southindia\": \"sin\",\r\n \"swedencentral\": \"swc\",\r\n \"switzerlandnorth\": \"swn\",\r\n \"switzerlandwest\": \"sww\",\r\n \"uaecentral\": \"uaec\",\r\n \"uaenorth\": \"uaen\",\r\n \"uksouth\": \"uks\",\r\n \"ukwest\": \"ukw\",\r\n \"westcentralus\": \"wcus\",\r\n \"westeurope\": \"weu\",\r\n \"westindia\": \"win\",\r\n \"westus\": \"wus\",\r\n \"westus2\": \"wus2\",\r\n \"westus3\": \"wus3\"\r\n }\r\n}", + "naming": "[json(variables('$fxv#0'))]", + "uniqueIdShort": "[substring(parameters('uniqueId'), 0, 5)]", + "resourceTypeToken": "RES_TYPE", + "namingBase": "[format('{0}-{1}-{2}-{3}', variables('resourceTypeToken'), parameters('workloadName'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", + "namingBaseUnique": "[format('{0}-{1}-{2}-{3}-{4}', variables('resourceTypeToken'), parameters('workloadName'), variables('uniqueIdShort'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", + "namingBaseNoWorkloadName": "[format('{0}-{1}-{2}', variables('resourceTypeToken'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", + "resourceTypeAbbreviations": "[variables('naming').resourceTypeAbbreviations]", + "keyVaultName": "[take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault), 24)]", + "resourceNames": { + "vnetSpoke": "[format('{0}-spoke', replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualNetwork))]", + "vnetHub": "[format('{0}-hub', replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualNetwork))]", + "applicationGateway": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway)]", + "applicationGatewayPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", + "applicationGatewayUserAssignedIdentity": "[format('{0}-{1}-KeyVaultSecretUser', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", + "applicationGatewayNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", + "pepNsg": "[format('{0}-pep', variables('naming').resourceTypeAbbreviations.networkSecurityGroup)]", + "applicationInsights": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationInsights)]", + "bastion": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion)]", + "bastionNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", + "bastionPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", + "containerAppsEnvironment": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerAppsEnvironment)]", + "containerAppsEnvironmentNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerAppsEnvironment))]", + "containerRegistry": "[take(toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')), 50)]", + "containerRegistryPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')))]", + "containerRegistryUserAssignedIdentity": "[format('{0}-{1}-AcrPull', variables('naming').resourceTypeAbbreviations.managedIdentity, toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')))]", + "redisCache": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.redisCache)]", + "redisCachePep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.redisCache))]", + "cosmosDbNoSql": "[toLower(take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.cosmosDbNoSql), 44))]", + "cosmosDbNoSqlPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.cosmosDbNoSql), 44)))]", + "frontDoorProfile": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]", + "keyVault": "[if(endsWith(variables('keyVaultName'), '-'), take(variables('keyVaultName'), 23), variables('keyVaultName'))]", + "keyVaultPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", + "logAnalyticsWorkspace": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.logAnalyticsWorkspace)]", + "serviceBus": "[replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus)]", + "serviceBusPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus))]", + "storageAccount": "[toLower(take(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.storageAccount), '-', ''), 24))]", + "storageAccountPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.storageAccount)))]", + "vmJumpBox": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine)]", + "vmJumpBoxNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine))]", + "vmJumpBoxNic": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkInterface, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine))]", + "frontDoor": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]" + } + }, + "resources": [], + "outputs": { + "resourcesNames": { + "type": "object", + "value": "[variables('resourceNames')]" + }, + "resourceTypeAbbreviations": { + "type": "object", + "value": "[variables('resourceTypeAbbreviations')]" + } + } + } + }, + "metadata": { + "description": "User-configured naming rules" } }, - "logAnalyticsWorkspaceId": { - "type": "string", - "metadata": { - "description": "The resource id of an existing Azure Log Analytics Workspace." - } - } - }, - "variables": { - "hubVNetResourceIdTokens": "[if(not(empty(parameters('hubVNetId'))), split(parameters('hubVNetId'), '/'), array(''))]", - "hubSubscriptionId": "[variables('hubVNetResourceIdTokens')[2]]", - "hubResourceGroupName": "[variables('hubVNetResourceIdTokens')[4]]", - "hubVNetName": "[variables('hubVNetResourceIdTokens')[8]]", - "telemetryId": "[format('9b4433d6-924a-4c07-b47c-7478619759c7-{0}-acasb', parameters('location'))]" - }, - "resources": [ { - "condition": "[parameters('enableTelemetry')]", + "condition": "[parameters('enableApplicationInsights')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2021-04-01", - "name": "[variables('telemetryId')]", + "apiVersion": "2022-09-01", + "name": "[take(format('applicationInsights-{0}', uniqueString(resourceGroup().id)), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('04-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationInsights]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "workspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceId')]" + } + }, "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", - "resources": {} + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "793513277786522105" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Insights." + } + }, + "appInsightsType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the log analytics workspace which the data will be ingested to. If left empty, applicationInsights will create one for us. This property is required to create an application with this API version. Applications from older versions will not have this property." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 90, + "allowedValues": [ + 30, + 60, + 90, + 120, + 180, + 270, + 365, + 550, + 730 + ], + "metadata": { + "description": "Optional. Retention period in days." + } + }, + "samplingPercentage": { + "type": "int", + "defaultValue": 100, + "minValue": 0, + "maxValue": 100, + "metadata": { + "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." + } + }, + "kind": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "properties": { + "Application_Type": "[parameters('appInsightsType')]", + "Request_Source": "rest", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "SamplingPercentage": "[parameters('samplingPercentage')]" + } + } + ], + "outputs": { + "appInsNname": { + "type": "string", + "metadata": { + "description": "The name of the application insights component." + }, + "value": "[parameters('name')]" + }, + "appInsResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights component." + }, + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" + }, + "appInsInstrumentationKey": { + "type": "string", + "metadata": { + "description": "The applicationInsights Instrumentation Key." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').InstrumentationKey]" + }, + "appInsConnectionString": { + "type": "string", + "metadata": { + "description": "The applicationInsights Connection String." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').ConnectionString]" + }, + "applicationId": { + "type": "string", + "metadata": { + "description": "The application ID of the application insights component." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').AppId]" + } + } } }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('04-sharedNamingDeployment-{0}', deployment().name), 64))]" + ], "metadata": { - "description": "Microsoft telemetry deployment." + "description": "Azure Application Insights, the workload' log & metric sink and APM tool" } }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('04-sharedNamingDeployment-{0}', deployment().name), 64)]", + "name": "[take(format('containerAppsEnvironment-{0}', uniqueString(resourceGroup().id)), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "uniqueId": { - "value": "[uniqueString(resourceGroup().id)]" - }, - "environment": { - "value": "[parameters('environment')]" - }, - "workloadName": { - "value": "[parameters('workloadName')]" + "name": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('04-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.containerAppsEnvironment]" }, "location": { "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "logAnalyticsWsResourceId": { + "value": "[parameters('logAnalyticsWorkspaceId')]" + }, + "subnetId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('spokeVNetName'), parameters('spokeInfraSubnetName'))]" + }, + "vnetEndpointInternal": { + "value": true + }, + "appInsightsInstrumentationKey": "[if(and(parameters('enableApplicationInsights'), parameters('enableDaprInstrumentation')), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('applicationInsights-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.appInsInstrumentationKey.value), createObject('value', ''))]", + "zoneRedundant": { + "value": "[parameters('deployZoneRedundantResources')]" } }, "template": { @@ -4899,106 +6941,150 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "14985913302549051532" + "version": "0.20.4.51522", + "templateHash": "209759171996106955" } }, "parameters": { - "workloadName": { + "name": { "type": "string", "metadata": { - "description": "The name of the workloard that is being deployed. Up to 10 characters long." - }, - "maxLength": 10, - "minLength": 2 + "description": "Required. Name of your Azure Container Apps Environment. " + } }, - "environment": { + "location": { "type": "string", - "maxLength": 8, "metadata": { - "description": "The name of the environment (e.g. \"dev\", \"test\", \"prod\", \"uat\", \"dr\", \"qa\") Up to 8 characters long." + "description": "Location for all resources." } }, - "location": { + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional, default value is false. Sets if the environment will use availability zones. Your Container App Environment and the apps in it will be zone redundant. This requieres vNet integration." + } + }, + "sku": { "type": "string", + "defaultValue": "Consumption", + "allowedValues": [ + "Consumption", + "Premium" + ], "metadata": { - "description": "Location for all Resources." + "description": "Mandatory, default is Consumption" } }, - "uniqueId": { + "vnetEndpointInternal": { + "type": "bool", + "metadata": { + "description": "If true, the endpoint is an internal load balancer. If false the hosted apps are exposed on an internet-accessible IP address " + } + }, + "subnetId": { "type": "string", "metadata": { - "description": "a unique ID that can be appended (or prepended) in azure resource names that require some kind of uniqueness" + "description": "Custome vnet configuration for the nevironment. NOTE: Current GA (Feb 2023): The subnet associated with a Container App Environment requires a CIDR prefix of /23 or larger" + } + }, + "logAnalyticsWsResourceId": { + "type": "string", + "metadata": { + "description": "mandatory for log-analytics" + } + }, + "appInsightsInstrumentationKey": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "optional, default is empty. App Insights instrumentation key provided to Dapr for tracing" } } }, "variables": { - "$fxv#0": "{\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\n \"resourceTypeAbbreviations\" : {\n \"applicationGateway\": \"agw\",\n \"applicationInsights\": \"appi\",\n \"appService\": \"app\",\n \"bastion\": \"bas\",\n \"containerAppsEnvironment\": \"cae\",\n \"containerRegistry\": \"cr\",\n \"cosmosDbNoSql\": \"cosno\",\n \"frontDoor\": \"afd\",\n \"frontDoorEndpoint\": \"fde\",\n \"frontDoorWaf\": \"fdfp\",\n \"keyVault\": \"kv\",\n \"logAnalyticsWorkspace\": \"log\",\n \"managedIdentity\": \"id\",\n \"networkInterface\": \"nic\",\n \"networkSecurityGroup\": \"nsg\",\n \"privateEndpoint\": \"pep\",\n \"privateLinkService\": \"pls\",\n \"publicIpAddress\": \"pip\",\n \"resourceGroup\": \"rg\",\n \"serviceBus\": \"sb\",\n \"serviceBusQueue\": \"sbq\",\n \"serviceBusTopic\": \"sbt\",\n \"storageAccount\": \"st\",\n \"virtualMachine\": \"vm\",\n \"virtualNetwork\": \"vnet\",\n \"redisCache\": \"redis\"\n },\n\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\n \"regionAbbreviations\" : {\n \"australiacentral\": \"auc\",\n \"australiacentral2\": \"auc2\",\n \"australiaeast\": \"aue\",\n \"australiasoutheast\": \"ause\",\n \"brazilsouth\": \"brs\",\n \"brazilsoutheast\": \"brse\",\n \"canadacentral\": \"canc\",\n \"canadaeast\": \"cane\",\n \"centralindia\": \"cin\",\n \"centralus\": \"cus\",\n \"centraluseuap\": \"cuseuap\",\n \"eastasia\": \"ea\",\n \"eastus\": \"eus\",\n \"eastus2\": \"eus2\",\n \"eastus2euap\": \"eus2euap\",\n \"francecentral\": \"frc\",\n \"francesouth\": \"frs\",\n \"germanynorth\": \"gern\",\n \"germanywestcentral\": \"gerwc\",\n \"japaneast\": \"jae\",\n \"japanwest\": \"jaw\",\n \"jioindiacentral\": \"jioinc\",\n \"jioindiawest\": \"jioinw\",\n \"koreacentral\": \"koc\",\n \"koreasouth\": \"kors\",\n \"northcentralus\": \"ncus\",\n \"northeurope\": \"neu\",\n \"norwayeast\": \"nore\",\n \"norwaywest\": \"norw\",\n \"southafricanorth\": \"san\",\n \"southafricawest\": \"saw\",\n \"southcentralus\": \"scus\",\n \"southeastasia\": \"sea\",\n \"southindia\": \"sin\",\n \"swedencentral\": \"swc\",\n \"switzerlandnorth\": \"swn\",\n \"switzerlandwest\": \"sww\",\n \"uaecentral\": \"uaec\",\n \"uaenorth\": \"uaen\",\n \"uksouth\": \"uks\",\n \"ukwest\": \"ukw\",\n \"westcentralus\": \"wcus\",\n \"westeurope\": \"weu\",\n \"westindia\": \"win\",\n \"westus\": \"wus\",\n \"westus2\": \"wus2\",\n \"westus3\": \"wus3\"\n }\n}", - "naming": "[json(variables('$fxv#0'))]", - "uniqueIdShort": "[substring(parameters('uniqueId'), 0, 5)]", - "resourceTypeToken": "RES_TYPE", - "namingBase": "[format('{0}-{1}-{2}-{3}', variables('resourceTypeToken'), parameters('workloadName'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", - "namingBaseUnique": "[format('{0}-{1}-{2}-{3}-{4}', variables('resourceTypeToken'), parameters('workloadName'), variables('uniqueIdShort'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", - "namingBaseNoWorkloadName": "[format('{0}-{1}-{2}', variables('resourceTypeToken'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", - "resourceTypeAbbreviations": "[variables('naming').resourceTypeAbbreviations]", - "keyVaultName": "[take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault), 24)]", - "resourceNames": { - "vnetSpoke": "[format('{0}-spoke', replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualNetwork))]", - "vnetHub": "[format('{0}-hub', replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualNetwork))]", - "applicationGateway": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway)]", - "applicationGatewayPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", - "applicationGatewayUserAssignedIdentity": "[format('{0}-{1}-KeyVaultSecretUser', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", - "applicationGatewayNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", - "applicationInsights": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationInsights)]", - "bastion": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion)]", - "bastionNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", - "bastionPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", - "containerAppsEnvironment": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerAppsEnvironment)]", - "containerAppsEnvironmentNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerAppsEnvironment))]", - "containerRegistry": "[take(toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')), 50)]", - "containerRegistryPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')))]", - "containerRegistryUserAssignedIdentity": "[format('{0}-{1}-AcrPull', variables('naming').resourceTypeAbbreviations.managedIdentity, toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')))]", - "redisCache": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.redisCache)]", - "redisCachePep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.redisCache))]", - "cosmosDbNoSql": "[toLower(take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.cosmosDbNoSql), 44))]", - "cosmosDbNoSqlPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.cosmosDbNoSql), 44)))]", - "frontDoorProfile": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]", - "keyVault": "[if(endsWith(variables('keyVaultName'), '-'), take(variables('keyVaultName'), 23), variables('keyVaultName'))]", - "keyVaultPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", - "keyVaultUserAssignedIdentity": "[format('{0}-{1}-KeyVaultReader', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", - "logAnalyticsWorkspace": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.logAnalyticsWorkspace)]", - "serviceBus": "[replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus)]", - "serviceBusPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus))]", - "storageAccount": "[toLower(take(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.storageAccount), '-', ''), 24))]", - "storageAccountPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.storageAccount)))]", - "vmJumpBox": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine)]", - "vmJumpBoxNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine))]", - "vmJumpBoxNic": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkInterface, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine))]", - "frontDoor": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]" - } + "lawsSplitTokens": "[if(not(empty(parameters('logAnalyticsWsResourceId'))), split(parameters('logAnalyticsWsResourceId'), '/'), array(''))]" }, - "resources": [], + "resources": [ + { + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2022-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('sku')]" + }, + "tags": "[parameters('tags')]", + "properties": { + "zoneRedundant": "[parameters('zoneRedundant')]", + "daprAIInstrumentationKey": "[parameters('appInsightsInstrumentationKey')]", + "vnetConfiguration": { + "internal": "[parameters('vnetEndpointInternal')]", + "infrastructureSubnetId": "[parameters('subnetId')]" + }, + "appLogsConfiguration": { + "destination": "log-analytics", + "logAnalyticsConfiguration": { + "customerId": "[if(not(empty(parameters('logAnalyticsWsResourceId'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('lawsSplitTokens')[2], variables('lawsSplitTokens')[4]), 'Microsoft.OperationalInsights/workspaces', variables('lawsSplitTokens')[8]), '2022-10-01').customerId, null())]", + "sharedKey": "[if(not(empty(parameters('logAnalyticsWsResourceId'))), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('lawsSplitTokens')[2], variables('lawsSplitTokens')[4]), 'Microsoft.OperationalInsights/workspaces', variables('lawsSplitTokens')[8]), '2022-10-01').primarySharedKey, null())]" + } + } + } + } + ], "outputs": { - "resourcesNames": { - "type": "object", - "value": "[variables('resourceNames')]" + "containerAppsEnvironmentName": { + "type": "string", + "metadata": { + "description": "The Name of the Azure container app environment." + }, + "value": "[parameters('name')]" }, - "resourceTypeAbbreviations": { - "type": "object", - "value": "[variables('resourceTypeAbbreviations')]" + "containerAppsEnvironmentNameId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure container app environment." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" + }, + "containerAppsEnvironmentDefaultDomain": { + "type": "string", + "metadata": { + "description": "The default domain of the Azure container app environment." + }, + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2022-10-01').defaultDomain]" + }, + "containerAppsEnvironmentLoadBalancerIP": { + "type": "string", + "metadata": { + "description": "The Azure container app environment's Load Balancer IP." + }, + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2022-10-01').staticIp]" } } } }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('applicationInsights-{0}', uniqueString(resourceGroup().id)), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('04-sharedNamingDeployment-{0}', deployment().name), 64))]" + ], "metadata": { - "description": "User-configured naming rules" + "description": "The Azure Container Apps (ACA) cluster." } }, { - "condition": "[parameters('enableApplicationInsights')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('applicationInsights-{0}', uniqueString(resourceGroup().id)), 64)]", + "name": "[format('containerAppsEnvironmentPrivateDnsZone-{0}', uniqueString(resourceGroup().id))]", + "subscriptionId": "[variables('hubSubscriptionId')]", + "resourceGroup": "[variables('hubResourceGroupName')]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -5006,16 +7092,32 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('04-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationInsights]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.containerAppsEnvironmentDefaultDomain.value]" }, - "location": { - "value": "[parameters('location')]" + "virtualNetworkLinks": { + "value": [ + { + "vnetName": "[parameters('spokeVNetName')]", + "vnetId": "[resourceId('Microsoft.Network/virtualNetworks', parameters('spokeVNetName'))]", + "registrationEnabled": false + }, + { + "vnetName": "[variables('hubVNetName')]", + "vnetId": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('hubSubscriptionId'), variables('hubResourceGroupName')), 'Microsoft.Network/virtualNetworks', variables('hubVNetName'))]", + "registrationEnabled": false + } + ] }, "tags": { "value": "[parameters('tags')]" }, - "workspaceResourceId": { - "value": "[parameters('logAnalyticsWorkspaceId')]" + "aRecords": { + "value": [ + { + "name": "*", + "ipv4Address": "[reference(resourceId('Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.containerAppsEnvironmentLoadBalancerIP.value]" + } + ] } }, "template": { @@ -5024,198 +7126,456 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "7311810097849381847" + "version": "0.20.4.51522", + "templateHash": "16481873424741287744" } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the Application Insights." - } - }, - "appInsightsType": { - "type": "string", - "defaultValue": "web", - "allowedValues": [ - "web", - "other" - ], - "metadata": { - "description": "Optional. Application type." - } - }, - "workspaceResourceId": { - "type": "string", - "metadata": { - "description": "Resource ID of the log analytics workspace which the data will be ingested to. If left empty, applicationInsights will create one for us. This property is required to create an application with this API version. Applications from older versions will not have this property." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." + "description": "Required. Name of the Private DNS Zone Service. For az private endpoints you might find info here: https://learn.microsoft.com/azure/private-link/private-endpoint-dns#azure-services-dns-zone-configuration" } }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." + "description": "Optional. Tags of the resource." } }, - "retentionInDays": { - "type": "int", - "defaultValue": 90, - "allowedValues": [ - 30, - 60, - 90, - 120, - 180, - 270, - 365, - 550, - 730 - ], + "virtualNetworkLinks": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. Retention period in days." + "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain vnetName, vnetId, registrationEnabled" } }, - "samplingPercentage": { - "type": "int", - "defaultValue": 100, - "maxValue": 100, - "minValue": 0, + "aRecords": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." + "description": "Optional. Array of A records to be added to the DNS Zone" } + } + }, + "resources": [ + { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('name')]", + "location": "global", + "tags": "[parameters('tags')]" }, - "kind": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." - } + { + "copy": { + "name": "privateDnsZoneLink", + "count": "[length(parameters('virtualNetworkLinks'))]" + }, + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2018-09-01", + "name": "[format('{0}/{1}', parameters('name'), format('{0}-link', parameters('virtualNetworkLinks')[copyIndex()].vnetName))]", + "location": "global", + "properties": { + "registrationEnabled": "[parameters('virtualNetworkLinks')[copyIndex()].registrationEnabled]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkLinks')[copyIndex()].vnetId]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + ] }, - "location": { + { + "copy": { + "name": "dnsARecord", + "count": "[length(parameters('aRecords'))]" + }, + "type": "Microsoft.Network/privateDnsZones/A", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('name'), parameters('aRecords')[copyIndex()].name)]", + "properties": { + "ttl": 60, + "aRecords": [ + { + "ipv4Address": "[parameters('aRecords')[copyIndex()].ipv4Address]" + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + ] + } + ], + "outputs": { + "privateDnsZonesId": { "type": "string", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags of the resource." - } + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}', uniqueString(resourceGroup().id)), 64))]" + ], + "metadata": { + "description": "The Private DNS zone containing the ACA load balancer IP" + } + } + ], + "outputs": { + "containerAppsEnvironmentId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container Apps environment." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.containerAppsEnvironmentNameId.value]" + }, + "containerAppsEnvironmentName": { + "type": "string", + "metadata": { + "description": "The name of the Container Apps environment." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.containerAppsEnvironmentName.value]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/deployments', take(format('hub-{0}-deployment', deployment().name), 64))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64))]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]" + ] + }, + { + "condition": "[parameters('deployHelloWorldSample')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('helloWorlSampleApp-{0}-deployment', deployment().name), 64)]", + "resourceGroup": "[variables('rgSpokeName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "containerRegistryUserAssignedIdentityId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('supportingServices-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.containerRegistryUserAssignedIdentityId.value]" + }, + "containerAppsEnvironmentId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.containerAppsEnvironmentId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "10333070679786055066" + } + }, + "parameters": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The location where the resources will be created. This needs to be the same region as the Azure Container Apps instances." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The tags to be assigned to the created resources." + } + }, + "helloWorldContainerAppName": { + "type": "string", + "defaultValue": "ca-simple-hello", + "minLength": 2, + "maxLength": 32, + "metadata": { + "description": "Optional. The name of the Container App. If set, it overrides the name generated by the template." + } + }, + "containerRegistryUserAssignedIdentityId": { + "type": "string", + "metadata": { + "description": "The resource ID of the existing user-assigned managed identity to be assigned to the Container App to be able to pull images from the container registry." + } + }, + "containerAppsEnvironmentId": { + "type": "string", + "metadata": { + "description": "The resource ID of the existing Container Apps environment in which the Container App will be deployed." + } + } + }, + "resources": [ + { + "type": "Microsoft.App/containerApps", + "apiVersion": "2022-10-01", + "name": "[parameters('helloWorldContainerAppName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', parameters('containerRegistryUserAssignedIdentityId'))]": {} + } + }, + "properties": { + "configuration": { + "activeRevisionsMode": "single", + "ingress": { + "allowInsecure": false, + "external": true, + "targetPort": 80, + "transport": "auto" }, - "resources": [ + "registries": [], + "secrets": [] + }, + "environmentId": "[parameters('containerAppsEnvironmentId')]", + "template": { + "containers": [ { - "type": "Microsoft.Insights/components", - "apiVersion": "2020-02-02", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "properties": { - "Application_Type": "[parameters('appInsightsType')]", - "Request_Source": "rest", - "WorkspaceResourceId": "[parameters('workspaceResourceId')]", - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "RetentionInDays": "[parameters('retentionInDays')]", - "SamplingPercentage": "[parameters('samplingPercentage')]" + "name": "simple-hello", + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", + "resources": { + "cpu": "[json('0.25')]", + "memory": "0.5Gi" } } ], - "outputs": { - "appInsNname": { - "type": "string", - "metadata": { - "description": "The name of the application insights component." - }, - "value": "[parameters('name')]" - }, - "appInsResourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the application insights component." - }, - "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" - }, - "appInsInstrumentationKey": { - "type": "string", - "metadata": { - "description": "The applicationInsights Instrumentation Key." - }, - "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').InstrumentationKey]" - }, - "appInsConnectionString": { - "type": "string", - "metadata": { - "description": "The applicationInsights Connection String." - }, - "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').ConnectionString]" - }, - "applicationId": { - "type": "string", - "metadata": { - "description": "The application ID of the application insights component." - }, - "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').AppId]" - } - } + "scale": { + "minReplicas": 1, + "maxReplicas": 10 + }, + "volumes": [] } }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('04-sharedNamingDeployment-{0}', deployment().name), 64))]" + "metadata": { + "description": "The \"Hello World\" Container App." + } + } + ], + "outputs": { + "helloWorldAppFqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the \"Hello World\" Container App." + }, + "value": "[reference(resourceId('Microsoft.App/containerApps', parameters('helloWorldContainerAppName')), '2022-10-01').configuration.ingress.fqdn]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}-deployment', deployment().name), 64))]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('supportingServices-{0}-deployment', deployment().name), 64))]" + ] + }, + { + "condition": "[parameters('deployHelloWorldSample')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('applicationGateway-{0}-deployment', deployment().name), 64)]", + "resourceGroup": "[variables('rgSpokeName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "environment": { + "value": "[parameters('environment')]" + }, + "workloadName": { + "value": "[parameters('workloadName')]" + }, + "applicationGatewayCertificateKeyName": { + "value": "[parameters('applicationGatewayCertificateKeyName')]" + }, + "applicationGatewayFqdn": { + "value": "[parameters('applicationGatewayFqdn')]" + }, + "applicationGatewayPrimaryBackendEndFqdn": "[if(parameters('deployHelloWorldSample'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('helloWorlSampleApp-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.helloWorldAppFqdn.value), createObject('value', ''))]", + "applicationGatewaySubnetId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.spokeApplicationGatewaySubnetId.value]" + }, + "enableApplicationGatewayCertificate": { + "value": "[parameters('enableApplicationGatewayCertificate')]" + }, + "keyVaultId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('supportingServices-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.keyVaultId.value]" + }, + "deployZoneRedundantResources": { + "value": "[parameters('deployZoneRedundantResources')]" + }, + "ddosProtectionMode": { + "value": "[parameters('ddosProtectionMode')]" + }, + "applicationGatewayLogAnalyticsId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.logAnalyticsWorkspaceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "16209531774533964108" + } + }, + "parameters": { + "workloadName": { + "type": "string", + "minLength": 2, + "maxLength": 10, + "metadata": { + "description": "The name of the workload that is being deployed. Up to 10 characters long." + } + }, + "environment": { + "type": "string", + "maxLength": 8, + "metadata": { + "description": "The name of the environment (e.g. \"dev\", \"test\", \"prod\", \"uat\", \"dr\", \"qa\"). Up to 8 characters long." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The location where the resources will be created. This needs to be the same region as the spoke." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The tags to be assigned to the created resources." + } + }, + "applicationGatewayFqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the Application Gateawy. Must match the TLS certificate." + } + }, + "applicationGatewaySubnetId": { + "type": "string", + "metadata": { + "description": "The existing subnet resource ID to use for Application Gateway." + } + }, + "applicationGatewayPrimaryBackendEndFqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the primary backend endpoint." + } + }, + "appGatewayBackendHealthProbePath": { + "type": "string", + "defaultValue": "/", + "metadata": { + "description": "The path to use for Application Gateway's backend health probe." + } + }, + "enableApplicationGatewayCertificate": { + "type": "bool", + "metadata": { + "description": "Enable or disable Application Gateway certificate (PFX)." + } + }, + "applicationGatewayCertificateKeyName": { + "type": "string", + "metadata": { + "description": "The name of the certificate key to use for Application Gateway certificate." + } + }, + "applicationGatewayLogAnalyticsId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The resource ID of the exsiting Log Analytics workload for diagnostic settngs, or nothing if you don't need any." + } + }, + "keyVaultId": { + "type": "string", + "metadata": { + "description": "The resource ID of the existing Key Vault which contains Application Gateway's cert." + } + }, + "deployZoneRedundantResources": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional, default value is true. If true, any resources that support AZ will be deployed in all three AZ. However if the selected region is not supporting AZ, this parameter needs to be set to false." + } + }, + "ddosProtectionMode": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled", + "VirtualNetworkInherited" ], "metadata": { - "description": "Azure Application Insights, the workload' log & metric sink and APM tool" + "description": "Optional. DDoS protection mode for the Public IP of the Application Gateway. See https://learn.microsoft.com/azure/ddos-protection/ddos-protection-sku-comparison#skus" } - }, + } + }, + "variables": { + "$fxv#0": "MIIKbwIBAzCCCiUGCSqGSIb3DQEHAaCCChYEggoSMIIKDjCCBIIGCSqGSIb3DQEHBqCCBHMwggRvAgEAMIIEaAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAib0WJNTWKS7AICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEHW9eewF9XfBaswcMEeJDKGAggQAPp4/eKGKvqc14RcyYpHwyrMnKmI1B9zu4Up0HZt8HdSKvGtlpQx488J516i/nvJuOjuPhDGTdCCHHM70r+ythml4h1k3OEXqUFeR9U9ENJY8GwMgjKjF1Dw1ZI7HtXsPHLlH6uthTqfLJXRkbSh1JDxyQEV7jMI54X5cy1nvenXhJ39xjk/ZhK2BouZnxxaK6r/x4vLCVqwnvvcmaAG53cF8k0oPcdxdoHnE3yQRrBEPJjHmfufZ6BpqXMfV3qRbDid2UoakEhyzLnCbh9UsT/i4BzBvzPoApDY03OM9MLc3r3+BCLjfFSdVsXKf1/+0ZbPP/T6ex1o57E2k1dCWAYNLUTG1dMoEfh8qJ7iNw18RWwvgzQTCVYDAHrMt1FVrjncS1rKQ91SR0lx7UqiOVRL5hH5q6zLJwelQ8AMij7bq8sMMqQnnNudX1XqE5eWzSCFU+qFTx1aegzve98on3NRIjdDhGs0I8fmCSFQ1JQiteMIpHwSVeSf2EJqfI+1ORrDw5FqVGCgUcjD4hNXylVutwzHvqogvL88ktMQuuzBlTO+JJtRBjMakcYaWHm3pTlc/6FYbAOQq9NeiKLreo3Onvd6VUPFhSaTxj6Yc+QVEMTNlvu2fD4aF49XlsNXiYD89Hppgjzyq+65rcWP3X0B4FKRZBgp3T11iTdsMZvjsFWeWQ8S7tfbGGiff4xo8JktKzA/lN8exZEQqccMUWKNUkL5ovWjuLlhVOroUeFE56fseI3CVcfgSOk9C7d21vbP/+sY5lZAKCHguX1w+Qsrw2rGpKXhF8bEPPjEAC4X/qw6YfxZSbP5YSs7fCqJtDLi8aaNUo8U90yAOwDoCPNJNb4IkCiuXrMAFND9p7+lFZe3L0CPO8Zc3XmV78xVHoHpQ3Gp2cEMBWpQULEj2m/FBnLOjbQ0o8mRQFdKbHfX8kvCPAVpqFFCei4+XyypMjAu4v6N6nJm3Ze4PPu0TTBEbS9Bo0mKjLDXtob1GqsStQ74SuwAokqGJyJSwTP9gaAuAFmdf56FRnIR0MvdT7eTe4I5q3VOZWWPl6zMs8MaP9lRSom8CaBK97N5n427VE0YaAERTies071M7j1/z5TavAYcde4w8phrnkE+PQpZbg0dIgINBrQAWOu5fUBLj6Y2JWudNn5h7bNMuU6RPRsJHf8nY13GBFVyoRfeXHSLE09GQ2EkOn/PslDYyKIIDnhVFKFLwGQSuGnmWMRTYd0Li9NN9PzKewrStwuEMW7Qwh2Gs4Zj7XUkCSmpX5eUQ9S09Zugo+G7vF6HdedN4HTcPpccaZ9kz6A+iEAxxWKSYkJXAmpss2Ol7D6Gl49zAexyrffIL9r0dYKZM7O+i7jCCBYQGCSqGSIb3DQEHAaCCBXUEggVxMIIFbTCCBWkGCyqGSIb3DQEMCgECoIIFMTCCBS0wVwYJKoZIhvcNAQUNMEowKQYJKoZIhvcNAQUMMBwECKJcTO/NpFybAgIIADAMBggqhkiG9w0CCQUAMB0GCWCGSAFlAwQBKgQQ3lO4+tUQ8LNz1gjulWNrpQSCBNAt6xylV++Av6DETcLjtNObdmwya3/twJsa58rW+VZTF3juXoskqDcWG3x9d2TIVySedo8K6ou5dzxPsyky+5+/hXMlYdjmXpboYL90tRg4ysjXsYmFxpEm8tcTv6pC58ayynB0d80Be1OwnMMCUhYYnj+4opFd6xK+Xehm//5XOUD3jyk9BfxptBrGyPG+halNhHnqbP7w1fv/eNRLXOGS5Uoaq7e5GwiIAHXyOiC3CDfEgtiZisGXKC5JRHYDt+gsjqwowmYF/x21etsJf79z1zx0F5Eu+V5BYaQ8sLevW5pnxwX2WvQ75gL9slICcyzt5NQ3i7qAzF/me0z6MmMXrsP+4QsC84xL13qYvc3u9Tja4XIpCLxoTxCFkI67zgqB4DQwst92sNwsGYAZry9Fjlt/icgN9R9k+ksrycOcEMkertZ9BiVZyk0UOBRalLNLcYNqUhvqmW1QSB+upgLRGgXOcxcygUXlWhHPIZ71I2wrDdb1Yn6zyeaTkjQo5J6VAMCuZ8gT7p+aTF33t3NEKShTfugBOoL6Np2d8Jfo4L7GITn4Kw24WoJFmwwjzFzq42WnuBuhkiKPTOGahFdl4pYkQSr054LU/GXKJrIQX3Pn2geeRLvMbddp2dk4yDCbE63EQxyXHfdGqXDrR8S6sShs59X5Qj/uJxXw6+gTLTOmjKd841zJE80fd8rwQYXq3v8+iqYKV1hERfTtqqXZuYmFkJjDenlzQmCIFzicHl4ltymV3X5Q2FRdsC9jne8CtqGBut3naeayJwhUKbc9gvF5u9EQBT3y7+BSgUcnBboaFWd41RUHD5uuZrTUsr3a61M77p6+SLl0mLHnnHCIzUHiB70cNrrUVmr6FyW46qhZ6g8sxUPw3E4K73eM/YWDPkv+xcawcwWwKGKATXoCwvcfuX6qpVQIKG1SQ0fz5D+4DULU/IY4S+dSrJk3AIbO+BkraLmPWc1mqNlVezo04xojEkahER2X9g0iEhDL65X4JezMontJJ8hVKDhbnvLN3rfFXIqcRzc0lmPD28VGC9y5X2VqcEuRDI9iLz9r18j5TTSRgWeRLj/AVeJL4i17M0x3jBhev4zJvZ8YO51pfAP4Pj2Q/MgJNRDLb2aPro7uTt8Wq2yECvHSgRILDrEQcK5fIbEpBU89+jXJcqjENCI81fP87oPHiIyS97NVhhU6GKL5Gx14EKUPu5JEA0n2n1M3AciYAAJs6G/XzcJQK6n8z83Wx6nu6crwFBbq8M5UMKJBXtUGRQIxRxpT6f7UhWJOTyGwr7c05c8TsloVgSLSjSnBdF2gv90ups9ZzcZheLtRqS395zciyPyncPLH9dMmz5WhLlZbFnIsWpoP6BRgyU/0AsJJstmXfYhv6/iC/PIHDdmcyaTF8q+WYKj9yGGvUBYI30USQzUbWV7Q18mskHS0HHF/vJtkOS8nLQxD7C1yZDDW4r0/vGjaklWCkRuLgjAR90TYXUV8ezfNrQpRyPohvU/4i1/WQpyPV9zOllLbBTj5a34y675DZ7np9stKRKlGWfIwSvfMp8pX2jV4P5vcFN0IZOaFhTC5hMC9RVeZzfW47BEFlAvbp9GdwgdnSLi6fsXC3NXDJ9l/I7pysCxptwalsK66BZBR+DElMCMGCSqGSIb3DQEJFTEWBBRYa3G5zDyNDmnDtwqNJ75gWXpYmTBBMDEwDQYJYIZIAWUDBAIBBQAEIGOuaxQnb7HkLGdd0HlJvhVruHiNPa/nw0DB7E1JwZjxBAj69WXROxcQcAICCAA=", + "keyVaultIdTokens": "[split(parameters('keyVaultId'), '/')]", + "keyVaultSubscriptionId": "[variables('keyVaultIdTokens')[2]]", + "keyVaultResourceGroupName": "[variables('keyVaultIdTokens')[4]]", + "keyVaultName": "[variables('keyVaultIdTokens')[8]]", + "applicationGatewayCertificatePath": "configuration/acahello.demoapp.com.pfx" + }, + "resources": [ { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('containerAppsEnvironment-{0}', uniqueString(resourceGroup().id)), 64)]", + "name": "[take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('04-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.containerAppsEnvironment]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "logAnalyticsWsResourceId": { - "value": "[parameters('logAnalyticsWorkspaceId')]" + "uniqueId": { + "value": "[uniqueString(resourceGroup().id)]" }, - "subnetId": { - "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('spokeVNetName'), parameters('spokeInfraSubnetName'))]" + "environment": { + "value": "[parameters('environment')]" }, - "vnetEndpointInternal": { - "value": true + "workloadName": { + "value": "[parameters('workloadName')]" }, - "appInsightsInstrumentationKey": "[if(and(parameters('enableApplicationInsights'), parameters('enableDaprInstrumentation')), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('applicationInsights-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.appInsInstrumentationKey.value), createObject('value', ''))]" + "location": { + "value": "[parameters('location')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -5223,148 +7583,105 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "15153833916265091433" + "version": "0.20.4.51522", + "templateHash": "6817832201461302860" } }, "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of your Azure Container Apps Environment. " - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location for all resources." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "zoneRedundant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional, default value is false. Sets if the environment will use availability zones. Your Container App Environment and the apps in it will be zone redundant. This requieres vNet integration." - } - }, - "sku": { + "workloadName": { "type": "string", - "defaultValue": "Consumption", - "allowedValues": [ - "Consumption", - "Premium" - ], - "metadata": { - "description": "Mandatory, default is Consumption" - } - }, - "vnetEndpointInternal": { - "type": "bool", + "minLength": 2, + "maxLength": 10, "metadata": { - "description": "If true, the endpoint is an internal load balancer. If false the hosted apps are exposed on an internet-accessible IP address " + "description": "The name of the workloard that is being deployed. Up to 10 characters long." } }, - "subnetId": { + "environment": { "type": "string", + "maxLength": 8, "metadata": { - "description": "Custome vnet configuration for the nevironment. NOTE: Current GA (Feb 2023): The subnet associated with a Container App Environment requires a CIDR prefix of /23 or larger" + "description": "The name of the environment (e.g. \"dev\", \"test\", \"prod\", \"uat\", \"dr\", \"qa\") Up to 8 characters long." } }, - "logAnalyticsWsResourceId": { + "location": { "type": "string", "metadata": { - "description": "mandatory for log-analytics" + "description": "Location for all Resources." } }, - "appInsightsInstrumentationKey": { + "uniqueId": { "type": "string", - "defaultValue": "", "metadata": { - "description": "optional, default is empty. App Insights instrumentation key provided to Dapr for tracing" + "description": "a unique ID that can be appended (or prepended) in azure resource names that require some kind of uniqueness" } } }, "variables": { - "lawsSplitTokens": "[if(not(empty(parameters('logAnalyticsWsResourceId'))), split(parameters('logAnalyticsWsResourceId'), '/'), array(''))]" - }, - "resources": [ - { - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2022-10-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "sku": { - "name": "[parameters('sku')]" - }, - "tags": "[parameters('tags')]", - "properties": { - "zoneRedundant": "[parameters('zoneRedundant')]", - "daprAIInstrumentationKey": "[parameters('appInsightsInstrumentationKey')]", - "vnetConfiguration": { - "internal": "[parameters('vnetEndpointInternal')]", - "infrastructureSubnetId": "[parameters('subnetId')]" - }, - "appLogsConfiguration": { - "destination": "log-analytics", - "logAnalyticsConfiguration": { - "customerId": "[if(not(empty(parameters('logAnalyticsWsResourceId'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('lawsSplitTokens')[2], variables('lawsSplitTokens')[4]), 'Microsoft.OperationalInsights/workspaces', variables('lawsSplitTokens')[8]), '2022-10-01').customerId, null())]", - "sharedKey": "[if(not(empty(parameters('logAnalyticsWsResourceId'))), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('lawsSplitTokens')[2], variables('lawsSplitTokens')[4]), 'Microsoft.OperationalInsights/workspaces', variables('lawsSplitTokens')[8]), '2022-10-01').primarySharedKey, null())]" - } - } - } + "$fxv#0": "{\r\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\r\n \"resourceTypeAbbreviations\" : {\r\n \"applicationGateway\": \"agw\",\r\n \"applicationInsights\": \"appi\",\r\n \"appService\": \"app\",\r\n \"bastion\": \"bas\",\r\n \"containerAppsEnvironment\": \"cae\",\r\n \"containerRegistry\": \"cr\",\r\n \"cosmosDbNoSql\": \"cosno\",\r\n \"frontDoor\": \"afd\",\r\n \"frontDoorEndpoint\": \"fde\",\r\n \"frontDoorWaf\": \"fdfp\",\r\n \"keyVault\": \"kv\",\r\n \"logAnalyticsWorkspace\": \"log\",\r\n \"managedIdentity\": \"id\",\r\n \"networkInterface\": \"nic\",\r\n \"networkSecurityGroup\": \"nsg\",\r\n \"privateEndpoint\": \"pep\",\r\n \"privateLinkService\": \"pls\",\r\n \"publicIpAddress\": \"pip\",\r\n \"resourceGroup\": \"rg\",\r\n \"serviceBus\": \"sb\",\r\n \"serviceBusQueue\": \"sbq\",\r\n \"serviceBusTopic\": \"sbt\",\r\n \"storageAccount\": \"st\",\r\n \"virtualMachine\": \"vm\",\r\n \"virtualNetwork\": \"vnet\",\r\n \"redisCache\": \"redis\"\r\n },\r\n\r\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\r\n \"regionAbbreviations\" : {\r\n \"australiacentral\": \"auc\",\r\n \"australiacentral2\": \"auc2\",\r\n \"australiaeast\": \"aue\",\r\n \"australiasoutheast\": \"ause\",\r\n \"brazilsouth\": \"brs\",\r\n \"brazilsoutheast\": \"brse\",\r\n \"canadacentral\": \"canc\",\r\n \"canadaeast\": \"cane\",\r\n \"centralindia\": \"cin\",\r\n \"centralus\": \"cus\",\r\n \"centraluseuap\": \"cuseuap\",\r\n \"eastasia\": \"ea\",\r\n \"eastus\": \"eus\",\r\n \"eastus2\": \"eus2\",\r\n \"eastus2euap\": \"eus2euap\",\r\n \"francecentral\": \"frc\",\r\n \"francesouth\": \"frs\",\r\n \"germanynorth\": \"gern\",\r\n \"germanywestcentral\": \"gerwc\",\r\n \"japaneast\": \"jae\",\r\n \"japanwest\": \"jaw\",\r\n \"jioindiacentral\": \"jioinc\",\r\n \"jioindiawest\": \"jioinw\",\r\n \"koreacentral\": \"koc\",\r\n \"koreasouth\": \"kors\",\r\n \"northcentralus\": \"ncus\",\r\n \"northeurope\": \"neu\",\r\n \"norwayeast\": \"nore\",\r\n \"norwaywest\": \"norw\",\r\n \"southafricanorth\": \"san\",\r\n \"southafricawest\": \"saw\",\r\n \"southcentralus\": \"scus\",\r\n \"southeastasia\": \"sea\",\r\n \"southindia\": \"sin\",\r\n \"swedencentral\": \"swc\",\r\n \"switzerlandnorth\": \"swn\",\r\n \"switzerlandwest\": \"sww\",\r\n \"uaecentral\": \"uaec\",\r\n \"uaenorth\": \"uaen\",\r\n \"uksouth\": \"uks\",\r\n \"ukwest\": \"ukw\",\r\n \"westcentralus\": \"wcus\",\r\n \"westeurope\": \"weu\",\r\n \"westindia\": \"win\",\r\n \"westus\": \"wus\",\r\n \"westus2\": \"wus2\",\r\n \"westus3\": \"wus3\"\r\n }\r\n}", + "naming": "[json(variables('$fxv#0'))]", + "uniqueIdShort": "[substring(parameters('uniqueId'), 0, 5)]", + "resourceTypeToken": "RES_TYPE", + "namingBase": "[format('{0}-{1}-{2}-{3}', variables('resourceTypeToken'), parameters('workloadName'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", + "namingBaseUnique": "[format('{0}-{1}-{2}-{3}-{4}', variables('resourceTypeToken'), parameters('workloadName'), variables('uniqueIdShort'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", + "namingBaseNoWorkloadName": "[format('{0}-{1}-{2}', variables('resourceTypeToken'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", + "resourceTypeAbbreviations": "[variables('naming').resourceTypeAbbreviations]", + "keyVaultName": "[take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault), 24)]", + "resourceNames": { + "vnetSpoke": "[format('{0}-spoke', replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualNetwork))]", + "vnetHub": "[format('{0}-hub', replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualNetwork))]", + "applicationGateway": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway)]", + "applicationGatewayPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", + "applicationGatewayUserAssignedIdentity": "[format('{0}-{1}-KeyVaultSecretUser', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", + "applicationGatewayNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", + "pepNsg": "[format('{0}-pep', variables('naming').resourceTypeAbbreviations.networkSecurityGroup)]", + "applicationInsights": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationInsights)]", + "bastion": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion)]", + "bastionNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", + "bastionPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", + "containerAppsEnvironment": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerAppsEnvironment)]", + "containerAppsEnvironmentNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerAppsEnvironment))]", + "containerRegistry": "[take(toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')), 50)]", + "containerRegistryPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')))]", + "containerRegistryUserAssignedIdentity": "[format('{0}-{1}-AcrPull', variables('naming').resourceTypeAbbreviations.managedIdentity, toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')))]", + "redisCache": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.redisCache)]", + "redisCachePep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.redisCache))]", + "cosmosDbNoSql": "[toLower(take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.cosmosDbNoSql), 44))]", + "cosmosDbNoSqlPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.cosmosDbNoSql), 44)))]", + "frontDoorProfile": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]", + "keyVault": "[if(endsWith(variables('keyVaultName'), '-'), take(variables('keyVaultName'), 23), variables('keyVaultName'))]", + "keyVaultPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", + "logAnalyticsWorkspace": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.logAnalyticsWorkspace)]", + "serviceBus": "[replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus)]", + "serviceBusPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus))]", + "storageAccount": "[toLower(take(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.storageAccount), '-', ''), 24))]", + "storageAccountPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.storageAccount)))]", + "vmJumpBox": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine)]", + "vmJumpBoxNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine))]", + "vmJumpBoxNic": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkInterface, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine))]", + "frontDoor": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]" } - ], + }, + "resources": [], "outputs": { - "containerAppsEnvironmentName": { - "type": "string", - "metadata": { - "description": "The Name of the Azure container app environment." - }, - "value": "[parameters('name')]" - }, - "containerAppsEnvironmentNameId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Azure container app environment." - }, - "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" - }, - "containerAppsEnvironmentDefaultDomain": { - "type": "string", - "metadata": { - "description": "The default domain of the Azure container app environment." - }, - "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2022-10-01').defaultDomain]" + "resourcesNames": { + "type": "object", + "value": "[variables('resourceNames')]" }, - "containerAppsEnvironmentLoadBalancerIP": { - "type": "string", - "metadata": { - "description": "The Azure container app environment's Load Balancer IP." - }, - "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2022-10-01').staticIp]" + "resourceTypeAbbreviations": { + "type": "object", + "value": "[variables('resourceTypeAbbreviations')]" } } } }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('applicationInsights-{0}', uniqueString(resourceGroup().id)), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('04-sharedNamingDeployment-{0}', deployment().name), 64))]" - ], "metadata": { - "description": "The Azure Container Apps (ACA) cluster." + "description": "User-configured naming rules" } }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('containerAppsEnvironmentPrivateDnsZone-{0}', uniqueString(resourceGroup().id))]", + "name": "[take(format('appGwUserAssignedIdentity-Deployment-{0}', uniqueString(resourceGroup().id)), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -5372,32 +7689,13 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.containerAppsEnvironmentDefaultDomain.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGatewayUserAssignedIdentity]" }, - "virtualNetworkLinks": { - "value": [ - { - "vnetName": "[parameters('spokeVNetName')]", - "vnetId": "[resourceId('Microsoft.Network/virtualNetworks', parameters('spokeVNetName'))]", - "registrationEnabled": false - }, - { - "vnetName": "[variables('hubVNetName')]", - "vnetId": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('hubSubscriptionId'), variables('hubResourceGroupName')), 'Microsoft.Network/virtualNetworks', variables('hubVNetName'))]", - "registrationEnabled": false - } - ] + "location": { + "value": "[parameters('location')]" }, "tags": { "value": "[parameters('tags')]" - }, - "aRecords": { - "value": [ - { - "name": "*", - "ipv4Address": "[reference(resourceId('Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.containerAppsEnvironmentLoadBalancerIP.value]" - } - ] } }, "template": { @@ -5406,15 +7704,23 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "8461334250568869203" + "version": "0.20.4.51522", + "templateHash": "16624770513957439457" } }, "parameters": { "name": { "type": "string", + "minLength": 3, + "maxLength": 128, "metadata": { - "description": "Required. Name of the Private DNS Zone Service. For az private endpoints you might find info here: https://learn.microsoft.com/azure/private-link/private-endpoint-dns#azure-services-dns-zone-configuration" + "description": "Required. The name of the user assigned managed Identity. 3-128, can contain \"-\" and \"_\"" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Optional. Location for all resources." } }, "tags": { @@ -5423,411 +7729,197 @@ "metadata": { "description": "Optional. Tags of the resource." } - }, - "virtualNetworkLinks": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain vnetName, vnetId, registrationEnabled" - } - }, - "aRecords": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of A records to be added to the DNS Zone" - } } }, "resources": [ { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2018-11-30", "name": "[parameters('name')]", - "location": "global", + "location": "[parameters('location')]", "tags": "[parameters('tags')]" + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the managedIDentity." + }, + "value": "[parameters('name')]" }, - { - "copy": { - "name": "privateDnsZoneLink", - "count": "[length(parameters('virtualNetworkLinks'))]" + "id": { + "type": "string", + "metadata": { + "description": "The id of the managedIDentity." }, - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2018-09-01", - "name": "[format('{0}/{1}', parameters('name'), format('{0}-link', parameters('virtualNetworkLinks')[copyIndex()].vnetName))]", - "location": "global", - "properties": { - "registrationEnabled": "[parameters('virtualNetworkLinks')[copyIndex()].registrationEnabled]", - "virtualNetwork": { - "id": "[parameters('virtualNetworkLinks')[copyIndex()].vnetId]" - } + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "type": { + "type": "string", + "metadata": { + "description": "The type of the managedIDentity." }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" - ] + "value": "Microsoft.ManagedIdentity/userAssignedIdentities" }, - { - "copy": { - "name": "dnsARecord", - "count": "[length(parameters('aRecords'))]" + "principalId": { + "type": "string", + "metadata": { + "description": "The ServicePrincipalId of the managedIDentity." }, - "type": "Microsoft.Network/privateDnsZones/A", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('name'), parameters('aRecords')[copyIndex()].name)]", - "properties": { - "ttl": 60, - "aRecords": [ - { - "ipv4Address": "[parameters('aRecords')[copyIndex()].ipv4Address]" - } - ] + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), '2018-11-30').principalId]" + }, + "tenantId": { + "type": "string", + "metadata": { + "description": "The TenantId of the managedIDentity." }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" - ] - } - ], - "outputs": { - "privateDnsZonesId": { + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), '2018-11-30').tenantId]" + }, + "clientId": { "type": "string", - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + "metadata": { + "description": "The clientId of the managedIDentity." + }, + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), '2018-11-30').clientId]" } } } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}', uniqueString(resourceGroup().id)), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64))]" ], "metadata": { - "description": "The Private DNS zone containing the ACA load balancer IP" - } - } - ], - "outputs": { - "containerAppsEnvironmentId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container Apps environment." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.containerAppsEnvironmentNameId.value]" - }, - "containerAppsEnvironmentName": { - "type": "string", - "metadata": { - "description": "The name of the Container Apps environment." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.containerAppsEnvironmentName.value]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/deployments', take(format('hub-{0}-deployment', deployment().name), 64))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64))]", - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('supportingServices-{0}-deployment', deployment().name), 64))]" - ] - }, - { - "condition": "[parameters('deployHelloWorldSample')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('helloWorlSampleApp-{0}-deployment', deployment().name), 64)]", - "resourceGroup": "[variables('rgSpokeName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "containerRegistryUserAssignedIdentityId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('supportingServices-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.containerRegistryUserAssignedIdentityId.value]" - }, - "containerAppsEnvironmentId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.containerAppsEnvironmentId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "15025788095162643616" - } - }, - "parameters": { - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "The location where the resources will be created. This needs to be the same region as the Azure Container Apps instances." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The tags to be assigned to the created resources." - } - }, - "helloWorldContainerAppName": { - "type": "string", - "defaultValue": "ca-simple-hello", - "maxLength": 32, - "minLength": 2, - "metadata": { - "description": "Optional. The name of the Container App. If set, it overrides the name generated by the template." - } - }, - "containerRegistryUserAssignedIdentityId": { - "type": "string", - "metadata": { - "description": "The resource ID of the existing user-assigned managed identity to be assigned to the Container App to be able to pull images from the container registry." + "description": "A user-assigned managed identity that enables Application Gateway to access Key Vault for its TLS certs." } }, - "containerAppsEnvironmentId": { - "type": "string", - "metadata": { - "description": "The resource ID of the existing Container Apps environment in which the Container App will be deployed." - } - } - }, - "resources": [ { - "type": "Microsoft.App/containerApps", - "apiVersion": "2022-10-01", - "name": "[parameters('helloWorldContainerAppName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": { - "type": "UserAssigned", - "userAssignedIdentities": { - "[format('{0}', parameters('containerRegistryUserAssignedIdentityId'))]": {} - } - }, + "condition": "[parameters('enableApplicationGatewayCertificate')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('appGatewayAddCertificates-Deployment-{0}', uniqueString(resourceGroup().id)), 64)]", + "subscriptionId": "[variables('keyVaultSubscriptionId')]", + "resourceGroup": "[variables('keyVaultResourceGroupName')]", "properties": { - "configuration": { - "activeRevisionsMode": "single", - "ingress": { - "allowInsecure": false, - "external": true, - "targetPort": 80, - "transport": "auto" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[variables('keyVaultName')]" }, - "registries": [], - "secrets": [] + "appGatewayCertificateData": { + "value": "[variables('$fxv#0')]" + }, + "appGatewayCertificateKeyName": { + "value": "[parameters('applicationGatewayCertificateKeyName')]" + }, + "appGatewayUserAssignedIdentityPrincipalId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('appGwUserAssignedIdentity-Deployment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.principalId.value]" + } }, - "environmentId": "[parameters('containerAppsEnvironmentId')]", "template": { - "containers": [ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.20.4.51522", + "templateHash": "5981313522980772638" + } + }, + "parameters": { + "keyVaultName": { + "type": "string" + }, + "appGatewayUserAssignedIdentityPrincipalId": { + "type": "string" + }, + "appGatewayCertificateKeyName": { + "type": "string" + }, + "appGatewayCertificateData": { + "type": "string" + } + }, + "variables": { + "keyVaultSecretUserRoleGuid": "4633458b-17de-408a-b874-0445c86b69e6" + }, + "resources": [ { - "name": "simple-hello", - "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", - "resources": { - "cpu": "[json('0.25')]", - "memory": "0.5Gi" + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('appGatewayCertificateKeyName'))]", + "properties": { + "value": "[parameters('appGatewayCertificateData')]", + "contentType": "application/x-pkcs12", + "attributes": { + "enabled": true + } } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('appGatewayCertificateKeyName'))]", + "name": "[guid(subscription().id, resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName')), parameters('appGatewayUserAssignedIdentityPrincipalId'), 'KeyVaultSecretUser')]", + "properties": { + "principalId": "[parameters('appGatewayUserAssignedIdentityPrincipalId')]", + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('keyVaultSecretUserRoleGuid'))]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('appGatewayCertificateKeyName'))]" + ] } ], - "scale": { - "minReplicas": 1, - "maxReplicas": 10 - }, - "volumes": [] + "outputs": { + "SecretUri": { + "type": "string", + "value": "[reference(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('appGatewayCertificateKeyName')), '2022-07-01').secretUri]" + } + } } }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('appGwUserAssignedIdentity-Deployment-{0}', uniqueString(resourceGroup().id)), 64))]" + ], "metadata": { - "description": "The \"Hello World\" Container App." - } - } - ], - "outputs": { - "helloWorldAppFqdn": { - "type": "string", - "metadata": { - "description": "The FQDN of the \"Hello World\" Container App." - }, - "value": "[reference(resourceId('Microsoft.App/containerApps', parameters('helloWorldContainerAppName')), '2022-10-01').configuration.ingress.fqdn]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('containerAppsEnvironment-{0}-deployment', deployment().name), 64))]", - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgSpokeName'))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('supportingServices-{0}-deployment', deployment().name), 64))]" - ] - }, - { - "condition": "[parameters('deployHelloWorldSample')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('applicationGateway-{0}-deployment', deployment().name), 64)]", - "resourceGroup": "[variables('rgSpokeName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "environment": { - "value": "[parameters('environment')]" - }, - "workloadName": { - "value": "[parameters('workloadName')]" - }, - "applicationGatewayCertificateKeyName": { - "value": "[parameters('applicationGatewayCertificateKeyName')]" - }, - "applicationGatewayFqdn": { - "value": "[parameters('applicationGatewayFqdn')]" - }, - "applicationGatewayPrimaryBackendEndFqdn": "[if(parameters('deployHelloWorldSample'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('helloWorlSampleApp-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.helloWorldAppFqdn.value), createObject('value', ''))]", - "applicationGatewaySubnetId": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.spokeApplicationGatewaySubnetId.value]" - }, - "enableApplicationGatewayCertificate": { - "value": "[parameters('enableApplicationGatewayCertificate')]" - }, - "keyVaultId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('supportingServices-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.keyVaultId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "10387356517610375308" - } - }, - "parameters": { - "workloadName": { - "type": "string", - "maxLength": 10, - "minLength": 2, - "metadata": { - "description": "The name of the workload that is being deployed. Up to 10 characters long." - } - }, - "environment": { - "type": "string", - "maxLength": 8, - "metadata": { - "description": "The name of the environment (e.g. \"dev\", \"test\", \"prod\", \"uat\", \"dr\", \"qa\"). Up to 8 characters long." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "The location where the resources will be created. This needs to be the same region as the spoke." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The tags to be assigned to the created resources." - } - }, - "applicationGatewayFqdn": { - "type": "string", - "metadata": { - "description": "The FQDN of the Application Gateawy. Must match the TLS certificate." - } - }, - "applicationGatewaySubnetId": { - "type": "string", - "metadata": { - "description": "The existing subnet resource ID to use for Application Gateway." - } - }, - "applicationGatewayPrimaryBackendEndFqdn": { - "type": "string", - "metadata": { - "description": "The FQDN of the primary backend endpoint." - } - }, - "appGatewayBackendHealthProbePath": { - "type": "string", - "defaultValue": "/", - "metadata": { - "description": "The path to use for Application Gateway's backend health probe." - } - }, - "enableApplicationGatewayCertificate": { - "type": "bool", - "metadata": { - "description": "Enable or disable Application Gateway certificate (PFX)." - } - }, - "applicationGatewayCertificateKeyName": { - "type": "string", - "metadata": { - "description": "The name of the certificate key to use for Application Gateway certificate." - } - }, - "applicationGatewayLogAnalyticsId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The resource ID of the exsiting Log Analytics workload for diagnostic settngs, or nothing if you don't need any." + "description": "Adds the PFX file into Azure Key Vault for consumption by Application Gateway." } }, - "keyVaultId": { - "type": "string", - "metadata": { - "description": "The resource ID of the existing Key Vault which contains Application Gateway's cert." - } - } - }, - "variables": { - "$fxv#0": "MIIKbwIBAzCCCiUGCSqGSIb3DQEHAaCCChYEggoSMIIKDjCCBIIGCSqGSIb3DQEHBqCCBHMwggRvAgEAMIIEaAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAib0WJNTWKS7AICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEHW9eewF9XfBaswcMEeJDKGAggQAPp4/eKGKvqc14RcyYpHwyrMnKmI1B9zu4Up0HZt8HdSKvGtlpQx488J516i/nvJuOjuPhDGTdCCHHM70r+ythml4h1k3OEXqUFeR9U9ENJY8GwMgjKjF1Dw1ZI7HtXsPHLlH6uthTqfLJXRkbSh1JDxyQEV7jMI54X5cy1nvenXhJ39xjk/ZhK2BouZnxxaK6r/x4vLCVqwnvvcmaAG53cF8k0oPcdxdoHnE3yQRrBEPJjHmfufZ6BpqXMfV3qRbDid2UoakEhyzLnCbh9UsT/i4BzBvzPoApDY03OM9MLc3r3+BCLjfFSdVsXKf1/+0ZbPP/T6ex1o57E2k1dCWAYNLUTG1dMoEfh8qJ7iNw18RWwvgzQTCVYDAHrMt1FVrjncS1rKQ91SR0lx7UqiOVRL5hH5q6zLJwelQ8AMij7bq8sMMqQnnNudX1XqE5eWzSCFU+qFTx1aegzve98on3NRIjdDhGs0I8fmCSFQ1JQiteMIpHwSVeSf2EJqfI+1ORrDw5FqVGCgUcjD4hNXylVutwzHvqogvL88ktMQuuzBlTO+JJtRBjMakcYaWHm3pTlc/6FYbAOQq9NeiKLreo3Onvd6VUPFhSaTxj6Yc+QVEMTNlvu2fD4aF49XlsNXiYD89Hppgjzyq+65rcWP3X0B4FKRZBgp3T11iTdsMZvjsFWeWQ8S7tfbGGiff4xo8JktKzA/lN8exZEQqccMUWKNUkL5ovWjuLlhVOroUeFE56fseI3CVcfgSOk9C7d21vbP/+sY5lZAKCHguX1w+Qsrw2rGpKXhF8bEPPjEAC4X/qw6YfxZSbP5YSs7fCqJtDLi8aaNUo8U90yAOwDoCPNJNb4IkCiuXrMAFND9p7+lFZe3L0CPO8Zc3XmV78xVHoHpQ3Gp2cEMBWpQULEj2m/FBnLOjbQ0o8mRQFdKbHfX8kvCPAVpqFFCei4+XyypMjAu4v6N6nJm3Ze4PPu0TTBEbS9Bo0mKjLDXtob1GqsStQ74SuwAokqGJyJSwTP9gaAuAFmdf56FRnIR0MvdT7eTe4I5q3VOZWWPl6zMs8MaP9lRSom8CaBK97N5n427VE0YaAERTies071M7j1/z5TavAYcde4w8phrnkE+PQpZbg0dIgINBrQAWOu5fUBLj6Y2JWudNn5h7bNMuU6RPRsJHf8nY13GBFVyoRfeXHSLE09GQ2EkOn/PslDYyKIIDnhVFKFLwGQSuGnmWMRTYd0Li9NN9PzKewrStwuEMW7Qwh2Gs4Zj7XUkCSmpX5eUQ9S09Zugo+G7vF6HdedN4HTcPpccaZ9kz6A+iEAxxWKSYkJXAmpss2Ol7D6Gl49zAexyrffIL9r0dYKZM7O+i7jCCBYQGCSqGSIb3DQEHAaCCBXUEggVxMIIFbTCCBWkGCyqGSIb3DQEMCgECoIIFMTCCBS0wVwYJKoZIhvcNAQUNMEowKQYJKoZIhvcNAQUMMBwECKJcTO/NpFybAgIIADAMBggqhkiG9w0CCQUAMB0GCWCGSAFlAwQBKgQQ3lO4+tUQ8LNz1gjulWNrpQSCBNAt6xylV++Av6DETcLjtNObdmwya3/twJsa58rW+VZTF3juXoskqDcWG3x9d2TIVySedo8K6ou5dzxPsyky+5+/hXMlYdjmXpboYL90tRg4ysjXsYmFxpEm8tcTv6pC58ayynB0d80Be1OwnMMCUhYYnj+4opFd6xK+Xehm//5XOUD3jyk9BfxptBrGyPG+halNhHnqbP7w1fv/eNRLXOGS5Uoaq7e5GwiIAHXyOiC3CDfEgtiZisGXKC5JRHYDt+gsjqwowmYF/x21etsJf79z1zx0F5Eu+V5BYaQ8sLevW5pnxwX2WvQ75gL9slICcyzt5NQ3i7qAzF/me0z6MmMXrsP+4QsC84xL13qYvc3u9Tja4XIpCLxoTxCFkI67zgqB4DQwst92sNwsGYAZry9Fjlt/icgN9R9k+ksrycOcEMkertZ9BiVZyk0UOBRalLNLcYNqUhvqmW1QSB+upgLRGgXOcxcygUXlWhHPIZ71I2wrDdb1Yn6zyeaTkjQo5J6VAMCuZ8gT7p+aTF33t3NEKShTfugBOoL6Np2d8Jfo4L7GITn4Kw24WoJFmwwjzFzq42WnuBuhkiKPTOGahFdl4pYkQSr054LU/GXKJrIQX3Pn2geeRLvMbddp2dk4yDCbE63EQxyXHfdGqXDrR8S6sShs59X5Qj/uJxXw6+gTLTOmjKd841zJE80fd8rwQYXq3v8+iqYKV1hERfTtqqXZuYmFkJjDenlzQmCIFzicHl4ltymV3X5Q2FRdsC9jne8CtqGBut3naeayJwhUKbc9gvF5u9EQBT3y7+BSgUcnBboaFWd41RUHD5uuZrTUsr3a61M77p6+SLl0mLHnnHCIzUHiB70cNrrUVmr6FyW46qhZ6g8sxUPw3E4K73eM/YWDPkv+xcawcwWwKGKATXoCwvcfuX6qpVQIKG1SQ0fz5D+4DULU/IY4S+dSrJk3AIbO+BkraLmPWc1mqNlVezo04xojEkahER2X9g0iEhDL65X4JezMontJJ8hVKDhbnvLN3rfFXIqcRzc0lmPD28VGC9y5X2VqcEuRDI9iLz9r18j5TTSRgWeRLj/AVeJL4i17M0x3jBhev4zJvZ8YO51pfAP4Pj2Q/MgJNRDLb2aPro7uTt8Wq2yECvHSgRILDrEQcK5fIbEpBU89+jXJcqjENCI81fP87oPHiIyS97NVhhU6GKL5Gx14EKUPu5JEA0n2n1M3AciYAAJs6G/XzcJQK6n8z83Wx6nu6crwFBbq8M5UMKJBXtUGRQIxRxpT6f7UhWJOTyGwr7c05c8TsloVgSLSjSnBdF2gv90ups9ZzcZheLtRqS395zciyPyncPLH9dMmz5WhLlZbFnIsWpoP6BRgyU/0AsJJstmXfYhv6/iC/PIHDdmcyaTF8q+WYKj9yGGvUBYI30USQzUbWV7Q18mskHS0HHF/vJtkOS8nLQxD7C1yZDDW4r0/vGjaklWCkRuLgjAR90TYXUV8ezfNrQpRyPohvU/4i1/WQpyPV9zOllLbBTj5a34y675DZ7np9stKRKlGWfIwSvfMp8pX2jV4P5vcFN0IZOaFhTC5hMC9RVeZzfW47BEFlAvbp9GdwgdnSLi6fsXC3NXDJ9l/I7pysCxptwalsK66BZBR+DElMCMGCSqGSIb3DQEJFTEWBBRYa3G5zDyNDmnDtwqNJ75gWXpYmTBBMDEwDQYJYIZIAWUDBAIBBQAEIGOuaxQnb7HkLGdd0HlJvhVruHiNPa/nw0DB7E1JwZjxBAj69WXROxcQcAICCAA=", - "keyVaultIdTokens": "[split(parameters('keyVaultId'), '/')]", - "keyVaultSubscriptionId": "[variables('keyVaultIdTokens')[2]]", - "keyVaultResourceGroupName": "[variables('keyVaultIdTokens')[4]]", - "keyVaultName": "[variables('keyVaultIdTokens')[8]]", - "applicationGatewayCertificatePath": "configuration/acahello.demoapp.com.pfx" - }, - "resources": [ { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)]", + "name": "[take(format('applicationGatewayPublicIp-Deployment-{0}', uniqueString(resourceGroup().id)), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "uniqueId": { - "value": "[uniqueString(resourceGroup().id)]" + "location": { + "value": "[parameters('location')]" }, - "environment": { - "value": "[parameters('environment')]" + "name": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGatewayPip]" }, - "workloadName": { - "value": "[parameters('workloadName')]" + "tags": { + "value": "[parameters('tags')]" }, - "location": { - "value": "[parameters('location')]" + "skuName": { + "value": "Standard" + }, + "publicIPAllocationMethod": { + "value": "Static" + }, + "zones": "[if(parameters('deployZoneRedundantResources'), createObject('value', createArray('1', '2', '3')), createObject('value', createArray()))]", + "diagnosticWorkspaceId": { + "value": "[parameters('applicationGatewayLogAnalyticsId')]" + }, + "ddosProtectionMode": { + "value": "[parameters('ddosProtectionMode')]" } }, "template": { @@ -5836,105 +7928,339 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "14985913302549051532" + "version": "0.20.4.51522", + "templateHash": "15442895641789348346" } }, "parameters": { - "workloadName": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIPPrefixResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Dynamic", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "zones": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + }, + "diagnosticStorageAccountId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The name of the workloard that is being deployed. Up to 10 characters long." - }, - "maxLength": 10, - "minLength": 2 + "description": "Optional. Resource ID of the diagnostic storage account." + } }, - "environment": { + "diagnosticWorkspaceId": { "type": "string", - "maxLength": 8, + "defaultValue": "", "metadata": { - "description": "The name of the environment (e.g. \"dev\", \"test\", \"prod\", \"uat\", \"dr\", \"qa\") Up to 8 characters long." + "description": "Optional. Resource ID of the diagnostic log analytics workspace." + } + }, + "diagnosticEventHubAuthorizationRuleId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "diagnosticEventHubName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category." + } + }, + "domainNameLabel": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "fqdn": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + }, + "lock": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "CanNotDelete", + "ReadOnly" + ], + "metadata": { + "description": "Optional. Specify the type of lock." } }, "location": { "type": "string", "metadata": { - "description": "Location for all Resources." + "description": "Optional. Location for all resources." } }, - "uniqueId": { + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticLogCategoriesToEnable": { + "type": "array", + "defaultValue": [ + "allLogs" + ], + "allowedValues": [ + "allLogs", + "DDoSProtectionNotifications", + "DDoSMitigationFlowLogs", + "DDoSMitigationReports" + ], + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource." + } + }, + "diagnosticMetricsToEnable": { + "type": "array", + "defaultValue": [ + "AllMetrics" + ], + "allowedValues": [ + "AllMetrics" + ], + "metadata": { + "description": "Optional. The name of metrics that will be streamed." + } + }, + "diagnosticSettingsName": { "type": "string", + "defaultValue": "", "metadata": { - "description": "a unique ID that can be appended (or prepended) in azure resource names that require some kind of uniqueness" + "description": "Optional. The name of the diagnostic setting, if deployed. If left empty, it defaults to \"-diagnosticSettings\"." + } + }, + "ddosProtectionMode": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled", + "VirtualNetworkInherited" + ], + "metadata": { + "description": "Optional. DDoS protection mode. see https://learn.microsoft.com/azure/ddos-protection/ddos-protection-sku-comparison#skus" } } }, "variables": { - "$fxv#0": "{\n // Recommended abreviations: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations\n \"resourceTypeAbbreviations\" : {\n \"applicationGateway\": \"agw\",\n \"applicationInsights\": \"appi\",\n \"appService\": \"app\",\n \"bastion\": \"bas\",\n \"containerAppsEnvironment\": \"cae\",\n \"containerRegistry\": \"cr\",\n \"cosmosDbNoSql\": \"cosno\",\n \"frontDoor\": \"afd\",\n \"frontDoorEndpoint\": \"fde\",\n \"frontDoorWaf\": \"fdfp\",\n \"keyVault\": \"kv\",\n \"logAnalyticsWorkspace\": \"log\",\n \"managedIdentity\": \"id\",\n \"networkInterface\": \"nic\",\n \"networkSecurityGroup\": \"nsg\",\n \"privateEndpoint\": \"pep\",\n \"privateLinkService\": \"pls\",\n \"publicIpAddress\": \"pip\",\n \"resourceGroup\": \"rg\",\n \"serviceBus\": \"sb\",\n \"serviceBusQueue\": \"sbq\",\n \"serviceBusTopic\": \"sbt\",\n \"storageAccount\": \"st\",\n \"virtualMachine\": \"vm\",\n \"virtualNetwork\": \"vnet\",\n \"redisCache\": \"redis\"\n },\n\n //copied from here: https://github.com/nianton/azure-naming/blob/main/datafiles/regionAbbreviations.json\n \"regionAbbreviations\" : {\n \"australiacentral\": \"auc\",\n \"australiacentral2\": \"auc2\",\n \"australiaeast\": \"aue\",\n \"australiasoutheast\": \"ause\",\n \"brazilsouth\": \"brs\",\n \"brazilsoutheast\": \"brse\",\n \"canadacentral\": \"canc\",\n \"canadaeast\": \"cane\",\n \"centralindia\": \"cin\",\n \"centralus\": \"cus\",\n \"centraluseuap\": \"cuseuap\",\n \"eastasia\": \"ea\",\n \"eastus\": \"eus\",\n \"eastus2\": \"eus2\",\n \"eastus2euap\": \"eus2euap\",\n \"francecentral\": \"frc\",\n \"francesouth\": \"frs\",\n \"germanynorth\": \"gern\",\n \"germanywestcentral\": \"gerwc\",\n \"japaneast\": \"jae\",\n \"japanwest\": \"jaw\",\n \"jioindiacentral\": \"jioinc\",\n \"jioindiawest\": \"jioinw\",\n \"koreacentral\": \"koc\",\n \"koreasouth\": \"kors\",\n \"northcentralus\": \"ncus\",\n \"northeurope\": \"neu\",\n \"norwayeast\": \"nore\",\n \"norwaywest\": \"norw\",\n \"southafricanorth\": \"san\",\n \"southafricawest\": \"saw\",\n \"southcentralus\": \"scus\",\n \"southeastasia\": \"sea\",\n \"southindia\": \"sin\",\n \"swedencentral\": \"swc\",\n \"switzerlandnorth\": \"swn\",\n \"switzerlandwest\": \"sww\",\n \"uaecentral\": \"uaec\",\n \"uaenorth\": \"uaen\",\n \"uksouth\": \"uks\",\n \"ukwest\": \"ukw\",\n \"westcentralus\": \"wcus\",\n \"westeurope\": \"weu\",\n \"westindia\": \"win\",\n \"westus\": \"wus\",\n \"westus2\": \"wus2\",\n \"westus3\": \"wus3\"\n }\n}", - "naming": "[json(variables('$fxv#0'))]", - "uniqueIdShort": "[substring(parameters('uniqueId'), 0, 5)]", - "resourceTypeToken": "RES_TYPE", - "namingBase": "[format('{0}-{1}-{2}-{3}', variables('resourceTypeToken'), parameters('workloadName'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", - "namingBaseUnique": "[format('{0}-{1}-{2}-{3}-{4}', variables('resourceTypeToken'), parameters('workloadName'), variables('uniqueIdShort'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", - "namingBaseNoWorkloadName": "[format('{0}-{1}-{2}', variables('resourceTypeToken'), parameters('environment'), variables('naming').regionAbbreviations[toLower(parameters('location'))])]", - "resourceTypeAbbreviations": "[variables('naming').resourceTypeAbbreviations]", - "keyVaultName": "[take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault), 24)]", - "resourceNames": { - "vnetSpoke": "[format('{0}-spoke', replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualNetwork))]", - "vnetHub": "[format('{0}-hub', replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualNetwork))]", - "applicationGateway": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway)]", - "applicationGatewayPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", - "applicationGatewayUserAssignedIdentity": "[format('{0}-{1}-KeyVaultSecretUser', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", - "applicationGatewayNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationGateway))]", - "applicationInsights": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.applicationInsights)]", - "bastion": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion)]", - "bastionNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", - "bastionPip": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.publicIpAddress, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.bastion))]", - "containerAppsEnvironment": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerAppsEnvironment)]", - "containerAppsEnvironmentNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerAppsEnvironment))]", - "containerRegistry": "[take(toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')), 50)]", - "containerRegistryPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')))]", - "containerRegistryUserAssignedIdentity": "[format('{0}-{1}-AcrPull', variables('naming').resourceTypeAbbreviations.managedIdentity, toLower(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.containerRegistry), '-', '')))]", - "redisCache": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.redisCache)]", - "redisCachePep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.redisCache))]", - "cosmosDbNoSql": "[toLower(take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.cosmosDbNoSql), 44))]", - "cosmosDbNoSqlPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(take(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.cosmosDbNoSql), 44)))]", - "frontDoorProfile": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]", - "keyVault": "[if(endsWith(variables('keyVaultName'), '-'), take(variables('keyVaultName'), 23), variables('keyVaultName'))]", - "keyVaultPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", - "keyVaultUserAssignedIdentity": "[format('{0}-{1}-KeyVaultReader', variables('naming').resourceTypeAbbreviations.managedIdentity, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.keyVault))]", - "logAnalyticsWorkspace": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.logAnalyticsWorkspace)]", - "serviceBus": "[replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus)]", - "serviceBusPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.serviceBus))]", - "storageAccount": "[toLower(take(replace(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.storageAccount), '-', ''), 24))]", - "storageAccountPep": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.privateEndpoint, toLower(replace(variables('namingBaseUnique'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.storageAccount)))]", - "vmJumpBox": "[replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine)]", - "vmJumpBoxNsg": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkSecurityGroup, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine))]", - "vmJumpBoxNic": "[format('{0}-{1}', variables('naming').resourceTypeAbbreviations.networkInterface, replace(variables('namingBaseNoWorkloadName'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.virtualMachine))]", - "frontDoor": "[replace(variables('namingBase'), variables('resourceTypeToken'), variables('naming').resourceTypeAbbreviations.frontDoor)]" - } + "copy": [ + { + "name": "diagnosticsLogsSpecified", + "count": "[length(filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs')))))]", + "input": { + "category": "[filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs'))))[copyIndex('diagnosticsLogsSpecified')]]", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + }, + { + "name": "diagnosticsMetrics", + "count": "[length(parameters('diagnosticMetricsToEnable'))]", + "input": { + "category": "[parameters('diagnosticMetricsToEnable')[copyIndex('diagnosticsMetrics')]]", + "timeGrain": null, + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + } + ], + "diagnosticsLogs": "[if(contains(parameters('diagnosticLogCategoriesToEnable'), 'allLogs'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true(), 'retentionPolicy', createObject('enabled', true(), 'days', parameters('diagnosticLogsRetentionInDays')))), variables('diagnosticsLogsSpecified'))]" }, - "resources": [], + "resources": [ + { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[parameters('zones')]", + "properties": { + "dnsSettings": "[if(not(empty(parameters('domainNameLabel'))), createObject('domainNameLabel', parameters('domainNameLabel'), 'fqdn', parameters('fqdn'), 'reverseFqdn', parameters('reverseFqdn')), null())]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIPPrefixResourceId'))), createObject('id', parameters('publicIPPrefixResourceId')), null())]", + "idleTimeoutInMinutes": 4, + "ipTags": [], + "ddosSettings": { + "protectionMode": "[parameters('ddosProtectionMode')]" + } + } + }, + { + "condition": "[not(empty(parameters('lock')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[format('{0}-{1}-lock', parameters('name'), parameters('lock'))]", + "properties": { + "level": "[parameters('lock')]", + "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + ] + }, + { + "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[if(not(empty(parameters('diagnosticSettingsName'))), parameters('diagnosticSettingsName'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", + "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", + "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", + "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", + "metrics": "[variables('diagnosticsMetrics')]", + "logs": "[variables('diagnosticsLogs')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + ] + } + ], "outputs": { - "resourcesNames": { - "type": "object", - "value": "[variables('resourceNames')]" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" }, - "resourceTypeAbbreviations": { - "type": "object", - "value": "[variables('resourceTypeAbbreviations')]" + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[if(contains(reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), '2022-07-01'), 'ipAddress'), reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), '2022-07-01').ipAddress, '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), '2022-07-01', 'full').location]" } } } }, - "metadata": { - "description": "User-configured naming rules" - } + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64))]" + ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('appGwUserAssignedIdentity-Deployment-{0}', uniqueString(resourceGroup().id)), 64)]", + "name": "[take(format('applicationGateway-Deployment-{0}', uniqueString(resourceGroup().id)), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -5942,13 +8268,144 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGatewayUserAssignedIdentity]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGateway]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentities": { + "value": { + "[format('{0}', reference(resourceId('Microsoft.Resources/deployments', take(format('appGwUserAssignedIdentity-Deployment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.id.value)]": {} + } + }, + "sku": { + "value": "WAF_v2" + }, + "diagnosticWorkspaceId": { + "value": "[parameters('applicationGatewayLogAnalyticsId')]" + }, + "gatewayIPConfigurations": { + "value": [ + { + "name": "appGatewayIpConfig", + "properties": { + "subnet": { + "id": "[parameters('applicationGatewaySubnetId')]" + } + } + } + ] + }, + "backendAddressPools": { + "value": [ + { + "name": "acaServiceBackend", + "properties": { + "backendAddresses": [ + { + "fqdn": "[parameters('applicationGatewayPrimaryBackendEndFqdn')]" + } + ] + } + } + ] + }, + "sslCertificates": "[if(parameters('enableApplicationGatewayCertificate'), createObject('value', createArray(createObject('name', parameters('applicationGatewayFqdn'), 'properties', createObject('keyVaultSecretId', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('keyVaultSubscriptionId'), variables('keyVaultResourceGroupName')), 'Microsoft.Resources/deployments', take(format('appGatewayAddCertificates-Deployment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.SecretUri.value)))), createObject('value', createArray()))]", + "frontendIPConfigurations": { + "value": [ + { + "name": "appGwPublicFrontendIp", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "publicIPAddress": { + "id": "[reference(resourceId('Microsoft.Resources/deployments', take(format('applicationGatewayPublicIp-Deployment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.resourceId.value]" + } + } + } + ] + }, + "frontendPorts": "[if(parameters('enableApplicationGatewayCertificate'), createObject('value', createArray(createObject('name', 'port_443', 'properties', createObject('port', 443)), createObject('name', 'port_80', 'properties', createObject('port', 80)))), createObject('value', createArray(createObject('name', 'port_80', 'properties', createObject('port', 80)))))]", + "backendHttpSettingsCollection": { + "value": [ + { + "name": "https", + "properties": { + "port": 443, + "protocol": "Https", + "cookieBasedAffinity": "Disabled", + "pickHostNameFromBackendAddress": true, + "requestTimeout": 20, + "probe": { + "id": "[resourceId('Microsoft.Network/applicationGateways/probes', reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGateway, 'webProbe')]" + } + } + } + ] + }, + "httpListeners": "[if(not(parameters('enableApplicationGatewayCertificate')), createObject('value', createArray(createObject('name', 'httpListener', 'properties', createObject('frontendIPConfiguration', createObject('id', format('{0}/frontendIPConfigurations/appGwPublicFrontendIp', resourceId('Microsoft.Network/applicationGateways', reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGateway))), 'frontendPort', createObject('id', format('{0}/frontendPorts/port_80', resourceId('Microsoft.Network/applicationGateways', reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGateway))), 'protocol', 'Http', 'hostnames', createArray(), 'requireServerNameIndication', false())))), createObject('value', createArray(createObject('name', 'httpListener', 'properties', createObject('frontendIPConfiguration', createObject('id', format('{0}/frontendIPConfigurations/appGwPublicFrontendIp', resourceId('Microsoft.Network/applicationGateways', reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGateway))), 'frontendPort', createObject('id', format('{0}/frontendPorts/port_443', resourceId('Microsoft.Network/applicationGateways', reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGateway))), 'protocol', 'Https', 'sslCertificate', createObject('id', format('{0}/sslCertificates/{1}', resourceId('Microsoft.Network/applicationGateways', reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGateway), parameters('applicationGatewayFqdn'))), 'hostnames', createArray(), 'requireServerNameIndication', false())))))]", + "requestRoutingRules": { + "value": [ + { + "name": "routingRules", + "properties": { + "ruleType": "Basic", + "priority": 100, + "httpListener": { + "id": "[format('{0}/httpListeners/httpListener', resourceId('Microsoft.Network/applicationGateways', reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGateway))]" + }, + "backendAddressPool": { + "id": "[format('{0}/backendAddressPools/acaServiceBackend', resourceId('Microsoft.Network/applicationGateways', reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGateway))]" + }, + "backendHttpSettings": { + "id": "[format('{0}/backendHttpSettingsCollection/https', resourceId('Microsoft.Network/applicationGateways', reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGateway))]" + } + } + } + ] + }, + "probes": { + "value": [ + { + "name": "webProbe", + "properties": { + "protocol": "Https", + "host": "[parameters('applicationGatewayPrimaryBackendEndFqdn')]", + "path": "[parameters('appGatewayBackendHealthProbePath')]", + "interval": 30, + "timeout": 30, + "unhealthyThreshold": 3, + "pickHostNameFromBackendHttpSettings": false, + "minServers": 0, + "match": { + "statusCodes": [ + "200-499" + ] + } + } + } + ] + }, + "zones": "[if(parameters('deployZoneRedundantResources'), createObject('value', createArray('1', '2', '3')), createObject('value', createArray()))]", + "webApplicationFirewallConfiguration": { + "value": { + "enabled": true, + "firewallMode": "Prevention", + "ruleSetType": "OWASP", + "ruleSetVersion": "3.2", + "disabledRuleGroups": [], + "requestBodyCheck": true, + "maxRequestBodySizeInKb": 128, + "fileUploadLimitInMb": 100 + } }, - "location": { - "value": "[parameters('location')]" + "sslPolicyType": { + "value": "Predefined" }, - "tags": { - "value": "[parameters('tags')]" + "sslPolicyName": { + "value": "AppGwSslPolicy20220101" } }, "template": { @@ -5957,507 +8414,553 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "18120221178179977349" + "version": "0.20.4.51522", + "templateHash": "11500690044078762189" } }, "parameters": { "name": { "type": "string", - "maxLength": 128, - "minLength": 3, + "maxLength": 80, "metadata": { - "description": "Required. The name of the user assigned managed Identity. 3-128, can contain \"-\" and \"_\"" + "description": "Required. Name of the Application Gateway." } }, "location": { "type": "string", "metadata": { - "description": "Optional. Location for all resources." + "description": "Location for all resources." } }, - "tags": { + "userAssignedIdentities": { "type": "object", "defaultValue": {}, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. The ID(s) to assign to the resource." } - } - }, - "resources": [ - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2018-11-30", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - } - ], - "outputs": { - "name": { - "type": "string", + }, + "authenticationCertificates": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "The name of the managedIDentity." - }, - "value": "[parameters('name')]" + "description": "Optional. Authentication certificates of the application gateway resource." + } }, - "id": { + "autoscaleMaxCapacity": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Upper bound on number of Application Gateway capacity." + } + }, + "autoscaleMinCapacity": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Lower bound on number of Application Gateway capacity." + } + }, + "backendAddressPools": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Backend address pool of the application gateway resource." + } + }, + "backendHttpSettingsCollection": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Backend http settings of the application gateway resource." + } + }, + "customErrorConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Custom error configurations of the application gateway resource." + } + }, + "enableFips": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether FIPS is enabled on the application gateway resource." + } + }, + "enableHttp2": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether HTTP2 is enabled on the application gateway resource." + } + }, + "firewallPolicyId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The id of the managedIDentity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + "description": "Optional. The resource ID of an associated firewall policy. Should be configured for security reasons." + } }, - "type": { + "frontendIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Frontend IP addresses of the application gateway resource." + } + }, + "frontendPorts": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Frontend ports of the application gateway resource." + } + }, + "gatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Subnets of the application gateway resource." + } + }, + "enableRequestBuffering": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable request buffering." + } + }, + "enableResponseBuffering": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable response buffering." + } + }, + "httpListeners": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Http listeners of the application gateway resource." + } + }, + "loadDistributionPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Load distribution policies of the application gateway resource." + } + }, + "privateLinkConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. PrivateLink configurations on application gateway." + } + }, + "probes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Probes of the application gateway resource." + } + }, + "redirectConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Redirect configurations of the application gateway resource." + } + }, + "requestRoutingRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Request routing rules of the application gateway resource." + } + }, + "rewriteRuleSets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Rewrite rules for the application gateway resource." + } + }, + "sku": { "type": "string", + "defaultValue": "WAF_Medium", + "allowedValues": [ + "Standard_Small", + "Standard_Medium", + "Standard_Large", + "WAF_Medium", + "WAF_Large", + "Standard_v2", + "WAF_v2" + ], "metadata": { - "description": "The type of the managedIDentity." - }, - "value": "Microsoft.ManagedIdentity/userAssignedIdentities" + "description": "Optional. The name of the SKU for the Application Gateway." + } }, - "principalId": { + "capacity": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. The number of Application instances to be configured." + } + }, + "sslCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. SSL certificates of the application gateway resource." + } + }, + "sslPolicyCipherSuites": { + "type": "array", + "defaultValue": [ + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" + ], + "allowedValues": [ + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384" + ], + "metadata": { + "description": "Optional. Ssl cipher suites to be enabled in the specified order to application gateway." + } + }, + "sslPolicyMinProtocolVersion": { "type": "string", + "defaultValue": "TLSv1_2", + "allowedValues": [ + "TLSv1_0", + "TLSv1_1", + "TLSv1_2", + "TLSv1_3" + ], "metadata": { - "description": "The ServicePrincipalId of the managedIDentity." - }, - "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), '2018-11-30').principalId]" + "description": "Optional. Ssl protocol enums." + } }, - "tenantId": { + "sslPolicyName": { "type": "string", + "defaultValue": "", + "allowedValues": [ + "AppGwSslPolicy20150501", + "AppGwSslPolicy20170401", + "AppGwSslPolicy20170401S", + "AppGwSslPolicy20220101", + "AppGwSslPolicy20220101S", + "" + ], "metadata": { - "description": "The TenantId of the managedIDentity." - }, - "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), '2018-11-30').tenantId]" + "description": "Optional. Ssl predefined policy name enums." + } }, - "clientId": { + "sslPolicyType": { "type": "string", + "defaultValue": "Custom", + "allowedValues": [ + "Custom", + "CustomV2", + "Predefined" + ], "metadata": { - "description": "The clientId of the managedIDentity." - }, - "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), '2018-11-30').clientId]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64))]" - ], - "metadata": { - "description": "A user-assigned managed identity that enables Application Gateway to access Key Vault for its TLS certs." - } - }, - { - "condition": "[parameters('enableApplicationGatewayCertificate')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('appGatewayAddCertificates-Deployment-{0}', uniqueString(resourceGroup().id)), 64)]", - "subscriptionId": "[variables('keyVaultSubscriptionId')]", - "resourceGroup": "[variables('keyVaultResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[variables('keyVaultName')]" - }, - "appGatewayCertificateData": { - "value": "[variables('$fxv#0')]" - }, - "appGatewayCertificateKeyName": { - "value": "[parameters('applicationGatewayCertificateKeyName')]" - }, - "appGatewayUserAssignedIdentityPrincipalId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('appGwUserAssignedIdentity-Deployment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.principalId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "2334743273643540547" - } - }, - "parameters": { - "keyVaultName": { - "type": "string" + "description": "Optional. Type of Ssl Policy." + } }, - "appGatewayUserAssignedIdentityPrincipalId": { - "type": "string" + "sslProfiles": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. SSL profiles of the application gateway resource." + } }, - "appGatewayCertificateKeyName": { - "type": "string" + "trustedClientCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Trusted client certificates of the application gateway resource." + } + }, + "trustedRootCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Trusted Root certificates of the application gateway resource." + } + }, + "urlPathMaps": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. URL path map of the application gateway resource." + } + }, + "webApplicationFirewallConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Application gateway web application firewall configuration. Should be configured for security reasons." + } + }, + "zones": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. A list of availability zones denoting where the resource needs to come from." + } }, - "appGatewayCertificateData": { - "type": "string" - } - }, - "variables": { - "keyVaultSecretUserRoleGuid": "4633458b-17de-408a-b874-0445c86b69e6" - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('appGatewayCertificateKeyName'))]", - "properties": { - "value": "[parameters('appGatewayCertificateData')]", - "contentType": "application/x-pkcs12", - "attributes": { - "enabled": true - } + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." } }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('appGatewayCertificateKeyName'))]", - "name": "[guid(subscription().id, resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName')), parameters('appGatewayUserAssignedIdentityPrincipalId'), 'KeyVaultSecretUser')]", - "properties": { - "principalId": "[parameters('appGatewayUserAssignedIdentityPrincipalId')]", - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('keyVaultSecretUserRoleGuid'))]", - "principalType": "ServicePrincipal" - }, - "dependsOn": [ - "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('appGatewayCertificateKeyName'))]" - ] - } - ], - "outputs": { - "SecretUri": { + "diagnosticStorageAccountId": { "type": "string", - "value": "[reference(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('appGatewayCertificateKeyName')), '2022-07-01').secretUri]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('appGwUserAssignedIdentity-Deployment-{0}', uniqueString(resourceGroup().id)), 64))]" - ], - "metadata": { - "description": "Adds the PFX file into Azure Key Vault for consumption by Application Gateway." - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('appGatewayConfiguration-Deployment-{0}', uniqueString(resourceGroup().id)), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appGatewayName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGateway]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "appGatewayFqdn": { - "value": "[parameters('applicationGatewayFqdn')]" - }, - "appGatewayPrimaryBackendEndFqdn": { - "value": "[parameters('applicationGatewayPrimaryBackendEndFqdn')]" - }, - "appGatewayBackendHealthProbePath": { - "value": "[parameters('appGatewayBackendHealthProbePath')]" - }, - "appGatewayPublicIpName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64)), '2022-09-01').outputs.resourcesNames.value.applicationGatewayPip]" - }, - "appGatewaySubnetId": { - "value": "[parameters('applicationGatewaySubnetId')]" - }, - "appGatewayUserAssignedIdentityId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('appGwUserAssignedIdentity-Deployment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.id.value]" - }, - "keyVaultSecretId": "[if(parameters('enableApplicationGatewayCertificate'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('keyVaultSubscriptionId'), variables('keyVaultResourceGroupName')), 'Microsoft.Resources/deployments', take(format('appGatewayAddCertificates-Deployment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.SecretUri.value), createObject('value', ''))]", - "appGatewayLogAnalyticsId": { - "value": "[parameters('applicationGatewayLogAnalyticsId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.17.1.54307", - "templateHash": "3151893290969817230" - } - }, - "parameters": { - "appGatewayName": { - "type": "string" + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } }, - "appGatewayFqdn": { + "diagnosticWorkspaceId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The FQDN of the Application Gateawy.Must match the TLS Certificate." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "appGatewaySubnetId": { + "diagnosticEventHubAuthorizationRuleId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The subnet resource id to use for Application Gateway." + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." } }, - "appGatewayPrimaryBackendEndFqdn": { - "type": "string" - }, - "appGatewayBackendHealthProbePath": { - "type": "string" + "diagnosticEventHubName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } }, - "appGatewayUserAssignedIdentityId": { - "type": "string" + "diagnosticLogCategoriesToEnable": { + "type": "array", + "defaultValue": [ + "allLogs" + ], + "allowedValues": [ + "allLogs", + "ApplicationGatewayAccessLog", + "ApplicationGatewayPerformanceLog", + "ApplicationGatewayFirewallLog" + ], + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource." + } }, - "appGatewayPublicIpName": { - "type": "string" + "diagnosticMetricsToEnable": { + "type": "array", + "defaultValue": [ + "AllMetrics" + ], + "allowedValues": [ + "AllMetrics" + ], + "metadata": { + "description": "Optional. The name of metrics that will be streamed." + } }, - "appGatewayLogAnalyticsId": { + "diagnosticSettingsName": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Provide a resource ID of the Web Analytics WS if you need diagnostic settngs, or nothing if you don t need any" + "description": "Optional. The name of the diagnostic setting, if deployed. If left empty, it defaults to \"-diagnosticSettings\"." } }, - "keyVaultSecretId": { - "type": "securestring" - }, "tags": { "type": "object", "defaultValue": {}, "metadata": { - "description": "Optional. The tags to be assigned to the created resources." + "description": "Optional. Resource tags." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]" + "backendSettingsCollection": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Backend settings of the application gateway resource. For default limits, see [Application Gateway limits](https://learn.microsoft.com/azure/azure-subscription-service-limits#application-gateway-limits)." + } + }, + "listeners": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Listeners of the application gateway resource. For default limits, see [Application Gateway limits](https://learn.microsoft.com/azure/azure-subscription-service-limits#application-gateway-limits)." + } + }, + "routingRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Routing rules of the application gateway resource." + } + }, + "enableDefaultTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." + } } }, + "variables": { + "copy": [ + { + "name": "diagnosticsLogsSpecified", + "count": "[length(filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs')))))]", + "input": { + "category": "[filter(parameters('diagnosticLogCategoriesToEnable'), lambda('item', not(equals(lambdaVariables('item'), 'allLogs'))))[copyIndex('diagnosticsLogsSpecified')]]", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + }, + { + "name": "diagnosticsMetrics", + "count": "[length(parameters('diagnosticMetricsToEnable'))]", + "input": { + "category": "[parameters('diagnosticMetricsToEnable')[copyIndex('diagnosticsMetrics')]]", + "timeGrain": null, + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + } + ], + "identityType": "[if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None')]", + "identity": "[if(not(equals(variables('identityType'), 'None')), createObject('type', variables('identityType'), 'userAssignedIdentities', if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), null())), null())]", + "diagnosticsLogs": "[if(contains(parameters('diagnosticLogCategoriesToEnable'), 'allLogs'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true(), 'retentionPolicy', createObject('enabled', true(), 'days', parameters('diagnosticLogsRetentionInDays')))), variables('diagnosticsLogsSpecified'))]" + }, "resources": [ { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2021-02-01", - "name": "[parameters('appGatewayPublicIpName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "Standard", - "tier": "Regional" - }, + "condition": "[parameters('enableDefaultTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2021-04-01", + "name": "[format('pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-{0}', uniqueString(deployment().name, parameters('location')))]", "properties": { - "publicIPAllocationMethod": "Static" + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } } }, { "type": "Microsoft.Network/applicationGateways", - "apiVersion": "2019-09-01", - "name": "[parameters('appGatewayName')]", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "identity": { - "type": "UserAssigned", - "userAssignedIdentities": { - "[format('{0}', parameters('appGatewayUserAssignedIdentityId'))]": {} - } - }, - "properties": { - "sku": { - "name": "WAF_v2", - "tier": "WAF_v2" - }, - "gatewayIPConfigurations": [ - { - "name": "appGatewayIpConfig", - "properties": { - "subnet": { - "id": "[parameters('appGatewaySubnetId')]" - } - } - } - ], - "sslCertificates": "[if(not(empty(parameters('keyVaultSecretId'))), createArray(createObject('name', parameters('appGatewayFqdn'), 'properties', createObject('keyVaultSecretId', parameters('keyVaultSecretId')))), createArray())]", - "trustedRootCertificates": [], - "frontendIPConfigurations": [ - { - "name": "appGwPublicFrontendIp", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('appGatewayPublicIpName'))]" - } - } - } - ], - "frontendPorts": "[if(not(empty(parameters('keyVaultSecretId'))), createArray(createObject('name', 'port_443', 'properties', createObject('port', 443)), createObject('name', 'port_80', 'properties', createObject('port', 80))), createArray(createObject('name', 'port_80', 'properties', createObject('port', 80))))]", - "backendAddressPools": [ - { - "name": "acaServiceBackend", - "properties": { - "backendAddresses": [ - { - "fqdn": "[parameters('appGatewayPrimaryBackendEndFqdn')]" - } - ] - } - } - ], - "backendHttpSettingsCollection": [ - { - "name": "defaultHttpBackendHttpSetting", - "properties": { - "port": 80, - "protocol": "Http", - "cookieBasedAffinity": "Disabled", - "pickHostNameFromBackendAddress": true, - "affinityCookieName": "ApplicationGatewayAffinity", - "requestTimeout": 120 - } - }, - { - "name": "https", - "properties": { - "port": 443, - "protocol": "Https", - "cookieBasedAffinity": "Disabled", - "pickHostNameFromBackendAddress": true, - "requestTimeout": 20, - "probe": { - "id": "[resourceId('Microsoft.Network/applicationGateways/probes', parameters('appGatewayName'), 'webProbe')]" - } - } - } - ], - "httpListeners": "[if(empty(parameters('keyVaultSecretId')), createArray(createObject('name', 'httpListener', 'properties', createObject('frontendIPConfiguration', createObject('id', format('{0}/frontendIPConfigurations/appGwPublicFrontendIp', resourceId('Microsoft.Network/applicationGateways', parameters('appGatewayName')))), 'frontendPort', createObject('id', format('{0}/frontendPorts/port_80', resourceId('Microsoft.Network/applicationGateways', parameters('appGatewayName')))), 'protocol', 'Http', 'hostnames', createArray(), 'requireServerNameIndication', false()))), createArray(createObject('name', 'httpListener', 'properties', createObject('frontendIPConfiguration', createObject('id', format('{0}/frontendIPConfigurations/appGwPublicFrontendIp', resourceId('Microsoft.Network/applicationGateways', parameters('appGatewayName')))), 'frontendPort', createObject('id', format('{0}/frontendPorts/port_443', resourceId('Microsoft.Network/applicationGateways', parameters('appGatewayName')))), 'protocol', 'Https', 'sslCertificate', createObject('id', format('{0}/sslCertificates/{1}', resourceId('Microsoft.Network/applicationGateways', parameters('appGatewayName')), parameters('appGatewayFqdn'))), 'hostnames', createArray(), 'requireServerNameIndication', false()))))]", - "urlPathMaps": [], - "requestRoutingRules": [ - { - "name": "routingRules", - "properties": { - "ruleType": "Basic", - "httpListener": { - "id": "[format('{0}/httpListeners/httpListener', resourceId('Microsoft.Network/applicationGateways', parameters('appGatewayName')))]" - }, - "backendAddressPool": { - "id": "[format('{0}/backendAddressPools/acaServiceBackend', resourceId('Microsoft.Network/applicationGateways', parameters('appGatewayName')))]" - }, - "backendHttpSettings": { - "id": "[format('{0}/backendHttpSettingsCollection/https', resourceId('Microsoft.Network/applicationGateways', parameters('appGatewayName')))]" - } - } - } - ], - "probes": [ - { - "name": "webProbe", - "properties": { - "protocol": "Https", - "host": "[parameters('appGatewayPrimaryBackendEndFqdn')]", - "path": "[parameters('appGatewayBackendHealthProbePath')]", - "interval": 30, - "timeout": 30, - "unhealthyThreshold": 3, - "pickHostNameFromBackendHttpSettings": false, - "minServers": 0, - "match": { - "statusCodes": [ - "200-499" - ] - } - } - } - ], - "rewriteRuleSets": [], - "redirectConfigurations": [], - "webApplicationFirewallConfiguration": { - "enabled": true, - "firewallMode": "Detection", - "ruleSetType": "OWASP", - "ruleSetVersion": "3.0", - "disabledRuleGroups": [], - "requestBodyCheck": true, - "maxRequestBodySizeInKb": 128, - "fileUploadLimitInMb": 100 - }, - "enableHttp2": true, - "autoscaleConfiguration": { - "minCapacity": 2, - "maxCapacity": 3 - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/publicIPAddresses', parameters('appGatewayPublicIpName'))]" - ] + "identity": "[variables('identity')]", + "properties": "[union(createObject('authenticationCertificates', parameters('authenticationCertificates'), 'autoscaleConfiguration', if(and(greater(parameters('autoscaleMaxCapacity'), 0), greaterOrEquals(parameters('autoscaleMinCapacity'), 0)), createObject('maxCapacity', parameters('autoscaleMaxCapacity'), 'minCapacity', parameters('autoscaleMinCapacity')), null()), 'backendAddressPools', parameters('backendAddressPools'), 'backendHttpSettingsCollection', parameters('backendHttpSettingsCollection'), 'backendSettingsCollection', parameters('backendSettingsCollection'), 'customErrorConfigurations', parameters('customErrorConfigurations'), 'enableHttp2', parameters('enableHttp2'), 'firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'forceFirewallPolicyAssociation', not(empty(parameters('firewallPolicyId'))), 'frontendIPConfigurations', parameters('frontendIPConfigurations'), 'frontendPorts', parameters('frontendPorts'), 'gatewayIPConfigurations', parameters('gatewayIPConfigurations'), 'globalConfiguration', createObject('enableRequestBuffering', parameters('enableRequestBuffering'), 'enableResponseBuffering', parameters('enableResponseBuffering')), 'httpListeners', parameters('httpListeners'), 'loadDistributionPolicies', parameters('loadDistributionPolicies'), 'listeners', parameters('listeners'), 'privateLinkConfigurations', parameters('privateLinkConfigurations'), 'probes', parameters('probes'), 'redirectConfigurations', parameters('redirectConfigurations'), 'requestRoutingRules', parameters('requestRoutingRules'), 'routingRules', parameters('routingRules'), 'rewriteRuleSets', parameters('rewriteRuleSets'), 'sku', createObject('name', parameters('sku'), 'tier', if(endsWith(parameters('sku'), 'v2'), parameters('sku'), substring(parameters('sku'), 0, indexOf(parameters('sku'), '_'))), 'capacity', if(and(greater(parameters('autoscaleMaxCapacity'), 0), greaterOrEquals(parameters('autoscaleMinCapacity'), 0)), null(), parameters('capacity'))), 'sslCertificates', parameters('sslCertificates'), 'sslPolicy', if(not(equals(parameters('sslPolicyType'), 'Predefined')), createObject('cipherSuites', parameters('sslPolicyCipherSuites'), 'minProtocolVersion', parameters('sslPolicyMinProtocolVersion'), 'policyName', if(empty(parameters('sslPolicyName')), null(), parameters('sslPolicyName')), 'policyType', parameters('sslPolicyType')), createObject('policyName', if(empty(parameters('sslPolicyName')), null(), parameters('sslPolicyName')), 'policyType', parameters('sslPolicyType'))), 'sslProfiles', parameters('sslProfiles'), 'trustedClientCertificates', parameters('trustedClientCertificates'), 'trustedRootCertificates', parameters('trustedRootCertificates'), 'urlPathMaps', parameters('urlPathMaps')), if(parameters('enableFips'), createObject('enableFips', parameters('enableFips')), createObject()), if(not(empty(parameters('webApplicationFirewallConfiguration'))), createObject('webApplicationFirewallConfiguration', parameters('webApplicationFirewallConfiguration')), createObject()))]", + "zones": "[parameters('zones')]" }, { - "condition": "[not(empty(parameters('appGatewayLogAnalyticsId')))]", + "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/applicationGateways/{0}', parameters('appGatewayName'))]", - "name": "[format('agw-diagnostics-{0}', uniqueString(resourceGroup().id))]", + "scope": "[format('Microsoft.Network/applicationGateways/{0}', parameters('name'))]", + "name": "[if(not(empty(parameters('diagnosticSettingsName'))), parameters('diagnosticSettingsName'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { - "workspaceId": "[parameters('appGatewayLogAnalyticsId')]", - "logs": [ - { - "categoryGroup": "allLogs", - "enabled": true, - "retentionPolicy": { - "enabled": false, - "days": 0 - } - } - ], - "metrics": [ - { - "category": "AllMetrics", - "enabled": false, - "retentionPolicy": { - "enabled": false, - "days": 0 - } - } - ] + "storageAccountId": "[if(empty(parameters('diagnosticStorageAccountId')), null(), parameters('diagnosticStorageAccountId'))]", + "workspaceId": "[if(empty(parameters('diagnosticWorkspaceId')), null(), parameters('diagnosticWorkspaceId'))]", + "eventHubAuthorizationRuleId": "[if(empty(parameters('diagnosticEventHubAuthorizationRuleId')), null(), parameters('diagnosticEventHubAuthorizationRuleId'))]", + "eventHubName": "[if(empty(parameters('diagnosticEventHubName')), null(), parameters('diagnosticEventHubName'))]", + "metrics": "[if(and(and(and(empty(parameters('diagnosticStorageAccountId')), empty(parameters('diagnosticWorkspaceId'))), empty(parameters('diagnosticEventHubAuthorizationRuleId'))), empty(parameters('diagnosticEventHubName'))), null(), variables('diagnosticsMetrics'))]", + "logs": "[if(and(and(and(empty(parameters('diagnosticStorageAccountId')), empty(parameters('diagnosticWorkspaceId'))), empty(parameters('diagnosticEventHubAuthorizationRuleId'))), empty(parameters('diagnosticEventHubName'))), null(), variables('diagnosticsLogs'))]" }, "dependsOn": [ - "[resourceId('Microsoft.Network/applicationGateways', parameters('appGatewayName'))]" + "[resourceId('Microsoft.Network/applicationGateways', parameters('name'))]" ] } ], "outputs": { - "applicationGatewayFqdn": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the application gateway." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application gateway." + }, + "value": "[resourceId('Microsoft.Network/applicationGateways', parameters('name'))]" + }, + "resourceGroupName": { "type": "string", "metadata": { - "description": "The FQDN of the application gateway." + "description": "The resource group the application gateway was deployed into." }, - "value": "[parameters('appGatewayFqdn')]" + "value": "[resourceGroup().name]" }, - "applicationGatewayPublicIp": { + "location": { "type": "string", "metadata": { - "description": "The public IP address of the application gateway." + "description": "The location the resource was deployed into." }, - "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('appGatewayPublicIpName')), '2021-02-01').ipAddress]" + "value": "[reference(resourceId('Microsoft.Network/applicationGateways', parameters('name')), '2022-07-01', 'full').location]" } } } }, "dependsOn": [ "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('keyVaultSubscriptionId'), variables('keyVaultResourceGroupName')), 'Microsoft.Resources/deployments', take(format('appGatewayAddCertificates-Deployment-{0}', uniqueString(resourceGroup().id)), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('applicationGatewayPublicIp-Deployment-{0}', uniqueString(resourceGroup().id)), 64))]", "[resourceId('Microsoft.Resources/deployments', take(format('06-sharedNamingDeployment-{0}', deployment().name), 64))]", "[resourceId('Microsoft.Resources/deployments', take(format('appGwUserAssignedIdentity-Deployment-{0}', uniqueString(resourceGroup().id)), 64))]" - ], - "metadata": { - "description": "Azure Application Gateway, which acts as the public Internet gateway and WAF for the workload." - } + ] } ], "outputs": { @@ -6466,14 +8969,14 @@ "metadata": { "description": "The FQDN of the Azure Application Gateway." }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('appGatewayConfiguration-Deployment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.applicationGatewayFqdn.value]" + "value": "[parameters('applicationGatewayFqdn')]" }, "applicationGatewayPublicIp": { "type": "string", "metadata": { "description": "The public IP address of the Azure Application Gateway." }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('appGatewayConfiguration-Deployment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.applicationGatewayPublicIp.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('applicationGatewayPublicIp-Deployment-{0}', uniqueString(resourceGroup().id)), 64)), '2022-09-01').outputs.ipAddress.value]" } } } @@ -6536,13 +9039,6 @@ }, "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.spokeInfraSubnetName.value]" }, - "spokePrivateEndpointsSubnetId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Spoke Private Endpoints Subnet." - }, - "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', take(format('spoke-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.spokePrivateEndpointsSubnetId.value]" - }, "spokePrivateEndpointsSubnetName": { "type": "string", "metadata": { @@ -6599,13 +9095,6 @@ }, "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('supportingServices-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.keyVaultName.value]" }, - "keyVaultUserAssignedIdentityId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user assigned managed identity to access the key vault." - }, - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('rgSpokeName')), 'Microsoft.Resources/deployments', take(format('supportingServices-{0}-deployment', deployment().name), 64)), '2022-09-01').outputs.keyVaultUserAssignedIdentityId.value]" - }, "containerAppsEnvironmentId": { "type": "string", "metadata": { diff --git a/scenarios/aca-internal/azure-resource-manager/main.parameters.jsonc b/scenarios/aca-internal/azure-resource-manager/main.parameters.jsonc index bacb59b6..989c4700 100644 --- a/scenarios/aca-internal/azure-resource-manager/main.parameters.jsonc +++ b/scenarios/aca-internal/azure-resource-manager/main.parameters.jsonc @@ -4,7 +4,7 @@ "parameters": { // The name of the workload 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": { - "value": "lzaaca" + "value": "lzaaca02" }, //The name of the environment (e.g. "dev", "test", "prod", "preprod", "staging", "uat", "dr", "qa"). Up to 8 characters long. "environment": { @@ -12,7 +12,10 @@ }, "tags": { "value": {} - }, + }, + "enableTelemetry": { + "value": true + }, // The name of the hub resource group to create the resources in. If set, it overrides the name generated by the template. "hubResourceGroupName": { "value": "" @@ -23,10 +26,34 @@ }, "vnetAddressPrefixes": { "value": ["10.0.0.0/24"] - }, + }, + "enableBastion": { + "value": true + }, + "gatewaySubnetAddressPrefix": { + "value": "10.0.0.0/27" + }, + "azureFirewallSubnetAddressPrefix": { + "value": "10.0.0.64/26" + }, "bastionSubnetAddressPrefix": { - "value": "10.0.0.128/26" - }, + "value": "10.0.0.128/26" + }, + "vmSize": { + "value": "Standard_B2ms" + }, + "vmAdminUsername": { + "value": "azureuser" + }, + "vmAdminPassword": { + "value": "Password123" + }, + "vmLinuxSshAuthorizedKeys": { + "value": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDpNpoh248rsraL3uejAwKlla+pHaDLbp4DM7bKFoc3Rt1DeXPs0XTutJcNtq4iRq+ooRQ1T7WaK42MfQQxt3qkXwjyv8lPJ4v7aElWkAbxZIRYVYmQVxxwfw+zyB1rFdaCQD/kISg/zXxCWw+gdds4rEy7eq23/bXFM0l7pNvbAULIB6ZY7MRpC304lIAJusuZC59iwvjT3dWsDNWifA1SJtgr39yaxB9Fb01UdacwJNuvfGC35GNYH0VJ56c+iCFeAnMXIT00cYuHf0FCRTP0WvTKl+PQmeD1pwxefdFvKCVpidU2hOARb4ooapT0SDM1SODqjaZ/qwWP18y/qQ/v imported-openssh-key" + }, + "vmJumpboxOSType": { + "value": "linux" + }, "vmJumpBoxSubnetAddressPrefix": { "value": "10.1.2.32/27" }, @@ -41,22 +68,6 @@ }, "spokeApplicationGatewaySubnetAddressPrefix": { "value": "10.1.3.0/24" - }, - // select one of the following options: (['linux', 'windows', 'none']) - "vmJumpboxOSType": { - "value": "linux" - }, - "vmSize": { - "value": "Standard_B2ms" - }, - "vmAdminUsername": { - "value": "azureuser" - }, - "vmAdminPassword": { - "value": "Password123" - }, - "vmLinuxSshAuthorizedKeys": { - "value": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDpNpoh248rsraL3uejAwKlla+pHaDLbp4DM7bKFoc3Rt1DeXPs0XTutJcNtq4iRq+ooRQ1T7WaK42MfQQxt3qkXwjyv8lPJ4v7aElWkAbxZIRYVYmQVxxwfw+zyB1rFdaCQD/kISg/zXxCWw+gdds4rEy7eq23/bXFM0l7pNvbAULIB6ZY7MRpC304lIAJusuZC59iwvjT3dWsDNWifA1SJtgr39yaxB9Fb01UdacwJNuvfGC35GNYH0VJ56c+iCFeAnMXIT00cYuHf0FCRTP0WvTKl+PQmeD1pwxefdFvKCVpidU2hOARb4ooapT0SDM1SODqjaZ/qwWP18y/qQ/v imported-openssh-key" }, // If you want to deploy Application Insights, set this to true "enableApplicationInsights": { @@ -68,19 +79,16 @@ }, // Set this to true if you want to deploy the sample application and the application gateway "deployHelloWorldSample": { - "value": false + "value": true }, // if true Azure Cache for Redis (Premium SKU), together with Private Endpoint and the relavant Private DNS Zone will be deployed "deployRedisCache": { "value": false }, - "enableTelemetry": { - "value": true - }, - "enableBastion": { - "value": true + // DDoS protection mode for the Public IP of the Application Gateway. allowed values are "VirtualNetworkInherited", "Enabled" and "Disabled" + "ddosProtectionMode": { + "value": "Enabled" }, - ///////////////////////////////////// // The FQDN of the Application Gateway. Must match the TLS Certificate. "applicationGatewayFqdn": { "value": "acahello.demoapp.com" @@ -90,6 +98,14 @@ }, "applicationGatewayCertificateKeyName": { "value": "agwcert" - } + }, + //If true, Azure Policies will be deployed + "deployAzurePolicies": { + "value": true + }, + //If true, any resources that support AZ will be deployed in all three AZ. However if the selected region is not supporting AZ, this parameter needs to be set to false. + "deployZoneRedundantResources": { + "value": true + } } } \ No newline at end of file