From 8fc4a039831bb5b6baf4fe9cdfd478652a7ce168 Mon Sep 17 00:00:00 2001 From: Suhas Rao Date: Sun, 28 Aug 2022 21:34:02 +1000 Subject: [PATCH 01/77] Bicep with latest APIs --- .../{deploy_std.sh => commands_std.azcli} | 147 ++--- deployment/deploy_ha.sh | 214 ------- deployment/templates/appgw.bicep | 240 +++++++ deployment/templates/appgw.json | 312 --------- deployment/templates/ase.bicep | 61 ++ deployment/templates/ase.json | 334 ---------- deployment/templates/dns.bicep | 67 ++ deployment/templates/dns.json | 101 --- deployment/templates/firewall.bicep | 198 ++++++ deployment/templates/firewall.json | 254 -------- deployment/templates/jumpbox.bicep | 138 ++++ deployment/templates/jumpbox.json | 215 ------- deployment/templates/network.bicep | 49 ++ deployment/templates/network.json | 80 --- deployment/templates/rbac.bicep | 33 + deployment/templates/rbac.json | 52 -- deployment/templates/services.bicep | 293 +++++++++ deployment/templates/services.json | 420 ------------ deployment/templates/sites.bicep | 496 +++++++++++++++ deployment/templates/sites.json | 599 ------------------ 20 files changed, 1613 insertions(+), 2690 deletions(-) rename deployment/{deploy_std.sh => commands_std.azcli} (50%) delete mode 100644 deployment/deploy_ha.sh create mode 100644 deployment/templates/appgw.bicep delete mode 100644 deployment/templates/appgw.json create mode 100644 deployment/templates/ase.bicep delete mode 100644 deployment/templates/ase.json create mode 100644 deployment/templates/dns.bicep delete mode 100644 deployment/templates/dns.json create mode 100644 deployment/templates/firewall.bicep delete mode 100644 deployment/templates/firewall.json create mode 100644 deployment/templates/jumpbox.bicep delete mode 100644 deployment/templates/jumpbox.json create mode 100644 deployment/templates/network.bicep delete mode 100644 deployment/templates/network.json create mode 100644 deployment/templates/rbac.bicep delete mode 100644 deployment/templates/rbac.json create mode 100644 deployment/templates/services.bicep delete mode 100644 deployment/templates/services.json create mode 100644 deployment/templates/sites.bicep delete mode 100644 deployment/templates/sites.json diff --git a/deployment/deploy_std.sh b/deployment/commands_std.azcli similarity index 50% rename from deployment/deploy_std.sh rename to deployment/commands_std.azcli index 86a3bd5..ba05848 100644 --- a/deployment/deploy_std.sh +++ b/deployment/commands_std.azcli @@ -1,8 +1,15 @@ -#!/usr/bin/env bash - -# App url -APPGW_APP1_URL=votingapp-std.contoso.com -APPGW_APP2_URL=testapp-std.contoso.com +#requirements +#az cli +#jq + +#Parameters +RGNAME=yourResourceGroupName +RGLOCATION=yourLocation +SQLADMINUSER=yoursqlAdminUser +SQLADMINPASSWORD=yoursqlAdminPassword +JUMPBOX_USER=yourJumpBoxUser +JUMPBOX_PASSWORD=yourPassword +$ADMIN_USER_ID=$(az ad signed-in-user show --query id -o tsv) # IP Addresses NET_PREFIX=10.0.0.0/16 @@ -12,55 +19,52 @@ ASE_PREFIX=10.0.100.0/24 FIREWALL_PREFIX=10.0.200.0/24 JUMPBOX_PREFIX=10.0.250.0/24 -# create self-signed SSL certificate -openssl req -x509 -nodes -days 365 -newkey rsa:2048 -subj "/CN=${APPGW_APP1_URL}" -out appgw_std.crt -keyout appgw_std.key -openssl pkcs12 -export -out appgw_std.pfx -in appgw_std.crt -inkey appgw_std.key -passout pass:$PFX_PASSWORD -CERT_DATA_1=$(cat appgw_std.pfx | base64 | tr -d '\n' | tr -d '\r') -rm appgw_std.crt appgw_std.key appgw_std.pfx +#Suhas params - delete before commits +RGNAME=asev3-rg +RGLOCATION=westus3 +SQLADMINUSER=suadmin +SQLADMINPASSWORD=P@ssword1234 +JUMPBOX_USER=sujumpboxuser +JUMPBOX_PASSWORD=P@ssword1234 +az account set -n 'suhas-sub' -openssl req -x509 -nodes -days 365 -newkey rsa:2048 -subj "/CN=${APPGW_APP2_URL}" -out appgw_std.crt -keyout appgw_std.key -openssl pkcs12 -export -out appgw_std.pfx -in appgw_std.crt -inkey appgw_std.key -passout pass:$PFX_PASSWORD -CERT_DATA_2=$(cat appgw_std.pfx | base64 | tr -d '\n' | tr -d '\r') -rm appgw_std.crt appgw_std.key appgw_std.pfx # 1. creates the resource group az group create --name "${RGNAME}" --location "${RGLOCATION}" # 2. deploy global network related resources VNET_NAME=$(az network vnet list -g $RGNAME --query "[?contains(addressSpace.addressPrefixes, '${NET_PREFIX}')]" --query [0].name -o tsv) -az deployment group create --resource-group $RGNAME --template-file templates/network.json --parameters existentVnetName=$VNET_NAME vnetAddressPrefix=$NET_PREFIX +az deployment group create --resource-group $RGNAME --template-file templates/network.bicep --parameters existentVnetName=$VNET_NAME vnetAddressPrefix=$NET_PREFIX VNET_NAME=$(az deployment group show -g $RGNAME -n network --query properties.outputs.vnetName.value -o tsv) VNET_ROUTE_NAME=$(az deployment group show -g $RGNAME -n network --query properties.outputs.vnetRouteName.value -o tsv) # 3. deploy ASE -az deployment group create --resource-group $RGNAME --template-file templates/ase.json -n ase --parameters vnetName=$VNET_NAME vnetRouteName=$VNET_ROUTE_NAME aseSubnetAddressPrefix=$ASE_PREFIX +az deployment group create --resource-group $RGNAME --template-file templates/ase.bicep -n ase --parameters vnetName=$VNET_NAME vnetRouteName=$VNET_ROUTE_NAME aseSubnetAddressPrefix=$ASE_PREFIX ASE_DNS_SUFFIX=$(az deployment group show -g $RGNAME -n ase --query properties.outputs.dnsSuffix.value -o tsv) ASE_SUBNET_NAME=$(az deployment group show -g $RGNAME -n ase --query properties.outputs.aseSubnetName.value -o tsv) ASE_NAME=$(az deployment group show -g $RGNAME -n ase --query properties.outputs.aseName.value -o tsv) ASE_ID=$(az deployment group show -g $RGNAME -n ase --query properties.outputs.aseId.value -o tsv) -ASE_ILB_IP_ADDRESS=$(az resource show --ids ${ASE_ID}/capacities/virtualip --api-version 2018-02-01 --query internalIpAddress --output tsv) - -# Obtain ASE management IP endpoints -# This is equivalent to what is described in https://docs.microsoft.com/en-us/azure/app-service/environment/management-addresses#get-your-management-addresses-from-api but using az instead, and using JQ to parse the results. -ENDPOINTS_LIST=$(az rest --method get --uri $ASE_ID/inboundnetworkdependenciesendpoints?api-version=2016-09-01 | jq '.value[0].endpoints | join(", ")' -j) +ASE_ILB_IP_ADDRESS=$(az resource show --resource-group $RGNAME --name $ASE_NAME --resource-type "Microsoft.Web/hostingEnvironments" | jq -r '.properties.networkingConfiguration.internalInboundIpAddresses[]') +# 4. Deploy Firewall # Deploy AF -az deployment group create --resource-group $RGNAME --template-file templates/firewall.json \ - --parameters vnetName=$VNET_NAME firewallSubnetPrefix=$FIREWALL_PREFIX vnetRouteName=$VNET_ROUTE_NAME \ - aseManagementEndpointsList="$ENDPOINTS_LIST" +az deployment group create --resource-group $RGNAME --template-file templates/firewall.bicep --parameters vnetName=$VNET_NAME firewallSubnetPrefix=$FIREWALL_PREFIX + -# 4. deploy the private DNS zone -az deployment group create --resource-group $RGNAME --template-file templates/dns.json -n dns --parameters vnetName=$VNET_NAME zoneName=$ASE_DNS_SUFFIX ipAddress=$ASE_ILB_IP_ADDRESS +# 5. deploy the private DNS zone +az deployment group create --resource-group $RGNAME --template-file templates/dns.bicep -n dns --parameters vnetName=$VNET_NAME zoneName=$ASE_DNS_SUFFIX ipAddress=$ASE_ILB_IP_ADDRESS -# 5. deploy jumpbox -az deployment group create --resource-group $RGNAME --template-file templates/jumpbox.json --parameters vnetName=$VNET_NAME \ + +# 6. deploy jumpbox +az deployment group create --resource-group $RGNAME --template-file templates/jumpbox.bicep --parameters vnetName=$VNET_NAME \ subnetAddressPrefix=$JUMPBOX_PREFIX adminUsername=$JUMPBOX_USER adminPassword=$JUMPBOX_PASSWORD JUMPBOX_PUBLIC_IP=$(az deployment group show -g $RGNAME -n jumpbox --query properties.outputs.jumpboxPublicIpAddress.value -o tsv) JUMPBOX_SUBNET_NAME=$(az deployment group show -g $RGNAME -n jumpbox --query properties.outputs.jumpboxSubnetName.value -o tsv) -# 6. deploy services: cosmos, sql, servicebus and storage + +# 7. deploy services: cosmos, sql, servicebus and storage ALLOWED_SUBNET_NAMES=${ASE_SUBNET_NAME},${JUMPBOX_SUBNET_NAME} -az deployment group create --resource-group $RGNAME --template-file templates/services.json \ +az deployment group create --resource-group $RGNAME --template-file templates/services.bicep \ --parameters vnetName=$VNET_NAME allowedSubnetNames=$ALLOWED_SUBNET_NAMES \ sqlAdminUserName=$SQLADMINUSER sqlAdminPassword=$SQLADMINPASSWORD sqlAadAdminSid=$ADMIN_USER_ID COSMOSDB_NAME=$(az deployment group show -g $RGNAME -n services --query properties.outputs.cosmosDbName.value -o tsv) @@ -74,8 +78,8 @@ RESOURCES_CONTAINER_NAME=$(az deployment group show -g $RGNAME -n services --que az storage blob upload -c $RESOURCES_CONTAINER_NAME -f Microsoft_Azure_logo_small.png -n Microsoft_Azure_logo_small.png --account-name $RESOURCES_STORAGE_ACCOUNT RESOURCE_URL="$(az storage account show -n $RESOURCES_STORAGE_ACCOUNT --query primaryEndpoints.blob -o tsv)$RESOURCES_CONTAINER_NAME/Microsoft_Azure_logo_small.png" -# 7. deploy the application services inside the ASE -az deployment group create --resource-group $RGNAME --template-file templates/sites.json -n sites --parameters aseName=$ASE_NAME \ +# 8. Create the app service plans and the sites +az deployment group create --resource-group $RGNAME --template-file templates/sites.bicep -n sites --parameters aseName=$ASE_NAME \ vnetName=$VNET_NAME redisSubnetAddressPrefix=$REDIS_PREFIX cosmosDbName=$COSMOSDB_NAME \ sqlServerName=$SQL_SERVER sqlDatabaseName=$SQL_DATABASE keyVaultName=$KEYVAULT_NAME \ aseDnsSuffix=$ASE_DNS_SUFFIX @@ -87,86 +91,11 @@ VOTING_COUNTER_FUNCTION_PRINCIPAL_ID=$(az deployment group show -g $RGNAME -n si VOTING_API_NAME=$(az deployment group show -g $RGNAME -n sites --query properties.outputs.votingApiName.value -o tsv) && \ VOTING_API_PRINCIPAL_ID=$(az deployment group show -g $RGNAME -n sites --query properties.outputs.votingApiIdentityPrincipalId.value -o tsv) -# Deploy RBAC for resources after AAD propagation +# 9. Deploy RBAC for resources after AAD propagation until az ad sp show --id ${VOTING_WEB_APP_PRINCIPAL_ID} &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done until az ad sp show --id ${VOTING_API_PRINCIPAL_ID} &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done until az ad sp show --id ${VOTING_COUNTER_FUNCTION_PRINCIPAL_ID} &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done -az deployment group create --resource-group $RGNAME --template-file templates/rbac.json \ +az deployment group create --resource-group $RGNAME --template-file templates/rbac.bicep \ --parameters votingWebAppIdentityPrincipalId=$VOTING_WEB_APP_PRINCIPAL_ID votingCounterFunctionIdentityPrincipalId=$VOTING_COUNTER_FUNCTION_PRINCIPAL_ID \ keyVaultName=$KEYVAULT_NAME -# Generates parameters file for appgw arm script -cat < appgwApps.parameters.json -[ - { - "name": "votapp", - "hostName": "${APPGW_APP1_URL}", - "backendAddresses": [ - { - "fqdn": "${INTERNAL_APP1_URL}" - } - ], - "certificate": { - "data": "${CERT_DATA_1}", - "password": "${PFX_PASSWORD}" - }, - "probePath": "/health" - }, - { - "name": "testapp", - "hostName": "${APPGW_APP2_URL}", - "backendAddresses": [ - { - "fqdn": "${INTERNAL_APP2_URL}" - } - ], - "certificate": { - "data": "${CERT_DATA_2}", - "password": "${PFX_PASSWORD}" - }, - "probePath": "/" - } -] -EOF - -# 8. deploy the application gateway -az deployment group create --resource-group $RGNAME --template-file templates/appgw.json --parameters vnetName=$VNET_NAME appgwSubnetAddressPrefix=$APPGW_PREFIX appgwApplications=@appgwApps.parameters.json -APPGW_PUBLIC_IP=$(az deployment group show -g $RGNAME -n appgw --query properties.outputs.appGwPublicIpAddress.value -o tsv) - -# Removes autogenerated parameter file -rm appgwApps.parameters.json - - -cat << EOF - -NEXT STEPS ----- ----- - -To finish setting up the managed identities as users in the Sql Database run the following script authenticated as the AAD Admin for the database server -Instructions on create_sqlserver_msi_integration.md - -1) Please, go to azure portal in the resource group: ${RGNAME} and click on **Azure Cosmos Db Account** -a. then select **Firewall and virtual network**, there you can see: -**Add IP ranges to allow access from the internet or your on-premises networks**, so click on -**Add my current ip**, and finally save it. -b. then select **cacheContainer** then click on **Items**. Click on **New Item**. - -Replace the whole json payload with below content and click **Save** - -{"id": "1", "Message": "Powered by Azure", "MessageType": "AD", "Url": "${RESOURCE_URL}"} - -c. then select **Firewall and virtual network**, and delete your public IP - -2) Map the Azure Application Gateway public ip address to the voting and test application domain names. To do that, please open `C:\windows\system32\drivers\etc\hosts` and add the following records in local host file: - ${APPGW_PUBLIC_IP} ${APPGW_APP1_URL} - ${APPGW_PUBLIC_IP} ${APPGW_APP2_URL} - -> Note: domains names are sent as a http request header. This way Azure Application Gateway know how to route the requests appropriately. - -3) RDP to ${JUMPBOX_PUBLIC_IP} and the deploy the testing app using the readme instruction - prepare_jumpbox.md - compile_and_deploy.md - -4) Browse to https://${APPGW_APP1_URL} and https://${APPGW_APP2_URL} - -EOF diff --git a/deployment/deploy_ha.sh b/deployment/deploy_ha.sh deleted file mode 100644 index 1c96370..0000000 --- a/deployment/deploy_ha.sh +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/env bash - -# App url -APPGW_APP1_URL=votingapp-ha.contoso.com -APPGW_APP2_URL=testapp-ha.contoso.com - -# Zones -ZONE1=1 -ZONE2=3 - -# IP Addresses -NET_PREFIX=10.0.0.0/16 -APPGW_PREFIX=10.0.1.0/24 -REDIS1_PREFIX=10.0.11.0/24 -REDIS2_PREFIX=10.0.12.0/24 -ASE1_PREFIX=10.0.101.0/24 -ASE2_PREFIX=10.0.102.0/24 -FIREWALL_PREFIX=10.0.200.0/24 -JUMPBOX_PREFIX=10.0.250.0/24 - -# create self-signed SSL certificate -openssl req -x509 -nodes -days 365 -newkey rsa:2048 -subj "/CN=${APPGW_APP1_URL}" -out appgw_ha.crt -keyout appgw_ha.key -openssl pkcs12 -export -out appgw_ha.pfx -in appgw_ha.crt -inkey appgw_ha.key -passout pass:$PFX_PASSWORD -CERT_DATA_1=$(cat appgw_ha.pfx | base64 | tr -d '\n' | tr -d '\r') -rm appgw_ha.crt appgw_ha.key appgw_ha.pfx - -openssl req -x509 -nodes -days 365 -newkey rsa:2048 -subj "/CN=${APPGW_APP2_URL}" -out appgw_ha.crt -keyout appgw_ha.key -openssl pkcs12 -export -out appgw_ha.pfx -in appgw_ha.crt -inkey appgw_ha.key -passout pass:$PFX_PASSWORD -CERT_DATA_2=$(cat appgw_ha.pfx | base64 | tr -d '\n' | tr -d '\r') -rm appgw_ha.crt appgw_ha.key appgw_ha.pfx - -# 1. creates the resource group -az group create --name "${RGNAME}" --location "${RGLOCATION}" - -# 2. deploy global network related resources -VNET_NAME=$(az network vnet list -g $RGNAME --query "[?contains(addressSpace.addressPrefixes, '${NET_PREFIX}')]" --query [0].name -o tsv) -az deployment group create --resource-group $RGNAME --template-file templates/network.json --parameters existentVnetName=$VNET_NAME vnetAddressPrefix=$NET_PREFIX -VNET_NAME=$(az deployment group show -g $RGNAME -n network --query properties.outputs.vnetName.value -o tsv) -VNET_ROUTE_NAME=$(az deployment group show -g $RGNAME -n network --query properties.outputs.vnetRouteName.value -o tsv) - -# 3. deploy ASE - ZONE 1 & 2 -az deployment group create --resource-group $RGNAME --template-file templates/ase.json -n ase1 --parameters vnetName=$VNET_NAME vnetRouteName=$VNET_ROUTE_NAME aseSubnetAddressPrefix=$ASE1_PREFIX zone=$ZONE1 & -az deployment group create --resource-group $RGNAME --template-file templates/ase.json -n ase2 --parameters vnetName=$VNET_NAME vnetRouteName=$VNET_ROUTE_NAME aseSubnetAddressPrefix=$ASE2_PREFIX zone=$ZONE2 & -wait -ASE1_DNS_SUFFIX=$(az deployment group show -g $RGNAME -n ase1 --query properties.outputs.dnsSuffix.value -o tsv) -ASE1_SUBNET_NAME=$(az deployment group show -g $RGNAME -n ase1 --query properties.outputs.aseSubnetName.value -o tsv) -ASE1_NAME=$(az deployment group show -g $RGNAME -n ase1 --query properties.outputs.aseName.value -o tsv) -ASE1_ID=$(az deployment group show -g $RGNAME -n ase1 --query properties.outputs.aseId.value -o tsv) -ASE1_ILB_IP_ADDRESS=$(az resource show --ids ${ASE1_ID}/capacities/virtualip --api-version 2018-02-01 --query internalIpAddress --output tsv) -ASE2_DNS_SUFFIX=$(az deployment group show -g $RGNAME -n ase2 --query properties.outputs.dnsSuffix.value -o tsv) -ASE2_SUBNET_NAME=$(az deployment group show -g $RGNAME -n ase2 --query properties.outputs.aseSubnetName.value -o tsv) -ASE2_NAME=$(az deployment group show -g $RGNAME -n ase2 --query properties.outputs.aseName.value -o tsv) -ASE2_ID=$(az deployment group show -g $RGNAME -n ase2 --query properties.outputs.aseId.value -o tsv) -ASE2_ILB_IP_ADDRESS=$(az resource show --ids ${ASE2_ID}/capacities/virtualip --api-version 2018-02-01 --query internalIpAddress --output tsv) - -# Obtain ASE management IP endpoints -ENDPOINTS_LIST=$(az rest --method get --uri $ASE1_ID/inboundnetworkdependenciesendpoints?api-version=2016-09-01 | jq '.value[0].endpoints | join(", ")' -j) - -# Deploy AF -az deployment group create --resource-group $RGNAME --template-file templates/firewall.json \ - --parameters vnetName=$VNET_NAME firewallSubnetPrefix=$FIREWALL_PREFIX vnetRouteName=$VNET_ROUTE_NAME \ - aseManagementEndpointsList="$ENDPOINTS_LIST" - -# 4. deploy the private DNS zone - ZONE 1 & 2 -az deployment group create --resource-group $RGNAME --template-file templates/dns.json -n dns1 --parameters vnetName=$VNET_NAME zoneName=$ASE1_DNS_SUFFIX ipAddress=$ASE1_ILB_IP_ADDRESS & -az deployment group create --resource-group $RGNAME --template-file templates/dns.json -n dns2 --parameters vnetName=$VNET_NAME zoneName=$ASE2_DNS_SUFFIX ipAddress=$ASE2_ILB_IP_ADDRESS & -wait - -# 5. deploy jumpbox -az deployment group create --resource-group $RGNAME --template-file templates/jumpbox.json --parameters vnetName=$VNET_NAME \ - subnetAddressPrefix=$JUMPBOX_PREFIX adminUsername=$JUMPBOX_USER adminPassword=$JUMPBOX_PASSWORD -JUMPBOX_PUBLIC_IP=$(az deployment group show -g $RGNAME -n jumpbox --query properties.outputs.jumpboxPublicIpAddress.value -o tsv) -JUMPBOX_SUBNET_NAME=$(az deployment group show -g $RGNAME -n jumpbox --query properties.outputs.jumpboxSubnetName.value -o tsv) - -# 6. deploy services: cosmos, sql, servicebus and storage -ALLOWED_SUBNET_NAMES=${ASE1_SUBNET_NAME},${ASE2_SUBNET_NAME},${JUMPBOX_SUBNET_NAME} -az deployment group create --resource-group $RGNAME --template-file templates/services.json \ - --parameters vnetName=$VNET_NAME allowedSubnetNames=$ALLOWED_SUBNET_NAMES \ - sqlAdminUserName=$SQLADMINUSER sqlAdminPassword=$SQLADMINPASSWORD sqlAadAdminSid=$ADMIN_USER_ID \ - zoneRedundant="true" -COSMOSDB_NAME=$(az deployment group show -g $RGNAME -n services --query properties.outputs.cosmosDbName.value -o tsv) -SQL_SERVER=$(az deployment group show -g $RGNAME -n services --query properties.outputs.sqlServerName.value -o tsv) -SQL_DATABASE=$(az deployment group show -g $RGNAME -n services --query properties.outputs.sqlDatabaseName.value -o tsv) -KEYVAULT_NAME=$(az deployment group show -g $RGNAME -n services --query properties.outputs.keyVaultName.value -o tsv) -RESOURCES_STORAGE_ACCOUNT=$(az deployment group show -g $RGNAME -n services --query properties.outputs.resourcesStorageAccountName.value -o tsv) -RESOURCES_CONTAINER_NAME=$(az deployment group show -g $RGNAME -n services --query properties.outputs.resourcesContainerName.value -o tsv) - -# Uploads image to the storage account -az storage blob upload -c $RESOURCES_CONTAINER_NAME -f Microsoft_Azure_logo_small.png -n Microsoft_Azure_logo_small.png --account-name $RESOURCES_STORAGE_ACCOUNT -RESOURCE_URL="$(az storage account show -n $RESOURCES_STORAGE_ACCOUNT --query primaryEndpoints.blob -o tsv)$RESOURCES_CONTAINER_NAME/Microsoft_Azure_logo_small.png" - -# 7. deploy the application services inside the ASE - ZONE 1 & 2 -az deployment group create --resource-group $RGNAME --template-file templates/sites.json -n sites1 --parameters aseName=$ASE1_NAME \ - vnetName=$VNET_NAME redisSubnetAddressPrefix=$REDIS1_PREFIX cosmosDbName=$COSMOSDB_NAME \ - sqlServerName=$SQL_SERVER sqlDatabaseName=$SQL_DATABASE keyVaultName=$KEYVAULT_NAME \ - aseDnsSuffix=$ASE1_DNS_SUFFIX zone=$ZONE1 & -az deployment group create --resource-group $RGNAME --template-file templates/sites.json -n sites2 --parameters aseName=$ASE2_NAME \ - vnetName=$VNET_NAME redisSubnetAddressPrefix=$REDIS2_PREFIX cosmosDbName=$COSMOSDB_NAME \ - sqlServerName=$SQL_SERVER sqlDatabaseName=$SQL_DATABASE keyVaultName=$KEYVAULT_NAME \ - aseDnsSuffix=$ASE2_DNS_SUFFIX zone=$ZONE2 & -wait -INTERNAL_APP1_URL1=$(az deployment group show -g $RGNAME -n sites1 --query properties.outputs.votingAppUrl.value -o tsv) && \ -INTERNAL_APP1_URL2=$(az deployment group show -g $RGNAME -n sites2 --query properties.outputs.votingAppUrl.value -o tsv) && \ -INTERNAL_APP2_URL1=$(az deployment group show -g $RGNAME -n sites1 --query properties.outputs.testAppUrl.value -o tsv) && \ -INTERNAL_APP2_URL2=$(az deployment group show -g $RGNAME -n sites2 --query properties.outputs.testAppUrl.value -o tsv) && \ -VOTING_WEB_APP1_PRINCIPAL_ID=$(az deployment group show -g $RGNAME -n sites1 --query properties.outputs.votingWebAppIdentityPrincipalId.value -o tsv) && \ -VOTING_WEB_APP2_PRINCIPAL_ID=$(az deployment group show -g $RGNAME -n sites2 --query properties.outputs.votingWebAppIdentityPrincipalId.value -o tsv) && \ -VOTING_COUNTER_FUNCTION1_NAME=$(az deployment group show -g $RGNAME -n sites1 --query properties.outputs.votingFunctionName.value -o tsv) && \ -VOTING_COUNTER_FUNCTION2_NAME=$(az deployment group show -g $RGNAME -n sites2 --query properties.outputs.votingFunctionName.value -o tsv) && \ -VOTING_COUNTER_FUNCTION1_PRINCIPAL_ID=$(az deployment group show -g $RGNAME -n sites1 --query properties.outputs.votingCounterFunctionIdentityPrincipalId.value -o tsv) && \ -VOTING_COUNTER_FUNCTION2_PRINCIPAL_ID=$(az deployment group show -g $RGNAME -n sites2 --query properties.outputs.votingCounterFunctionIdentityPrincipalId.value -o tsv) && \ -VOTING_API1_NAME=$(az deployment group show -g $RGNAME -n sites1 --query properties.outputs.votingApiName.value -o tsv) && \ -VOTING_API2_NAME=$(az deployment group show -g $RGNAME -n sites2 --query properties.outputs.votingApiName.value -o tsv) && \ -VOTING_API1_PRINCIPAL_ID=$(az deployment group show -g $RGNAME -n sites1 --query properties.outputs.votingApiIdentityPrincipalId.value -o tsv) && \ -VOTING_API2_PRINCIPAL_ID=$(az deployment group show -g $RGNAME -n sites2 --query properties.outputs.votingApiIdentityPrincipalId.value -o tsv) - -# Deploy RBAC for resources after AAD propagation -until az ad sp show --id ${VOTING_WEB_APP1_PRINCIPAL_ID} &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done -until az ad sp show --id ${VOTING_WEB_APP2_PRINCIPAL_ID} &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done -until az ad sp show --id ${VOTING_API1_PRINCIPAL_ID} &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done -until az ad sp show --id ${VOTING_API2_PRINCIPAL_ID} &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done -until az ad sp show --id ${VOTING_COUNTER_FUNCTION1_PRINCIPAL_ID} &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done -until az ad sp show --id ${VOTING_COUNTER_FUNCTION2_PRINCIPAL_ID} &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done -az deployment group create --resource-group $RGNAME -n rbac1 --template-file templates/rbac.json \ - --parameters votingWebAppIdentityPrincipalId=$VOTING_WEB_APP1_PRINCIPAL_ID votingCounterFunctionIdentityPrincipalId=$VOTING_COUNTER_FUNCTION1_PRINCIPAL_ID \ - keyVaultName=$KEYVAULT_NAME & -az deployment group create --resource-group $RGNAME -n rbac2 --template-file templates/rbac.json \ - --parameters votingWebAppIdentityPrincipalId=$VOTING_WEB_APP2_PRINCIPAL_ID votingCounterFunctionIdentityPrincipalId=$VOTING_COUNTER_FUNCTION2_PRINCIPAL_ID \ - keyVaultName=$KEYVAULT_NAME & -wait - -# Generates parameters file for appgw arm script -cat < appgwApps.parameters.json -[ - { - "name": "votapp", - "hostName": "${APPGW_APP1_URL}", - "backendAddresses": [ - { - "fqdn": "${INTERNAL_APP1_URL1}" - }, - { - "fqdn": "${INTERNAL_APP1_URL2}" - } - ], - "certificate": { - "data": "${CERT_DATA_1}", - "password": "${PFX_PASSWORD}" - }, - "probePath": "/health" - }, - { - "name": "testapp", - "hostName": "${APPGW_APP2_URL}", - "backendAddresses": [ - { - "fqdn": "${INTERNAL_APP2_URL1}" - }, - { - "fqdn": "${INTERNAL_APP2_URL2}" - } - ], - "certificate": { - "data": "${CERT_DATA_2}", - "password": "${PFX_PASSWORD}" - }, - "probePath": "/" - } -] -EOF - -# 8. deploy the application gateway -ZONES=${ZONE1},${ZONE2} -az deployment group create --resource-group $RGNAME --template-file templates/appgw.json --parameters vnetName=$VNET_NAME appgwSubnetAddressPrefix=$APPGW_PREFIX \ - appgwApplications=@appgwApps.parameters.json appgwZones=$ZONES -APPGW_PUBLIC_IP=$(az deployment group show -g $RGNAME -n appgw --query properties.outputs.appGwPublicIpAddress.value -o tsv) - -# Removes autogenerated parameter file -rm appgwApps.parameters.json - - -cat << EOF - -NEXT STEPS ----- ----- - -To finish setting up the managed identities as users in the Sql Database run the following script authenticated as the AAD Admin for the database server -Instructions on create_sqlserver_msi_integration.md - -1) Please, go to azure portal in the resource group: ${RGNAME} and click on **Azure Cosmos Db Account** -a. then select **Firewall and virtual network**, there you can see: -**Add IP ranges to allow access from the internet or your on-premises networks**, so click on -**Add my current ip**, and finally save it. -b. then select **cacheContainer** then click on **Items**. Click on **New Item**. - -Replace the whole json payload with below content and click **Save** - -{"id": "1", "Message": "Powered by Azure", "MessageType": "AD", "Url": "${RESOURCE_URL}"} - -c. then select **Firewall and virtual network**, and delete your public IP - -2) Map the Azure Application Gateway public ip address to the voting and test application domain names. To do that, please open `C:\windows\system32\drivers\etc\hosts` and add the following records in local host file: - ${APPGW_PUBLIC_IP} ${APPGW_APP1_URL} - ${APPGW_PUBLIC_IP} ${APPGW_APP2_URL} - -> Note: domains names are sent as a http request header. This way Azure Application Gateway know how to route the requests appropriately. - -3) RDP to ${JUMPBOX_PUBLIC_IP} and the deploy the testing app using the readme instruction - prepare_jumpbox.md - compile_and_deploy.md - -4) Browse to https://${APPGW_APP1_URL} and https://${APPGW_APP2_URL} - -EOF diff --git a/deployment/templates/appgw.bicep b/deployment/templates/appgw.bicep new file mode 100644 index 0000000..40509e6 --- /dev/null +++ b/deployment/templates/appgw.bicep @@ -0,0 +1,240 @@ +@description('The location in which the resources should be deployed.') +param location string = resourceGroup().location + +@description('The vnet name where the gateway will be connected.') +param vnetName string + +@description('The ip address prefix that gateway will use.') +param appgwSubnetAddressPrefix string + +@description('List of applications to configure. Each element format is: { name, hostName, backendAddresses, certificate: { data, password }, probePath }') +param appgwApplications array + +@description('Comma separated application gateway zones.') +param appgwZones string = '' + +var appgwName_var = 'appgw' +//var appgwId = resourceId('',appgwName) +var appgwSubnetName = 'appgw-subnet-${appgwName_var}' +var appgwSubnetId = vnetName_appgwSubnetName.id +var appgwNSGName_var = '${vnetName}-APPGW-NSG' +var appgwPublicIpAddressName_var = 'AppGatewayIp' +var appGwPublicIpAddressId = appgwPublicIpAddressName.id +var appgwIpConfigName = '${appgwName_var}-ipconfig' +var appgwFrontendName = '${appgwName_var}-frontend' +var appgwBackendName = '${appgwName_var}-backend-' +var appgwHttpSettingsName = '${appgwName_var}-httpsettings-' +var appgwHealthProbeName = '${appgwName_var}-healthprobe-' +var appgwListenerName = '${appgwName_var}-listener-' +var appgwSslCertificateName = '${appgwName_var}-ssl-' +var appgwRouteRulesName = '${appgwName_var}-routerules-' +var appgwAutoScaleMinCapacity = 0 +var appgwAutoScaleMaxCapacity = 10 +var appgwZonesArray = (empty(appgwZones) ? json('null') : split(appgwZones, ',')) + +resource appgwPublicIpAddressName 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: appgwPublicIpAddressName_var + location: location + sku: { + name: 'Standard' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource appgwNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: appgwNSGName_var + location: location + tags: { + displayName: appgwNSGName_var + } + properties: { + securityRules: [ + { + name: 'APPGW-inbound-allow_infrastructure' + properties: { + description: 'Used to manage AppGW from Azure' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '65200-65535' + sourceAddressPrefix: 'GatewayManager' + destinationAddressPrefix: '*' + access: 'Allow' + priority: 200 + direction: 'Inbound' + } + } + { + name: 'APPGW-Inbound-load-balancer' + properties: { + description: 'Allow communication from Load Balancer' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: 'AzureLoadBalancer' + destinationAddressPrefix: '*' + access: 'Allow' + priority: 201 + direction: 'Inbound' + } + } + { + name: 'APPGW-inbound-allow_web' + properties: { + description: 'Allow web traffic from internet' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRanges: [ + '80' + '443' + ] + sourceAddressPrefix: 'Internet' + destinationAddressPrefix: appgwSubnetAddressPrefix + access: 'Allow' + priority: 202 + direction: 'Inbound' + } + } + ] + } +} + +resource vnetName_appgwSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + name: '${vnetName}/${appgwSubnetName}' + //location: location + properties: { + addressPrefix: appgwSubnetAddressPrefix + networkSecurityGroup: { id: appgwNSGName.id } + } +} + +resource appgwName 'Microsoft.Network/applicationGateways@2022-01-01' = { + name: appgwName_var + location: location + zones: appgwZonesArray + tags: { + } + properties: { + sku: { + name: 'WAF_v2' + tier: 'WAF_v2' + } + gatewayIPConfigurations: [ + { + name: appgwIpConfigName + properties: { + subnet: { + id: appgwSubnetId + } + } + } + ] + frontendIPConfigurations: [ + { + name: appgwFrontendName + properties: { + publicIPAddress: { + id: appGwPublicIpAddressId + } + } + } + ] + frontendPorts: [ + { + name: 'port_443' + properties: { + port: 443 + } + } + ] + autoscaleConfiguration: { + minCapacity: appgwAutoScaleMinCapacity + maxCapacity: appgwAutoScaleMaxCapacity + } + webApplicationFirewallConfiguration: { + enabled: true + firewallMode: 'Detection' + ruleSetType: 'OWASP' + ruleSetVersion: '3.0' + } + enableHttp2: false + backendAddressPools: [for item in appgwApplications: { + name: '${appgwBackendName}${item.name}' + properties: { + backendAddresses: item.backendAddresses + } + }] + backendHttpSettingsCollection: [for item in appgwApplications: { + name: '${appgwHttpSettingsName}${item.name}' + properties: { + port: 443 + protocol: 'Https' + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: true + requestTimeout: 20 + probe: { + id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/probes/${appgwHealthProbeName}${item.name}' + } + } + }] + httpListeners: [for item in appgwApplications: { + name: '${appgwListenerName}${item.name}' + properties: { + frontendIPConfiguration: { + id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/frontendIPConfigurations/${appgwFrontendName}' + } + frontendPort: { + id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/frontendPorts/port_443' + } + protocol: 'Https' + sslCertificate: { + id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/sslCertificates/${appgwSslCertificateName}${item.name}' + } + hostName: item.hostName + requireServerNameIndication: true + } + }] + requestRoutingRules: [for item in appgwApplications: { + name: '${appgwRouteRulesName}${item.name}' + properties: { + ruleType: 'Basic' + httpListener: { + id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/httpListeners/${appgwListenerName}${item.name}' + } + backendAddressPool: { + id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/backendAddressPools/${appgwBackendName}${item.name}' + } + backendHttpSettings: { + id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/backendHttpSettingsCollection/${appgwHttpSettingsName}${item.name}' + } + } + }] + probes: [for item in appgwApplications: { + name: '${appgwHealthProbeName}${item.name}' + properties: { + protocol: 'Https' + path: item.probePath + interval: 30 + timeout: 30 + unhealthyThreshold: 3 + pickHostNameFromBackendHttpSettings: true + minServers: 0 + match: { + statusCodes: [ + '200-399' + ] + } + } + }] + sslCertificates: [for item in appgwApplications: { + name: '${appgwSslCertificateName}${item.name}' + properties: { + data: item.certificate.data + password: item.certificate.password + } + }] + } +} + +output appGwPublicIpAddress string = appgwPublicIpAddressName.properties.ipAddress diff --git a/deployment/templates/appgw.json b/deployment/templates/appgw.json deleted file mode 100644 index d2723d5..0000000 --- a/deployment/templates/appgw.json +++ /dev/null @@ -1,312 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "The location in which the resources should be deployed." - } - }, - "vnetName": { - "type": "string", - "metadata": { - "description": "The vnet name where the gateway will be connected." - } - }, - "appgwSubnetAddressPrefix": { - "type": "string", - "metadata": { - "description": "The ip address prefix that gateway will use." - } - }, - "appgwApplications": { - "type": "array", - "metadata": { - "description": "List of applications to configure. Each element format is: { name, hostName, backendAddresses, certificate: { data, password }, probePath }" - } - }, - "appgwZones": { - "defaultValue": "", - "type": "string", - "metadata": { - "description": "Comma separated application gateway zones." - } - } - }, - "variables": { - "appgwName": "appgw", - "appgwId": "[resourceId('Microsoft.Network/applicationGateways', variables('appgwName'))]", - "appgwSubnetName": "[concat('appgw-subnet-', variables('appgwName'))]", - "appgwSubnetId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), variables('appgwSubnetName'))]", - "appgwNSGName": "[concat(parameters('vnetName'),'-APPGW-NSG')]", - "appgwPublicIpAddressName": "AppGatewayIp", - "appGwPublicIpAddressId": "[resourceId('Microsoft.Network/publicIPAddresses', variables('appgwPublicIpAddressName'))]", - "appgwIpConfigName": "[concat(variables('appgwName'), '-ipconfig')]", - "appgwFrontendName": "[concat(variables('appgwName'), '-frontend')]", - "appgwBackendName": "[concat(variables('appgwName'), '-backend-')]", - "appgwHttpSettingsName": "[concat(variables('appgwName'), '-httpsettings-')]", - "appgwHealthProbeName": "[concat(variables('appgwName'), '-healthprobe-')]", - "appgwListenerName": "[concat(variables('appgwName'), '-listener-')]", - "appgwSslCertificateName": "[concat(variables('appgwName'), '-ssl-')]", - "appgwRouteRulesName": "[concat(variables('appgwName'), '-routerules-')]", - "appgwAutoScaleMinCapacity": 0, - "appgwAutoScaleMaxCapacity": 10, - "appgwZonesArray": "[if(empty(parameters('appgwZones')),json('null'),split(parameters('appgwZones'), ','))]" - }, - "resources": [ - { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2019-11-01", - "name": "[variables('appgwPublicIpAddressName')]", - "location": "[parameters('location')]", - "sku": { - "name": "Standard" - }, - "properties": { - "publicIPAllocationMethod": "Static" - } - }, - - { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2019-11-01", - "name": "[variables('appgwNSGName')]", - "location": "[parameters('location')]", - "tags": { - "displayName": "[variables('appgwNSGName')]" - }, - "properties": { - "securityRules": [ - { - "name": "APPGW-inbound-allow_infrastructure", - "properties": { - "description": "Used to manage AppGW from Azure", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "65200-65535", - "sourceAddressPrefix": "GatewayManager", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 200, - "direction": "Inbound" - } - }, - { - "name": "APPGW-Inbound-load-balancer", - "properties": { - "description": "Allow communication from Load Balancer", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "*", - "sourceAddressPrefix": "AzureLoadBalancer", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 201, - "direction": "Inbound" - } - }, - { - "name": "APPGW-inbound-allow_web", - "properties": { - "description": "Allow web traffic from internet", - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRanges": [ - "80", - "443" - ], - "sourceAddressPrefix": "Internet", - "destinationAddressPrefix": "[parameters('appgwSubnetAddressPrefix')]", - "access": "Allow", - "priority": 202, - "direction": "Inbound" - } - } - ] - } - }, - - { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2019-11-01", - "name": "[concat(parameters('vnetName'), '/', variables('appgwSubnetName'))]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('appgwNSGName'))]" - ], - "properties": { - "addressPrefix": "[parameters('appgwSubnetAddressPrefix')]", - "networkSecurityGroup": { - "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('appgwNSGName'))]" - } - } - }, - - { - "type": "Microsoft.Network/applicationGateways", - "apiVersion": "2019-11-01", - "name": "[variables('appgwName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[variables('appgwSubnetId')]", - "[variables('appGwPublicIpAddressId')]" - ], - "zones": "[variables('appgwZonesArray')]", - "tags": {}, - "properties": { - "sku": { - "name": "WAF_v2", - "tier": "WAF_v2" - }, - "gatewayIPConfigurations": [ - { - "name": "[variables('appgwIpConfigName')]", - "properties": { - "subnet": { - "id": "[variables('appgwSubnetId')]" - } - } - } - ], - "frontendIPConfigurations": [ - { - "name": "[variables('appgwFrontendName')]", - "properties": { - "PublicIPAddress": { - "id": "[variables('appGwPublicIpAddressId')]" - } - } - } - ], - "frontendPorts": [ - { - "name": "port_443", - "properties": { - "Port": 443 - } - } - ], - "autoscaleConfiguration": { - "minCapacity": "[variables('appgwAutoScaleMinCapacity')]", - "maxCapacity": "[variables('appgwAutoScaleMaxCapacity')]" - }, - "webApplicationFirewallConfiguration": { - "enabled": true, - "firewallMode": "Detection", - "ruleSetType": "OWASP", - "ruleSetVersion": "3.0" - }, - "enableHttp2": false, - "copy": [ - { - "name": "backendAddressPools", - "count": "[length(parameters('appgwApplications'))]", - "input": { - "name": "[concat(variables('appgwBackendName'), parameters('appgwApplications')[copyIndex('backendAddressPools')].name)]", - "properties": { - "backendAddresses": "[parameters('appgwApplications')[copyIndex('backendAddressPools')].backendAddresses]" - } - } - }, - { - "name": "backendHttpSettingsCollection", - "count": "[length(parameters('appgwApplications'))]", - "input": { - "name": "[concat(variables('appgwHttpSettingsName'), parameters('appgwApplications')[copyIndex('backendHttpSettingsCollection')].name)]", - "properties": { - "Port": 443, - "Protocol": "Https", - "cookieBasedAffinity": "Disabled", - "pickHostNameFromBackendAddress": true, - "requestTimeout": 20, - "probe": { - "id": "[concat(variables('appgwId'), '/probes/', variables('appgwHealthProbeName'), parameters('appgwApplications')[copyIndex('backendHttpSettingsCollection')].name)]" - } - } - } - }, - { - "name": "httpListeners", - "count": "[length(parameters('appgwApplications'))]", - "input": { - "name": "[concat(variables('appgwListenerName'), parameters('appgwApplications')[copyIndex('httpListeners')].name)]", - "properties": { - "frontendIPConfiguration": { - "id": "[concat(variables('appgwId'), '/frontendIPConfigurations/', variables('appgwFrontendName'))]" - }, - "frontendPort": { - "id": "[concat(variables('appgwId'), '/frontendPorts/port_443')]" - }, - "protocol": "Https", - "sslCertificate": { - "id": "[concat(variables('appgwId'), '/sslCertificates/', variables('appgwSslCertificateName'), parameters('appgwApplications')[copyIndex('httpListeners')].name)]" - }, - "hostName": "[parameters('appgwApplications')[copyIndex('httpListeners')].hostName]", - "requireServerNameIndication": true - } - } - }, - { - "name": "requestRoutingRules", - "count": "[length(parameters('appgwApplications'))]", - "input": { - "Name": "[concat(variables('appgwRouteRulesName'), parameters('appgwApplications')[copyIndex('requestRoutingRules')].name)]", - "properties": { - "RuleType": "Basic", - "httpListener": { - "id": "[concat(variables('appgwId'), '/httpListeners/', variables('appgwListenerName'), parameters('appgwApplications')[copyIndex('requestRoutingRules')].name)]" - }, - "backendAddressPool": { - "id": "[concat(variables('appgwId'), '/backendAddressPools/', variables('appgwBackendName'), parameters('appgwApplications')[copyIndex('requestRoutingRules')].name)]" - }, - "backendHttpSettings": { - "id": "[concat(variables('appgwId'), '/backendHttpSettingsCollection/', variables('appgwHttpSettingsName'), parameters('appgwApplications')[copyIndex('requestRoutingRules')].name)]" - } - } - } - }, - { - "name": "probes", - "count": "[length(parameters('appgwApplications'))]", - "input": { - "name": "[concat(variables('appgwHealthProbeName'), parameters('appgwApplications')[copyIndex('probes')].name)]", - "properties": { - "protocol": "Https", - "path": "[parameters('appgwApplications')[copyIndex('probes')].probePath]", - "interval": 30, - "timeout": 30, - "unhealthyThreshold": 3, - "pickHostNameFromBackendHttpSettings": true, - "minServers": 0, - "match": { - "statusCodes": [ - "200-399" - ] - } - } - } - }, - { - "name": "sslCertificates", - "count": "[length(parameters('appgwApplications'))]", - "input": { - "name": "[concat(variables('appgwSslCertificateName'), parameters('appgwApplications')[copyIndex('sslCertificates')].name)]", - "properties": { - "data": "[parameters('appgwApplications')[copyIndex('sslCertificates')].certificate.data]", - "password": "[parameters('appgwApplications')[copyIndex('sslCertificates')].certificate.password]" - } - } - } - ] - } - } - ], - "outputs": { - "appGwPublicIpAddress": { - "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', variables('appgwPublicIpAddressName'))).ipAddress]", - "type": "string" - } - } -} diff --git a/deployment/templates/ase.bicep b/deployment/templates/ase.bicep new file mode 100644 index 0000000..d898edd --- /dev/null +++ b/deployment/templates/ase.bicep @@ -0,0 +1,61 @@ +@description('The location in which the resources should be deployed.') +param location string = resourceGroup().location + +@description('The vnet name where the ASE will be connected.') +param vnetName string + +@description('The vnet route name for ASE subnet.') +param vnetRouteName string + +@description('The ip address prefix that ASE will use.') +param aseSubnetAddressPrefix string + +@description('Required. Dedicated host count of ASEv3.') +param dedicatedHostCount int = 0 + +@description('Required. Zone redundant of ASEv3.') +param zoneRedundant bool = false + + +var aseName_var = 'ASE-${uniqueString(resourceGroup().id)}' +var aseId = aseName.id +var aseSubnetName = 'ase-subnet-${aseName_var}' +var aseSubnetId = vnetName_aseSubnetName.id +var aseLoadBalancingMode = 'Web, Publishing' + +resource vnetName_aseSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + name: '${vnetName}/${aseSubnetName}' + properties: { + addressPrefix: aseSubnetAddressPrefix + delegations: [ + { + name: 'Microsoft.Web.hostingEnvironments' + properties: { + serviceName: 'Microsoft.Web/hostingEnvironments' + } + } + ] + routeTable: { + id: resourceId('Microsoft.Network/routeTables', vnetRouteName) + } + } +} + +resource aseName 'Microsoft.Web/hostingEnvironments@2022-03-01' = { + name: aseName_var + location: location + kind: 'ASEV3' + properties: { + dedicatedHostCount: dedicatedHostCount + zoneRedundant: zoneRedundant + internalLoadBalancingMode: aseLoadBalancingMode + virtualNetwork: { + id: aseSubnetId + } + } +} + +output dnsSuffix string = reference(aseId).dnsSuffix +output aseId string = aseId +output aseSubnetName string = aseSubnetName +output aseName string = aseName_var diff --git a/deployment/templates/ase.json b/deployment/templates/ase.json deleted file mode 100644 index 50161bb..0000000 --- a/deployment/templates/ase.json +++ /dev/null @@ -1,334 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "location": { - "defaultValue": "[resourceGroup().location]", - "type": "string", - "metadata": { - "description": "The location in which the resources should be deployed." - } - }, - "vnetName": { - "type": "string", - "metadata": { - "description": "The vnet name where the ASE will be connected." - } - }, - "vnetRouteName": { - "type": "string", - "metadata": { - "description": "The vnet route name for ASE subnet." - } - }, - "aseSubnetAddressPrefix": { - "type": "string", - "metadata": { - "description": "The ip address prefix that ASE will use." - } - }, - "zone": { - "defaultValue": "", - "type": "string", - "metadata": { - "description": "The availability zone to deploy. Valid values are: 1, 2 or 3. Use empty to not use zones." - } - } - }, - "variables": { - "instanceIndex": "[if(empty(parameters('zone')),'0',parameters('zone'))]", - "aseName": "[concat('ASE-', uniqueString(resourceGroup().id), '-', variables('instanceIndex'))]", - "aseNSGName": "[concat(parameters('vnetName'),'-ASE-', variables('instanceIndex'), '-NSG')]", - "aseId": "[resourceId('Microsoft.Web/hostingEnvironments', variables('aseName'))]", - "aseSubnetName": "[concat('ase-subnet-', variables('aseName'))]", - "aseSubnetId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), variables('aseSubnetName'))]", - "aseLoadBalancingMode": 3 - }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2019-11-01", - "name": "[variables('aseNSGName')]", - "location": "[parameters('location')]", - "tags": { - "displayName": "[variables('aseNSGName')]" - }, - "properties": { - "securityRules": [ - { - "name": "ASE-internal-inbound", - "properties": { - "description": "ASE-internal-inbound", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "*", - "sourceAddressPrefix": "[parameters('aseSubnetAddressPrefix')]", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 200, - "direction": "Inbound" - } - }, - { - "name": "ASE-Inbound-management", - "properties": { - "description": "Used to manage ASE from public VIP", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "454-455", - "sourceAddressPrefix": "AppServiceManagement", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 210, - "direction": "Inbound" - } - }, - { - "name": "ASE-Inbound-load-balancer-keep-alive", - "properties": { - "description": "Allow communication to ASE from Load Balancer", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "16001", - "sourceAddressPrefix": "AzureLoadBalancer", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 211, - "direction": "Inbound" - } - }, - { - "name": "ASE-Inbound-HTTP_HTTPS", - "properties": { - "description": "Allow HTTP/HTTPS", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "80", - "443" - ], - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 212, - "direction": "Inbound" - } - }, - { - "name": "ASE-Inbound-FTP_FTPS", - "properties": { - "description": "Allow FTP and FTPS", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "21", - "990", - "10001-10020" - ], - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 213, - "direction": "Inbound" - } - }, - { - "name": "ASE-Inbound-Remote-Debugging", - "properties": { - "description": "Visual Studio remote debugging", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "4016-4022", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 214, - "direction": "Inbound" - } - }, - { - "name": "ASE-Inbound-Web-Deploy-Service", - "properties": { - "description": "Web deploy service", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "8172", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 215, - "direction": "Inbound" - } - }, - - { - "name": "ASE-internal-outbound", - "properties": { - "description": "ASE-internal-outbound", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "*", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "[parameters('aseSubnetAddressPrefix')]", - "access": "Allow", - "priority": 200, - "direction": "Outbound" - } - }, - { - "name": "ASE-Outbound-HTTP_HTTPS", - "properties": { - "description": "Allow HTTP and HTTPS traffic (needed to access storage)", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "80", - "443" - ], - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 210, - "direction": "Outbound" - } - }, - { - "name": "ASE-Outbound-DB", - "properties": { - "description": "Allow access to database", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "1433", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "Sql", - "access": "Allow", - "priority": 211, - "direction": "Outbound" - } - }, - { - "name": "ASE-Outbound-DNS", - "properties": { - "description": "Allow access to DNS", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "53", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 212, - "direction": "Outbound" - } - }, - { - "name": "ASE-Outbound-NTP", - "properties": { - "description": "Allow access to clock synchronization", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "123", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 213, - "direction": "Outbound" - } - } - ] - } - }, - { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2019-11-01", - "name": "[concat(parameters('vnetName'), '/', variables('aseSubnetName'))]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups/', variables('aseNSGName'))]" - ], - "properties": { - "addressPrefix": "[parameters('aseSubnetAddressPrefix')]", - "networkSecurityGroup": { - "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('aseNSGName'))]" - }, - "routeTable": { - "id": "[resourceId('Microsoft.Network/routeTables', parameters('vnetRouteName'))]" - }, - "serviceEndpoints": [ - { - "service": "Microsoft.AzureCosmosDB", - "locations": [ - "[resourceGroup().location]" - ] - }, - { - "service": "Microsoft.KeyVault", - "locations": [ - "[resourceGroup().location]" - ] - }, - { - "service": "Microsoft.ServiceBus", - "locations": [ - "[resourceGroup().location]" - ] - }, - { - "service": "Microsoft.Sql", - "locations": [ - "[resourceGroup().location]" - ] - }, - { - "service": "Microsoft.Storage", - "locations": [ - "[resourceGroup().location]" - ] - }, - { - "service": "Microsoft.EventHub", - "locations": [ - "[resourceGroup().location]" - ] - } - ] - } - }, - { - "type": "Microsoft.Web/hostingEnvironments", - "apiVersion": "2019-08-01", - "name": "[variables('aseName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[variables('aseSubnetId')]" - ], - "kind": "ASEV2", - "zones": "[if(empty(parameters('zone')),json('null'),array(parameters('zone')))]", - "properties": { - "name": "[variables('aseName')]", - "location": "[parameters('location')]", - "internalLoadBalancingMode": "[variables('aseLoadBalancingMode')]", - "virtualNetwork": { - "Id": "[variables('aseSubnetId')]" - } - } - } - ], - "outputs": { - "dnsSuffix": { - "value": "[reference(variables('aseId')).dnsSuffix]", - "type": "string" - }, - "aseId": { - "value": "[variables('aseId')]", - "type": "string" - }, - "aseSubnetName": { - "value": "[variables('aseSubnetName')]", - "type": "string" - }, - "aseName": { - "value": "[variables('aseName')]", - "type": "string" - } - } -} diff --git a/deployment/templates/dns.bicep b/deployment/templates/dns.bicep new file mode 100644 index 0000000..abdba71 --- /dev/null +++ b/deployment/templates/dns.bicep @@ -0,0 +1,67 @@ +@description('The vnet name of the ASE vnet.') +param vnetName string + +@description('The name of the zone. Must match the DNS prefix of the ILB ASE.') +param zoneName string + +@description('The IP address of the ILB.') +param ipAddress string + +var vnetId = resourceId('Microsoft.Network/virtualNetworks', vnetName) + +resource zoneName_resource 'Microsoft.Network/privateDnsZones@2018-09-01' = { + name: zoneName + location: 'global' + properties: { } +} + +resource Microsoft_Network_privateDnsZones_A_record1 'Microsoft.Network/privateDnsZones/A@2018-09-01' = { + parent: zoneName_resource + name: '@' + properties: { + ttl: 3600 + aRecords: [ + { + ipv4Address: ipAddress + } + ] + } +} + +resource Microsoft_Network_privateDnsZones_A_record2 'Microsoft.Network/privateDnsZones/A@2018-09-01' = { + parent: zoneName_resource + name: '*' + properties: { + ttl: 3600 + aRecords: [ + { + ipv4Address: ipAddress + } + ] + } +} + +resource Microsoft_Network_privateDnsZones_A_record3 'Microsoft.Network/privateDnsZones/A@2020-06-01' = { + parent: zoneName_resource + name: '*.scm' + properties: { + ttl: 3600 + aRecords: [ + { + ipv4Address: ipAddress + } + ] + } +} + +resource zoneName_dns_to_vnet_link 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = { + parent: zoneName_resource + name: 'dns-to-vnet-link' + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: vnetId + } + } +} diff --git a/deployment/templates/dns.json b/deployment/templates/dns.json deleted file mode 100644 index 06f79b9..0000000 --- a/deployment/templates/dns.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "vnetName": { - "type": "string", - "metadata": { - "description": "The vnet name of the ASE vnet." - } - }, - "zoneName": { - "type": "string", - "metadata": { - "description": "The name of the zone. Must match the DNS prefix of the ILB ASE." - } - }, - "ipAddress": { - "type": "string", - "metadata": { - "description": "The IP address of the ILB." - } - } - }, - "variables": { - "vnetId": "[resourceId('Microsoft.Network/virtualNetworks', parameters('vnetName'))]" - }, - "resources": [ - { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2018-09-01", - "name": "[parameters('zoneName')]", - "location": "global", - "resources": [ - { - "type": "A", - "apiVersion": "2018-09-01", - "name": "*", - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', parameters('zoneName'))]" - ], - "properties": { - "ttl": 3600, - "aRecords": [ - { - "ipv4Address": "[parameters('ipAddress')]" - } - ] - } - }, - { - "type": "A", - "apiVersion": "2018-09-01", - "name": "@", - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', parameters('zoneName'))]" - ], - "properties": { - "ttl": 3600, - "aRecords": [ - { - "ipv4Address": "[parameters('ipAddress')]" - } - ] - } - }, - { - "type": "A", - "apiVersion": "2018-09-01", - "name": "*.scm", - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', parameters('zoneName'))]" - ], - "properties": { - "ttl": 3600, - "aRecords": [ - { - "ipv4Address": "[parameters('ipAddress')]" - } - ] - } - } - ] - }, - { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2018-09-01", - "name": "[concat(parameters('zoneName'), '/dns-to-vnet-link')]", - "location": "global", - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', parameters('zoneName'))]" - ], - "properties": { - "registrationEnabled": false, - "virtualNetwork": { - "id": "[variables('vnetId')]" - } - } - } - ], - "outputs": {} -} \ No newline at end of file diff --git a/deployment/templates/firewall.bicep b/deployment/templates/firewall.bicep new file mode 100644 index 0000000..9624f56 --- /dev/null +++ b/deployment/templates/firewall.bicep @@ -0,0 +1,198 @@ +@description('The location in which the resources should be deployed.') +param location string = resourceGroup().location +param vnetName string + +@description('The ip prefix the firewall will use.') +param firewallSubnetPrefix string + +var firewallSubnetName = 'AzureFirewallSubnet' +var firewallPublicIpName_var = 'firewallIp-${uniqueString(resourceGroup().id)}' +var firewallName_var = 'firewall-${uniqueString(resourceGroup().id)}' + +/*resource vnetRouteName_resource 'Microsoft.Network/routeTables@2019-11-01' = { + name: vnetRouteName + location: location + tags: { + displayName: 'UDR - Subnet' + } + properties: { + routes: concat(aseManagementIpRoutes, array(json('{ "name": "Firewall", "properties": { "addressPrefix": "0.0.0.0/0", "nextHopType": "VirtualAppliance", "nextHopIpAddress": "${reference('Microsoft.Network/azureFirewalls/${firewallName_var}', '2019-09-01', 'Full').properties.ipConfigurations[0].properties.privateIPAddress}" } }'))) + } + dependsOn: [ + firewallName + ] +} + +*/ + +resource vnetName_firewallSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + name: '${vnetName}/${firewallSubnetName}' + properties: { + addressPrefix: firewallSubnetPrefix + serviceEndpoints: [ + { + service: 'Microsoft.AzureCosmosDB' + locations: [ + location + ] + } + { + service: 'Microsoft.KeyVault' + locations: [ + location + ] + } + { + service: 'Microsoft.ServiceBus' + locations: [ + location + ] + } + { + service: 'Microsoft.Sql' + locations: [ + location + ] + } + ] + } +} + +resource firewallPublicIpName 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + location: location + name: firewallPublicIpName_var + sku: { + name: 'Standard' + } + properties: { + publicIPAddressVersion: 'IPv4' + publicIPAllocationMethod: 'Static' + idleTimeoutInMinutes: 4 + } +} + +resource firewallName 'Microsoft.Network/azureFirewalls@2022-01-01' = { + name: firewallName_var + location: location + properties: { + threatIntelMode: 'Alert' + ipConfigurations: [ + { + name: 'clusterIpConfig' + properties: { + publicIPAddress: { + id: firewallPublicIpName.id + } + subnet: { + id: vnetName_firewallSubnetName.id + } + } + } + ] + networkRuleCollections: [ + { + name: 'Time' + properties: { + priority: 300 + action: { + type: 'Allow' + } + rules: [ + { + name: 'NTP' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + destinationAddresses: [ + '*' + ] + destinationPorts: [ + '123' + ] + } + { + name: 'Triage' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + destinationAddresses: [ + '*' + ] + destinationPorts: [ + '12000' + ] + } + ] + } + } + { + name: 'AzureMonitor' + properties: { + priority: 500 + action: { + type: 'Allow' + } + rules: [ + { + name: 'AzureMonitor' + protocols: [ + 'TCP' + ] + sourceAddresses: [ + '*' + ] + destinationAddresses: [ + 'AzureMonitor' + ] + destinationPorts: [ + '80' + '443' + ] + } + ] + } + } + ] + applicationRuleCollections: [ + { + name: 'AppServiceEnvironment' + properties: { + priority: 500 + action: { + type: 'Allow' + } + rules: [ + { + name: 'AppServiceEnvironment' + protocols: [ + { + protocolType: 'Http' + port: 80 + } + { + protocolType: 'Https' + port: 443 + } + ] + fqdnTags: [ + 'AppServiceEnvironment' + 'WindowsUpdate' + ] + sourceAddresses: [ + '*' + ] + } + ] + } + } + ] + } +} + +output firewallSubnetName string = firewallSubnetName diff --git a/deployment/templates/firewall.json b/deployment/templates/firewall.json deleted file mode 100644 index c05856e..0000000 --- a/deployment/templates/firewall.json +++ /dev/null @@ -1,254 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "location": { - "defaultValue": "[resourceGroup().location]", - "type": "string", - "metadata": { - "description": "The location in which the resources should be deployed." - } - }, - "vnetName": { - "type": "string" - }, - "firewallSubnetPrefix": { - "type": "string", - "metadata": { - "description": "The ip prefix the firewall will use." - } - }, - "vnetRouteName": { - "type": "string", - "metadata": { - "description": "The name of the route table associated to the ASE subnets" - } - }, - "aseManagementEndpointsList": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The list of ASE management endpoints expressed as IP ranges" - } - } - }, - "variables": { - "firewallSubnetName": "AzureFirewallSubnet", - "firewallPublicIpName": "[concat('firewallIp', '-', uniqueString(resourceGroup().id))]", - "firewallName": "[concat('firewall', '-', uniqueString(resourceGroup().id))]", - "aseManagementEndpoints": "[split(replace(parameters('aseManagementEndpointsList') ,' ', ''), ',')]", - "copy": [ - { - "name": "aseManagementIpRoutes", - "count": "[length(variables('aseManagementEndpoints'))]", - "input": { - "name": "[replace(variables('aseManagementEndpoints')[copyIndex('aseManagementIpRoutes')], '/', '-')]", - "properties": { - "addressPrefix": "[variables('aseManagementEndpoints')[copyIndex('aseManagementIpRoutes')]]", - "nextHopType": "Internet" - } - } - } - ] - }, - "resources": [ - { - "type": "Microsoft.Network/routeTables", - "apiVersion": "2019-11-01", - "name": "[parameters('vnetRouteName')]", - "location": "[parameters('location')]", - "tags": { - "displayName": "UDR - Subnet" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/azureFirewalls', variables('firewallName'))]" - ], - "properties": { - "routes": "[concat(variables('aseManagementIpRoutes'), array(json(concat('{ \"name\": \"Firewall\", \"properties\": { \"addressPrefix\": \"0.0.0.0/0\", \"nextHopType\": \"VirtualAppliance\", \"nextHopIpAddress\": \"', reference(concat('Microsoft.Network/azureFirewalls/', variables('firewallName')),'2019-09-01','Full').properties.ipConfigurations[0].properties.privateIPAddress, '\" } }'))))]" - } - }, - { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2019-11-01", - "name": "[concat(parameters('vnetName'), '/', variables('firewallSubnetName'))]", - "properties": { - "addressPrefix": "[parameters('firewallSubnetPrefix')]", - "serviceEndpoints": [ - { - "service": "Microsoft.AzureCosmosDB", - "locations": [ - "[parameters('location')]" - ] - }, - { - "service": "Microsoft.KeyVault", - "locations": [ - "[parameters('location')]" - ] - }, - { - "service": "Microsoft.ServiceBus", - "locations": [ - "[parameters('location')]" - ] - }, - { - "service": "Microsoft.Sql", - "locations": [ - "[parameters('location')]" - ] - } - ] - } - }, - { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2019-09-01", - "location": "[parameters('location')]", - "name": "[variables('firewallPublicIpName')]", - "sku": { - "name": "Standard" - }, - "properties": { - "publicIPAddressVersion": "IPv4", - "publicIPAllocationMethod": "Static", - "idleTimeoutInMinutes": 4 - } - }, - { - "type": "Microsoft.Network/azureFirewalls", - "apiVersion": "2019-09-01", - "name": "[variables('firewallName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Network/publicIPAddresses', variables('firewallPublicIpName'))]", - "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), variables('firewallSubnetName'))]" - ], - "properties": { - "threatIntelMode": "Alert", - "ipConfigurations": [ - { - "name": "clusterIpConfig", - "properties": { - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('firewallPublicIpName'))]" - }, - "subnet": { - "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), variables('firewallSubnetName'))]" - } - } - } - ], - "networkRuleCollections": [ - { - "name": "Time", - "properties": { - "priority": 300, - "action": { - "type": "Allow" - }, - "rules": [ - { - "name": "NTP", - "protocols": [ - "Any" - ], - "sourceAddresses": [ - "*" - ], - "destinationAddresses": [ - "*" - ], - "destinationPorts": [ - "123" - ] - }, - { - "name": "Triage", - "protocols": [ - "Any" - ], - "sourceAddresses": [ - "*" - ], - "destinationAddresses": [ - "*" - ], - "destinationPorts": [ - "12000" - ] - } - ] - } - }, - { - "name": "AzureMonitor", - "properties": { - "priority": 500, - "action": { - "type": "Allow" - }, - "rules": [ - { - "name": "AzureMonitor", - "protocols": [ - "TCP" - ], - "sourceAddresses": [ - "*" - ], - "destinationAddresses": [ - "AzureMonitor" - ], - "destinationPorts": [ - "80", - "443" - ] - } - ] - } - } - ], - "applicationRuleCollections": [ - { - "name": "AppServiceEnvironment", - "properties": { - "priority": 500, - "action": { - "type": "Allow" - }, - "rules": [ - { - "name": "AppServiceEnvironment", - "protocols": [ - { - "protocolType": "Http", - "port": 80 - }, - { - "protocolType": "Https", - "port": 443 - } - ], - "fqdnTags": [ - "AppServiceEnvironment", - "WindowsUpdate" - ], - "sourceAddresses": [ - "*" - ] - } - ] - } - } - ] - } - } - ], - "outputs": { - "firewallSubnetName": { - "value": "[variables('firewallSubnetName')]", - "type": "string" - } - } -} \ No newline at end of file diff --git a/deployment/templates/jumpbox.bicep b/deployment/templates/jumpbox.bicep new file mode 100644 index 0000000..931eee8 --- /dev/null +++ b/deployment/templates/jumpbox.bicep @@ -0,0 +1,138 @@ +@description('The location in which the resources should be deployed.') +param location string = resourceGroup().location + +@description('The vnet name where the jumpbox will be connected.') +param vnetName string + +@description('The ip address prefix that jumpbox subnet will use.') +param subnetAddressPrefix string + +@description('The admin user name.') +param adminUsername string + +@description('The admin password.') +@secure() +param adminPassword string + +var computerName = 'votingjb' +var jumpboxName_var = 'jumpbox-${computerName}${uniqueString(resourceGroup().id)}' +var jumpboxSubnetName = 'jumpbox-subnet-${uniqueString(resourceGroup().id)}' +var jumpboxSubnetId = vnetName_jumpboxSubnetName.id +var jumpboxPublicIpName_var = 'jumpbox-pip-${uniqueString(resourceGroup().id)}' +var jumpboxNSGName_var = '${vnetName}-JUMPBOX-NSG' +var jumpboxNicName_var = 'jumpbox-nic-${uniqueString(resourceGroup().id)}' + +resource jumpboxPublicIpName 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: jumpboxPublicIpName_var + location: location + properties: { + publicIPAllocationMethod: 'Static' + } + sku: { + name: 'Standard' + } +} + +resource jumpboxNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: jumpboxNSGName_var + location: location + tags: { + displayName: jumpboxNSGName_var + } + properties: { + securityRules: [ + { + name: 'JUMPBOX-inbound-allow_RDP' + properties: { + description: 'Allow Inbound-JumpBoxRDP' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '3389' + sourceAddressPrefix: '*' + destinationAddressPrefix: subnetAddressPrefix + access: 'Allow' + priority: 100 + direction: 'Inbound' + } + } + ] + } +} + +resource vnetName_jumpboxSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + name: '${vnetName}/${jumpboxSubnetName}' + properties: { + addressPrefix: subnetAddressPrefix + networkSecurityGroup: { + id: jumpboxNSGName.id + } + } +} + +resource jumpboxNicName 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: jumpboxNicName_var + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: jumpboxSubnetId + } + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: resourceId(resourceGroup().name, 'Microsoft.Network/publicIpAddresses', jumpboxPublicIpName_var) + } + } + } + ] + } +} + +resource jumpboxName 'Microsoft.Compute/virtualMachines@2019-07-01' = { + name: jumpboxName_var + location: location + properties: { + hardwareProfile: { + vmSize: 'Standard_DS2_v2' + } + storageProfile: { + osDisk: { + createOption: 'fromImage' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2019-Datacenter-smalldisk' + version: 'latest' + } + dataDisks: [ + { + diskSizeGB: 512 + lun: 0 + createOption: 'Empty' + } + ] + } + networkProfile: { + networkInterfaces: [ + { + id: jumpboxNicName.id + } + ] + } + osProfile: { + computerName: computerName + adminUsername: adminUsername + adminPassword: adminPassword + } + } +} + +output jumpboxName string = jumpboxName_var +output jumpboxSubnetName string = jumpboxSubnetName +output jumpboxPublicIpAddress string = jumpboxPublicIpName.properties.ipAddress diff --git a/deployment/templates/jumpbox.json b/deployment/templates/jumpbox.json deleted file mode 100644 index 3b20c8a..0000000 --- a/deployment/templates/jumpbox.json +++ /dev/null @@ -1,215 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "location": { - "defaultValue": "[resourceGroup().location]", - "type": "string", - "metadata": { - "description": "The location in which the resources should be deployed." - } - }, - "vnetName": { - "type": "string", - "metadata": { - "description": "The vnet name where the jumpbox will be connected." - } - }, - "subnetAddressPrefix": { - "type": "string", - "metadata": { - "description": "The ip address prefix that jumpbox subnet will use." - } - }, - "adminUsername": { - "type": "string", - "metadata": { - "description": "The admin user name." - } - }, - "adminPassword": { - "type": "secureString", - "metadata": { - "description": "The admin password." - } - } - }, - "variables": { - "computerName": "votingjb", - "jumpboxName": "[concat('jumpbox-', variables('computerName'), uniqueString(resourceGroup().id))]", - "jumpboxSubnetName": "[concat('jumpbox-subnet-', uniqueString(resourceGroup().id))]", - "jumpboxSubnetId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), variables('jumpboxSubnetName'))]", - "jumpboxPublicIpName": "[concat('jumpbox-pip-', uniqueString(resourceGroup().id))]", - "jumpboxNSGName": "[concat(parameters('vnetName'),'-JUMPBOX-NSG')]", - "jumpboxNicName": "[concat('jumpbox-nic-', uniqueString(resourceGroup().id))]" - }, - "resources": [ - { - "type": "Microsoft.Network/publicIpAddresses", - "apiVersion": "2019-11-01", - "name": "[variables('jumpboxPublicIpName')]", - "location": "[parameters('location')]", - "properties": { - "publicIpAllocationMethod": "Static" - }, - "sku": { - "name": "Standard" - } - }, - { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2019-11-01", - "name": "[variables('jumpboxNSGName')]", - "location": "[parameters('location')]", - "tags": { - "displayName": "[variables('jumpboxNSGName')]" - }, - "properties": { - "securityRules": [ - { - "name": "JUMPBOX-inbound-allow_RDP", - "properties": { - "description": "Allow Inbound-JumpBoxRDP", - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRange": "3389", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "[parameters('subnetAddressPrefix')]", - "access": "Allow", - "priority": 100, - "direction": "Inbound" - } - } - ] - } - }, - { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2019-11-01", - "name": "[concat(parameters('vnetName'), '/', variables('jumpboxSubnetName'))]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('jumpboxNSGName'))]" - ], - "properties": { - "addressPrefix": "[parameters('subnetAddressPrefix')]", - "networkSecurityGroup": { - "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('jumpboxNSGName'))]" - }, - "serviceEndpoints": [ - { - "service": "Microsoft.AzureCosmosDB", - "locations": [ - "[resourceGroup().location]" - ] - }, - { - "service": "Microsoft.KeyVault", - "locations": [ - "[resourceGroup().location]" - ] - }, - { - "service": "Microsoft.ServiceBus", - "locations": [ - "[resourceGroup().location]" - ] - }, - { - "service": "Microsoft.Sql", - "locations": [ - "[resourceGroup().location]" - ] - } - ] - } - }, - { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2019-11-01", - "name": "[variables('jumpboxNicName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[variables('jumpboxSubnetId')]", - "[concat('Microsoft.Network/publicIpAddresses/', variables('jumpboxPublicIpName'))]" - ], - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "subnet": { - "id": "[variables('jumpboxSubnetId')]" - }, - "privateIPAllocationMethod": "Dynamic", - "publicIpAddress": { - "id": "[resourceId(resourceGroup().name, 'Microsoft.Network/publicIpAddresses', variables('jumpboxPublicIpName'))]" - } - } - } - ] - } - }, - { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2019-07-01", - "name": "[variables('jumpboxName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', variables('jumpboxNicName'))]" - ], - "properties": { - "hardwareProfile": { - "vmSize": "Standard_DS2_v2" - }, - "storageProfile": { - "osDisk": { - "createOption": "fromImage", - "managedDisk": { - "storageAccountType": "Premium_LRS" - } - }, - "imageReference": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2019-Datacenter-smalldisk", - "version": "latest" - }, - "dataDisks": [ - { - "diskSizeGB": 512, - "lun": 0, - "createOption": "Empty" - } - ] - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('jumpboxNicName'))]" - } - ] - }, - "osProfile": { - "computerName": "[variables('computerName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]" - } - } - } - ], - "outputs": { - "jumpboxName": { - "type": "string", - "value": "[variables('jumpboxName')]" - }, - "jumpboxSubnetName": { - "value": "[variables('jumpboxSubnetName')]", - "type": "string" - }, - "jumpboxPublicIpAddress": { - "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', variables('jumpboxPublicIpName'))).ipAddress]", - "type": "string" - } - } -} diff --git a/deployment/templates/network.bicep b/deployment/templates/network.bicep new file mode 100644 index 0000000..fc8c6aa --- /dev/null +++ b/deployment/templates/network.bicep @@ -0,0 +1,49 @@ +@description('The location in which the resources should be deployed.') +param location string = resourceGroup().location + +@description('The IP address prefix the network will use.') +param vnetAddressPrefix string + +@description('The name of the vnet to use. Leave empty to create a new vnet.') +param existentVnetName string = '' + +var mustCreateVNet = empty(existentVnetName) +var vnetName = (empty(existentVnetName) ? 'ASE-VNET${uniqueString(resourceGroup().id)}' : existentVnetName) +var vnetRouteName = 'ASE-VNETRT${uniqueString(resourceGroup().id)}' + +resource vnet 'Microsoft.Network/virtualNetworks@2022-01-01' = if (mustCreateVNet) { + name: vnetName + location: location + tags: { + displayName: 'ASE-VNET' + } + properties: { + addressSpace: { + addressPrefixes: [ + vnetAddressPrefix + ] + } + } +} + +resource vnetRoute 'Microsoft.Network/routeTables@2022-01-01' = { + name: vnetRouteName + location: location + tags: { + displayName: 'UDR - Subnet' + } + properties: { + routes: [ + { + name: '${vnetRouteName}-route' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + } +} + +output vnetName string = vnet.name +output vnetRouteName string = vnetRoute.name diff --git a/deployment/templates/network.json b/deployment/templates/network.json deleted file mode 100644 index 4166fe7..0000000 --- a/deployment/templates/network.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "location": { - "defaultValue": "[resourceGroup().location]", - "type": "string", - "metadata": { - "description": "The location in which the resources should be deployed." - } - }, - "vnetAddressPrefix": { - "type": "string", - "metadata": { - "description": "The IP address prefix the network will use." - } - }, - "existentVnetName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The name of the vnet to use. Leave empty to create a new vnet." - } - } - }, - "variables": { - "mustCreateVNet": "[empty(parameters('existentVnetName'))]", - "vnetName": "[if(empty(parameters('existentVnetName')),concat('ASE-VNET', uniqueString(resourceGroup().id)),parameters('existentVnetName'))]", - "vnetRouteName": "[concat('ASE-VNETRT', uniqueString(resourceGroup().id))]" - }, - "resources": [ - { - "condition": "[variables('mustCreateVNet')]", - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2019-11-01", - "name": "[variables('vnetName')]", - "location": "[parameters('location')]", - "tags": { - "displayName": "ASE-VNET" - }, - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[parameters('vnetAddressPrefix')]" - ] - } - } - }, - { - "type": "Microsoft.Network/routeTables", - "apiVersion": "2019-11-01", - "name": "[variables('vnetRouteName')]", - "location": "[parameters('location')]", - "tags": { - "displayName": "UDR - Subnet" - }, - "properties": { - "routes": [ - { - "name": "[concat(variables('vnetRouteName'), '-route')]", - "properties": { - "addressPrefix": "0.0.0.0/0", - "nextHopType": "Internet" - } - } - ] - } - } - ], - "outputs": { - "vnetName": { - "value": "[variables('vnetName')]", - "type": "string" - }, - "vnetRouteName": { - "value": "[variables('vnetRouteName')]", - "type": "string" - } - } -} diff --git a/deployment/templates/rbac.bicep b/deployment/templates/rbac.bicep new file mode 100644 index 0000000..11123a5 --- /dev/null +++ b/deployment/templates/rbac.bicep @@ -0,0 +1,33 @@ +param votingWebAppIdentityPrincipalId string +param votingCounterFunctionIdentityPrincipalId string +param keyVaultName string + +resource keyVaultName_add 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { + name: '${keyVaultName}/add' + properties: { + accessPolicies: [ + { + tenantId: subscription().tenantId + objectId: votingWebAppIdentityPrincipalId + permissions: { + keys: [] + secrets: [ + 'Get' + ] + certificates: [] + } + } + { + tenantId: subscription().tenantId + objectId: votingCounterFunctionIdentityPrincipalId + permissions: { + keys: [] + secrets: [ + 'Get' + ] + certificates: [] + } + } + ] + } +} diff --git a/deployment/templates/rbac.json b/deployment/templates/rbac.json deleted file mode 100644 index c9800c9..0000000 --- a/deployment/templates/rbac.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "votingWebAppIdentityPrincipalId": { - "type": "string" - }, - "votingCounterFunctionIdentityPrincipalId": { - "type": "string" - }, - "keyVaultName": { - "type": "string" - } - }, - "variables": { - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/accessPolicies", - "name": "[concat(parameters('keyVaultName'), '/add')]", - "apiVersion": "2018-02-14", - "properties": { - "accessPolicies": [ - { - "tenantId": "[subscription().tenantId]", - "objectId": "[parameters('votingWebAppIdentityPrincipalId')]", - "permissions": { - "keys": [], - "secrets": [ - "Get" - ], - "certificates": [ - ] - } - }, - { - "tenantId": "[subscription().tenantId]", - "objectId": "[parameters('votingCounterFunctionIdentityPrincipalId')]", - "permissions": { - "keys": [], - "secrets": [ - "Get" - ], - "certificates": [ - ] - } - } - ] - } - } - ] -} \ No newline at end of file diff --git a/deployment/templates/services.bicep b/deployment/templates/services.bicep new file mode 100644 index 0000000..835c2e9 --- /dev/null +++ b/deployment/templates/services.bicep @@ -0,0 +1,293 @@ +@description('The location in which the resources should be deployed.') +param location string = resourceGroup().location + +@description('The vnet name where the gateway will be connected.') +param vnetName string + +@description('The name for the sql server admin user.') +param sqlAdminUserName string + +@description('The password for the sql server admin user.') +@secure() +param sqlAdminPassword string + +@description('The SID for the AAD user to be the AD admin for the database server') +param sqlAadAdminSid string + +@description('True for high availability deployments, False otherwise.') +param zoneRedundant bool = false + +@description('Comma separated subnet names that can access the services.') +param allowedSubnetNames string + +var cosmosName_var = 'votingcosmos-${uniqueString(resourceGroup().id)}' +var cosmosDatabaseName = 'cacheDB' +var cosmosContainerName = 'cacheContainer' +var cosmosPartitionKeyPaths = [ + '/MessageType' +] +var sqlServerName_var = 'sqlserver${uniqueString(resourceGroup().id)}' +var sqlDatabaseName = 'voting' +var serviceBusName_var = 'votingservicebus${uniqueString(resourceGroup().id)}' +var serviceBusQueue = 'votingqueue' +var resourcesStorageAccountName_var = toLower('resources${uniqueString(resourceGroup().id)}') +var resourcesContainerName = 'rscontainer' +var keyVaultName_var = 'keyvault-${uniqueString(resourceGroup().id)}' +var allowedSubnetNamesArray = split(allowedSubnetNames, ',') + +resource cosmosName 'Microsoft.DocumentDB/databaseAccounts@2022-05-15' = { + name: cosmosName_var + location: location + tags: { + defaultExperience: 'Core (SQL)' + } + kind: 'GlobalDocumentDB' + properties: { + //ipRangeFilter: '' + enableAutomaticFailover: false + enableMultipleWriteLocations: true + isVirtualNetworkFilterEnabled: true + databaseAccountOfferType: 'Standard' + consistencyPolicy: { + defaultConsistencyLevel: 'Session' + maxIntervalInSeconds: 5 + maxStalenessPrefix: 100 + } + locations: [ + { + locationName: location + failoverPriority: 0 + isZoneRedundant: zoneRedundant + } + ] + capabilities: [] + } +} + +resource cosmosName_cosmosDatabaseName 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2022-05-15' = { + parent: cosmosName + name: cosmosDatabaseName + properties: { + resource: { + id: cosmosDatabaseName + } + options: { + throughput: 400 + } + } +} + +resource cosmosName_cosmosDatabaseName_cosmosContainerName 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2022-05-15' = { + parent: cosmosName_cosmosDatabaseName + name: cosmosContainerName + properties: { + options: { + throughput: 400 + } + resource: { + id: cosmosContainerName + indexingPolicy: { + indexingMode: 'consistent' + includedPaths: [ + { + path: '/*' + } + ] + excludedPaths: [ + { + path: '/"_etag"/?' + } + ] + } + partitionKey: { + paths: cosmosPartitionKeyPaths + kind: 'Hash' + } + } + } +} + +resource sqlServerName 'Microsoft.Sql/servers@2022-02-01-preview' = { + name: sqlServerName_var + location: location + properties: { + administratorLogin: sqlAdminUserName + administratorLoginPassword: sqlAdminPassword + version: '12.0' + } +} + +resource sqlServerName_sqlDatabaseName 'Microsoft.Sql/servers/databases@2022-02-01-preview' = { + parent: sqlServerName + name: sqlDatabaseName + location: location + sku: { + name: (zoneRedundant ? 'BC_Gen5' : 'GP_Gen5') + tier: (zoneRedundant ? 'BusinessCritical' : 'GeneralPurpose') + family: 'Gen5' + capacity: 2 + } + //kind: 'v12.0,user,vcore' + properties: { + collation: 'SQL_Latin1_General_CP1_CI_AS' + maxSizeBytes: 1073741824 + zoneRedundant: zoneRedundant + } +} + +resource sqlServerName_activeDirectory 'Microsoft.Sql/servers/administrators@2022-02-01-preview' = { + parent: sqlServerName + name: 'activeDirectory' + //location: location + properties: { + administratorType: 'ActiveDirectory' + login: 'ADMIN' + sid: sqlAadAdminSid + tenantId: subscription().tenantId + } +} + +/* resource sqlServerName_allow_subnet_sql 'Microsoft.Sql/servers/virtualNetworkRules@2022-02-01-preview' = [for (item, i) in allowedSubnetNamesArray: { + name: '${sqlServerName_var}/allow-subnet-sql-${i}' + //location: location + properties: { + virtualNetworkSubnetId: resourceId('Microsoft.Network/virtualNetworks/subnets', vnetName, item) + } + dependsOn: [ + sqlServerName + ] +}] */ + +resource keyVaultName 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName_var + location: location + properties: { + accessPolicies: [] + sku: { + family: 'A' + name: 'standard' + } + tenantId: subscription().tenantId + } +} + +resource keyVaultName_CosmosKey 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { + parent: keyVaultName + name: 'CosmosKey' + properties: { + value: listKeys(cosmosName.id, '2022-05-15').primaryMasterKey //Microsoft.DocumentDB/databaseAccounts@2022-05-15 + } +} + +resource keyVaultName_ServiceBusListenerConnectionString 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { + parent: keyVaultName + name: 'ServiceBusListenerConnectionString' + properties: { + value: listKeys(serviceBusName_ListenerSharedAccessKey.id, '2021-11-01').primaryConnectionString //Microsoft.ServiceBus/namespaces/AuthorizationRules + } +} + +resource keyVaultName_ServiceBusSenderConnectionString 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { + parent: keyVaultName + name: 'ServiceBusSenderConnectionString' + properties: { + value: listKeys(serviceBusName_SenderSharedAccessKey.id, '2021-11-01').primaryConnectionString //Microsoft.ServiceBus/namespaces/AuthorizationRules + } +} + +resource serviceBusName 'Microsoft.ServiceBus/namespaces@2022-01-01-preview' = { + name: serviceBusName_var + location: location + sku: { + name: 'Premium' + tier: 'Premium' + capacity: 1 + } + properties: { + zoneRedundant: zoneRedundant + } +} + +resource serviceBusName_ListenerSharedAccessKey 'Microsoft.ServiceBus/namespaces/AuthorizationRules@2022-01-01-preview' = { + parent: serviceBusName + name: 'ListenerSharedAccessKey' + //location: location + properties: { + rights: [ + 'Listen' + ] + } +} + +resource serviceBusName_SenderSharedAccessKey 'Microsoft.ServiceBus/namespaces/AuthorizationRules@2022-01-01-preview' = { + parent: serviceBusName + name: 'SenderSharedAccessKey' + //location: location + properties: { + rights: [ + 'Send' + ] + } +} + +resource serviceBusName_serviceBusQueue 'Microsoft.ServiceBus/namespaces/queues@2022-01-01-preview' = { + parent: serviceBusName + name: serviceBusQueue + //location: location + properties: { + lockDuration: 'PT1M' + maxSizeInMegabytes: 1024 + requiresDuplicateDetection: false + requiresSession: false + defaultMessageTimeToLive: 'P10675199DT2H48M5.4775807S' + deadLetteringOnMessageExpiration: false + enableBatchedOperations: true + duplicateDetectionHistoryTimeWindow: 'PT10M' + maxDeliveryCount: 10 + status: 'Active' + autoDeleteOnIdle: 'P10675199DT2H48M5.4775807S' + enablePartitioning: false + enableExpress: false + } +} +/* +resource serviceBusName_allow_subnet_sb 'Microsoft.ServiceBus/namespaces/virtualnetworkrules@2018-01-01-preview' = [for (item, i) in allowedSubnetNamesArray: { + name: '${serviceBusName_var}/allow-subnet-sb-${i}' + //location: location + properties: { + virtualNetworkSubnetId: resourceId('Microsoft.Network/virtualNetworks/subnets', vnetName, item) + } + dependsOn: [ + serviceBusName + ] +}] */ + +resource resourcesStorageAccountName 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: resourcesStorageAccountName_var + location: location + kind: 'StorageV2' + sku: { + name: (zoneRedundant ? 'Standard_ZRS' : 'Standard_LRS') + //tier: 'Standard' + } + properties: { + accessTier: 'Hot' + } +} + +resource resourcesStorageAccountName_default_resourcesContainerName 'Microsoft.Storage/storageAccounts/blobServices/containers@2021-09-01' = { + name: '${resourcesStorageAccountName_var}/default/${resourcesContainerName}' + properties: { + publicAccess: 'Blob' + } + dependsOn: [ + resourcesStorageAccountName + ] +} + +output cosmosDbName string = cosmosName_var +output sqlServerName string = sqlServerName_var +output sqlDatabaseName string = sqlDatabaseName +output resourcesStorageAccountName string = resourcesStorageAccountName_var +output resourcesContainerName string = resourcesContainerName +output keyVaultName string = keyVaultName_var diff --git a/deployment/templates/services.json b/deployment/templates/services.json deleted file mode 100644 index 64a9f1b..0000000 --- a/deployment/templates/services.json +++ /dev/null @@ -1,420 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "location": { - "defaultValue": "[resourceGroup().location]", - "type": "string", - "metadata": { - "description": "The location in which the resources should be deployed." - } - }, - "vnetName": { - "type": "string", - "metadata": { - "description": "The vnet name where the gateway will be connected." - } - }, - "sqlAdminUserName": { - "type": "string", - "metadata": { - "description": "The name for the sql server admin user." - } - }, - "sqlAdminPassword": { - "type": "securestring", - "metadata": { - "description": "The password for the sql server admin user." - } - }, - "sqlAadAdminSid": { - "type": "string", - "metadata": { - "description": "The SID for the AAD user to be the AD admin for the database server" - } - }, - "zoneRedundant": { - "defaultValue": false, - "type": "bool", - "metadata": { - "description": "True for high availability deployments, False otherwise." - } - }, - "allowedSubnetNames": { - "type": "string", - "metadata": { - "description": "Comma separated subnet names that can access the services." - } - } - }, - "variables": { - "cosmosName": "[concat('votingcosmos-',uniqueString(resourceGroup().id))]", - "cosmosDatabaseName": "cacheDB", - "cosmosContainerName": "cacheContainer", - "cosmosPartitionKeyPaths": [ - "/MessageType" - ], - "sqlServerName": "[concat('sqlserver', uniqueString(resourceGroup().id))]", - "sqlDatabaseName": "voting", - "serviceBusName": "[concat('votingservicebus', uniqueString(resourceGroup().id))]", - "serviceBusQueue": "votingqueue", - "resourcesStorageAccountName": "[toLower(concat('resources', uniqueString(resourceGroup().id)))]", - "resourcesContainerName": "rscontainer", - "keyVaultName": "[concat( 'keyvault-',uniqueString(resourceGroup().id) ) ]", - "allowedSubnetNamesArray": "[split(parameters('allowedSubnetNames'), ',')]" - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2019-12-12", - "name": "[variables('cosmosName')]", - "location": "[parameters('location')]", - "tags": { - "defaultExperience": "Core (SQL)" - }, - "kind": "GlobalDocumentDB", - "properties": { - "ipRangeFilter": "", - "enableAutomaticFailover": false, - "enableMultipleWriteLocations": true, - "isVirtualNetworkFilterEnabled": true, - "copy": [ - { - "name": "virtualNetworkRules", - "count": "[length(variables('allowedSubnetNamesArray'))]", - "input": { - "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), variables('allowedSubnetNamesArray')[copyIndex('virtualNetworkRules')])]" - } - } - ], - "databaseAccountOfferType": "Standard", - "consistencyPolicy": { - "defaultConsistencyLevel": "Session", - "maxIntervalInSeconds": 5, - "maxStalenessPrefix": 100 - }, - "locations": [ - { - "locationName": "[parameters('location')]", - "failoverPriority": 0, - "isZoneRedundant": "[parameters('zoneRedundant')]" - } - ], - "capabilities": [] - } - }, - { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2019-12-12", - "name": "[concat(variables('cosmosName'), '/', variables('cosmosDatabaseName'))]", - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosName'))]" - ], - "properties": { - "resource": { - "id": "[variables('cosmosDatabaseName')]" - }, - "options": { - "throughput": "400" - } - } - }, - { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", - "apiVersion": "2019-12-12", - "name": "[concat(variables('cosmosName'), '/', variables('cosmosDatabaseName'), '/', variables('cosmosContainerName'))]", - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('cosmosName'), variables('cosmosDatabaseName'))]" - ], - "properties": { - "options": { - "throughput": "400" - }, - "resource": { - "id": "[variables('cosmosContainerName')]", - "indexingPolicy": { - "indexingMode": "consistent", - "includedPaths": [ - { - "path": "/*" - } - ], - "excludedPaths": [ - { - "path": "/\"_etag\"/?" - } - ] - }, - "partitionKey": { - "paths": "[variables('cosmosPartitionKeyPaths')]", - "kind": "Hash" - } - } - } - }, - { - "type": "Microsoft.Sql/servers", - "apiVersion": "2015-05-01-preview", - "name": "[variables('sqlServerName')]", - "location": "[parameters('location')]", - "properties": { - "administratorLogin": "[parameters('sqlAdminUserName')]", - "administratorLoginPassword": "[parameters('sqlAdminPassword')]", - "version": "12.0" - }, - "resources": [ - { - "type": "databases", - "apiVersion": "2017-10-01-preview", - "name": "[variables('sqlDatabaseName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[variables('sqlServerName')]" - ], - "sku": { - "name": "[if(parameters('zoneRedundant'), 'BC_Gen5', 'GP_Gen5')]", - "tier": "[if(parameters('zoneRedundant'), 'BusinessCritical', 'GeneralPurpose')]", - "family": "Gen5", - "capacity": 2 - }, - "kind": "v12.0,user,vcore", - "properties": { - "collation": "SQL_Latin1_General_CP1_CI_AS", - "maxSizeBytes": "1073741824", - "zoneRedundant": "[parameters('zoneRedundant')]" - } - }, - { - "name": "activeDirectory", - "type": "administrators", - "apiVersion": "2018-06-01-preview", - "dependsOn": [ - "[variables('sqlServerName')]" - ], - "location": "[parameters('location')]", - "properties": { - "administratorType": "ActiveDirectory", - "login": "ADMIN", - "sid": "[parameters('sqlAadAdminSid')]", - "tenantId": "[subscription().tenantId]" - } - } - ] - }, - { - "type": "Microsoft.Sql/servers/virtualNetworkRules", - "apiVersion": "2015-05-01-preview", - "name": "[concat(variables('sqlServerName'), '/allow-subnet-sql-', copyIndex())]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Sql/servers', variables('sqlServerName'))]" - ], - "properties": { - "virtualNetworkSubnetId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), variables('allowedSubnetNamesArray')[copyIndex()])]" - }, - "copy": { - "name": "sqlVirtualNetworkRuleCopy", - "count": "[length(variables('allowedSubnetNamesArray'))]" - } - }, - { - "type": "Microsoft.KeyVault/vaults", - "name": "[variables('keyVaultName')]", - "apiVersion": "2016-10-01", - "location": "[resourceGroup().location]", - "properties": { - "accessPolicies": [], - "sku": { - "family": "A", - "name": "standard" - }, - "tenantId": "[subscription().tenantId]", - "networkAcls": { - "bypass": "AzureServices", - "defaultAction": "Deny", - "copy": [ - { - "name": "virtualNetworkRules", - "count": "[length(variables('allowedSubnetNamesArray'))]", - "input": { - "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), variables('allowedSubnetNamesArray')[copyIndex('virtualNetworkRules')])]" - } - } - ] - } - } - }, - { - "type": "Microsoft.KeyVault/vaults/secrets", - "name": "[concat(variables('keyVaultName'), '/CosmosKey')]", - "apiVersion": "2015-06-01", - "dependsOn": [ - "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]", - "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosName'))]" - ], - "properties": { - "value": "[listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts',variables('cosmosName')),'2015-04-08').primaryMasterKey]" - } - }, - { - "type": "Microsoft.KeyVault/vaults/secrets", - "name": "[concat(variables('keyVaultName'), '/ServiceBusListenerConnectionString')]", - "apiVersion": "2015-06-01", - "dependsOn": [ - "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]", - "[resourceId('Microsoft.ServiceBus/namespaces/AuthorizationRules', variables('serviceBusName'), 'ListenerSharedAccessKey')]" - ], - "properties": { - "value": "[listKeys(resourceId('Microsoft.ServiceBus/namespaces/AuthorizationRules',variables('serviceBusName'),'ListenerSharedAccessKey'),'2015-08-01').primaryConnectionString]" - } - }, - { - "type": "Microsoft.KeyVault/vaults/secrets", - "name": "[concat(variables('keyVaultName'), '/ServiceBusSenderConnectionString')]", - "apiVersion": "2015-06-01", - "dependsOn": [ - "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]", - "[resourceId('Microsoft.ServiceBus/namespaces/AuthorizationRules', variables('serviceBusName'), 'SenderSharedAccessKey')]" - ], - "properties": { - "value": "[listKeys(resourceId('Microsoft.ServiceBus/namespaces/AuthorizationRules',variables('serviceBusName'),'SenderSharedAccessKey'),'2015-08-01').primaryConnectionString]" - } - }, - { - "type": "Microsoft.ServiceBus/namespaces", - "apiVersion": "2017-04-01", - "name": "[variables('serviceBusName')]", - "location": "[parameters('location')]", - "sku": { - "name": "Premium", - "tier": "Premium", - "capacity": 1 - }, - "properties": { - "zoneRedundant": "[parameters('zoneRedundant')]" - } - }, - { - "type": "Microsoft.ServiceBus/namespaces/AuthorizationRules", - "apiVersion": "2017-04-01", - "name": "[concat(variables('serviceBusName'), '/ListenerSharedAccessKey')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusName'))]" - ], - "properties": { - "rights": [ - "Listen" - ] - } - }, - { - "type": "Microsoft.ServiceBus/namespaces/AuthorizationRules", - "apiVersion": "2017-04-01", - "name": "[concat(variables('serviceBusName'), '/SenderSharedAccessKey')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusName'))]" - ], - "properties": { - "rights": [ - "Send" - ] - } - }, - { - "type": "Microsoft.ServiceBus/namespaces/queues", - "apiVersion": "2017-04-01", - "name": "[concat(variables('serviceBusName'), '/', variables('serviceBusQueue'))]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusName'))]" - ], - "properties": { - "lockDuration": "PT1M", - "maxSizeInMegabytes": 1024, - "requiresDuplicateDetection": false, - "requiresSession": false, - "defaultMessageTimeToLive": "P10675199DT2H48M5.4775807S", - "deadLetteringOnMessageExpiration": false, - "enableBatchedOperations": true, - "duplicateDetectionHistoryTimeWindow": "PT10M", - "maxDeliveryCount": 10, - "status": "Active", - "autoDeleteOnIdle": "P10675199DT2H48M5.4775807S", - "enablePartitioning": false, - "enableExpress": false - } - }, - { - "type": "Microsoft.ServiceBus/namespaces/virtualnetworkrules", - "apiVersion": "2018-01-01-preview", - "name": "[concat(variables('serviceBusName'), '/allow-subnet-sb-', copyIndex())]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.ServiceBus/namespaces', variables('serviceBusName'))]" - ], - "properties": { - "virtualNetworkSubnetId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), variables('allowedSubnetNamesArray')[copyIndex()])]" - }, - "copy": { - "name": "sbVirtualNetworkRuleCopy", - "count": "[length(variables('allowedSubnetNamesArray'))]" - } - }, - - { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2019-06-01", - "name": "[variables('resourcesStorageAccountName')]", - "location": "[parameters('location')]", - "kind": "StorageV2", - "sku": { - "name": "[if(parameters('zoneRedundant'), 'Standard_ZRS', 'Standard_LRS')]", - "tier": "Standard" - }, - "properties": { - "accessTier": "Hot" - }, - "resources": [ - { - "type": "blobServices/containers", - "apiVersion": "2018-07-01", - "name": "[concat('default/', variables('resourcesContainerName'))]", - "dependsOn": [ - "[variables('resourcesStorageAccountName')]" - ], - "properties": { - "publicAccess": "Blob" - } - } - ] - } - ], - "outputs": { - "cosmosDbName": { - "value": "[variables('cosmosName')]", - "type": "string" - }, - "sqlServerName": { - "value": "[variables('sqlServerName')]", - "type": "string" - }, - "sqlDatabaseName": { - "value": "[variables('sqlDatabaseName')]", - "type": "string" - }, - "resourcesStorageAccountName": { - "value": "[variables('resourcesStorageAccountName')]", - "type": "string" - }, - "resourcesContainerName": { - "value": "[variables('resourcesContainerName')]", - "type": "string" - }, - "keyVaultName": { - "value": "[variables('keyVaultName')]", - "type": "string" - } - } -} diff --git a/deployment/templates/sites.bicep b/deployment/templates/sites.bicep new file mode 100644 index 0000000..0657a53 --- /dev/null +++ b/deployment/templates/sites.bicep @@ -0,0 +1,496 @@ +@description('The location in which the resources should be deployed.') +param location string = resourceGroup().location + +@description('The vnet name where redis will be connected.') +param vnetName string + +@description('The ip address prefix REDIS will use.') +param redisSubnetAddressPrefix string + +@description('The ASE name where to host the applications') +param aseName string + +@description('DNS suffix where the app will be deployed') +param aseDnsSuffix string + +@description('The name of the key vault name') +param keyVaultName string + +@description('The cosmos DB name') +param cosmosDbName string + +@description('The name for the sql server') +param sqlServerName string + +@description('The name for the sql database') +param sqlDatabaseName string + +@description('The availability zone to deploy. Valid values are: 1, 2 or 3. Use empty to not use zones.') +param zone string = '' + +var instanceIndex = (empty(zone) ? '0' : zone) +var redisName_var = 'REDIS-${uniqueString(resourceGroup().id)}-${instanceIndex}' +var redisSubnetName = 'redis-subnet-${uniqueString(resourceGroup().id)}-${instanceIndex}' +var redisSubnetId = vnetName_redisSubnetName.id +var redisNSGName_var = '${vnetName}-REDIS-${instanceIndex}-NSG' +var redisSecretName = 'RedisConnectionString${instanceIndex}' +var cosmosKeySecretName = 'CosmosKey' +var serviceBusListenerConnectionStringSecretName = 'ServiceBusListenerConnectionString' +var serviceBusSenderConnectionStringSecretName = 'ServiceBusSenderConnectionString' +var votingApiName_var = 'votingapiapp-${instanceIndex}-${uniqueString(resourceGroup().id)}' +var votingWebName_var = 'votingwebapp-${instanceIndex}-${uniqueString(resourceGroup().id)}' +var testWebName_var = 'testwebapp-${instanceIndex}-${uniqueString(resourceGroup().id)}' +var votingFunctionName_var = 'votingfuncapp-${instanceIndex}-${uniqueString(resourceGroup().id)}' +var votingApiPlanName_var = '${votingApiName_var}-plan' +var votingWebPlanName_var = '${votingWebName_var}-plan' +var testWebPlanName_var = '${testWebName_var}-plan' +var votingFunctionPlanName_var = '${votingFunctionName_var}-plan' +var aseId = resourceId('Microsoft.Web/hostingEnvironments', aseName) + +resource redisNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: redisNSGName_var + location: location + tags: { + displayName: redisNSGName_var + } + properties: { + securityRules: [ + { + name: 'REDIS-inbound-vnet' + properties: { + description: 'Client communication inside vnet' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRanges: [ + '6379' + '6380' + '13000-13999' + '15000-15999' + ] + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: redisSubnetAddressPrefix + access: 'Allow' + priority: 200 + direction: 'Inbound' + } + } + { + name: 'REDIS-inbound-loadbalancer' + properties: { + description: 'Allow communication from Load Balancer' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: 'AzureLoadBalancer' + destinationAddressPrefix: redisSubnetAddressPrefix + access: 'Allow' + priority: 201 + direction: 'Inbound' + } + } + { + name: 'REDIS-inbound-allow_internal-communication' + properties: { + description: 'Internal communications for Redis' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRanges: [ + '6379' + '6380' + '8443' + '10221-10231' + '20226' + ] + sourceAddressPrefix: redisSubnetAddressPrefix + destinationAddressPrefix: redisSubnetAddressPrefix + access: 'Allow' + priority: 202 + direction: 'Inbound' + } + } + { + name: 'REDIS-outbound-allow_storage' + properties: { + description: 'Redis dependencies on Azure Storage/PKI (Internet)' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRanges: [ + '80' + '443' + ] + sourceAddressPrefix: redisSubnetAddressPrefix + destinationAddressPrefix: '*' + access: 'Allow' + priority: 200 + direction: 'Outbound' + } + } + { + name: 'REDIS-outbound-allow_DNS' + properties: { + description: 'Redis dependencies on DNS (Internet/VNet)' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '53' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + access: 'Allow' + priority: 201 + direction: 'Outbound' + } + } + { + name: 'REDIS-outbound-allow_ports-within-subnet' + properties: { + description: 'Internal communications for Redis' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: redisSubnetAddressPrefix + destinationAddressPrefix: redisSubnetAddressPrefix + access: 'Allow' + priority: 202 + direction: 'Outbound' + } + } + ] + } +} + +resource vnetName_redisSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + name: '${vnetName}/${redisSubnetName}' + //location: location + properties: { + addressPrefix: redisSubnetAddressPrefix + networkSecurityGroup: { + id: redisNSGName.id + } + } +} + +resource redisName 'Microsoft.Cache/Redis@2019-07-01' = { + name: redisName_var + location: location + zones: (empty(zone) ? json('null') : array(zone)) + properties: { + sku: { + name: 'Premium' + family: 'P' + capacity: 3 + } + enableNonSslPort: false + redisConfiguration: { + maxclients: '5000' + } + subnetId: redisSubnetId + } +} + +resource keyVaultName_redisSecretName 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { + name: '${keyVaultName}/${redisSecretName}' + properties: { + value: '${redisName_var}.redis.cache.windows.net:6380,abortConnect=false,ssl=true,password=${listKeys(redisName.id, '2015-08-01').primaryKey}' + } +} + +resource votingFunctionName 'Microsoft.Insights/components@2020-02-02' = { + name: votingFunctionName_var + location: location + kind: 'web' + properties: { + Application_Type: 'web' + Flow_Type: 'Redfield' + Request_Source: 'AppServiceEnablementCreate' + } +} + +resource votingApiName 'Microsoft.Insights/components@2020-02-02' = { + name: votingApiName_var + location: location + kind: 'web' + properties: { + Application_Type: 'web' + Flow_Type: 'Redfield' + HockeyAppId: '' + } +} + +resource votingWebName 'Microsoft.Insights/components@2020-02-02' = { + name: votingWebName_var + location: location + kind: 'web' + properties: { + Application_Type: 'web' + Flow_Type: 'Redfield' + HockeyAppId: '' + } +} + +resource testWebName 'Microsoft.Insights/components@2020-02-02' = { + name: testWebName_var + location: location + kind: 'web' + properties: { + Application_Type: 'web' + Flow_Type: 'Redfield' + HockeyAppId: '' + } +} + +resource votingFunctionPlanName 'Microsoft.Web/serverfarms@2022-03-01' = { + name: votingFunctionPlanName_var + location: location + sku: { + name: 'I1V2' + tier: 'IsolatedV2' + } + //kind: 'functionapp' + properties: { + //name: votingFunctionPlanName_var + perSiteScaling: false + reserved: false + targetWorkerCount: 0 + targetWorkerSizeId: 0 + //hostingEnvironment: aseName + hostingEnvironmentProfile: { + id:aseId + } + } +} + +resource votingApiPlanName 'Microsoft.Web/serverfarms@2022-03-01' = { + name: votingApiPlanName_var + location: location + sku: { + name: 'I1V2' + tier: 'IsolatedV2' + } + kind: 'app' + properties: { + //name: votingApiPlanName_var + perSiteScaling: false + reserved: false + targetWorkerCount: 0 + targetWorkerSizeId: 0 + //hostingEnvironment: aseName + hostingEnvironmentProfile: { + id:aseId + } + } +} + +resource votingWebPlanName 'Microsoft.Web/serverfarms@2022-03-01' = { + name: votingWebPlanName_var + location: location + sku: { + name: 'I1V2' + tier: 'IsolatedV2' + } + kind: 'app' + properties: { + //name: votingWebPlanName_var + perSiteScaling: false + reserved: false + targetWorkerCount: 0 + targetWorkerSizeId: 0 + //hostingEnvironment: aseName + hostingEnvironmentProfile: { + id:aseId + } + } +} + +resource testWebPlanName 'Microsoft.Web/serverfarms@2022-03-01' = { + name: testWebPlanName_var + location: location + sku: { + name: 'I1V2' + tier: 'IsolatedV2' + } + kind: 'app' + properties: { + //name: testWebPlanName_var + perSiteScaling: false + reserved: false + targetWorkerCount: 0 + targetWorkerSizeId: 0 + //hostingEnvironment: aseName + hostingEnvironmentProfile: { + id:aseId + } + } +} + +resource Microsoft_Web_sites_votingFunctionName 'Microsoft.Web/sites@2022-03-01' = { + name: votingFunctionName_var + location: location + kind: 'functionapp' + identity: { + type: 'SystemAssigned' + } + properties: { + enabled: true + //name: votingFunctionName_var + hostingEnvironmentProfile: { + id:aseId + } + serverFarmId: votingFunctionPlanName.id + siteConfig: { + alwaysOn: true + appSettings: [ + { + name: 'FUNCTIONS_EXTENSION_VERSION' + value: '~3' + } + { + name: 'FUNCTIONS_WORKER_RUNTIME' + value: 'dotnet' + } + { + name: 'APPINSIGHTS_INSTRUMENTATIONKEY' + value: reference(votingFunctionName.id, '2020-02-02').InstrumentationKey + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: 'InstrumentationKey=${reference(votingFunctionName.id, '2020-02-02').InstrumentationKey}' + } + { + name: 'SERVICEBUS_CONNECTION_STRING' + value: '@Microsoft.KeyVault(SecretUri=${reference(resourceId('Microsoft.KeyVault/vaults/secrets', keyVaultName, serviceBusListenerConnectionStringSecretName), '2022-07-01').secretUriWithVersion})' + } + { + name: 'sqldb_connection' + value: 'Server=${reference(resourceId('Microsoft.Sql/servers', sqlServerName), '2022-02-01-preview').fullyQualifiedDomainName},1433;Database=${sqlDatabaseName};' + } + ] + } + } +} + +resource Microsoft_Web_sites_votingApiName 'Microsoft.Web/sites@2022-03-01' = { + name: votingApiName_var + location: location + kind: 'app' + identity: { + type: 'SystemAssigned' + } + properties: { + enabled: true + //name: votingApiName_var + hostingEnvironmentProfile: { + id:aseId + } + serverFarmId: votingApiPlanName.id + siteConfig: { + appSettings: [ + { + name: 'APPINSIGHTS_INSTRUMENTATIONKEY' + value: reference(votingApiName.id, '2020-02-02').InstrumentationKey + } + { + name: 'ApplicationInsights:InstrumentationKey' + value: reference(votingApiName.id, '2020-02-02').InstrumentationKey + } + { + name: 'ConnectionStrings:SqlDbConnection' + value: 'Server=${reference(resourceId('Microsoft.Sql/servers', sqlServerName), '2022-02-01-preview').fullyQualifiedDomainName},1433;Database=${sqlDatabaseName};' + } + ] + } + } +} + +resource Microsoft_Web_sites_votingWebName 'Microsoft.Web/sites@2018-11-01' = { + name: votingWebName_var + location: location + kind: 'app' + identity: { + type: 'SystemAssigned' + } + properties: { + enabled: true + //name: votingWebName_var + hostingEnvironmentProfile: { + id:aseId + } + serverFarmId: votingWebPlanName.id + siteConfig: { + appSettings: [ + { + name: 'APPINSIGHTS_INSTRUMENTATIONKEY' + value: reference(votingWebName.id, '2020-02-02').InstrumentationKey + } + { + name: 'ConnectionStrings:sbConnectionString' + value: '@Microsoft.KeyVault(SecretUri=${reference(resourceId('Microsoft.KeyVault/vaults/secrets', keyVaultName, serviceBusSenderConnectionStringSecretName), '2022-07-01').secretUriWithVersion})' + } + { + name: 'ConnectionStrings:VotingDataAPIBaseUri' + value: 'https://${Microsoft_Web_sites_votingApiName.properties.hostNames[0]}' + } + { + name: 'ApplicationInsights:InstrumentationKey' + value: reference(votingWebName.id, '2020-02-02').InstrumentationKey + } + { + name: 'ConnectionStrings:RedisConnectionString' + value: '@Microsoft.KeyVault(SecretUri=${reference(keyVaultName_redisSecretName.id, '2022-07-01').secretUriWithVersion})' + } + { + name: 'ConnectionStrings:queueName' + value: 'votingqueue' + } + { + name: 'ConnectionStrings:CosmosUri' + value: reference(resourceId('Microsoft.DocumentDB/databaseAccounts', cosmosDbName), '2022-05-15').documentEndpoint + } + { + name: 'ConnectionStrings:CosmosKey' + value: '@Microsoft.KeyVault(SecretUri=${reference(resourceId('Microsoft.KeyVault/vaults/secrets', keyVaultName, cosmosKeySecretName), '2022-07-01').secretUriWithVersion})' + } + ] + } + } +} + +resource Microsoft_Web_sites_testWebName 'Microsoft.Web/sites@2022-03-01' = { + name: testWebName_var + location: location + kind: 'app' + identity: { + type: 'SystemAssigned' + } + properties: { + enabled: true + //name: testWebName_var + hostingEnvironmentProfile: { + id:aseId + } + serverFarmId: testWebPlanName.id + siteConfig: { + appSettings: [ + { + name: 'APPINSIGHTS_INSTRUMENTATIONKEY' + value: reference(testWebName.id, '2020-02-02').InstrumentationKey + } + { + name: 'ApplicationInsights:InstrumentationKey' + value: reference(testWebName.id, '2020-02-02').InstrumentationKey + } + ] + } + } +} + +output redisName string = redisName_var +output redisSubnetId string = redisSubnetId +output redisSubnetName string = redisSubnetName +output votingWebName string = votingWebName_var +output testWebName string = testWebName_var +output votingAppUrl string = '${votingWebName_var}.${aseDnsSuffix}' +output testAppUrl string = '${testWebName_var}.${aseDnsSuffix}' +output votingApiName string = votingApiName_var +output votingFunctionName string = votingFunctionName_var +output votingWebAppIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingWebName_var}', '2018-11-01', 'Full').identity.principalId +output votingApiIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingApiName_var}', '2018-11-01', 'Full').identity.principalId +output votingCounterFunctionIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingFunctionName_var}', '2018-11-01', 'Full').identity.principalId diff --git a/deployment/templates/sites.json b/deployment/templates/sites.json deleted file mode 100644 index 03da91c..0000000 --- a/deployment/templates/sites.json +++ /dev/null @@ -1,599 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "location": { - "defaultValue": "[resourceGroup().location]", - "type": "string", - "metadata": { - "description": "The location in which the resources should be deployed." - } - }, - "vnetName": { - "type": "string", - "metadata": { - "description": "The vnet name where redis will be connected." - } - }, - "redisSubnetAddressPrefix": { - "type": "string", - "metadata": { - "description": "The ip address prefix REDIS will use." - } - }, - "aseName": { - "type": "string", - "metadata": { - "description": "The ASE name where to host the applications" - } - }, - "aseDnsSuffix": { - "type": "string", - "metadata": { - "description": "DNS suffix where the app will be deployed" - } - }, - "keyVaultName": { - "type": "string", - "metadata": { - "description": "The name of the key vault name" - } - }, - "cosmosDbName": { - "type": "string", - "metadata": { - "description": "The cosmos DB name" - } - }, - "sqlServerName": { - "type": "string", - "metadata": { - "description": "The name for the sql server" - } - }, - "sqlDatabaseName": { - "type": "string", - "metadata": { - "description": "The name for the sql database" - } - }, - "zone": { - "defaultValue": "", - "type": "string", - "metadata": { - "description": "The availability zone to deploy. Valid values are: 1, 2 or 3. Use empty to not use zones." - } - } - }, - "variables": { - "instanceIndex": "[if(empty(parameters('zone')),'0',parameters('zone'))]", - "redisName": "[concat('REDIS-', uniqueString(resourceGroup().id), '-', variables('instanceIndex'))]", - "redisSubnetName": "[concat('redis-subnet-', uniqueString(resourceGroup().id), '-', variables('instanceIndex'))]", - "redisSubnetId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), variables('redisSubnetName'))]", - "redisNSGName": "[concat(parameters('vnetName'), '-REDIS-', variables('instanceIndex'), '-NSG')]", - "redisSecretName": "[concat('RedisConnectionString', variables('instanceIndex'))]", - "cosmosKeySecretName": "CosmosKey", - "serviceBusListenerConnectionStringSecretName": "ServiceBusListenerConnectionString", - "serviceBusSenderConnectionStringSecretName": "ServiceBusSenderConnectionString", - "votingApiName": "[concat('votingapiapp', '-', variables('instanceIndex'), '-', uniqueString(resourceGroup().id))]", - "votingWebName": "[concat('votingwebapp', '-', variables('instanceIndex'), '-', uniqueString(resourceGroup().id))]", - "testWebName": "[concat('testwebapp', '-', variables('instanceIndex'), '-', uniqueString(resourceGroup().id))]", - "votingFunctionName": "[concat('votingfuncapp', '-', variables('instanceIndex'), '-', uniqueString(resourceGroup().id))]", - "votingApiPlanName": "[concat(variables('votingApiName'), '-plan')]", - "votingWebPlanName": "[concat(variables('votingWebName'), '-plan')]", - "testWebPlanName": "[concat(variables('testWebName'), '-plan')]", - "votingFunctionPlanName": "[concat(variables('votingFunctionName'), '-plan')]", - "aseId": "[resourceId('Microsoft.Web/hostingEnvironments', parameters('aseName'))]" - }, - "resources": [ - { - "apiVersion": "2017-06-01", - "type": "Microsoft.Network/networkSecurityGroups", - "name": "[variables('redisNSGName')]", - "location": "[parameters('location')]", - "tags": { - "displayName": "[variables('redisNSGName')]" - }, - "properties": { - "securityRules": [ - { - "name": "REDIS-inbound-vnet", - "properties": { - "description": "Client communication inside vnet", - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRanges": [ - "6379", - "6380", - "13000-13999", - "15000-15999" - ], - "sourceAddressPrefix": "VirtualNetwork", - "destinationAddressPrefix": "[parameters('redisSubnetAddressPrefix')]", - "access": "Allow", - "priority": 200, - "direction": "Inbound" - } - }, - { - "name": "REDIS-inbound-loadbalancer", - "properties": { - "description": "Allow communication from Load Balancer", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "*", - "sourceAddressPrefix": "AzureLoadBalancer", - "destinationAddressPrefix": "[parameters('redisSubnetAddressPrefix')]", - "access": "Allow", - "priority": 201, - "direction": "Inbound" - } - }, - { - "name": "REDIS-inbound-allow_internal-communication", - "properties": { - "description": "Internal communications for Redis", - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRanges": [ - "6379", - "6380", - "8443", - "10221-10231", - "20226" - ], - "sourceAddressPrefix": "[parameters('redisSubnetAddressPrefix')]", - "destinationAddressPrefix": "[parameters('redisSubnetAddressPrefix')]", - "access": "Allow", - "priority": 202, - "direction": "Inbound" - } - }, - - { - "name": "REDIS-outbound-allow_storage", - "properties": { - "description": "Redis dependencies on Azure Storage/PKI (Internet)", - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRanges": [ - "80", - "443" - ], - "sourceAddressPrefix": "[parameters('redisSubnetAddressPrefix')]", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 200, - "direction": "Outbound" - } - }, - { - "name": "REDIS-outbound-allow_DNS", - "properties": { - "description": "Redis dependencies on DNS (Internet/VNet)", - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "53", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 201, - "direction": "Outbound" - } - }, - { - "name": "REDIS-outbound-allow_ports-within-subnet", - "properties": { - "description": "Internal communications for Redis", - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRange": "*", - "sourceAddressPrefix": "[parameters('redisSubnetAddressPrefix')]", - "destinationAddressPrefix": "[parameters('redisSubnetAddressPrefix')]", - "access": "Allow", - "priority": 202, - "direction": "Outbound" - } - } - ] - } - }, - { - "apiVersion": "2018-04-01", - "type": "Microsoft.Network/virtualNetworks/subnets", - "name": "[concat(parameters('vnetName'), '/', variables('redisSubnetName'))]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups/', variables('redisNSGName'))]" - ], - "properties": { - "addressPrefix": "[parameters('redisSubnetAddressPrefix')]", - "networkSecurityGroup": { - "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('redisNSGName'))]" - } - } - }, - { - "type": "Microsoft.Cache/Redis", - "apiVersion": "2019-07-01", - "name": "[variables('redisName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[variables('redisSubnetId')]" - ], - "zones": "[if(empty(parameters('zone')),json('null'),array(parameters('zone')))]", - "properties": { - "sku": { - "name": "Premium", - "family": "P", - "capacity": 3 - }, - "enableNonSslPort": false, - "redisConfiguration": { - "maxclients": "5000" - }, - "subnetId": "[variables('redisSubnetId')]" - } - }, - { - "type": "Microsoft.KeyVault/vaults/secrets", - "name": "[concat(parameters('keyVaultName'), '/', variables('redisSecretName'))]", - "apiVersion": "2015-06-01", - "dependsOn": [ - "[resourceId('Microsoft.Cache/Redis', variables('redisName'))]" - ], - "properties": { - "value": "[concat(variables('redisName'),'.redis.cache.windows.net:6380,abortConnect=false,ssl=true,password=', listKeys(resourceId('Microsoft.Cache/Redis', variables('redisName')), '2015-08-01').primaryKey)]" - } - }, - { - "type": "Microsoft.Insights/components", - "apiVersion": "2015-05-01", - "name": "[variables('votingFunctionName')]", - "location": "[parameters('location')]", - "kind": "web", - "properties": { - "Application_Type": "web", - "Flow_Type": "Redfield", - "Request_Source": "AppServiceEnablementCreate" - } - }, - { - "type": "Microsoft.Insights/components", - "apiVersion": "2015-05-01", - "name": "[variables('votingApiName')]", - "location": "[parameters('location')]", - "kind": "web", - "properties": { - "Application_Type": "web", - "Flow_Type": "Redfield", - "HockeyAppId": "" - } - }, - { - "type": "Microsoft.Insights/components", - "apiVersion": "2015-05-01", - "name": "[variables('votingWebName')]", - "location": "[parameters('location')]", - "kind": "web", - "properties": { - "Application_Type": "web", - "Flow_Type": "Redfield", - "HockeyAppId": "" - } - }, - { - "type": "Microsoft.Insights/components", - "apiVersion": "2015-05-01", - "name": "[variables('testWebName')]", - "location": "[parameters('location')]", - "kind": "web", - "properties": { - "Application_Type": "web", - "Flow_Type": "Redfield", - "HockeyAppId": "" - } - }, - { - "type": "Microsoft.Web/serverfarms", - "apiVersion": "2016-09-01", - "name": "[variables('votingFunctionPlanName')]", - "location": "[parameters('location')]", - "sku": { - "name": "I1", - "tier": "Isolated" - }, - "kind": "functionapp", - "properties": { - "name": "[variables('votingFunctionPlanName')]", - "perSiteScaling": false, - "reserved": false, - "targetWorkerCount": 0, - "targetWorkerSizeId": 0, - "hostingEnvironment": "[parameters('aseName')]" - } - }, - { - "type": "Microsoft.Web/serverfarms", - "apiVersion": "2016-09-01", - "name": "[variables('votingApiPlanName')]", - "location": "[parameters('location')]", - "sku": { - "name": "I1", - "tier": "Isolated" - }, - "kind": "app", - "properties": { - "name": "[variables('votingApiPlanName')]", - "perSiteScaling": false, - "reserved": false, - "targetWorkerCount": 0, - "targetWorkerSizeId": 0, - "hostingEnvironment": "[parameters('aseName')]" - } - }, - { - "type": "Microsoft.Web/serverfarms", - "apiVersion": "2016-09-01", - "name": "[variables('votingWebPlanName')]", - "location": "[parameters('location')]", - "sku": { - "name": "I1", - "tier": "Isolated" - }, - "kind": "app", - "properties": { - "name": "[variables('votingWebPlanName')]", - "perSiteScaling": false, - "reserved": false, - "targetWorkerCount": 0, - "targetWorkerSizeId": 0, - "hostingEnvironment": "[parameters('aseName')]" - } - }, - { - "type": "Microsoft.Web/serverfarms", - "apiVersion": "2016-09-01", - "name": "[variables('testWebPlanName')]", - "location": "[parameters('location')]", - "sku": { - "name": "I1", - "tier": "Isolated" - }, - "kind": "app", - "properties": { - "name": "[variables('testWebPlanName')]", - "perSiteScaling": false, - "reserved": false, - "targetWorkerCount": 0, - "targetWorkerSizeId": 0, - "hostingEnvironment": "[parameters('aseName')]" - } - }, - { - "type": "Microsoft.Web/sites", - "apiVersion": "2018-11-01", - "name": "[variables('votingFunctionName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Web/serverfarms', variables('votingFunctionPlanName'))]", - "[resourceId('Microsoft.Insights/components', variables('votingFunctionName'))]" - ], - "kind": "functionapp", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "enabled": true, - "name": "[variables('votingFunctionName')]", - "hostingEnvironment": "[variables('aseId')]", - "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('votingFunctionPlanName'))]", - "siteConfig": { - "alwaysOn": true, - "appSettings": [ - { - "name": "FUNCTIONS_EXTENSION_VERSION", - "value": "~3" - }, - { - "name": "FUNCTIONS_WORKER_RUNTIME", - "value": "dotnet" - }, - { - "name": "APPINSIGHTS_INSTRUMENTATIONKEY", - "value": "[reference(resourceId('Microsoft.Insights/components', variables('votingFunctionName')), '2014-04-01').InstrumentationKey]" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[concat('InstrumentationKey=', reference(resourceId('Microsoft.Insights/components', variables('votingFunctionName')), '2014-04-01').InstrumentationKey)]" - }, - { - "name": "SERVICEBUS_CONNECTION_STRING", - "value": "[concat('@Microsoft.KeyVault(SecretUri=', reference(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), variables('serviceBusListenerConnectionStringSecretName')), '2016-10-01').secretUriWithVersion, ')')]" - }, - { - "name": "sqldb_connection", - "value": "[concat('Server=', reference(resourceId('Microsoft.Sql/servers', parameters('sqlServerName')), '2015-05-01-preview').fullyQualifiedDomainName, ',1433;Database=', parameters('sqlDatabaseName'), ';')]" - } - ] - } - } - }, - { - "type": "Microsoft.Web/sites", - "apiVersion": "2018-11-01", - "name": "[variables('votingApiName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Web/serverfarms', variables('votingApiPlanName'))]", - "[resourceId('Microsoft.Insights/components', variables('votingApiName'))]" - ], - "kind": "app", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "enabled": true, - "name": "[variables('votingApiName')]", - "hostingEnvironment": "[variables('aseId')]", - "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('votingApiPlanName'))]", - "siteConfig": { - "appSettings": [ - { - "name": "APPINSIGHTS_INSTRUMENTATIONKEY", - "value": "[reference(resourceId('Microsoft.Insights/components', variables('votingApiName')), '2014-04-01').InstrumentationKey]" - }, - { - "name": "ApplicationInsights:InstrumentationKey", - "value": "[reference(resourceId('Microsoft.Insights/components', variables('votingApiName')), '2014-04-01').InstrumentationKey]" - }, - { - "name": "ConnectionStrings:SqlDbConnection", - "value": "[concat('Server=', reference(resourceId('Microsoft.Sql/servers', parameters('sqlServerName')), '2015-05-01-preview').fullyQualifiedDomainName, ',1433;Database=', parameters('sqlDatabaseName'), ';')]" - } - ] - } - } - }, - { - "type": "Microsoft.Web/sites", - "apiVersion": "2018-11-01", - "name": "[variables('votingWebName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Web/serverfarms', variables('votingWebPlanName'))]", - "[resourceId('Microsoft.Insights/components', variables('votingWebName'))]", - "[resourceId('Microsoft.Web/sites', variables('votingApiName'))]" - ], - "kind": "app", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "enabled": true, - "name": "[variables('votingWebName')]", - "hostingEnvironment": "[variables('aseId')]", - "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('votingWebPlanName'))]", - "siteConfig": { - "appSettings": [ - { - "name": "APPINSIGHTS_INSTRUMENTATIONKEY", - "value": "[reference(resourceId('Microsoft.Insights/components', variables('votingWebName')), '2014-04-01').InstrumentationKey]" - }, - { - "name": "ConnectionStrings:sbConnectionString", - "value": "[concat('@Microsoft.KeyVault(SecretUri=', reference(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), variables('serviceBusSenderConnectionStringSecretName')), '2016-10-01').secretUriWithVersion, ')')]" - }, - { - "name": "ConnectionStrings:VotingDataAPIBaseUri", - "value": "[concat('https://', reference(resourceId('Microsoft.Web/sites', variables('votingApiName'))).hostNames[0])]" - }, - { - "name": "ApplicationInsights:InstrumentationKey", - "value": "[reference(resourceId('Microsoft.Insights/components', variables('votingWebName')), '2014-04-01').InstrumentationKey]" - }, - { - "name": "ConnectionStrings:RedisConnectionString", - "value": "[concat('@Microsoft.KeyVault(SecretUri=', reference(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), variables('redisSecretName')), '2016-10-01').secretUriWithVersion, ')')]" - }, - { - "name": "ConnectionStrings:queueName", - "value": "votingqueue" - }, - { - "name": "ConnectionStrings:CosmosUri", - "value": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosDbName')),'2019-12-12').documentEndpoint]" - }, - { - "name": "ConnectionStrings:CosmosKey", - "value": "[concat('@Microsoft.KeyVault(SecretUri=', reference(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), variables('cosmosKeySecretName')), '2016-10-01').secretUriWithVersion, ')')]" - } - ] - } - } - }, - { - "type": "Microsoft.Web/sites", - "apiVersion": "2018-11-01", - "name": "[variables('testWebName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Web/serverfarms', variables('testWebPlanName'))]", - "[resourceId('Microsoft.Insights/components', variables('testWebName'))]" - ], - "kind": "app", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "enabled": true, - "name": "[variables('testWebName')]", - "hostingEnvironment": "[variables('aseId')]", - "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('testWebPlanName'))]", - "siteConfig": { - "appSettings": [ - { - "name": "APPINSIGHTS_INSTRUMENTATIONKEY", - "value": "[reference(resourceId('Microsoft.Insights/components', variables('testWebName')), '2014-04-01').InstrumentationKey]" - }, - { - "name": "ApplicationInsights:InstrumentationKey", - "value": "[reference(resourceId('Microsoft.Insights/components', variables('testWebName')), '2014-04-01').InstrumentationKey]" - } - ] - } - } - } - - ], - "outputs": { - "redisName": { - "value": "[variables('redisName')]", - "type": "string" - }, - "redisSubnetId": { - "value": "[variables('redisSubnetId')]", - "type": "string" - }, - "redisSubnetName": { - "value": "[variables('redisSubnetName')]", - "type": "string" - }, - "votingWebName": { - "value": "[variables('votingWebName')]", - "type": "string" - }, - "testWebName": { - "value": "[variables('testWebName')]", - "type": "string" - }, - "votingAppUrl": { - "value": "[concat(variables('votingWebName'), '.', parameters('aseDnsSuffix'))]", - "type": "string" - }, - "testAppUrl": { - "value": "[concat(variables('testWebName'), '.', parameters('aseDnsSuffix'))]", - "type": "string" - }, - "votingApiName": { - "value": "[variables('votingApiName')]", - "type": "string" - }, - "votingFunctionName": { - "value": "[variables('votingFunctionName')]", - "type": "string" - }, - "votingWebAppIdentityPrincipalId": { - "value": "[reference(concat('Microsoft.Web/sites/', variables('votingWebName')), '2018-11-01', 'Full').identity.principalId]", - "type": "string" - }, - "votingApiIdentityPrincipalId": { - "value": "[reference(concat('Microsoft.Web/sites/', variables('votingApiName')), '2018-11-01', 'Full').identity.principalId]", - "type": "string" - }, - "votingCounterFunctionIdentityPrincipalId": { - "value": "[reference(concat('Microsoft.Web/sites/', variables('votingFunctionName')), '2018-11-01', 'Full').identity.principalId]", - "type": "string" - } - } -} From 6c170591fdb503bbdb1b3f5dd346b56d2e33943f Mon Sep 17 00:00:00 2001 From: Suhas Rao Date: Sat, 10 Sep 2022 20:10:00 +1000 Subject: [PATCH 02/77] All tested and fixed --- deployment/commands_std.azcli | 37 +++++++++++++++++++++++++++-- deployment/templates/services.bicep | 9 ++++--- deployment/templates/sites.bicep | 13 ++++++++++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/deployment/commands_std.azcli b/deployment/commands_std.azcli index ba05848..09c933f 100644 --- a/deployment/commands_std.azcli +++ b/deployment/commands_std.azcli @@ -2,6 +2,10 @@ #az cli #jq +# App url +APPGW_APP1_URL=votingapp-std.contoso.com +APPGW_APP2_URL=testapp-std.contoso.com + #Parameters RGNAME=yourResourceGroupName RGLOCATION=yourLocation @@ -9,7 +13,7 @@ SQLADMINUSER=yoursqlAdminUser SQLADMINPASSWORD=yoursqlAdminPassword JUMPBOX_USER=yourJumpBoxUser JUMPBOX_PASSWORD=yourPassword -$ADMIN_USER_ID=$(az ad signed-in-user show --query id -o tsv) +ADMIN_USER_ID=$(az ad signed-in-user show --query id -o tsv) # IP Addresses NET_PREFIX=10.0.0.0/16 @@ -74,9 +78,10 @@ KEYVAULT_NAME=$(az deployment group show -g $RGNAME -n services --query properti RESOURCES_STORAGE_ACCOUNT=$(az deployment group show -g $RGNAME -n services --query properties.outputs.resourcesStorageAccountName.value -o tsv) RESOURCES_CONTAINER_NAME=$(az deployment group show -g $RGNAME -n services --query properties.outputs.resourcesContainerName.value -o tsv) + # Uploads image to the storage account az storage blob upload -c $RESOURCES_CONTAINER_NAME -f Microsoft_Azure_logo_small.png -n Microsoft_Azure_logo_small.png --account-name $RESOURCES_STORAGE_ACCOUNT -RESOURCE_URL="$(az storage account show -n $RESOURCES_STORAGE_ACCOUNT --query primaryEndpoints.blob -o tsv)$RESOURCES_CONTAINER_NAME/Microsoft_Azure_logo_small.png" +RESOURCE_URL="$(az storage account show -g $RGNAME -n $RESOURCES_STORAGE_ACCOUNT --query primaryEndpoints.blob -o tsv)$RESOURCES_CONTAINER_NAME/Microsoft_Azure_logo_small.png" # 8. Create the app service plans and the sites az deployment group create --resource-group $RGNAME --template-file templates/sites.bicep -n sites --parameters aseName=$ASE_NAME \ @@ -91,6 +96,34 @@ VOTING_COUNTER_FUNCTION_PRINCIPAL_ID=$(az deployment group show -g $RGNAME -n si VOTING_API_NAME=$(az deployment group show -g $RGNAME -n sites --query properties.outputs.votingApiName.value -o tsv) && \ VOTING_API_PRINCIPAL_ID=$(az deployment group show -g $RGNAME -n sites --query properties.outputs.votingApiIdentityPrincipalId.value -o tsv) + + +#Suhas Test +echo $VNET_NAME +echo $VNET_ROUTE_NAME +echo $ASE_DNS_SUFFIX +echo $ASE_SUBNET_NAME +echo $ASE_NAME +echo $ASE_ID +echo $ASE_ILB_IP_ADDRESS +echo $JUMPBOX_PUBLIC_IP +echo $JUMPBOX_SUBNET_NAME +echo $COSMOSDB_NAME +echo $SQL_SERVER +echo $SQL_DATABASE +echo $KEYVAULT_NAME +echo $RESOURCES_STORAGE_ACCOUNT +echo $RESOURCES_CONTAINER_NAME +echo $RESOURCE_URL +echo $INTERNAL_APP1_URL +echo $INTERNAL_APP2_URL +echo $VOTING_WEB_APP_PRINCIPAL_ID +echo $VOTING_COUNTER_FUNCTION_NAME +echo $VOTING_COUNTER_FUNCTION_PRINCIPAL_ID +echo $VOTING_API_NAME +echo $VOTING_API_PRINCIPAL_ID + + # 9. Deploy RBAC for resources after AAD propagation until az ad sp show --id ${VOTING_WEB_APP_PRINCIPAL_ID} &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done until az ad sp show --id ${VOTING_API_PRINCIPAL_ID} &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done diff --git a/deployment/templates/services.bicep b/deployment/templates/services.bicep index 835c2e9..95ee3f9 100644 --- a/deployment/templates/services.bicep +++ b/deployment/templates/services.bicep @@ -32,7 +32,7 @@ var serviceBusName_var = 'votingservicebus${uniqueString(resourceGroup().id)}' var serviceBusQueue = 'votingqueue' var resourcesStorageAccountName_var = toLower('resources${uniqueString(resourceGroup().id)}') var resourcesContainerName = 'rscontainer' -var keyVaultName_var = 'keyvault-${uniqueString(resourceGroup().id)}' +var keyVaultName_var = 'akv-${uniqueString(resourceGroup().id)}' var allowedSubnetNamesArray = split(allowedSubnetNames, ',') resource cosmosName 'Microsoft.DocumentDB/databaseAccounts@2022-05-15' = { @@ -135,6 +135,8 @@ resource sqlServerName_sqlDatabaseName 'Microsoft.Sql/servers/databases@2022-02- } } +/* + resource sqlServerName_activeDirectory 'Microsoft.Sql/servers/administrators@2022-02-01-preview' = { parent: sqlServerName name: 'activeDirectory' @@ -147,7 +149,7 @@ resource sqlServerName_activeDirectory 'Microsoft.Sql/servers/administrators@202 } } -/* resource sqlServerName_allow_subnet_sql 'Microsoft.Sql/servers/virtualNetworkRules@2022-02-01-preview' = [for (item, i) in allowedSubnetNamesArray: { + resource sqlServerName_allow_subnet_sql 'Microsoft.Sql/servers/virtualNetworkRules@2022-02-01-preview' = [for (item, i) in allowedSubnetNamesArray: { name: '${sqlServerName_var}/allow-subnet-sql-${i}' //location: location properties: { @@ -275,6 +277,7 @@ resource resourcesStorageAccountName 'Microsoft.Storage/storageAccounts@2021-09- } } +/* resource resourcesStorageAccountName_default_resourcesContainerName 'Microsoft.Storage/storageAccounts/blobServices/containers@2021-09-01' = { name: '${resourcesStorageAccountName_var}/default/${resourcesContainerName}' properties: { @@ -283,7 +286,7 @@ resource resourcesStorageAccountName_default_resourcesContainerName 'Microsoft.S dependsOn: [ resourcesStorageAccountName ] -} +}*/ output cosmosDbName string = cosmosName_var output sqlServerName string = sqlServerName_var diff --git a/deployment/templates/sites.bicep b/deployment/templates/sites.bicep index 0657a53..5691259 100644 --- a/deployment/templates/sites.bicep +++ b/deployment/templates/sites.bicep @@ -25,6 +25,9 @@ param sqlServerName string @description('The name for the sql database') param sqlDatabaseName string +@description('The name for the log analytics workspace') +param logAnalyticsWorkspace string = '${uniqueString(resourceGroup().id)}la' + @description('The availability zone to deploy. Valid values are: 1, 2 or 3. Use empty to not use zones.') param zone string = '' @@ -193,6 +196,12 @@ resource keyVaultName_redisSecretName 'Microsoft.KeyVault/vaults/secrets@2022-07 } } +resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = { + name: logAnalyticsWorkspace + location: location +} + + resource votingFunctionName 'Microsoft.Insights/components@2020-02-02' = { name: votingFunctionName_var location: location @@ -201,6 +210,7 @@ resource votingFunctionName 'Microsoft.Insights/components@2020-02-02' = { Application_Type: 'web' Flow_Type: 'Redfield' Request_Source: 'AppServiceEnablementCreate' + WorkspaceResourceId: logAnalytics.id } } @@ -212,6 +222,7 @@ resource votingApiName 'Microsoft.Insights/components@2020-02-02' = { Application_Type: 'web' Flow_Type: 'Redfield' HockeyAppId: '' + WorkspaceResourceId: logAnalytics.id } } @@ -223,6 +234,7 @@ resource votingWebName 'Microsoft.Insights/components@2020-02-02' = { Application_Type: 'web' Flow_Type: 'Redfield' HockeyAppId: '' + WorkspaceResourceId: logAnalytics.id } } @@ -234,6 +246,7 @@ resource testWebName 'Microsoft.Insights/components@2020-02-02' = { Application_Type: 'web' Flow_Type: 'Redfield' HockeyAppId: '' + WorkspaceResourceId: logAnalytics.id } } From be58472db5b682dd71339e2b5db48637fbfb963c Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Thu, 29 Dec 2022 11:58:16 +1100 Subject: [PATCH 03/77] App Gateway Template Added and Bash Script Completed (#1) * changing the resourcesid * App Gateway Support Added and Bash Script Completed * examples removed --- deployment/commands_std.azcli | 61 ++++++++++++++++++++++++- deployment/templates/appgw.bicep | 77 ++++++++++++++++---------------- 2 files changed, 99 insertions(+), 39 deletions(-) diff --git a/deployment/commands_std.azcli b/deployment/commands_std.azcli index 09c933f..88ab2f5 100644 --- a/deployment/commands_std.azcli +++ b/deployment/commands_std.azcli @@ -13,6 +13,7 @@ SQLADMINUSER=yoursqlAdminUser SQLADMINPASSWORD=yoursqlAdminPassword JUMPBOX_USER=yourJumpBoxUser JUMPBOX_PASSWORD=yourPassword +PFX_PASSWORD=yourPassword ADMIN_USER_ID=$(az ad signed-in-user show --query id -o tsv) # IP Addresses @@ -25,14 +26,29 @@ JUMPBOX_PREFIX=10.0.250.0/24 #Suhas params - delete before commits RGNAME=asev3-rg -RGLOCATION=westus3 +RGLOCATION=eastus SQLADMINUSER=suadmin SQLADMINPASSWORD=P@ssword1234 JUMPBOX_USER=sujumpboxuser JUMPBOX_PASSWORD=P@ssword1234 +PFX_PASSWORD=P@ssword1234 +VNET_NAME=ASE-VNETaimoczwhjiepc +INTERNAL_APP1_URL="kind-ocean-006539010.2.azurestaticapps.net" +INTERNAL_APP2_URL="kind-ocean-006539010.2.azurestaticapps.net" az account set -n 'suhas-sub' +# 0. Create self-signed SSL certificate +openssl req -x509 -nodes -days 365 -newkey rsa:2048 -subj "/CN=${APPGW_APP1_URL}" -out appgw_std.crt -keyout appgw_std.key +openssl pkcs12 -export -out appgw_std.pfx -in appgw_std.crt -inkey appgw_std.key -passout pass:$PFX_PASSWORD +CERT_DATA_1=$(cat appgw_std.pfx | base64 | tr -d '\n' | tr -d '\r') +rm appgw_std.crt appgw_std.key appgw_std.pfx + +openssl req -x509 -nodes -days 365 -newkey rsa:2048 -subj "/CN=${APPGW_APP2_URL}" -out appgw_std.crt -keyout appgw_std.key +openssl pkcs12 -export -out appgw_std.pfx -in appgw_std.crt -inkey appgw_std.key -passout pass:$PFX_PASSWORD +CERT_DATA_2=$(cat appgw_std.pfx | base64 | tr -d '\n' | tr -d '\r') +rm appgw_std.crt appgw_std.key appgw_std.pfx + # 1. creates the resource group az group create --name "${RGNAME}" --location "${RGLOCATION}" @@ -132,3 +148,46 @@ az deployment group create --resource-group $RGNAME --template-file templates/rb --parameters votingWebAppIdentityPrincipalId=$VOTING_WEB_APP_PRINCIPAL_ID votingCounterFunctionIdentityPrincipalId=$VOTING_COUNTER_FUNCTION_PRINCIPAL_ID \ keyVaultName=$KEYVAULT_NAME +# 10. Deploy App Gateway + +cat < appgwApps.parameters.json +[ + { + "name": "votapp", + "routingPriority": 100, + "hostName": "${APPGW_APP1_URL}", + "backendAddresses": [ + { + "fqdn": "${INTERNAL_APP1_URL}" + } + ], + "certificate": { + "data": "${CERT_DATA_1}", + "password": "${PFX_PASSWORD}" + }, + "probePath": "/health" + }, + { + "name": "testapp", + "routingPriority": 101, + "hostName": "${APPGW_APP2_URL}", + "backendAddresses": [ + { + "fqdn": "${INTERNAL_APP2_URL}" + } + ], + "certificate": { + "data": "${CERT_DATA_2}", + "password": "${PFX_PASSWORD}" + }, + "probePath": "/" + } +] +EOF + +az deployment group create --resource-group $RGNAME --template-file templates/appgw.bicep --parameters vnetName=$VNET_NAME subnetAddressWithPrefix=$APPGW_PREFIX appgwApplications=@appgwApps.parameters.json +APPGW_PUBLIC_IP=$(az deployment group show -g $RGNAME -n appgw --query properties.outputs.appGwPublicIpAddress.value -o tsv) + +# Removes autogenerated parameter file +rm appgwApps.parameters.json +rm appgw_std.key \ No newline at end of file diff --git a/deployment/templates/appgw.bicep b/deployment/templates/appgw.bicep index 40509e6..29c3e1a 100644 --- a/deployment/templates/appgw.bicep +++ b/deployment/templates/appgw.bicep @@ -5,7 +5,7 @@ param location string = resourceGroup().location param vnetName string @description('The ip address prefix that gateway will use.') -param appgwSubnetAddressPrefix string +param subnetAddressWithPrefix string @description('List of applications to configure. Each element format is: { name, hostName, backendAddresses, certificate: { data, password }, probePath }') param appgwApplications array @@ -13,27 +13,28 @@ param appgwApplications array @description('Comma separated application gateway zones.') param appgwZones string = '' -var appgwName_var = 'appgw' -//var appgwId = resourceId('',appgwName) -var appgwSubnetName = 'appgw-subnet-${appgwName_var}' -var appgwSubnetId = vnetName_appgwSubnetName.id -var appgwNSGName_var = '${vnetName}-APPGW-NSG' -var appgwPublicIpAddressName_var = 'AppGatewayIp' -var appGwPublicIpAddressId = appgwPublicIpAddressName.id -var appgwIpConfigName = '${appgwName_var}-ipconfig' -var appgwFrontendName = '${appgwName_var}-frontend' -var appgwBackendName = '${appgwName_var}-backend-' -var appgwHttpSettingsName = '${appgwName_var}-httpsettings-' -var appgwHealthProbeName = '${appgwName_var}-healthprobe-' -var appgwListenerName = '${appgwName_var}-listener-' -var appgwSslCertificateName = '${appgwName_var}-ssl-' -var appgwRouteRulesName = '${appgwName_var}-routerules-' +var appGatewayName = '${vnetName}-appgw' +var subnetNameWithoutSegment = '${appGatewayName}-subnet' +var subnetName = '${vnetName}/${subnetNameWithoutSegment}' +var appgwId = resourceId('Microsoft.Network/applicationGateways', appGatewayName) +var appgwSubnetId = resourceId('Microsoft.Network/virtualNetworks/subnets', vnetName, subnetNameWithoutSegment) +var appgwNSGName = '${vnetName}-appgw-NSG' +var appgwPublicIpAddressName = '${vnetName}-appgw-Ip' +var appGwPublicIpAddressId = resourceId('Microsoft.Network/publicIPAddresses',appgwPublicIpAddressName) +var appgwIpConfigName = '${appGatewayName}-ipconfig' +var appgwFrontendName = '${appGatewayName}-frontend' +var appgwBackendName = '${appGatewayName}-backend-' +var appgwHttpSettingsName = '${appGatewayName}-httpsettings-' +var appgwHealthProbeName = '${appGatewayName}-healthprobe-' +var appgwListenerName = '${appGatewayName}-listener-' +var appgwSslCertificateName = '${appGatewayName}-ssl-' +var appgwRouteRulesName = '${appGatewayName}-routerules-' var appgwAutoScaleMinCapacity = 0 var appgwAutoScaleMaxCapacity = 10 var appgwZonesArray = (empty(appgwZones) ? json('null') : split(appgwZones, ',')) -resource appgwPublicIpAddressName 'Microsoft.Network/publicIPAddresses@2022-01-01' = { - name: appgwPublicIpAddressName_var +resource publicIPAddress 'Microsoft.Network/publicIPAddresses@2022-05-01' = { + name: appgwPublicIpAddressName location: location sku: { name: 'Standard' @@ -43,11 +44,11 @@ resource appgwPublicIpAddressName 'Microsoft.Network/publicIPAddresses@2022-01-0 } } -resource appgwNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { - name: appgwNSGName_var +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2022-05-01' = { + name: appgwNSGName location: location tags: { - displayName: appgwNSGName_var + displayName: appgwNSGName } properties: { securityRules: [ @@ -90,7 +91,7 @@ resource appgwNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { '443' ] sourceAddressPrefix: 'Internet' - destinationAddressPrefix: appgwSubnetAddressPrefix + destinationAddressPrefix: subnetAddressWithPrefix access: 'Allow' priority: 202 direction: 'Inbound' @@ -100,17 +101,16 @@ resource appgwNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { } } -resource vnetName_appgwSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { - name: '${vnetName}/${appgwSubnetName}' - //location: location +resource appGatewaySubnet 'Microsoft.Network/virtualNetworks/subnets@2022-05-01' = { + name: subnetName properties: { - addressPrefix: appgwSubnetAddressPrefix - networkSecurityGroup: { id: appgwNSGName.id } + addressPrefix: subnetAddressWithPrefix + networkSecurityGroup: { id: networkSecurityGroup.id, location: location } } } -resource appgwName 'Microsoft.Network/applicationGateways@2022-01-01' = { - name: appgwName_var +resource appGateway 'Microsoft.Network/applicationGateways@2022-05-01' = { + name: appGatewayName location: location zones: appgwZonesArray tags: { @@ -161,7 +161,7 @@ resource appgwName 'Microsoft.Network/applicationGateways@2022-01-01' = { enableHttp2: false backendAddressPools: [for item in appgwApplications: { name: '${appgwBackendName}${item.name}' - properties: { + properties: { backendAddresses: item.backendAddresses } }] @@ -174,7 +174,7 @@ resource appgwName 'Microsoft.Network/applicationGateways@2022-01-01' = { pickHostNameFromBackendAddress: true requestTimeout: 20 probe: { - id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/probes/${appgwHealthProbeName}${item.name}' + id: '${appgwId}/probes/${appgwHealthProbeName}${item.name}' } } }] @@ -182,14 +182,14 @@ resource appgwName 'Microsoft.Network/applicationGateways@2022-01-01' = { name: '${appgwListenerName}${item.name}' properties: { frontendIPConfiguration: { - id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/frontendIPConfigurations/${appgwFrontendName}' + id: '${appgwId}/frontendIPConfigurations/${appgwFrontendName}' } frontendPort: { - id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/frontendPorts/port_443' + id: '${appgwId}/frontendPorts/port_443' } protocol: 'Https' sslCertificate: { - id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/sslCertificates/${appgwSslCertificateName}${item.name}' + id: '${appgwId}/sslCertificates/${appgwSslCertificateName}${item.name}' } hostName: item.hostName requireServerNameIndication: true @@ -198,15 +198,16 @@ resource appgwName 'Microsoft.Network/applicationGateways@2022-01-01' = { requestRoutingRules: [for item in appgwApplications: { name: '${appgwRouteRulesName}${item.name}' properties: { + priority: item.routingPriority ruleType: 'Basic' httpListener: { - id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/httpListeners/${appgwListenerName}${item.name}' + id: '${appgwId}/httpListeners/${appgwListenerName}${item.name}' } backendAddressPool: { - id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/backendAddressPools/${appgwBackendName}${item.name}' + id: '${appgwId}/backendAddressPools/${appgwBackendName}${item.name}' } backendHttpSettings: { - id: '${resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwName_var)}/backendHttpSettingsCollection/${appgwHttpSettingsName}${item.name}' + id: '${appgwId}/backendHttpSettingsCollection/${appgwHttpSettingsName}${item.name}' } } }] @@ -237,4 +238,4 @@ resource appgwName 'Microsoft.Network/applicationGateways@2022-01-01' = { } } -output appGwPublicIpAddress string = appgwPublicIpAddressName.properties.ipAddress +output appGwPublicIpAddress string = publicIPAddress.properties.ipAddress From d88af232cf87177f920abb7f3f84be074d0ffa0c Mon Sep 17 00:00:00 2001 From: DeeplyDiligent Date: Mon, 23 Jan 2023 08:58:27 +1100 Subject: [PATCH 04/77] updated versions of deployed resources --- deployment/commands_std.azcli | 2 +- deployment/templates/firewall.bicep | 6 +++--- deployment/templates/jumpbox.bicep | 12 ++++++------ deployment/templates/sites.bicep | 19 ++++++++----------- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/deployment/commands_std.azcli b/deployment/commands_std.azcli index 88ab2f5..c26399f 100644 --- a/deployment/commands_std.azcli +++ b/deployment/commands_std.azcli @@ -188,6 +188,6 @@ EOF az deployment group create --resource-group $RGNAME --template-file templates/appgw.bicep --parameters vnetName=$VNET_NAME subnetAddressWithPrefix=$APPGW_PREFIX appgwApplications=@appgwApps.parameters.json APPGW_PUBLIC_IP=$(az deployment group show -g $RGNAME -n appgw --query properties.outputs.appGwPublicIpAddress.value -o tsv) -# Removes autogenerated parameter file +# 10.1 Removes autogenerated parameter file rm appgwApps.parameters.json rm appgw_std.key \ No newline at end of file diff --git a/deployment/templates/firewall.bicep b/deployment/templates/firewall.bicep index 9624f56..889abd5 100644 --- a/deployment/templates/firewall.bicep +++ b/deployment/templates/firewall.bicep @@ -25,7 +25,7 @@ var firewallName_var = 'firewall-${uniqueString(resourceGroup().id)}' */ -resource vnetName_firewallSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { +resource vnetName_firewallSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-07-01' = { name: '${vnetName}/${firewallSubnetName}' properties: { addressPrefix: firewallSubnetPrefix @@ -58,7 +58,7 @@ resource vnetName_firewallSubnetName 'Microsoft.Network/virtualNetworks/subnets@ } } -resource firewallPublicIpName 'Microsoft.Network/publicIPAddresses@2022-01-01' = { +resource firewallPublicIpName 'Microsoft.Network/publicIPAddresses@2022-07-01' = { location: location name: firewallPublicIpName_var sku: { @@ -71,7 +71,7 @@ resource firewallPublicIpName 'Microsoft.Network/publicIPAddresses@2022-01-01' = } } -resource firewallName 'Microsoft.Network/azureFirewalls@2022-01-01' = { +resource firewallName 'Microsoft.Network/azureFirewalls@2022-07-01' = { name: firewallName_var location: location properties: { diff --git a/deployment/templates/jumpbox.bicep b/deployment/templates/jumpbox.bicep index 931eee8..96dbd67 100644 --- a/deployment/templates/jumpbox.bicep +++ b/deployment/templates/jumpbox.bicep @@ -22,7 +22,7 @@ var jumpboxPublicIpName_var = 'jumpbox-pip-${uniqueString(resourceGroup().id)}' var jumpboxNSGName_var = '${vnetName}-JUMPBOX-NSG' var jumpboxNicName_var = 'jumpbox-nic-${uniqueString(resourceGroup().id)}' -resource jumpboxPublicIpName 'Microsoft.Network/publicIPAddresses@2022-01-01' = { +resource jumpboxPublicIpName 'Microsoft.Network/publicIPAddresses@2022-07-01' = { name: jumpboxPublicIpName_var location: location properties: { @@ -33,7 +33,7 @@ resource jumpboxPublicIpName 'Microsoft.Network/publicIPAddresses@2022-01-01' = } } -resource jumpboxNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { +resource jumpboxNSGName 'Microsoft.Network/networkSecurityGroups@2022-07-01' = { name: jumpboxNSGName_var location: location tags: { @@ -59,8 +59,8 @@ resource jumpboxNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { } } -resource vnetName_jumpboxSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { - name: '${vnetName}/${jumpboxSubnetName}' +resource vnetName_jumpboxSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-07-01' = { + name: '${vnetName}/${jumpboxSubnetName}' properties: { addressPrefix: subnetAddressPrefix networkSecurityGroup: { @@ -69,7 +69,7 @@ resource vnetName_jumpboxSubnetName 'Microsoft.Network/virtualNetworks/subnets@2 } } -resource jumpboxNicName 'Microsoft.Network/networkInterfaces@2022-01-01' = { +resource jumpboxNicName 'Microsoft.Network/networkInterfaces@2022-07-01' = { name: jumpboxNicName_var location: location properties: { @@ -90,7 +90,7 @@ resource jumpboxNicName 'Microsoft.Network/networkInterfaces@2022-01-01' = { } } -resource jumpboxName 'Microsoft.Compute/virtualMachines@2019-07-01' = { +resource jumpboxName 'Microsoft.Compute/virtualMachines@2022-08-01' = { name: jumpboxName_var location: location properties: { diff --git a/deployment/templates/sites.bicep b/deployment/templates/sites.bicep index 5691259..237ccc5 100644 --- a/deployment/templates/sites.bicep +++ b/deployment/templates/sites.bicep @@ -50,7 +50,7 @@ var testWebPlanName_var = '${testWebName_var}-plan' var votingFunctionPlanName_var = '${votingFunctionName_var}-plan' var aseId = resourceId('Microsoft.Web/hostingEnvironments', aseName) -resource redisNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { +resource redisNSGName 'Microsoft.Network/networkSecurityGroups@2022-07-01' = { name: redisNSGName_var location: location tags: { @@ -160,7 +160,7 @@ resource redisNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { } } -resource vnetName_redisSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { +resource vnetName_redisSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-07-01' = { name: '${vnetName}/${redisSubnetName}' //location: location properties: { @@ -171,7 +171,7 @@ resource vnetName_redisSubnetName 'Microsoft.Network/virtualNetworks/subnets@202 } } -resource redisName 'Microsoft.Cache/Redis@2019-07-01' = { +resource redisName 'Microsoft.Cache/Redis@2022-06-01' = { name: redisName_var location: location zones: (empty(zone) ? json('null') : array(zone)) @@ -182,9 +182,6 @@ resource redisName 'Microsoft.Cache/Redis@2019-07-01' = { capacity: 3 } enableNonSslPort: false - redisConfiguration: { - maxclients: '5000' - } subnetId: redisSubnetId } } @@ -196,7 +193,7 @@ resource keyVaultName_redisSecretName 'Microsoft.KeyVault/vaults/secrets@2022-07 } } -resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = { +resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { name: logAnalyticsWorkspace location: location } @@ -413,7 +410,7 @@ resource Microsoft_Web_sites_votingApiName 'Microsoft.Web/sites@2022-03-01' = { } } -resource Microsoft_Web_sites_votingWebName 'Microsoft.Web/sites@2018-11-01' = { +resource Microsoft_Web_sites_votingWebName 'Microsoft.Web/sites@2022-03-01' = { name: votingWebName_var location: location kind: 'app' @@ -504,6 +501,6 @@ output votingAppUrl string = '${votingWebName_var}.${aseDnsSuffix}' output testAppUrl string = '${testWebName_var}.${aseDnsSuffix}' output votingApiName string = votingApiName_var output votingFunctionName string = votingFunctionName_var -output votingWebAppIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingWebName_var}', '2018-11-01', 'Full').identity.principalId -output votingApiIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingApiName_var}', '2018-11-01', 'Full').identity.principalId -output votingCounterFunctionIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingFunctionName_var}', '2018-11-01', 'Full').identity.principalId +output votingWebAppIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingWebName_var}', '2022-03-01', 'Full').identity.principalId +output votingApiIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingApiName_var}', '2022-03-01', 'Full').identity.principalId +output votingCounterFunctionIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingFunctionName_var}', '2022-03-01', 'Full').identity.principalId From 2f234e97c17a94b7f27a79948c17444016c6cab4 Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Wed, 25 Jan 2023 10:23:17 +1100 Subject: [PATCH 05/77] updated versions of deployed resources (#2) --- deployment/commands_std.azcli | 2 +- deployment/templates/firewall.bicep | 6 +++--- deployment/templates/jumpbox.bicep | 12 ++++++------ deployment/templates/sites.bicep | 19 ++++++++----------- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/deployment/commands_std.azcli b/deployment/commands_std.azcli index 88ab2f5..c26399f 100644 --- a/deployment/commands_std.azcli +++ b/deployment/commands_std.azcli @@ -188,6 +188,6 @@ EOF az deployment group create --resource-group $RGNAME --template-file templates/appgw.bicep --parameters vnetName=$VNET_NAME subnetAddressWithPrefix=$APPGW_PREFIX appgwApplications=@appgwApps.parameters.json APPGW_PUBLIC_IP=$(az deployment group show -g $RGNAME -n appgw --query properties.outputs.appGwPublicIpAddress.value -o tsv) -# Removes autogenerated parameter file +# 10.1 Removes autogenerated parameter file rm appgwApps.parameters.json rm appgw_std.key \ No newline at end of file diff --git a/deployment/templates/firewall.bicep b/deployment/templates/firewall.bicep index 9624f56..889abd5 100644 --- a/deployment/templates/firewall.bicep +++ b/deployment/templates/firewall.bicep @@ -25,7 +25,7 @@ var firewallName_var = 'firewall-${uniqueString(resourceGroup().id)}' */ -resource vnetName_firewallSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { +resource vnetName_firewallSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-07-01' = { name: '${vnetName}/${firewallSubnetName}' properties: { addressPrefix: firewallSubnetPrefix @@ -58,7 +58,7 @@ resource vnetName_firewallSubnetName 'Microsoft.Network/virtualNetworks/subnets@ } } -resource firewallPublicIpName 'Microsoft.Network/publicIPAddresses@2022-01-01' = { +resource firewallPublicIpName 'Microsoft.Network/publicIPAddresses@2022-07-01' = { location: location name: firewallPublicIpName_var sku: { @@ -71,7 +71,7 @@ resource firewallPublicIpName 'Microsoft.Network/publicIPAddresses@2022-01-01' = } } -resource firewallName 'Microsoft.Network/azureFirewalls@2022-01-01' = { +resource firewallName 'Microsoft.Network/azureFirewalls@2022-07-01' = { name: firewallName_var location: location properties: { diff --git a/deployment/templates/jumpbox.bicep b/deployment/templates/jumpbox.bicep index 931eee8..96dbd67 100644 --- a/deployment/templates/jumpbox.bicep +++ b/deployment/templates/jumpbox.bicep @@ -22,7 +22,7 @@ var jumpboxPublicIpName_var = 'jumpbox-pip-${uniqueString(resourceGroup().id)}' var jumpboxNSGName_var = '${vnetName}-JUMPBOX-NSG' var jumpboxNicName_var = 'jumpbox-nic-${uniqueString(resourceGroup().id)}' -resource jumpboxPublicIpName 'Microsoft.Network/publicIPAddresses@2022-01-01' = { +resource jumpboxPublicIpName 'Microsoft.Network/publicIPAddresses@2022-07-01' = { name: jumpboxPublicIpName_var location: location properties: { @@ -33,7 +33,7 @@ resource jumpboxPublicIpName 'Microsoft.Network/publicIPAddresses@2022-01-01' = } } -resource jumpboxNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { +resource jumpboxNSGName 'Microsoft.Network/networkSecurityGroups@2022-07-01' = { name: jumpboxNSGName_var location: location tags: { @@ -59,8 +59,8 @@ resource jumpboxNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { } } -resource vnetName_jumpboxSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { - name: '${vnetName}/${jumpboxSubnetName}' +resource vnetName_jumpboxSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-07-01' = { + name: '${vnetName}/${jumpboxSubnetName}' properties: { addressPrefix: subnetAddressPrefix networkSecurityGroup: { @@ -69,7 +69,7 @@ resource vnetName_jumpboxSubnetName 'Microsoft.Network/virtualNetworks/subnets@2 } } -resource jumpboxNicName 'Microsoft.Network/networkInterfaces@2022-01-01' = { +resource jumpboxNicName 'Microsoft.Network/networkInterfaces@2022-07-01' = { name: jumpboxNicName_var location: location properties: { @@ -90,7 +90,7 @@ resource jumpboxNicName 'Microsoft.Network/networkInterfaces@2022-01-01' = { } } -resource jumpboxName 'Microsoft.Compute/virtualMachines@2019-07-01' = { +resource jumpboxName 'Microsoft.Compute/virtualMachines@2022-08-01' = { name: jumpboxName_var location: location properties: { diff --git a/deployment/templates/sites.bicep b/deployment/templates/sites.bicep index 5691259..237ccc5 100644 --- a/deployment/templates/sites.bicep +++ b/deployment/templates/sites.bicep @@ -50,7 +50,7 @@ var testWebPlanName_var = '${testWebName_var}-plan' var votingFunctionPlanName_var = '${votingFunctionName_var}-plan' var aseId = resourceId('Microsoft.Web/hostingEnvironments', aseName) -resource redisNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { +resource redisNSGName 'Microsoft.Network/networkSecurityGroups@2022-07-01' = { name: redisNSGName_var location: location tags: { @@ -160,7 +160,7 @@ resource redisNSGName 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { } } -resource vnetName_redisSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { +resource vnetName_redisSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-07-01' = { name: '${vnetName}/${redisSubnetName}' //location: location properties: { @@ -171,7 +171,7 @@ resource vnetName_redisSubnetName 'Microsoft.Network/virtualNetworks/subnets@202 } } -resource redisName 'Microsoft.Cache/Redis@2019-07-01' = { +resource redisName 'Microsoft.Cache/Redis@2022-06-01' = { name: redisName_var location: location zones: (empty(zone) ? json('null') : array(zone)) @@ -182,9 +182,6 @@ resource redisName 'Microsoft.Cache/Redis@2019-07-01' = { capacity: 3 } enableNonSslPort: false - redisConfiguration: { - maxclients: '5000' - } subnetId: redisSubnetId } } @@ -196,7 +193,7 @@ resource keyVaultName_redisSecretName 'Microsoft.KeyVault/vaults/secrets@2022-07 } } -resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = { +resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { name: logAnalyticsWorkspace location: location } @@ -413,7 +410,7 @@ resource Microsoft_Web_sites_votingApiName 'Microsoft.Web/sites@2022-03-01' = { } } -resource Microsoft_Web_sites_votingWebName 'Microsoft.Web/sites@2018-11-01' = { +resource Microsoft_Web_sites_votingWebName 'Microsoft.Web/sites@2022-03-01' = { name: votingWebName_var location: location kind: 'app' @@ -504,6 +501,6 @@ output votingAppUrl string = '${votingWebName_var}.${aseDnsSuffix}' output testAppUrl string = '${testWebName_var}.${aseDnsSuffix}' output votingApiName string = votingApiName_var output votingFunctionName string = votingFunctionName_var -output votingWebAppIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingWebName_var}', '2018-11-01', 'Full').identity.principalId -output votingApiIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingApiName_var}', '2018-11-01', 'Full').identity.principalId -output votingCounterFunctionIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingFunctionName_var}', '2018-11-01', 'Full').identity.principalId +output votingWebAppIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingWebName_var}', '2022-03-01', 'Full').identity.principalId +output votingApiIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingApiName_var}', '2022-03-01', 'Full').identity.principalId +output votingCounterFunctionIdentityPrincipalId string = reference('Microsoft.Web/sites/${votingFunctionName_var}', '2022-03-01', 'Full').identity.principalId From 9a82b879b1d4c34adec0ab4ef68b7a6df3657b44 Mon Sep 17 00:00:00 2001 From: DeeplyDiligent Date: Mon, 13 Feb 2023 13:46:14 +1100 Subject: [PATCH 06/77] testing bugs - removed duplicate names --- deployment/commands_std.azcli | 5 ++--- deployment/templates/appgw.bicep | 2 +- deployment/templates/ase.bicep | 2 +- deployment/templates/services.bicep | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/deployment/commands_std.azcli b/deployment/commands_std.azcli index c26399f..51ddf10 100644 --- a/deployment/commands_std.azcli +++ b/deployment/commands_std.azcli @@ -71,7 +71,7 @@ ASE_ILB_IP_ADDRESS=$(az resource show --resource-group $RGNAME --name $ASE_NAME az deployment group create --resource-group $RGNAME --template-file templates/firewall.bicep --parameters vnetName=$VNET_NAME firewallSubnetPrefix=$FIREWALL_PREFIX -# 5. deploy the private DNS zone +# 5. deploy the private DNS az deployment group create --resource-group $RGNAME --template-file templates/dns.bicep -n dns --parameters vnetName=$VNET_NAME zoneName=$ASE_DNS_SUFFIX ipAddress=$ASE_ILB_IP_ADDRESS @@ -189,5 +189,4 @@ az deployment group create --resource-group $RGNAME --template-file templates/ap APPGW_PUBLIC_IP=$(az deployment group show -g $RGNAME -n appgw --query properties.outputs.appGwPublicIpAddress.value -o tsv) # 10.1 Removes autogenerated parameter file -rm appgwApps.parameters.json -rm appgw_std.key \ No newline at end of file +rm appgwApps.parameters.json \ No newline at end of file diff --git a/deployment/templates/appgw.bicep b/deployment/templates/appgw.bicep index 29c3e1a..f67294c 100644 --- a/deployment/templates/appgw.bicep +++ b/deployment/templates/appgw.bicep @@ -17,7 +17,7 @@ var appGatewayName = '${vnetName}-appgw' var subnetNameWithoutSegment = '${appGatewayName}-subnet' var subnetName = '${vnetName}/${subnetNameWithoutSegment}' var appgwId = resourceId('Microsoft.Network/applicationGateways', appGatewayName) -var appgwSubnetId = resourceId('Microsoft.Network/virtualNetworks/subnets', vnetName, subnetNameWithoutSegment) +var appgwSubnetId = appGatewaySubnet.id var appgwNSGName = '${vnetName}-appgw-NSG' var appgwPublicIpAddressName = '${vnetName}-appgw-Ip' var appGwPublicIpAddressId = resourceId('Microsoft.Network/publicIPAddresses',appgwPublicIpAddressName) diff --git a/deployment/templates/ase.bicep b/deployment/templates/ase.bicep index d898edd..93af8f6 100644 --- a/deployment/templates/ase.bicep +++ b/deployment/templates/ase.bicep @@ -24,7 +24,7 @@ var aseSubnetId = vnetName_aseSubnetName.id var aseLoadBalancingMode = 'Web, Publishing' resource vnetName_aseSubnetName 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { - name: '${vnetName}/${aseSubnetName}' + name: '${vnetName}/${aseSubnetName}-1' properties: { addressPrefix: aseSubnetAddressPrefix delegations: [ diff --git a/deployment/templates/services.bicep b/deployment/templates/services.bicep index 95ee3f9..e989825 100644 --- a/deployment/templates/services.bicep +++ b/deployment/templates/services.bicep @@ -32,7 +32,7 @@ var serviceBusName_var = 'votingservicebus${uniqueString(resourceGroup().id)}' var serviceBusQueue = 'votingqueue' var resourcesStorageAccountName_var = toLower('resources${uniqueString(resourceGroup().id)}') var resourcesContainerName = 'rscontainer' -var keyVaultName_var = 'akv-${uniqueString(resourceGroup().id)}' +var keyVaultName_var = 'akvault-${uniqueString(resourceGroup().id)}' var allowedSubnetNamesArray = split(allowedSubnetNames, ',') resource cosmosName 'Microsoft.DocumentDB/databaseAccounts@2022-05-15' = { From 66d8873b0ac52a63a2129fab4f6c00cb597667cd Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Tue, 14 Feb 2023 15:42:09 +1100 Subject: [PATCH 07/77] Create workflow --- .github/workflows/main.yml | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..b795875 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,39 @@ +name: Build and deploy Docker app to Azure + +on: + push: + branches: + - main + +env: + AZURE_WEBAPP_NAME: your-app-name # set this to your application's name + AZURE_WEBAPP_PACKAGE_PATH: '.' # set this to the path to your web app project, defaults to the repository root + DOCKERHUB_USERNAME: your-dockerhub-username # Replace with your Docker Hub username + DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} # Create this secret in the repository + IMAGE_NAME: your-image-name # Replace with your image name as per the step below + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Login to Docker Hub + run: echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u ${{ env.DOCKERHUB_USERNAME }} --password-stdin + + - name: Build and push image to Docker Hub + run: | + docker build . -t ${{ env.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:${{ github.sha }} + docker push ${{ env.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:${{ github.sha }} + + - name: 'Login via Azure CLI' + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: 'Deploy to Azure Web App' + uses: azure/webapps-deploy@v2 + with: + app-name: ${{ env.AZURE_WEBAPP_NAME }} + images: '${{ env.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:${{ github.sha }}' From ec341d998c9e899fc0d359ecd1dbdaacb8bae64a Mon Sep 17 00:00:00 2001 From: DeeplyDiligent Date: Sat, 4 Mar 2023 20:42:47 +0530 Subject: [PATCH 08/77] readme --- README.md | 4 ++++ deployment/commands_std.azcli | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ad214a7..05b7678 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ This reference implementation shows how you can improve the resiliency of an ASE deployment by deploying in multiple availability zones. The standard deployment is also covered. For more information about this scenario, see the reference architecture: [High availability enterprise deployment using App Services Environment](https://docs.microsoft.com/azure/architecture/reference-architectures/enterprise-integration/ase-high-availability-deployment) +## TODO + +[] Make sure you delete secrets + ## Prerequisites - [azure-cli](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest) 2.37.0 or newer. diff --git a/deployment/commands_std.azcli b/deployment/commands_std.azcli index 855483a..5a435c7 100644 --- a/deployment/commands_std.azcli +++ b/deployment/commands_std.azcli @@ -16,7 +16,7 @@ JUMPBOX_PASSWORD=yourPassword PFX_PASSWORD=yourPassword ADMIN_USER_ID=$(az ad signed-in-user show --query id -o tsv) -# IP Addresses +#IP Addresses NET_PREFIX=10.0.0.0/16 APPGW_PREFIX=10.0.1.0/24 REDIS_PREFIX=10.0.2.0/24 From 01cf218c68a8103c689944e9f058611c1d5b8f3c Mon Sep 17 00:00:00 2001 From: DeeplyDiligent Date: Tue, 7 Mar 2023 14:39:40 +0530 Subject: [PATCH 09/77] function app github action --- .github/workflows/function-app.yml | 108 +++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 .github/workflows/function-app.yml diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml new file mode 100644 index 0000000..61ef158 --- /dev/null +++ b/.github/workflows/function-app.yml @@ -0,0 +1,108 @@ +variables: + appEnvironmentName: 'production' + appPath: code/function-app-ri/FunctionApp + deploymentMethod: runFromPackage # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/deploy/azure-function-app?view=azure-devops#deployment-methods + + +trigger: + branches: + include: + - master + - workflow-for-actions + paths: + include: + - $(appPath) + + +stages: +- stage: Build + jobs: + - job: VoteCounterAppBuild + displayName: Vote Counter App Continous Integration + pool: + name: $(poolName) + continueOnError: false + steps: + - task: UseDotNet@2 + displayName: 'Use .Net Core sdk 3.1.x' + inputs: + version: 3.1.x + + - task: DotNetCoreCLI@2 + displayName: Restore + inputs: + command: restore + projects: $(appPath)/VoteCounter.csproj + + - task: DotNetCoreCLI@2 + displayName: Build + inputs: + projects: $(appPath)/VoteCounter.csproj + arguments: '--configuration $(BuildConfiguration) --no-restore' + + - task: DotNetCoreCLI@2 + displayName: Publish + inputs: + command: publish + publishWebProjects: false + workingDirectory: $(appPath) + arguments: '--configuration release --output "$(build.artifactstagingdirectory)" --no-restore' + zipAfterPublish: false + + - task: ArchiveFiles@2 + displayName: 'Archive files' + inputs: + archiveFile: '$(build.artifactstagingdirectory)/votecounter-$(build.buildid).zip' + rootFolderOrFile: '$(build.artifactstagingdirectory)' + includeRootFolder: false + archiveType: zip + + - task: PublishPipelineArtifact@1 + displayName: 'Publish Artifact' + inputs: + targetPath: '$(build.artifactstagingdirectory)/votecounter-$(build.buildid).zip' + artifactName: 'drop' + +- stage: DeployZone1 + dependsOn: + - Build + jobs: + - deployment: VoteCounterAppZone1Deploy + displayName: Vote Counter App Counter Zone 1 Continous Deployment + pool: + name: $(poolName) + environment: $(appEnvironmentName) + strategy: + runOnce: + deploy: + steps: + - task: AzureFunctionApp@1 + displayName: 'Azure Function App Deploy: votingfuncapp-1' + inputs: + azureSubscription: $(azureSubscription) + appType: functionApp + appName: $(functionAppNameZone1) + package: '$(Pipeline.Workspace)/drop/votecounter-$(build.buildid).zip' + deploymentMethod: $(deploymentMethod) + +- stage: DeployZone3 + dependsOn: + - Build + jobs: + - deployment: VoteCounterAppZone3Deploy + displayName: Vote Counter App Counter Zone 3 Continous Deployment + pool: + name: $(poolName) + environment: $(appEnvironmentName) + strategy: + runOnce: + deploy: + steps: + - task: AzureFunctionApp@1 + displayName: 'Azure Function App Deploy: votingfuncapp-3' + inputs: + azureSubscription: $(azureSubscription) + appType: functionApp + appName: $(functionAppNameZone3) + package: '$(Pipeline.Workspace)/drop/votecounter-$(build.buildid).zip' + deploymentMethod: $(deploymentMethod) From 2bdf2844c5db530ab92c83cf347c43b7a896dc96 Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Wed, 8 Mar 2023 15:40:22 +0530 Subject: [PATCH 10/77] Update function-app.yml --- .github/workflows/function-app.yml | 151 +++++++++++------------------ 1 file changed, 54 insertions(+), 97 deletions(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index 61ef158..6ad314b 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -1,108 +1,65 @@ -variables: - appEnvironmentName: 'production' - appPath: code/function-app-ri/FunctionApp - deploymentMethod: runFromPackage # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/deploy/azure-function-app?view=azure-devops#deployment-methods +name: Build and Deploy Vote Counter App +env: + deploymentMethod: runFromPackage -trigger: - branches: - include: - - master - - workflow-for-actions - paths: - include: - - $(appPath) +on: + push: + branches: + - master + - workflow-for-actions +# paths: +# - 'code/function-app-ri/FunctionApp' - -stages: -- stage: Build - jobs: - - job: VoteCounterAppBuild - displayName: Vote Counter App Continous Integration - pool: - name: $(poolName) - continueOnError: false +jobs: + build: + runs-on: windows-latest steps: - - task: UseDotNet@2 - displayName: 'Use .Net Core sdk 3.1.x' - inputs: - version: 3.1.x + - name: Checkout + uses: actions/checkout@v2 - - task: DotNetCoreCLI@2 - displayName: Restore - inputs: - command: restore - projects: $(appPath)/VoteCounter.csproj + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 3.1.x - - task: DotNetCoreCLI@2 - displayName: Build - inputs: - projects: $(appPath)/VoteCounter.csproj - arguments: '--configuration $(BuildConfiguration) --no-restore' + - name: Restore NuGet Packages + run: dotnet restore ${{ env.appPath }}/VoteCounter.csproj - - task: DotNetCoreCLI@2 - displayName: Publish - inputs: - command: publish - publishWebProjects: false - workingDirectory: $(appPath) - arguments: '--configuration release --output "$(build.artifactstagingdirectory)" --no-restore' - zipAfterPublish: false + - name: Build + run: dotnet build ${{ env.appPath }}/VoteCounter.csproj --configuration ${{ env.buildConfiguration }} --no-restore - - task: ArchiveFiles@2 - displayName: 'Archive files' - inputs: - archiveFile: '$(build.artifactstagingdirectory)/votecounter-$(build.buildid).zip' - rootFolderOrFile: '$(build.artifactstagingdirectory)' - includeRootFolder: false - archiveType: zip + - name: Publish + run: dotnet publish ${{ env.appPath }}/VoteCounter.csproj --configuration ${{ env.buildConfiguration }} --output '$(github.workspace)' --no-restore - - task: PublishPipelineArtifact@1 - displayName: 'Publish Artifact' - inputs: - targetPath: '$(build.artifactstagingdirectory)/votecounter-$(build.buildid).zip' - artifactName: 'drop' + - name: Archive Files + uses: actions/upload-artifact@v2 + with: + name: drop + path: ${{ github.workspace }}/votecounter-${{ github.run_id }}.zip -- stage: DeployZone1 - dependsOn: - - Build - jobs: - - deployment: VoteCounterAppZone1Deploy - displayName: Vote Counter App Counter Zone 1 Continous Deployment - pool: - name: $(poolName) - environment: $(appEnvironmentName) - strategy: - runOnce: - deploy: - steps: - - task: AzureFunctionApp@1 - displayName: 'Azure Function App Deploy: votingfuncapp-1' - inputs: - azureSubscription: $(azureSubscription) - appType: functionApp - appName: $(functionAppNameZone1) - package: '$(Pipeline.Workspace)/drop/votecounter-$(build.buildid).zip' - deploymentMethod: $(deploymentMethod) + deploy-zone1: + needs: build + runs-on: ubuntu-latest + environment: 'production' + steps: + - name: Deploy to Zone 1 + uses: azure/webapps-deploy@v2 + with: + app-name: 'app-service-app-1' + package: ${{ github.workspace }}/drop/votecounter-${{ github.run_id }}.zip + slot-name: production + publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} -- stage: DeployZone3 - dependsOn: - - Build - jobs: - - deployment: VoteCounterAppZone3Deploy - displayName: Vote Counter App Counter Zone 3 Continous Deployment - pool: - name: $(poolName) - environment: $(appEnvironmentName) - strategy: - runOnce: - deploy: - steps: - - task: AzureFunctionApp@1 - displayName: 'Azure Function App Deploy: votingfuncapp-3' - inputs: - azureSubscription: $(azureSubscription) - appType: functionApp - appName: $(functionAppNameZone3) - package: '$(Pipeline.Workspace)/drop/votecounter-$(build.buildid).zip' - deploymentMethod: $(deploymentMethod) +# deploy-zone3: +# needs: build +# runs-on: ubuntu-latest +# environment: ${{ env.appEnvironmentName }} +# steps: +# - name: Deploy to Zone 3 +# uses: azure/webapps-deploy@v2 +# with: +# app-name: ${{ secrets.functionAppNameZone3 }} +# package: ${{ github.workspace }}/drop/votecounter-${{ github.run_id }}.zip +# slot-name: production +# publish-profile: ${{ secrets.azureFunctionAppPublishProfile }} From ee093cc56fcb18cf9bb133e6e3ef865b25d122fc Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Wed, 8 Mar 2023 15:51:20 +0530 Subject: [PATCH 11/77] Update function-app.yml --- .github/workflows/function-app.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index 6ad314b..a3ad9fd 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -24,13 +24,13 @@ jobs: dotnet-version: 3.1.x - name: Restore NuGet Packages - run: dotnet restore ${{ env.appPath }}/VoteCounter.csproj + run: dotnet restore ${{ env.appPath }} - name: Build - run: dotnet build ${{ env.appPath }}/VoteCounter.csproj --configuration ${{ env.buildConfiguration }} --no-restore + run: dotnet build ${{ env.appPath }} --configuration ${{ env.buildConfiguration }} --no-restore - name: Publish - run: dotnet publish ${{ env.appPath }}/VoteCounter.csproj --configuration ${{ env.buildConfiguration }} --output '$(github.workspace)' --no-restore + run: dotnet publish ${{ env.appPath }} --configuration ${{ env.buildConfiguration }} --output '$(github.workspace)' --no-restore - name: Archive Files uses: actions/upload-artifact@v2 From 6bdd5cd2f6c245f5aa61c5872fdd3d7857c44ed3 Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Wed, 8 Mar 2023 15:59:07 +0530 Subject: [PATCH 12/77] Update function-app.yml --- .github/workflows/function-app.yml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index a3ad9fd..ca580c1 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -1,8 +1,5 @@ name: Build and Deploy Vote Counter App -env: - deploymentMethod: runFromPackage - on: push: branches: @@ -24,13 +21,13 @@ jobs: dotnet-version: 3.1.x - name: Restore NuGet Packages - run: dotnet restore ${{ env.appPath }} + run: dotnet restore ${{ vars.appPath }} - name: Build - run: dotnet build ${{ env.appPath }} --configuration ${{ env.buildConfiguration }} --no-restore + run: dotnet build ${{ vars.appPath }} --configuration ${{ vars.buildConfiguration }} --no-restore - name: Publish - run: dotnet publish ${{ env.appPath }} --configuration ${{ env.buildConfiguration }} --output '$(github.workspace)' --no-restore + run: dotnet publish ${{ vars.appPath }} --configuration ${{ vars.buildConfiguration }} --output '$(github.workspace)' --no-restore - name: Archive Files uses: actions/upload-artifact@v2 @@ -54,7 +51,7 @@ jobs: # deploy-zone3: # needs: build # runs-on: ubuntu-latest -# environment: ${{ env.appEnvironmentName }} +# environment: ${{ vars.appEnvironmentName }} # steps: # - name: Deploy to Zone 3 # uses: azure/webapps-deploy@v2 From 8bec0aec2e531d1dcc4ad0ebaa56e9c15855b8b1 Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Wed, 8 Mar 2023 16:03:04 +0530 Subject: [PATCH 13/77] Update function-app.yml --- .github/workflows/function-app.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index ca580c1..e1ee2e1 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -21,13 +21,13 @@ jobs: dotnet-version: 3.1.x - name: Restore NuGet Packages - run: dotnet restore ${{ vars.appPath }} + run: dotnet restore ${{ vars.APPPATH }} - name: Build - run: dotnet build ${{ vars.appPath }} --configuration ${{ vars.buildConfiguration }} --no-restore + run: dotnet build ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --no-restore - name: Publish - run: dotnet publish ${{ vars.appPath }} --configuration ${{ vars.buildConfiguration }} --output '$(github.workspace)' --no-restore + run: dotnet publish ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --output '$(github.workspace)' --no-restore - name: Archive Files uses: actions/upload-artifact@v2 From b13ebf7b33b1bd2b929ed8f41e98dc478f3ca282 Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Wed, 8 Mar 2023 16:48:29 +0530 Subject: [PATCH 14/77] Update function-app.yml --- .github/workflows/function-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index e1ee2e1..025f811 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -18,7 +18,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 3.1.x + dotnet-version: 5.0.x - name: Restore NuGet Packages run: dotnet restore ${{ vars.APPPATH }} From 5245a9cdd011ead73c02875be5591d35a0922b2e Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Thu, 9 Mar 2023 10:29:56 +0530 Subject: [PATCH 15/77] Update function-app.yml --- .github/workflows/function-app.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index 025f811..cb34136 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -15,10 +15,15 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - name: Setup .NET Core + - name: Setup .NET Core 3 uses: actions/setup-dotnet@v1 with: - dotnet-version: 5.0.x + dotnet-version: 3.1.x + + - name: Setup .NET Core 5 + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 5.x - name: Restore NuGet Packages run: dotnet restore ${{ vars.APPPATH }} From b1571f62016d0981ab8feaf215036fc2822a2a4f Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Thu, 9 Mar 2023 11:33:45 +0530 Subject: [PATCH 16/77] Update function-app.yml --- .github/workflows/function-app.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index cb34136..308fd6a 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -45,6 +45,11 @@ jobs: runs-on: ubuntu-latest environment: 'production' steps: + - uses: actions/download-artifact@master + with: + name: drop + path: ${{ github.workspace }}/votecounter-${{ github.run_id }}.zip + - name: Deploy to Zone 1 uses: azure/webapps-deploy@v2 with: From 6ceaa2d6200943185530ef3c3643e43f1ba35510 Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Thu, 9 Mar 2023 11:40:25 +0530 Subject: [PATCH 17/77] Update function-app.yml --- .github/workflows/function-app.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index 308fd6a..eb39042 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -48,7 +48,6 @@ jobs: - uses: actions/download-artifact@master with: name: drop - path: ${{ github.workspace }}/votecounter-${{ github.run_id }}.zip - name: Deploy to Zone 1 uses: azure/webapps-deploy@v2 From 54f0b21acde73bda1ec660a76ee69b94ddd3bb81 Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Thu, 9 Mar 2023 11:50:04 +0530 Subject: [PATCH 18/77] Update function-app.yml --- .github/workflows/function-app.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index eb39042..457291f 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -32,7 +32,7 @@ jobs: run: dotnet build ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --no-restore - name: Publish - run: dotnet publish ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --output '$(github.workspace)' --no-restore + run: dotnet publish ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --output ${{ github.workspace }} --no-restore - name: Archive Files uses: actions/upload-artifact@v2 @@ -48,12 +48,13 @@ jobs: - uses: actions/download-artifact@master with: name: drop + path: ${{ github.workspace }}/votecounter-${{ github.run_id }}.zip - name: Deploy to Zone 1 uses: azure/webapps-deploy@v2 with: app-name: 'app-service-app-1' - package: ${{ github.workspace }}/drop/votecounter-${{ github.run_id }}.zip + package: ${{ github.workspace }}/votecounter-${{ github.run_id }}.zip slot-name: production publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} From 921206a5a95b4d408010c56abf453cda0d606b07 Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Thu, 9 Mar 2023 12:02:09 +0530 Subject: [PATCH 19/77] Update function-app.yml --- .github/workflows/function-app.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index 457291f..54bb39a 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -33,7 +33,10 @@ jobs: - name: Publish run: dotnet publish ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --output ${{ github.workspace }} --no-restore - + + - name: Tree + run: tree + - name: Archive Files uses: actions/upload-artifact@v2 with: From b12f2b802f4ba98939bae925877ab035d9eb0cbd Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Thu, 9 Mar 2023 12:02:42 +0530 Subject: [PATCH 20/77] Update function-app.yml --- .github/workflows/function-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index 54bb39a..683e201 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -35,7 +35,7 @@ jobs: run: dotnet publish ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --output ${{ github.workspace }} --no-restore - name: Tree - run: tree + run: tree ${{ github.workspace }} - name: Archive Files uses: actions/upload-artifact@v2 From 7ac884c10adfd9d2a3a9bdea1bf3a89734d31a3b Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Thu, 9 Mar 2023 12:09:07 +0530 Subject: [PATCH 21/77] Update function-app.yml --- .github/workflows/function-app.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index 683e201..864505c 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -35,13 +35,13 @@ jobs: run: dotnet publish ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --output ${{ github.workspace }} --no-restore - name: Tree - run: tree ${{ github.workspace }} + run: dir ${{ github.workspace }}/VoteCounter/ - name: Archive Files uses: actions/upload-artifact@v2 with: name: drop - path: ${{ github.workspace }}/votecounter-${{ github.run_id }}.zip + path: ${{ github.workspace }}/VoteCounter/votecounter-${{ github.run_id }}.zip deploy-zone1: needs: build @@ -51,13 +51,13 @@ jobs: - uses: actions/download-artifact@master with: name: drop - path: ${{ github.workspace }}/votecounter-${{ github.run_id }}.zip + path: ${{ github.workspace }}/VoteCounter/votecounter-${{ github.run_id }}.zip - name: Deploy to Zone 1 uses: azure/webapps-deploy@v2 with: app-name: 'app-service-app-1' - package: ${{ github.workspace }}/votecounter-${{ github.run_id }}.zip + package: ${{ github.workspace }}/VoteCounter/votecounter-${{ github.run_id }}.zip slot-name: production publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} From 587f8ecd9b6da03670fe6a868b61b16b98bc3cb2 Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Thu, 9 Mar 2023 12:30:23 +0530 Subject: [PATCH 22/77] Update function-app.yml --- .github/workflows/function-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index 864505c..5d5148a 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -35,7 +35,7 @@ jobs: run: dotnet publish ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --output ${{ github.workspace }} --no-restore - name: Tree - run: dir ${{ github.workspace }}/VoteCounter/ + run: dir ${{ github.workspace }} /s /b /o:gn - name: Archive Files uses: actions/upload-artifact@v2 From e853e6dbf575b4447e8994e641a3f811489062bd Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Thu, 9 Mar 2023 12:54:06 +0530 Subject: [PATCH 23/77] Update function-app.yml --- .github/workflows/function-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index 5d5148a..4ca47e1 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -35,7 +35,7 @@ jobs: run: dotnet publish ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --output ${{ github.workspace }} --no-restore - name: Tree - run: dir ${{ github.workspace }} /s /b /o:gn + run: dir ${{ github.workspace }} -r | % { if ($_.PsIsContainer) { $_.FullName + "\" } else { $_.FullName } } - name: Archive Files uses: actions/upload-artifact@v2 From 7179953d8c81c1622a2adc00530ed67a93c1e1a4 Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Tue, 14 Mar 2023 13:49:40 +1100 Subject: [PATCH 24/77] Update function-app.yml --- .github/workflows/function-app.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index 4ca47e1..cfadfe4 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -32,16 +32,14 @@ jobs: run: dotnet build ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --no-restore - name: Publish - run: dotnet publish ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --output ${{ github.workspace }} --no-restore - - - name: Tree - run: dir ${{ github.workspace }} -r | % { if ($_.PsIsContainer) { $_.FullName + "\" } else { $_.FullName } } + run: dotnet publish ${{ vars.APPPATH }} --configuration ${{ vars.BUILDCONFIGURATION }} --output ${{ github.workspace }}/VoteCounter --no-restore + - name: Archive Files uses: actions/upload-artifact@v2 with: name: drop - path: ${{ github.workspace }}/VoteCounter/votecounter-${{ github.run_id }}.zip + path: ${{ github.workspace }}/VoteCounter deploy-zone1: needs: build @@ -51,13 +49,13 @@ jobs: - uses: actions/download-artifact@master with: name: drop - path: ${{ github.workspace }}/VoteCounter/votecounter-${{ github.run_id }}.zip + path: ${{ github.workspace }}/VoteCounter - name: Deploy to Zone 1 uses: azure/webapps-deploy@v2 with: app-name: 'app-service-app-1' - package: ${{ github.workspace }}/VoteCounter/votecounter-${{ github.run_id }}.zip + package: ${{ github.workspace }}/VoteCounter slot-name: production publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} From 843cef8e7604019a3750c5791ff0cb466fe4fb27 Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Tue, 14 Mar 2023 15:49:53 +1100 Subject: [PATCH 25/77] Update function-app.yml --- .github/workflows/function-app.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index cfadfe4..ae3cc24 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -5,8 +5,6 @@ on: branches: - master - workflow-for-actions -# paths: -# - 'code/function-app-ri/FunctionApp' jobs: build: @@ -54,7 +52,7 @@ jobs: - name: Deploy to Zone 1 uses: azure/webapps-deploy@v2 with: - app-name: 'app-service-app-1' + app-name: 'ase-update-1' package: ${{ github.workspace }}/VoteCounter slot-name: production publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} From ef7f431d48983c4e34e56905205d21986dfe5942 Mon Sep 17 00:00:00 2001 From: DeeplyDiligent Date: Tue, 14 Mar 2023 15:58:46 +1100 Subject: [PATCH 26/77] updated dotnet version --- code/function-app-ri/FunctionApp/VoteCounter.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/function-app-ri/FunctionApp/VoteCounter.csproj b/code/function-app-ri/FunctionApp/VoteCounter.csproj index 3049975..5335953 100644 --- a/code/function-app-ri/FunctionApp/VoteCounter.csproj +++ b/code/function-app-ri/FunctionApp/VoteCounter.csproj @@ -1,6 +1,6 @@  - net5.0 + net7.0 v3 From 399b479862371381b9df2454c6968e969c52adbe Mon Sep 17 00:00:00 2001 From: Deep Bhattacharyya Date: Sun, 19 Mar 2023 19:10:30 +1100 Subject: [PATCH 27/77] Update function-app.yml --- .github/workflows/function-app.yml | 36 +++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/.github/workflows/function-app.yml b/.github/workflows/function-app.yml index ae3cc24..5ca709d 100644 --- a/.github/workflows/function-app.yml +++ b/.github/workflows/function-app.yml @@ -21,7 +21,7 @@ jobs: - name: Setup .NET Core 5 uses: actions/setup-dotnet@v1 with: - dotnet-version: 5.x + dotnet-version: 7.0.x - name: Restore NuGet Packages run: dotnet restore ${{ vars.APPPATH }} @@ -41,7 +41,7 @@ jobs: deploy-zone1: needs: build - runs-on: ubuntu-latest + runs-on: windows-latest environment: 'production' steps: - uses: actions/download-artifact@master @@ -52,20 +52,24 @@ jobs: - name: Deploy to Zone 1 uses: azure/webapps-deploy@v2 with: - app-name: 'ase-update-1' + app-name: ${{ vars.FUNCTION_APP_ZONE_1 }} + package: ${{ github.workspace }}/VoteCounter + slot-name: production + publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} + deploy-zone3: + needs: build + runs-on: windows-latest + environment: 'production' + steps: + - uses: actions/download-artifact@master + with: + name: drop + path: ${{ github.workspace }}/VoteCounter + + - name: Deploy to Zone 3 + uses: azure/webapps-deploy@v2 + with: + app-name: ${{ vars.FUNCTION_APP_ZONE_3 }} package: ${{ github.workspace }}/VoteCounter slot-name: production publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} - -# deploy-zone3: -# needs: build -# runs-on: ubuntu-latest -# environment: ${{ vars.appEnvironmentName }} -# steps: -# - name: Deploy to Zone 3 -# uses: azure/webapps-deploy@v2 -# with: -# app-name: ${{ secrets.functionAppNameZone3 }} -# package: ${{ github.workspace }}/drop/votecounter-${{ github.run_id }}.zip -# slot-name: production -# publish-profile: ${{ secrets.azureFunctionAppPublishProfile }} From cf41afefc936b167b85267026fddb1af83625541 Mon Sep 17 00:00:00 2001 From: DeeplyDiligent Date: Sun, 19 Mar 2023 19:15:55 +1100 Subject: [PATCH 28/77] update dotnet --- code/web-app-ri/VotingData/VotingData.csproj | 2 +- code/web-app-ri/VotingWeb/VotingWeb.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/web-app-ri/VotingData/VotingData.csproj b/code/web-app-ri/VotingData/VotingData.csproj index 78c2943..79355df 100644 --- a/code/web-app-ri/VotingData/VotingData.csproj +++ b/code/web-app-ri/VotingData/VotingData.csproj @@ -1,7 +1,7 @@  - net5.0 + net7.0 746f30e9-2ecb-4b24-b825-02d383365fc3 diff --git a/code/web-app-ri/VotingWeb/VotingWeb.csproj b/code/web-app-ri/VotingWeb/VotingWeb.csproj index 37f411d..7913d6a 100644 --- a/code/web-app-ri/VotingWeb/VotingWeb.csproj +++ b/code/web-app-ri/VotingWeb/VotingWeb.csproj @@ -1,7 +1,7 @@  - net5.0 + net7.0 d2110877-4dcc-4be2-862a-15df3591e3ac