Quickstart: Create a private endpoint by using an ARM template

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

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 endpoint for an instance of Azure SQL Database.

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": {
    "sqlAdministratorLogin": {
      "type": "string",
      "metadata": {
        "description": "The administrator username of the SQL logical server"
      }
    },
    "sqlAdministratorLoginPassword": {
      "type": "securestring",
      "metadata": {
        "description": "The administrator password of the SQL logical server."
      }
    },
    "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",
    "vnetAddressPrefix": "10.0.0.0/16",
    "subnet1Prefix": "10.0.0.0/24",
    "subnet1Name": "mySubnet",
    "sqlServerName": "[concat('sqlserver', uniqueString(resourceGroup().id))]",
    "databaseName": "[concat(variables('sqlServerName'),'/sample-db')]",
    "privateEndpointName": "myPrivateEndpoint",
    "privateDnsZoneName": "[concat('privatelink', environment().suffixes.sqlServerHostname)]",
    "pvtendpointdnsgroupname": "[concat(variables('privateEndpointName'),'/mydnsgroupname')]",
    "vmName": "[take(concat('myVm', uniqueString(resourceGroup().id)),15)]",
    "publicIpAddressName": "[concat(variables('vmName'), 'PublicIP' )]",
    "networkInterfaceName": "[concat(variables('vmName'),'NetInt')]",
    "osDiskType": "StandardSSD_LRS"
  },
  "resources": [
    {
      "type": "Microsoft.Sql/servers",
      "apiVersion": "2020-02-02-preview",
      "name": "[variables('sqlServerName')]",
      "location": "[parameters('location')]",
      "kind": "v12.0",
      "tags": {
        "displayName": "[variables('sqlServerName')]"
      },
      "properties": {
        "administratorLogin": "[parameters('sqlAdministratorLogin')]",
        "administratorLoginPassword": "[parameters('sqlAdministratorLoginPassword')]",
        "version": "12.0",
        "publicNetworkAccess": "Disabled"
      },
      "resources": [
      ]
    },
    {
      "type": "Microsoft.Sql/servers/databases",
      "apiVersion": "2020-02-02-preview",
      "name": "[variables('databaseName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Basic",
        "tier": "Basic",
        "capacity": 5
      },
      "dependsOn": [
        "[resourceId('Microsoft.Sql/servers', variables('sqlServerName'))]"
      ],
      "tags": {
        "displayName": "[variables('databaseName')]"
      },
      "properties": {
        "collation": "SQL_Latin1_General_CP1_CI_AS",
        "edition": "Basic",
        "maxSizeBytes": 104857600,
        "requestedServiceObjectiveName": "Basic",
        "sampleName": "AdventureWorksLT"
      }
    },

    {
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2020-06-01",
      "name": "[variables('vnetName')]",
      "location": "[parameters('location')]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[variables('vnetAddressPrefix')]"
          ]
        }
      },
      "resources": [
        {
          "type": "subnets",
          "apiVersion": "2020-06-01",
          "name": "[variables('subnet1Name')]",
          "location": "[parameters('location')]",
          "dependsOn": [
            "[variables('vnetName')]"
          ],
          "properties": {
            "addressPrefix": "[variables('subnet1Prefix')]",
            "privateEndpointNetworkPolicies": "Disabled"
          }
        }
      ]
    },
    {
      "type": "Microsoft.Network/privateEndpoints",
      "apiVersion": "2020-06-01",
      "name": "[variables('privateEndpointName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[variables('vnetName')]",
        "[variables('sqlServerName')]"
      ],
      "properties": {
        "subnet": {
          "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('vnetName'), variables('subnet1Name'))]"
        },
        "privateLinkServiceConnections": [
          {
            "name": "[variables('privateEndpointName')]",
            "properties": {
              "privateLinkServiceId": "[resourceId('Microsoft.Sql/servers',variables('sqlServerName'))]",
              "groupIds": [
                "sqlServer"
              ]
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/privateDnsZones",
      "apiVersion": "2020-01-01",
      "name": "[variables('privateDnsZoneName')]",
      "location": "global",
      "dependsOn": [
        "[variables('vnetName')]"
      ],
      "properties": ""
    },
    {
      "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
      "apiVersion": "2020-01-01",
      "name": "[concat(variables('privateDnsZoneName'), '/', variables('privateDnsZoneName'), '-link')]",
      "location": "global",
      "dependsOn": [
        "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]",
        "[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]"
      ],
      "properties": {
        "registrationEnabled": false,
        "virtualNetwork": {
          "id": "[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]"
        }
      }
    },
    {
      "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
      "apiVersion": "2020-06-01",
      "name": "[variables('pvtendpointdnsgroupname')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]",
        "[variables('privateEndpointName')]"
      ],
      "properties": {
        "privateDnsZoneConfigs": [
          {
            "name": "config1",
            "properties": {
              "privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2020-06-01",
      "name": "[variables('publicIpAddressName')]",
      "location": "[parameters('location')]",
      "tags": {
        "displayName": "[variables('publicIpAddressName')]"
      },
      "properties": {
        "publicIPAllocationMethod": "Dynamic",
        "dnsSettings": {
          "domainNameLabel": "[tolower(variables('vmName'))]"
        }
      }
    },
    {
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2020-06-01",
      "name": "[variables('networkInterfaceName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpAddressName'))]",
        "[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]"
      ],
      "tags": {
        "displayName": "[variables('networkInterfaceName')]"
      },
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipConfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpAddressName'))]"
              },
              "subnet": {
                "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('vnetName'), variables('subnet1Name'))]"
              }
            }
          }
        ]
      }
    },
    {
      "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'))]"
            }
          ]
        }
      }
    }
  ]
}

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 the private endpoint, the instance of SQL Database, the network infrastructure, and a virtual machine to validate.

    Deploy to Azure

  2. Select or create your resource group.

  3. Type the SQL Administrator sign-in and password.

  4. Type the virtual machine administrator username and password.

  5. Read the terms and conditions statement. If you agree, select I agree to the terms and conditions stated above > Purchase. The deployment can take 20 minutes or longer to complete.

Validate the deployment

Note

The ARM template generates a unique name for the virtual machine myVm{uniqueid} resource, and for the SQL Database sqlserver{uniqueid} resource. Substitute your generated value for {uniqueid}.

Connect to a VM from the internet

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

  1. In the portal's search bar, enter myVm{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 SQL Database server privately from the VM

Here's how to connect to the SQL Database server from the VM by using the private endpoint.

  1. In the Remote Desktop of myVM{uniqueid}, open PowerShell.

  2. Enter the following: nslookup sqlserver{uniqueid}.database.windows.net.  You'll receive a message similar to this:

      Server:  UnKnown
      Address:  168.63.129.16
      Non-authoritative answer:
      Name:    sqlserver.privatelink.database.windows.net
      Address:  10.0.0.5
      Aliases:  sqlserver.database.windows.net
    
  3. Install SQL Server Management Studio.

  4. In Connect to server, enter or select this information:

    • Server type: Select Database Engine.
    • Server name: Select sqlserver{uniqueid}.database.windows.net.
    • Username: Enter a username provided during creation.
    • Password: Enter a password provided during creation.
    • Remember password: Select Yes.
  5. Select Connect.

  6. From the menu on the left, go to Databases.

  7. Optionally, you can create or query information from sample-db.

  8. Close the Remote Desktop connection to myVm{uniqueid}.

Clean up resources

When you no longer need the resources that you created with the private endpoint, delete the resource group. This removes the private endpoint 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: