Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ Note: Take into account that sql database enforce [password complexity](https://
- You choose a valid resource group name

```bash
LOCATION=westus3
LOCATION=westeurope
BASE_NAME=<base-resource-name (between 3 and 6 characters)>

RESOURCE_GROUP=<resource-group-name>
az group create --location $LOCATION --resource-group $RESOURCE_GROUP

az deployment group create --template-file ./infra-as-code/bicep/main.bicep \
az deployment group what-if --template-file ./infra-as-code/bicep/main.bicep \
--resource-group $RESOURCE_GROUP \
--parameters @./infra-as-code/bicep/parameters.json \
--parameters baseName=$BASE_NAME
Expand Down
20 changes: 10 additions & 10 deletions infra-as-code/bicep/database.bicep
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Deploy a SQL server with a sample database, a private endpoint and a private DNS zone
Deploy a SQL server with a database, a private endpoint and a private DNS zone
*/
@description('This is the base name for each Azure resource name (6-12 chars)')
param baseName string
Expand All @@ -9,29 +9,30 @@ param location string = resourceGroup().location

@description('The administrator username of the SQL server')
param sqlAdministratorLogin string

@description('The administrator password of the SQL server.')
@secure()
param sqlAdministratorLoginPassword string

// existing resource name params
// existing resource name params
param vnetName string
param privateEndpointsSubnetName string

// variables
var sqlServerName = 'sql-${baseName}'
var sampleSqlDatabaseName = 'sqldb-adventureworks'
var sqlDatabaseName = 'sqldb-${baseName}'
var sqlPrivateEndpointName = 'pep-${sqlServerName}'
var sqlDnsGroupName = '${sqlPrivateEndpointName}/default'
var sqlDnsZoneName = 'privatelink${environment().suffixes.sqlServerHostname}'
var sqlConnectionString = 'Server=tcp:${sqlServerName}${environment().suffixes.sqlServerHostname},1433;Initial Catalog=${sampleSqlDatabaseName};Persist Security Info=False;User ID=${sqlAdministratorLogin};Password=${sqlAdministratorLoginPassword};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;'
var sqlConnectionString = 'Server=tcp:${sqlServerName}${environment().suffixes.sqlServerHostname},1433;Initial Catalog=${sqlDatabaseName};Persist Security Info=False;User ID=${sqlAdministratorLogin};Password=${sqlAdministratorLoginPassword};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;'

// ---- Existing resources ----
resource vnet 'Microsoft.Network/virtualNetworks@2022-11-01' existing = {
resource vnet 'Microsoft.Network/virtualNetworks@2022-11-01' existing = {
name: vnetName

resource privateEndpointsSubnet 'subnets' existing = {
name: privateEndpointsSubnetName
}
}
}

// ---- Sql resources ----
Expand All @@ -53,7 +54,7 @@ resource sqlServer 'Microsoft.Sql/servers@2021-11-01' = {

//database
resource slqDatabase 'Microsoft.Sql/servers/databases@2021-11-01' = {
name: sampleSqlDatabaseName
name: sqlDatabaseName
parent: sqlServer
location: location

Expand All @@ -63,12 +64,11 @@ resource slqDatabase 'Microsoft.Sql/servers/databases@2021-11-01' = {
capacity: 5
}
tags: {
displayName: sampleSqlDatabaseName
displayName: sqlDatabaseName
}
properties: {
collation: 'SQL_Latin1_General_CP1_CI_AS'
maxSizeBytes: 104857600
sampleName: 'AdventureWorksLT'
}
}

Expand Down Expand Up @@ -128,5 +128,5 @@ resource sqlServerDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZon
]
}

@description('The connection string to the sample database.')
@description('The connection string to the database.')
output sqlConnectionString string = sqlConnectionString
79 changes: 45 additions & 34 deletions infra-as-code/bicep/gateway.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,12 @@ param baseName string
@description('The resource group location')
param location string = resourceGroup().location

@description('Optional. When true will deploy a cost-optimised environment for development purposes.')
param developmentEnvironment bool

@description('Domain name to use for App Gateway')
param customDomainName string

param availabilityZones array
param gatewayCertSecretUri string

// existing resource name params
// existing resource name params
param vnetName string
param appGatewaySubnetName string
param appName string
Expand All @@ -29,12 +25,12 @@ var appGateWayName = 'agw-${baseName}'
var appGatewayManagedIdentityName = 'id-${appGateWayName}'
var appGatewayPublicIpName = 'pip-${baseName}'
var appGateWayFqdn = 'fe-${baseName}'
var wafPolicyName= 'waf-${baseName}'
var wafPolicyName = 'waf-${baseName}'

// ---- Existing resources ----
resource vnet 'Microsoft.Network/virtualNetworks@2022-11-01' existing = {
resource vnet 'Microsoft.Network/virtualNetworks@2022-11-01' existing = {
name: vnetName

resource appGatewaySubnet 'subnets' existing = {
name: appGatewaySubnetName
}
Expand All @@ -56,7 +52,7 @@ resource keyVaultSecretsUserRole 'Microsoft.Authorization/roleDefinitions@2022-0

// ---- App Gateway resources ----

// Managed Identity for App Gateway.
// Managed Identity for App Gateway.
resource appGatewayManagedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: appGatewayManagedIdentityName
location: location
Expand All @@ -76,7 +72,6 @@ module appGatewaySecretsUserRoleAssignmentModule './modules/keyvaultRoleAssignme
resource appGatewayPublicIp 'Microsoft.Network/publicIPAddresses@2022-11-01' = {
name: appGatewayPublicIpName
location: location
zones: !developmentEnvironment ? availabilityZones : null
sku: {
name: 'Standard'
}
Expand Down Expand Up @@ -121,7 +116,6 @@ resource wafPolicy 'Microsoft.Network/ApplicationGatewayWebApplicationFirewallPo
resource appGateWay 'Microsoft.Network/applicationGateways@2022-11-01' = {
name: appGateWayName
location: location
zones: !developmentEnvironment ? availabilityZones : null
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
Expand All @@ -134,17 +128,14 @@ resource appGateWay 'Microsoft.Network/applicationGateways@2022-11-01' = {
tier: 'WAF_v2'
}
sslPolicy: {
policyType: 'Custom'
cipherSuites: [
'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384'
'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'
]
minProtocolVersion: 'TLSv1_2'
policyType: 'CustomV2'
cipherSuites: []
minProtocolVersion: 'TLSv1_3'
}

gatewayIPConfigurations: [
{
name: 'appGatewayIpConfig'
name: 'app-gateway-ip-config'
properties: {
subnet: {
id: vnet::appGatewaySubnet.id
Expand All @@ -154,7 +145,7 @@ resource appGateWay 'Microsoft.Network/applicationGateways@2022-11-01' = {
]
frontendIPConfigurations: [
{
name: 'appGwPublicFrontendIp'
name: 'app-gateway-public-ip'
properties: {
privateIPAllocationMethod: 'Dynamic'
publicIPAddress: {
Expand All @@ -173,10 +164,10 @@ resource appGateWay 'Microsoft.Network/applicationGateways@2022-11-01' = {
]
probes: [
{
name: 'probe-web${baseName}'
name: 'probe-https-${baseName}'
properties: {
protocol: 'Https'
path: '/favicon.ico'
path: '/health'
interval: 30
timeout: 30
unhealthyThreshold: 3
Expand Down Expand Up @@ -218,60 +209,80 @@ resource appGateWay 'Microsoft.Network/applicationGateways@2022-11-01' = {
]
backendHttpSettingsCollection: [
{
name: 'WebAppBackendHttpSettings'
name: 'backend-https-${baseName}'
properties: {
port: 443
protocol: 'Https'
cookieBasedAffinity: 'Disabled'
pickHostNameFromBackendAddress: true
requestTimeout: 20
probe: {
id: resourceId('Microsoft.Network/applicationGateways/probes', appGateWayName, 'probe-web${baseName}')
id: resourceId('Microsoft.Network/applicationGateways/probes', appGateWayName, 'probe-https-${baseName}')
}
}
}
]
httpListeners: [
{
name: 'WebAppListener'
name: 'listener-https-${baseName}'
properties: {
frontendIPConfiguration: {
id: resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appGateWayName, 'appGwPublicFrontendIp')
id: resourceId(
'Microsoft.Network/applicationGateways/frontendIPConfigurations',
appGateWayName,
'app-gateway-public-ip'
)
}
frontendPort: {
id: resourceId('Microsoft.Network/applicationGateways/frontendPorts', appGateWayName, 'port-443')
}
protocol: 'Https'
sslCertificate: {
id: resourceId('Microsoft.Network/applicationGateways/sslCertificates', appGateWayName, '${appGateWayName}-ssl-certificate')
id: resourceId(
'Microsoft.Network/applicationGateways/sslCertificates',
appGateWayName,
'${appGateWayName}-ssl-certificate'
)
}
hostName: 'www.${customDomainName}'
hostName: customDomainName
hostNames: []
requireServerNameIndication: true
}
}
]
requestRoutingRules: [
{
name: 'WebAppRoutingRule'
name: 'https'
properties: {
ruleType: 'Basic'
priority: 100
httpListener: {
id: resourceId('Microsoft.Network/applicationGateways/httpListeners', appGateWayName, 'WebAppListener')
id: resourceId(
'Microsoft.Network/applicationGateways/httpListeners',
appGateWayName,
'listener-https-${baseName}'
)
}
backendAddressPool: {
id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', appGateWayName, 'pool-${appName}')
id: resourceId(
'Microsoft.Network/applicationGateways/backendAddressPools',
appGateWayName,
'pool-${appName}'
)
}
backendHttpSettings: {
id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', appGateWayName, 'WebAppBackendHttpSettings')
id: resourceId(
'Microsoft.Network/applicationGateways/backendHttpSettingsCollection',
appGateWayName,
'backend-https-${baseName}'
)
}
}
}
]
autoscaleConfiguration: {
minCapacity: developmentEnvironment ? 2 : 3
maxCapacity: developmentEnvironment ? 3 : 5
minCapacity: 2
maxCapacity: 3
}
}
dependsOn: [
Expand All @@ -281,7 +292,7 @@ resource appGateWay 'Microsoft.Network/applicationGateways@2022-11-01' = {

// App Gateway diagnostics
resource appGatewayDiagSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
name: '${appGateWay.name}-diagnosticSettings'
name: '${appGateWay.name}-diagnostic-settings'
scope: appGateWay
properties: {
workspaceId: logWorkspace.id
Expand Down
35 changes: 8 additions & 27 deletions infra-as-code/bicep/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ param sqlAdministratorLogin string
@secure()
param sqlAdministratorLoginPassword string

@description('Docker image to use for deployment')
param dockerImage string

@description('Domain name to use for App Gateway')
param customDomainName string = 'contoso.com'
param domainName string

@description('The certificate data for app gateway TLS termination. The value is base64 encoded')
@secure()
Expand All @@ -23,14 +26,8 @@ param appGatewayListenerCertificate string
@description('Optional. When true will deploy a cost-optimised environment for development purposes. Note that when this param is true, the deployment is not suitable or recommended for Production environments. Default = false.')
param developmentEnvironment bool = false

@description('The name of the web deploy file. The file should reside in a deploy container in the storage account. Defaults to SimpleWebApp.zip')
param publishFileName string = 'SimpleWebApp.zip'

// ---- Availability Zones ----
var availabilityZones = [ '1', '2', '3' ]
var logWorkspaceName = 'log-${baseName}'


// ---- Log Analytics workspace ----
resource logWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = {
name: logWorkspaceName
Expand All @@ -49,18 +46,6 @@ module networkModule 'network.bicep' = {
params: {
location: location
baseName: baseName
developmentEnvironment: developmentEnvironment
}
}

// Deploy storage account with private endpoint and private DNS zone
module storageModule 'storage.bicep' = {
name: 'storageDeploy'
params: {
location: location
baseName: baseName
vnetName: networkModule.outputs.vnetNName
privateEndpointsSubnetName: networkModule.outputs.privateEndpointsSubnetName
}
}

Expand Down Expand Up @@ -96,15 +81,14 @@ module webappModule 'webapp.bicep' = {
params: {
location: location
baseName: baseName
dockerImage: dockerImage
developmentEnvironment: developmentEnvironment
publishFileName: publishFileName
keyVaultName: secretsModule.outputs.keyVaultName
storageName: storageModule.outputs.storageName
vnetName: networkModule.outputs.vnetNName
appServicesSubnetName: networkModule.outputs.appServicesSubnetName
privateEndpointsSubnetName: networkModule.outputs.privateEndpointsSubnetName
logWorkspaceName: logWorkspace.name
}
}
}

//Deploy an Azure Application Gateway with WAF v2 and a custom domain name.
Expand All @@ -113,15 +97,12 @@ module gatewayModule 'gateway.bicep' = {
params: {
location: location
baseName: baseName
developmentEnvironment: developmentEnvironment
availabilityZones: availabilityZones
customDomainName: customDomainName
customDomainName: domainName
appName: webappModule.outputs.appName
vnetName: networkModule.outputs.vnetNName
appGatewaySubnetName: networkModule.outputs.appGatewaySubnetName
keyVaultName: secretsModule.outputs.keyVaultName
gatewayCertSecretUri: secretsModule.outputs.gatewayCertSecretUri
logWorkspaceName: logWorkspace.name
}
}
}

Loading