Skip to content

Commit 0f18906

Browse files
committed
Add P2S VPN gateway and other improvements
1 parent ee758e5 commit 0f18906

File tree

8 files changed

+149
-43
lines changed

8 files changed

+149
-43
lines changed

app/frontend/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

infra/abbreviations.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
"privateEndpoint": "pe-",
111111
"privateLink": "pl-",
112112
"purviewAccounts": "pview-",
113+
"privateDnsResolver": "pdr-",
113114
"recoveryServicesVaults": "rsv-",
114115
"resourcesResourceGroups": "rg-",
115116
"searchSearchServices": "srch-",

infra/core/host/container-app-upsert.bicep

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ param containerMaxReplicas int = 10
1515
param containerMemory string = '1.0Gi'
1616

1717
@description('The minimum number of replicas to run. Must be at least 1 for non-consumption workloads.')
18-
param containerMinReplicas int = 1
18+
param containerMinReplicas int = 0
1919

2020
@description('The name of the container')
2121
param containerName string = 'main'

infra/core/host/container-app.bicep

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ param containerMaxReplicas int = 10
2020
param containerMemory string = '1.0Gi'
2121

2222
@description('The minimum number of replicas to run. Must be at least 1.')
23-
param containerMinReplicas int = 1
23+
param containerMinReplicas int = 0
2424

2525
@description('The name of the container')
2626
param containerName string = 'main'

infra/core/host/container-apps.bicep

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ param containerRegistryName string
88
param containerRegistryResourceGroupName string = ''
99
param containerRegistryAdminUserEnabled bool = false
1010
param logAnalyticsWorkspaceResourceId string
11-
param applicationInsightsName string = '' // Not used here, was used for DAPR
12-
param virtualNetworkSubnetId string = ''
11+
12+
param subnetResourceId string = ''
13+
14+
param usePrivateIngress bool = true
15+
1316
@allowed(['Consumption', 'D4', 'D8', 'D16', 'D32', 'E4', 'E8', 'E16', 'E32', 'NC24-A100', 'NC48-A100', 'NC96-A100'])
1417
param workloadProfile string
1518

@@ -26,7 +29,7 @@ var workloadProfiles = workloadProfile == 'Consumption'
2629
workloadProfileType: 'Consumption'
2730
}
2831
{
29-
minimumCount: 0
32+
minimumCount: 1
3033
maximumCount: 2
3134
name: workloadProfile
3235
workloadProfileType: workloadProfile
@@ -51,7 +54,8 @@ module containerAppsEnvironment 'br/public:avm/res/app/managed-environment:0.8.0
5154
name: containerAppsEnvironmentName
5255
// Non-required parameters
5356
infrastructureResourceGroupName: containerRegistryResourceGroupName
54-
infrastructureSubnetId: virtualNetworkSubnetId
57+
infrastructureSubnetId: subnetResourceId
58+
internal: usePrivateIngress
5559
location: location
5660
tags: tags
5761
zoneRedundant: false
@@ -67,7 +71,9 @@ module containerRegistry 'br/public:avm/res/container-registry/registry:0.5.1' =
6771
params: {
6872
name: containerRegistryName
6973
location: location
74+
acrSku: usePrivateIngress ? 'Premium' : 'Standard'
7075
acrAdminUserEnabled: containerRegistryAdminUserEnabled
76+
publicNetworkAccess: usePrivateIngress ? 'Disabled' : 'Enabled'
7177
tags: tags
7278
}
7379
}

infra/main.bicep

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,9 @@ param publicNetworkAccess string = 'Enabled'
244244
@description('Add a private endpoints for network connectivity')
245245
param usePrivateEndpoint bool = false
246246

247+
@description('Use a P2S VPN Gateway for secure access to the private endpoints')
248+
param useVpnGateway bool = false
249+
247250
@description('Id of the user or app to assign application roles')
248251
param principalId string = ''
249252

@@ -529,7 +532,8 @@ module containerApps 'core/host/container-apps.bicep' = if (deploymentTarget ==
529532
containerAppsEnvironmentName: acaManagedEnvironmentName
530533
containerRegistryName: '${containerRegistryName}${resourceToken}'
531534
logAnalyticsWorkspaceResourceId: useApplicationInsights ? monitoring.outputs.logAnalyticsWorkspaceId : ''
532-
virtualNetworkSubnetId: usePrivateEndpoint ? isolation.outputs.appSubnetId : ''
535+
subnetResourceId: usePrivateEndpoint ? isolation.outputs.appSubnetId : ''
536+
usePrivateIngress: usePrivateEndpoint
533537
}
534538
}
535539

@@ -542,8 +546,8 @@ module acaBackend 'core/host/container-app-upsert.bicep' = if (deploymentTarget
542546
acaIdentity
543547
]
544548
params: {
545-
name: !empty(backendServiceName) ? backendServiceName : '${abbrs.webSitesContainerApps}backend-${resourceToken}'
546-
location: location
549+
name: !empty(backendServiceName) ? backendServiceName : '${abbrs.webSitesContainerApps}backend${resourceToken}'
550+
location: 'westus2'
547551
identityName: (deploymentTarget == 'containerapps') ? acaIdentityName : ''
548552
exists: webAppExists
549553
workloadProfile: azureContainerAppsWorkloadProfile
@@ -554,7 +558,7 @@ module acaBackend 'core/host/container-app-upsert.bicep' = if (deploymentTarget
554558
targetPort: 8000
555559
containerCpuCoreCount: '1.0'
556560
containerMemory: '2Gi'
557-
containerMinReplicas: 0
561+
containerMinReplicas: 1
558562
allowedOrigins: allowedOrigins
559563
env: union(appEnvVariables, {
560564
// For using managed identity to access Azure resources. See https://github.com/microsoft/azure-container-apps/issues/442
@@ -1165,7 +1169,10 @@ module isolation 'network-isolation.bicep' = if (usePrivateEndpoint) {
11651169
tags: tags
11661170
vnetName: '${abbrs.virtualNetworks}${resourceToken}'
11671171
usePrivateEndpoint: usePrivateEndpoint
1168-
containerAppsEnvName: acaManagedEnvironmentName
1172+
deploymentTarget: deploymentTarget
1173+
// Need to check deploymentTarget due to https://github.com/Azure/bicep/issues/3990
1174+
appServicePlanName: deploymentTarget == 'appservice' ? appServicePlan.outputs.name : ''
1175+
containerAppsEnvName: deploymentTarget == 'containerapps' ? acaManagedEnvironmentName : ''
11691176
}
11701177
}
11711178

@@ -1227,6 +1234,51 @@ module privateEndpoints 'private-endpoints.bicep' = if (usePrivateEndpoint) {
12271234
}
12281235
}
12291236

1237+
// Based on https://luke.geek.nz/azure/azure-point-to-site-vpn-and-private-dns-resolver/
1238+
// Manual step required of updating azurevpnconfig.xml to use the correct DNS server IP address
1239+
module dnsResolver 'br/public:avm/res/network/dns-resolver:0.5.3' = if (useVpnGateway) {
1240+
name: 'dnsResolverDeployment'
1241+
scope: resourceGroup
1242+
params: {
1243+
name: '${abbrs.privateDnsResolver}${resourceToken}'
1244+
location: location
1245+
virtualNetworkResourceId: isolation.outputs.vnetId
1246+
inboundEndpoints: [
1247+
{
1248+
name: 'inboundEndpoint'
1249+
subnetResourceId: useVpnGateway ? isolation.outputs.privateDnsResolverSubnetId : ''
1250+
}
1251+
]
1252+
}
1253+
}
1254+
1255+
module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:0.6.1' = if (useVpnGateway) {
1256+
name: 'virtualNetworkGatewayDeployment'
1257+
scope: resourceGroup
1258+
params: {
1259+
name: '${abbrs.networkVpnGateways}${resourceToken}'
1260+
clusterSettings: {
1261+
clusterMode: 'activePassiveNoBgp'
1262+
}
1263+
gatewayType: 'Vpn'
1264+
virtualNetworkResourceId: isolation.outputs.vnetId
1265+
vpnGatewayGeneration: 'Generation2'
1266+
vpnClientAddressPoolPrefix: '172.16.201.0/24'
1267+
skuName: 'VpnGw2'
1268+
vpnClientAadConfiguration: {
1269+
aadAudience: 'c632b3df-fb67-4d84-bdcf-b95ad541b5c8' // Azure VPN client
1270+
aadIssuer: 'https://sts.windows.net/${tenant().tenantId}/'
1271+
aadTenant: '${environment().authentication.loginEndpoint}${tenant().tenantId}'
1272+
vpnAuthenticationTypes: [
1273+
'AAD'
1274+
]
1275+
vpnClientProtocols: [
1276+
'OpenVPN'
1277+
]
1278+
}
1279+
}
1280+
}
1281+
12301282
// Used to read index definitions (required when using authentication)
12311283
// https://learn.microsoft.com/azure/search/search-security-rbac
12321284
module searchReaderRoleBackend 'core/security/role.bicep' = if (useAuthentication) {

infra/network-isolation.bicep

Lines changed: 76 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,52 +11,99 @@ param tags object = {}
1111

1212
param usePrivateEndpoint bool = false
1313

14+
@allowed(['appservice', 'containerapps'])
15+
param deploymentTarget string
16+
17+
@description('The name of an existing App Service Plan to connect to the VNet')
18+
param appServicePlanName string
19+
20+
@description('The name of an existing Container Apps Environment to connect to the VNet')
1421
param containerAppsEnvName string
1522

16-
resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' existing = {
17-
name: containerAppsEnvName
23+
param deployVpnGateway bool = false
24+
25+
resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' existing = if (deploymentTarget == 'appservice') {
26+
name: appServicePlanName
1827
}
1928

29+
resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' existing = if (deploymentTarget == 'containerapps') {
30+
name: containerAppsEnvName
31+
}
2032

