
PLE and AppGateway in Bicep
What led to this
Over the past year or so I’ve been working in an environment where an instance of API Management in an internal network configuration was about to run into scalability issue. This is with regards to the number of workloads connecting to it using VNET-peering. Peering is the preferred method to reduce latency between workloads in different networks in the same region, but has a maximum of 500 peering’s. This is one of the hard limits in Azure see networking limits.
So an alternative was required. Together with one of my colleagues we studied the possibilities of using PLE to replace the need for peering. In that journey we found an option to introduce an AppGateway, based on the properties that we’re present in the ARM template, namely the “privateLinkConfigurations” section see ARM template reference.
Overview
This sketch shows the concept of how connectivity is achieved and how traffic is isolated from Azure Public Network infrastructure by applying Azure Private Link.
How it works
In a nutshell, by defining a “privateLinkConfiguration” an AppGateway will create a private link service instance “under the hood”, so it can natively host connectivity via Private Link. The consumer then needs to create a private endpoint and link to that specific PLS resource. So far this is the relatively easy part. lets’t dive into the details of the setup.
Network setup
For the AppGateway in this setup we can use one VNET with three different subnets that are required.
- One is required for the front end listener(s)
- One is required for the Backend pool connectivity
- One is required for the Private Link service
Now, that final subnet also requires to set the property “privateLinkServiceNetworkPolicies” to “Disabled” (If you want to connect from the backend pool towards a workload that also requires PLE, you need to set the property “privateEndpointNetworkPolicies” to “Disabled”). For convenience a reference to the subnets has been defined as well.
resource appgwvnet 'Microsoft.Network/virtualNetworks@2020-06-01' = {
name: 'appgwvnet'
location: resourceGroup().location
properties: {
addressSpace: {
addressPrefixes: [
'10.1.0.0/16'
]
}
subnets: [
{
name: 'appgw-subnet'
properties: {
addressPrefix: '10.1.0.0/24'
}
}
{
name: 'backend-subnet'
properties: {
addressPrefix: '10.1.1.0/24'
privateEndpointNetworkPolicies: 'Disabled'
}
}
{
name: 'pls-subnet'
properties: {
addressPrefix: '10.1.2.0/24'
privateLinkServiceNetworkPolicies: 'Disabled'
}
}
]
}
}
resource appgwsubnet 'Microsoft.Network/virtualNetworks/subnets@2020-04-01' existing = {
name: '${appgwvnet.name}/appgw-subnet'
}
resource backendsubnet 'Microsoft.Network/virtualNetworks/subnets@2020-04-01' existing = {
name: '${appgwvnet.name}/backend-subnet'
}
resource plssubnet 'Microsoft.Network/virtualNetworks/subnets@2020-04-01' existing = {
name: '${appgwvnet.name}/pls-subnet'
}
Define the PLS in AppGateway
Now the magic of defining the PLS in the AppGateway is handled by setting two properties.
First defining the Private Link configuration as such:
privateLinkConfigurations:[
{
name:'appgw-pls-01'
properties:{
ipConfigurations:[
{
name:'appgw-pls-01-ipconfig-01'
properties:{
primary:true
privateIPAllocationMethod:'Dynamic'
subnet:{
id: subnetidforprivatelinkservice //plssubnet
}
}
}
]
}
}
]
Here I have defined a dynamic allocation method for the IP-Address, that is required. When you need to scale, you can add more configurations here.
We can now reference this configuration in the Frontend IP Configurations. The nice thing is that after this the AppGateway operates just as a without PLS enabled, so you can still use the default fronted IP and all the routing rules stay the same.
frontendIPConfigurations: [
{
name: 'pl-appgw-frontend-ipconfig-private'
properties: {
privateIPAddress: '10.1.0.10'
privateIPAllocationMethod: 'Static'
subnet: {
id: resourceId('Microsoft.Network/virtualNetworks/subnets', appgwvnetname, 'appgw-subnet')
}
privateLinkConfiguration:{
id: resourceId('Microsoft.Network/applicationGateways/privateLinkConfigurations', 'pl-appgw-v2', 'appgw-pls-01' )
}
}
}
Connect a private endpoint
To create a connection into the AppGateway using a private link endpoint we have to define the following resource definition:
resource consumerprivatelinkendpoint 'Microsoft.Network/privateEndpoints@2020-06-01' = {
name: 'consumer-01-AppGw-PLE-01'
location: resourceGroup().location
properties: {
subnet: {
id: resourceId('Microsoft.Network/virtualNetworks/subnets', consumervnet.name, 'consumervnet-subnet-01')
}
privateLinkServiceConnections: [
{
name: 'appgw-pls-01-connection-01'
properties: {
privateLinkServiceId: '<appgateway resourceid>'
groupIds: [
'pl-appgw-frontend-ipconfig-private' // THIS IS THE MAGIC!!!
]
}
}
]
}
}
The magic is to point at the resource ID of the AppGateway AND set the GroupIds to the NAME of the Frontend IP configuration as defined in the AppGateway.