Quickstart: Create a private link service by using an ARM template

In this quickstart, you use an Azure Resource Manager template (ARM template) to create a private link service.

An ARM template is a JavaScript Object Notation (JSON) file that defines the infrastructure and configuration for your project. The template uses declarative syntax. In declarative syntax, you describe your intended deployment without writing the sequence of programming commands to create the deployment.

You can also complete this quickstart by using the Azure portal, Azure PowerShell, or the Azure CLI.

If your environment meets the prerequisites and you're familiar with using ARM templates, select the Deploy to Azure button. The template will open in the Azure portal.

Deploy to Azure

Prerequisites

You need an Azure account with an active subscription. Create an account for free.

Review the template

This template creates a private link service.

The template used in this quickstart is from Azure Quickstart Templates.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "vmAdminUsername": {
      "type": "string",
      "metadata": {
        "description": "Username for the Virtual Machine."
      }
    },
    "vmAdminPassword": {
      "type": "secureString",
      "metadata": {
        "description": "Password for the Virtual Machine. The password must be at least 12 characters long and have lower case, upper characters, digit and a special character (Regex match)"
      }
    },
    "vmSize": {
      "type": "string",
      "defaultValue": "Standard_D2_v3",
      "metadata": {
        "description": "The size of the VM"
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for all resources."
      }
    }
  },
  "variables": {
    "vnetName": "myVirtualNetwork",
    "vnetConsumerName": "myPEVnet",
    "vnetAddressPrefix": "10.0.0.0/16",
    "frontendSubnetPrefix": "10.0.1.0/24",
    "frontendSubnetName": "frontendSubnet",
    "backendSubnetPrefix": "10.0.2.0/24",
    "backendSubnetName": "backendSubnet",
    "consumerSubnetPrefix": "10.0.0.0/24",
    "consumerSubnetName": "myPESubnet",
    "loadbalancername": "myILB",
    "backendpoolname": "myBackEndPool",
    "loadBalancerFrontEndIpConfigurationName": "myFrontEnd",
    "healthProbeName": "myHealthProbe",
    "privateEndpointName": "myPrivateEndpoint",
    "vmName": "[take(concat('myVm', uniqueString(resourceGroup().id)),15)]",
    "networkInterfaceName": "[concat(variables('vmName'),'NetInt')]",
    "vmConsumerName": "[take(concat('myConsumerVm', uniqueString(resourceGroup().id)),15)]",
    "publicIpAddressConsumerName": "[concat(variables('vmConsumerName'), 'PublicIP' )]",
    "networkInterfaceConsumerName": "[concat(variables('vmConsumerName'),'NetInt')]",
    "osDiskType": "StandardSSD_LRS",
    "privatelinkservicename": "myPLS",
    "loadbalancerId": "[resourceId('Microsoft.Network/loadBalancers', variables('loadbalancername'))]"

  },
  "resources": [
    {
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2020-06-01",
      "name": "[variables('vnetName')]",
      "location": "[parameters('location')]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[variables('vnetAddressPrefix')]"
          ]
        },
        "subnets": [
          {
            "name": "[variables('frontendSubnetName')]",
            "properties": {
              "addressPrefix": "[variables('frontendSubnetPrefix')]",
              "privateLinkServiceNetworkPolicies": "Disabled"
            }
          },
          {
            "name": "[variables('backendSubnetName')]",
            "properties": {
              "addressPrefix": "[variables('backendSubnetPrefix')]"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/loadBalancers",
      "apiVersion": "2020-06-01",
      "name": "[variables('loadbalancername')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard"
      },
      "dependsOn": [
        "[variables('vnetName')]"
      ],
      "properties": {
        "frontendIPConfigurations": [
          {
            "name": "[variables('loadBalancerFrontEndIpConfigurationName')]",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('vnetName'), variables('frontendSubnetName'))]"
              }
            }
          }
        ],
        "backendAddressPools": [
          {
            "name": "[variables('backendpoolname')]"
          }
        ],
        "inboundNatRules": [
          {
            "name": "RDP-VM0",
            "properties": {
              "frontendIPConfiguration": {
                "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIpConfigurations', variables('loadbalancername'), variables('loadBalancerFrontEndIpConfigurationName'))]"
              },
              "protocol": "Tcp",
              "frontendPort": 3389,
              "backendPort": 3389,
              "enableFloatingIP": false
            }
          }
        ],
        "loadBalancingRules": [
          {
            "Name": "myHTTPRule",
            "properties": {
              "frontendIPConfiguration": {
                "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIpConfigurations', variables('loadbalancername'), variables('loadBalancerFrontEndIpConfigurationName'))]"
              },
              "backendAddressPool": {
                "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', variables('loadbalancername'), variables('backendpoolname'))]"
              },
              "probe": {
                "id": "[resourceId('Microsoft.Network/loadBalancers/probes', variables('loadBalancerName'), variables('healthProbeName'))]"
              },
              "protocol": "Tcp",
              "frontendPort": 80,
              "backendPort": 80,
              "idleTimeoutInMinutes": 15
            }
          }
        ],
        "probes": [
          {
            "properties": {
              "protocol": "Tcp",
              "port": 80,
              "intervalInSeconds": 15,
              "numberOfProbes": 2
            },
            "name": "[variables('healthProbeName')]"
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2020-06-01",
      "name": "[variables('networkInterfaceName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[variables('loadbalancername')]"
      ],
      "tags": {
        "displayName": "[variables('networkInterfaceName')]"
      },
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipConfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('vnetName'), variables('backendSubnetName'))]"
              },
              "loadBalancerBackendAddressPools": [
                {
                  "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', variables('loadbalancername'), variables('backendpoolname'))]"
                }
              ],
              "loadBalancerInboundNatRules": [
                {
                  "id": "[resourceId('Microsoft.Network/loadBalancers/inboundNatRules/', variables('loadbalancername'), 'RDP-VM0')]"
                }
              ]
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2020-06-01",
      "name": "[variables('vmName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]"
      ],
      "tags": {
        "displayName": "[variables('vmName')]"
      },
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[variables('vmName')]",
          "adminUsername": "[parameters('vmAdminUsername')]",
          "adminPassword": "[parameters('vmAdminPassword')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "MicrosoftWindowsServer",
            "offer": "WindowsServer",
            "sku": "2019-Datacenter",
            "version": "latest"
          },
          "osDisk": {
            "name": "[concat(variables('vmName'),'OsDisk')]",
            "caching": "ReadWrite",
            "createOption": "FromImage",
            "managedDisk": {
              "storageAccountType": "[variables('osDiskType')]"
            },
            "diskSizeGB": 128
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]"
            }
          ]
        }
      }
    },
    {
      "type": "Microsoft.Compute/virtualMachines/extensions",
      "apiVersion": "2020-06-01",
      "name": "[concat(variables('vmName'),'/installcustomscript')]",
      "location": "[parameters('location')]",
      "tags": {
        "displayName": "install software for Windows VM"
      },
      "dependsOn": [
        "[resourceId('Microsoft.Compute/virtualMachines', variables('vmName'))]"
      ],
      "properties": {
        "publisher": "Microsoft.Compute",
        "type": "CustomScriptExtension",
        "typeHandlerVersion": "1.9",
        "autoUpgradeMinorVersion": true,
        "protectedSettings": {
          "commandToExecute": "powershell -ExecutionPolicy Unrestricted Install-WindowsFeature -Name Web-Server"
        }
      }
    },
    {
      "type": "Microsoft.Network/privateLinkServices",
      "apiVersion": "2020-06-01",
      "name": "[variables('privatelinkservicename')]",
      "location": "[parameters('location')]",
      "properties": {
        "enableProxyProtocol": false,
        "loadBalancerFrontendIpConfigurations": [
          {
            "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIpConfigurations', variables('loadbalancername'), variables('loadBalancerFrontEndIpConfigurationName'))]"
          }
        ],
        "ipConfigurations": [
          {
            "name": "snet-provider-default-1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "privateIPAddressVersion": "IPv4",
              "subnet": {
                "id": "[reference(variables('loadbalancerId'), '2019-06-01').frontendIPConfigurations[0].properties.subnet.id]"
              },
              "primary": false
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2020-06-01",
      "name": "[variables('vnetConsumerName')]",
      "location": "[parameters('location')]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[variables('vnetAddressPrefix')]"
          ]
        },
        "subnets": [
          {
            "name": "[variables('consumerSubnetName')]",
            "properties": {
              "addressPrefix": "[variables('consumerSubnetPrefix')]",
              "privateEndpointNetworkPolicies": "Disabled"
            }
          },
          {
            "name": "[variables('backendSubnetName')]",
            "properties": {
              "addressPrefix": "[variables('backendSubnetPrefix')]"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2020-06-01",
      "name": "[variables('publicIpAddressConsumerName')]",
      "location": "[parameters('location')]",
      "tags": {
        "displayName": "[variables('publicIpAddressConsumerName')]"
      },
      "properties": {
        "publicIPAllocationMethod": "Dynamic",
        "dnsSettings": {
          "domainNameLabel": "[tolower(variables('vmConsumerName'))]"
        }
      }
    },
    {
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2020-06-01",
      "name": "[variables('networkInterfaceConsumerName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[variables('vnetConsumerName')]",
        "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpAddressConsumerName'))]"
      ],
      "tags": {
        "displayName": "[variables('networkInterfaceConsumerName')]"
      },
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipConfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpAddressConsumerName'))]"
              },
              "subnet": {
                "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('vnetConsumerName'), variables('consumerSubnetName'))]"
              }
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2020-06-01",
      "name": "[variables('vmConsumerName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceConsumerName'))]"
      ],
      "tags": {
        "displayName": "[variables('vmConsumerName')]"
      },
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[variables('vmConsumerName')]",
          "adminUsername": "[parameters('vmAdminUsername')]",
          "adminPassword": "[parameters('vmAdminPassword')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "MicrosoftWindowsServer",
            "offer": "WindowsServer",
            "sku": "2019-Datacenter",
            "version": "latest"
          },
          "osDisk": {
            "name": "[concat(variables('vmConsumerName'),'OsDisk')]",
            "caching": "ReadWrite",
            "createOption": "FromImage",
            "managedDisk": {
              "storageAccountType": "[variables('osDiskType')]"
            },
            "diskSizeGB": 128
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceConsumerName'))]"
            }
          ]
        }
      }
    },
    {
      "type": "Microsoft.Network/privateEndpoints",
      "apiVersion": "2020-06-01",
      "name": "[variables('privateEndpointName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[variables('vnetConsumerName')]",
        "[variables('privatelinkservicename')]"
      ],
      "properties": {
        "subnet": {
          "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('vnetConsumerName'), variables('consumerSubnetName'))]"
        },
        "privateLinkServiceConnections": [
          {
            "name": "[variables('privateEndpointName')]",
            "properties": {
              "privateLinkServiceId": "[resourceId('Microsoft.Network/privateLinkServices',variables('privatelinkservicename'))]"
            }
          }
        ]
      }
    }
  ]
}

Multiple Azure resources are defined in the template:

Deploy the template

Here's how to deploy the ARM template to Azure:

  1. To sign in to Azure and open the template, select Deploy to Azure. The template creates a virtual machine, standard load balancer, private link service, private endpoint, networking, and a virtual machine to validate.

    Deploy to Azure

  2. Select or create your resource group.

  3. Type the virtual machine administrator username and password.

  4. Read the terms and conditions statement. If you agree, select I agree to the terms and conditions stated above > Purchase.

Validate the deployment

Note

The ARM template generates a unique name for the virtual machine myConsumerVm{uniqueid} resource. Substitute your generated value for {uniqueid}.

Connect to a VM from the internet

Connect to the VM myConsumerVm{uniqueid} from the internet as follows:

  1. In the portal's search bar, enter myConsumerVm{uniqueid}.

  2. Select Connect. Connect to virtual machine opens.

  3. Select Download RDP File. Azure creates a Remote Desktop Protocol (.rdp) file and downloads it to your computer.

  4. Open the downloaded .rdp file.

    a. If prompted, select Connect.

    b. Enter the username and password you specified when you created the VM.

    Note

    You might need to select More choices > Use a different account, to specify the credentials you entered when you created the VM.

  5. Select OK.

  6. You might receive a certificate warning during the sign-in process. If you receive a certificate warning, select Yes or Continue.

  7. After the VM desktop appears, minimize it to go back to your local desktop.

Access the http service privately from the VM

Here's how to connect to the http service from the VM by using the private endpoint.

  1. Go to the Remote Desktop of myConsumerVm{uniqueid}.
  2. Open a browser, and enter the private endpoint address: http://10.0.0.5/.
  3. The default IIS page appears.

Clean up resources

When you no longer need the resources that you created with the private link service, delete the resource group. This removes the private link service and all the related resources.

To delete the resource group, call the Remove-AzResourceGroup cmdlet:

Remove-AzResourceGroup -Name <your resource group name>

Next steps

For more information on the services that support a private endpoint, see: