Restrict network access to PaaS resources with virtual network service endpoints using PowerShell

Virtual network service endpoints enable you to limit network access to some Azure service resources to a virtual network subnet. You can also remove internet access to the resources. Service endpoints provide direct connection from your virtual network to supported Azure services, allowing you to use your virtual network's private address space to access the Azure services. Traffic destined to Azure resources through service endpoints always stays on the Microsoft Azure backbone network. In this article, you learn how to:

  • Create a virtual network with one subnet
  • Add a subnet and enable a service endpoint
  • Create an Azure resource and allow network access to it from only a subnet
  • Deploy a virtual machine (VM) to each subnet
  • Confirm access to a resource from a subnet
  • Confirm access is denied to a resource from a subnet and the internet

If you don't have an Azure subscription, create a free account before you begin.

Azure Cloud Shell

Azure hosts Azure Cloud Shell, an interactive shell environment that you can use through your browser. You can use either Bash or PowerShell with Cloud Shell to work with Azure services. You can use the Cloud Shell preinstalled commands to run the code in this article, without having to install anything on your local environment.

To start Azure Cloud Shell:

Option Example/Link
Select Try It in the upper-right corner of a code or command block. Selecting Try It doesn't automatically copy the code or command to Cloud Shell. Screenshot that shows an example of Try It for Azure Cloud Shell.
Go to https://shell.azure.com, or select the Launch Cloud Shell button to open Cloud Shell in your browser. Button to launch Azure Cloud Shell.
Select the Cloud Shell button on the menu bar at the upper right in the Azure portal. Screenshot that shows the Cloud Shell button in the Azure portal

To use Azure Cloud Shell:

  1. Start Cloud Shell.

  2. Select the Copy button on a code block (or command block) to copy the code or command.

  3. Paste the code or command into the Cloud Shell session by selecting Ctrl+Shift+V on Windows and Linux, or by selecting Cmd+Shift+V on macOS.

  4. Select Enter to run the code or command.

If you choose to install and use PowerShell locally, this article requires the Azure PowerShell module version 1.0.0 or later. Run Get-Module -ListAvailable Az to find the installed version. If you need to upgrade, see Install Azure PowerShell module. If you are running PowerShell locally, you also need to run Connect-AzAccount to create a connection with Azure.

Create a virtual network

Before creating a virtual network, you have to create a resource group for the virtual network, and all other resources created in this article. Create a resource group with New-AzResourceGroup. The following example creates a resource group named myResourceGroup:

New-AzResourceGroup -ResourceGroupName myResourceGroup -Location EastUS

Create a virtual network with New-AzVirtualNetwork. The following example creates a virtual network named myVirtualNetwork with the address prefix 10.0.0.0/16.

$virtualNetwork = New-AzVirtualNetwork `
  -ResourceGroupName myResourceGroup `
  -Location EastUS `
  -Name myVirtualNetwork `
  -AddressPrefix 10.0.0.0/16

Create a subnet configuration with New-AzVirtualNetworkSubnetConfig. The following example creates a subnet configuration for a subnet named Public:

$subnetConfigPublic = Add-AzVirtualNetworkSubnetConfig `
  -Name Public `
  -AddressPrefix 10.0.0.0/24 `
  -VirtualNetwork $virtualNetwork

Create the subnet in the virtual network by writing the subnet configuration to the virtual network with Set-AzVirtualNetwork:

$virtualNetwork | Set-AzVirtualNetwork

Enable a service endpoint

You can enable service endpoints only for services that support service endpoints. View service endpoint-enabled services available in an Azure location with Get-AzVirtualNetworkAvailableEndpointService. The following example returns a list of service-endpoint-enabled services available in the eastus region. The list of services returned will grow over time as more Azure services become service endpoint enabled.

Get-AzVirtualNetworkAvailableEndpointService -Location eastus | Select Name

Create an additional subnet in the virtual network. In this example, a subnet named Private is created with a service endpoint for Microsoft.Storage:

$subnetConfigPrivate = Add-AzVirtualNetworkSubnetConfig `
  -Name Private `
  -AddressPrefix 10.0.1.0/24 `
  -VirtualNetwork $virtualNetwork `
  -ServiceEndpoint Microsoft.Storage

$virtualNetwork | Set-AzVirtualNetwork

Restrict network access for a subnet

Create network security group security rules with New-AzNetworkSecurityRuleConfig. The following rule allows outbound access to the public IP addresses assigned to the Azure Storage service:

$rule1 = New-AzNetworkSecurityRuleConfig `
  -Name Allow-Storage-All `
  -Access Allow `
  -DestinationAddressPrefix Storage `
  -DestinationPortRange * `
  -Direction Outbound `
  -Priority 100 `
  -Protocol * `
  -SourceAddressPrefix VirtualNetwork `
  -SourcePortRange *

The following rule denies access to all public IP addresses. The previous rule overrides this rule, due to its higher priority, which allows access to the public IP addresses of Azure Storage.

$rule2 = New-AzNetworkSecurityRuleConfig `
  -Name Deny-Internet-All `
  -Access Deny `
  -DestinationAddressPrefix Internet `
  -DestinationPortRange * `
  -Direction Outbound `
  -Priority 110 `
  -Protocol * `
  -SourceAddressPrefix VirtualNetwork `
  -SourcePortRange *

The following rule allows Remote Desktop Protocol (RDP) traffic inbound to the subnet from anywhere. Remote desktop connections are allowed to the subnet, so that you can confirm network access to a resource in a later step.

$rule3 = New-AzNetworkSecurityRuleConfig `
  -Name Allow-RDP-All `
  -Access Allow `
  -DestinationAddressPrefix VirtualNetwork `
  -DestinationPortRange 3389 `
  -Direction Inbound `
  -Priority 120 `
  -Protocol * `
  -SourceAddressPrefix * `
  -SourcePortRange *

Create a network security group with New-AzNetworkSecurityGroup. The following example creates a network security group named myNsgPrivate.

$nsg = New-AzNetworkSecurityGroup `
  -ResourceGroupName myResourceGroup `
  -Location EastUS `
  -Name myNsgPrivate `
  -SecurityRules $rule1,$rule2,$rule3

Associate the network security group to the Private subnet with Set-AzVirtualNetworkSubnetConfig and then write the subnet configuration to the virtual network. The following example associates the myNsgPrivate network security group to the Private subnet:

Set-AzVirtualNetworkSubnetConfig `
  -VirtualNetwork $VirtualNetwork `
  -Name Private `
  -AddressPrefix 10.0.1.0/24 `
  -ServiceEndpoint Microsoft.Storage `
  -NetworkSecurityGroup $nsg

$virtualNetwork | Set-AzVirtualNetwork

Restrict network access to a resource

The steps necessary to restrict network access to resources created through Azure services enabled for service endpoints varies across services. See the documentation for individual services for specific steps for each service. The remainder of this article includes steps to restrict network access for an Azure Storage account, as an example.

Create a storage account

Create an Azure storage account with New-AzStorageAccount. Replace <replace-with-your-unique-storage-account-name> with a name that is unique across all Azure locations, between 3-24 characters in length, using only numbers and lower-case letters.

$storageAcctName = '<replace-with-your-unique-storage-account-name>'

New-AzStorageAccount `
  -Location EastUS `
  -Name $storageAcctName `
  -ResourceGroupName myResourceGroup `
  -SkuName Standard_LRS `
  -Kind StorageV2

After the storage account is created, retrieve the key for the storage account into a variable with Get-AzStorageAccountKey:

$storageAcctKey = (Get-AzStorageAccountKey `
  -ResourceGroupName myResourceGroup `
  -AccountName $storageAcctName).Value[0]

The key is used to create a file share in a later step. Enter $storageAcctKey and note the value, as you'll also need to manually enter it in a later step when you map the file share to a drive in a VM.

Create a file share in the storage account

Create a context for your storage account and key with New-AzStorageContext. The context encapsulates the storage account name and account key:

$storageContext = New-AzStorageContext $storageAcctName $storageAcctKey

Create a file share with New-AzStorageShare:

$share = New-AzStorageShare my-file-share -Context $storageContext

Deny all network access to a storage account

By default, storage accounts accept network connections from clients in any network. To limit access to selected networks, change the default action to Deny with Update-AzStorageAccountNetworkRuleSet. Once network access is denied, the storage account is not accessible from any network.

Update-AzStorageAccountNetworkRuleSet  `
  -ResourceGroupName "myresourcegroup" `
  -Name $storageAcctName `
  -DefaultAction Deny

Enable network access from a subnet

Retrieve the created virtual network with Get-AzVirtualNetwork and then retrieve the private subnet object into a variable with Get-AzVirtualNetworkSubnetConfig:

$privateSubnet = Get-AzVirtualNetwork `
  -ResourceGroupName "myResourceGroup" `
  -Name "myVirtualNetwork" `
  | Get-AzVirtualNetworkSubnetConfig `
  -Name "Private"

Allow network access to the storage account from the Private subnet with Add-AzStorageAccountNetworkRule.

Add-AzStorageAccountNetworkRule `
  -ResourceGroupName "myresourcegroup" `
  -Name $storageAcctName `
  -VirtualNetworkResourceId $privateSubnet.Id

Create virtual machines

To test network access to a storage account, deploy a VM to each subnet.

Create the first virtual machine

Create a virtual machine in the Public subnet with New-AzVM. When running the command that follows, you are prompted for credentials. The values that you enter are configured as the user name and password for the VM. The -AsJob option creates the VM in the background, so that you can continue to the next step.

New-AzVm `
    -ResourceGroupName "myResourceGroup" `
    -Location "East US" `
    -VirtualNetworkName "myVirtualNetwork" `
    -SubnetName "Public" `
    -Name "myVmPublic" `
    -AsJob

Output similar to the following example output is returned:

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command                  
--     ----            -------------   -----         -----------     --------             -------                  
1      Long Running... AzureLongRun... Running       True            localhost            New-AzVM     

Create the second virtual machine

Create a virtual machine in the Private subnet:

New-AzVm `
    -ResourceGroupName "myResourceGroup" `
    -Location "East US" `
    -VirtualNetworkName "myVirtualNetwork" `
    -SubnetName "Private" `
    -Name "myVmPrivate"

It takes a few minutes for Azure to create the VM. Do not continue to the next step until Azure finishes creating the VM and returns output to PowerShell.

Confirm access to storage account

Use Get-AzPublicIpAddress to return the public IP address of a VM. The following example returns the public IP address of the myVmPrivate VM:

Get-AzPublicIpAddress `
  -Name myVmPrivate `
  -ResourceGroupName myResourceGroup `
  | Select IpAddress

Replace <publicIpAddress> in the following command, with the public IP address returned from the previous command, and then enter the following command:

mstsc /v:<publicIpAddress>

A Remote Desktop Protocol (.rdp) file is created and downloaded to your computer. Open the downloaded rdp file. If prompted, select Connect. Enter the user name and password you specified when creating the VM. You may need to select More choices, then Use a different account, to specify the credentials you entered when you created the VM. Select OK. You may receive a certificate warning during the sign-in process. If you receive the warning, select Yes or Continue, to proceed with the connection.

On the myVmPrivate VM, map the Azure file share to drive Z using PowerShell. Before running the commands that follow, replace <storage-account-key> and <storage-account-name> with values from you supplied or retrieved in Create a storage account.

$acctKey = ConvertTo-SecureString -String "<storage-account-key>" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential -ArgumentList "Azure\<storage-account-name>", $acctKey
New-PSDrive -Name Z -PSProvider FileSystem -Root "\\<storage-account-name>.file.core.windows.net\my-file-share" -Credential $credential

PowerShell returns output similar to the following example output:

Name           Used (GB)     Free (GB) Provider      Root
----           ---------     --------- --------      ----
Z                                      FileSystem    \\vnt.file.core.windows.net\my-f...

The Azure file share successfully mapped to the Z drive.

Confirm that the VM has no outbound connectivity to any other public IP addresses:

ping bing.com

You receive no replies, because the network security group associated to the Private subnet does not allow outbound access to public IP addresses other than the addresses assigned to the Azure Storage service.

Close the remote desktop session to the myVmPrivate VM.

Confirm access is denied to storage account

Get the public IP address of the myVmPublic VM:

Get-AzPublicIpAddress `
  -Name myVmPublic `
  -ResourceGroupName myResourceGroup `
  | Select IpAddress

Replace <publicIpAddress> in the following command, with the public IP address returned from the previous command, and then enter the following command:

mstsc /v:<publicIpAddress>

On the myVmPublic VM, attempt to map the Azure file share to drive Z. Before running the commands that follow, replace <storage-account-key> and <storage-account-name> with values from you supplied or retrieved in Create a storage account.

$acctKey = ConvertTo-SecureString -String "<storage-account-key>" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential -ArgumentList "Azure\<storage-account-name>", $acctKey
New-PSDrive -Name Z -PSProvider FileSystem -Root "\\<storage-account-name>.file.core.windows.net\my-file-share" -Credential $credential

Access to the share is denied, and you receive a New-PSDrive : Access is denied error. Access is denied because the myVmPublic VM is deployed in the Public subnet. The Public subnet does not have a service endpoint enabled for Azure Storage, and the storage account only allows network access from the Private subnet, not the Public subnet.

Close the remote desktop session to the myVmPublic VM.

From your computer, attempt to view the file shares in the storage account with the following command:

Get-AzStorageFile `
  -ShareName my-file-share `
  -Context $storageContext

Access is denied, and you receive a Get-AzStorageFile : The remote server returned an error: (403) Forbidden. HTTP Status Code: 403 - HTTP Error Message: This request is not authorized to perform this operation error, because your computer is not in the Private subnet of the MyVirtualNetwork virtual network.

Clean up resources

When no longer needed, you can use Remove-AzResourceGroup to remove the resource group and all of the resources it contains:

Remove-AzResourceGroup -Name myResourceGroup -Force

Next steps

In this article, you enabled a service endpoint for a virtual network subnet. You learned that service endpoints can be enabled for resources deployed with multiple Azure services. You created an Azure Storage account and limited network access to the storage account to only resources within a virtual network subnet. To learn more about service endpoints, see Service endpoints overview and Manage subnets.

If you have multiple virtual networks in your account, you may want to connect two virtual networks together so the resources within each virtual network can communicate with each other. To learn how, see Connect virtual networks.