21-
module vnet './core/networking/vnet.bicep' = if (usePrivateEndpoint) {
22-
name: 'vnet'
23-
params: {
24-
name: vnetName
25-
location: location
26-
tags: tags
27-
subnets: [
28-
{
33+
// Always need this one
34+
var backendSubnet = {
2935
name: 'backend-subnet'
3036
properties: {
3137
addressPrefix: '10.0.1.0/24'
3238
privateEndpointNetworkPolicies: 'Enabled'
3339
privateLinkServiceNetworkPolicies: 'Enabled'
3440
}
3541
}
36-
{ // App Service / Container Apps specific subnet
37-
name: 'app-int-subnet'
38-
properties: {
39-
addressPrefix: '10.0.4.0/23'
40-
privateEndpointNetworkPolicies: 'Enabled'
41-
privateLinkServiceNetworkPolicies: 'Enabled'
42-
delegations: [
43-
{
44-
id: containerAppsEnvironment.id
45-
name: containerAppsEnvironment.name
46-
properties: {
47-
serviceName: 'Microsoft.App/environments'
48-
}
42+
43+
var appServiceSubnet = {
44+
name: 'app-int-subnet'
45+
properties: {
46+
addressPrefix: '10.0.3.0/24'
47+
privateEndpointNetworkPolicies: 'Enabled'
48+
privateLinkServiceNetworkPolicies: 'Enabled'
49+
delegations: [
50+
{
51+
id: appServicePlan.id
52+
name: appServicePlan.name
53+
properties: {
54+
serviceName: 'Microsoft.Web/serverFarms'
4955
}
50-
]
51-
}
56+
}
57+
]
58+
}
59+
}
60+
61+
var containerAppsSubnet = {
62+
name: 'app-int-subnet'
63+
properties: {
64+
addressPrefix: '10.0.4.0/23'
65+
privateEndpointNetworkPolicies: 'Enabled'
66+
privateLinkServiceNetworkPolicies: 'Enabled'
67+
delegations: [
68+
{
69+
id: containerAppsEnvironment.id
70+
name: containerAppsEnvironment.name
71+
properties: {
72+
serviceName: 'Microsoft.App/environments'
73+
}
74+
}
75+
]
5276
}
53-
]
54-
}
5577
}
5678

79+
var gatewaySubnet = {
80+
name: 'GatewaySubnet' // Required name for Gateway subnet
81+
addressPrefix: '10.0.255.0/27' // Using a /27 subnet size which is minimal required size for gateway subnet
82+
}
83+
84+
var privateDnsResolverSubnet = {
85+
name: 'dns-resolver-subnet' // Dedicated subnet for Azure Private DNS Resolver
86+
addressPrefix: '10.0.11.0/28' // Original value kept as requested
87+
delegation: 'Microsoft.Network/dnsResolvers'
88+
}
89+
90+
var subnets = union(
91+
[backendSubnet, deploymentTarget == 'appservice' ? appServiceSubnet : containerAppsSubnet],
92+
deployVpnGateway ? [gatewaySubnet, privateDnsResolverSubnet] : [])
93+
94+
module vnet './core/networking/vnet.bicep' = if (usePrivateEndpoint) {
95+
name: 'vnet'
96+
params: {
97+
name: vnetName
98+
location: location
99+
tags: tags
100+
subnets: subnets
101+
}
102+
}
57103

58104
output appSubnetId string = usePrivateEndpoint ? vnet.outputs.vnetSubnets[1].id : ''
105+
output appSubnetName string = usePrivateEndpoint ? vnet.outputs.vnetSubnets[1].name : ''
59106
output backendSubnetId string = usePrivateEndpoint ? vnet.outputs.vnetSubnets[0].id : ''
60-
output bastionSubnetId string = usePrivateEndpoint ? vnet.outputs.vnetSubnets[2].id : ''
61-
output vmSubnetId string = usePrivateEndpoint ? vnet.outputs.vnetSubnets[3].id : ''
107+
output privateDnsResolverSubnetId string = deployVpnGateway ? vnet.outputs.vnetSubnets[3].id : ''
62108
output vnetName string = usePrivateEndpoint ? vnet.outputs.name : ''
109+
output vnetId string = usePrivateEndpoint ? vnet.outputs.id : ''

infra/private-endpoints.bicep

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ module monitorPrivateEndpoint './core/networking/private-endpoint.bicep' = {
151151
}
152152
}
153153
{
154-
name: 'blob-dnszone' // dnsZones[dnsZoneBlobIndex].name
154+
name: dnsZones[dnsZoneBlobIndex].name
155155
properties: {
156-
privateDnsZoneId: '/subscriptions/77d8a3d0-8b18-47e9-b773-08bee327bb4a/resourceGroups/rg-pf-ragprivate/providers/Microsoft.Network/privateDnsZones/privatelink.blob.core.windows.net' // dnsZones[dnsZoneBlobIndex].outputs.id
156+
privateDnsZoneId: dnsZones[dnsZoneBlobIndex].outputs.id
157157
}
158158
}
159159
]

0 commit comments

Comments
 (0)