Accessing Azure Resources via Private Endpoints

In the era of the cloud, we are creating resources that in the majority of the cases are exposed to the public internet, lowering the security posture of the solution. Resources such as Virtual Machines, Database Servers, etc. can be easily left unprotected when the strategy and governance rules are not followed.

The storage account resource, for instance, when configured with a public endpoint, is reachable from all networks, including public internet. If we try to resolve the name of one of the endpoints of the storage account - let's take file for example - we'll be directed to a public IP address:

This can be considered a security risk since we are not only exposing the storage account to the entire internet but also allow data to traverse networks that we have no control over.

To avoid this risk, we can configure a Private Endpoint for the storage account on the VNet that the clients are connected to. When using a Private Endpoint, an interface to the storage account will be deployed that will expose the storage account services to a private IP within a VNet. 

As a good practice my suggestion is to use dedicated subnets for private endpoints so that traffic can be segregated. To create a new subnet, navigate to the 'Subnets' blade of the VNet and add a new subnet like below:

When creating the new subnet, make sure to select the respective service in the 'Services' drop down. If using an existing subnet, you can always add the service from the properties of the subnet. 

Now that we've got the VNet configured, we can deploy the private endpoint resource. Create a new resource of type Private Endpoint as shown below:

When going through the deployment wizard we first need to configure the basic settings of the endpoint, such as the subscription and resource group along with the name of the resource and the region to deploy to:

The next step of the wizard is to select the resource that will be exposed within the VNet. Things are a lot easier when searching for a resource in the same tenant, you just have to select the subscription and the type of the resource and then the available resources will be shown in a list:

There is the case where the resource to be exposed supports sub-resources, like storage accounts. Here I've selected to expose the 'file' service.

The last important step of the deployment process is to select the virtual network and the subnet to use. DNS resolution is also very important since the clients should be able to resolve the endpoints using the right names.

Here I've opted to create a Private DNS Zone in order to make things easier for this post.

When the deployment is completed, we have three new resources in our resource group:
Let's go through them one-by-one.

First we have the private DNS zone that was created as part of the deployment of the private endpoint. If you open the zone and list the records, we only see an A record pointing to an IP address belonging to the subnet we used:
Moving on to the next resource, we have the Private Endpoint. Not much to see here, except the 'DNS Configuration' blade. This is where you get the IP assigned to the endpoint and any DNS zone related information:
The last resource that was created as part of the deployment is a network interface that is the actual interface between the storage account and the VNet.

If you try to resolve the endpoint of the storage account, you should get a response with the private IP address instead of the public:

Now when the client connects to the storage account via this endpoint, the data will go through the Microsoft backbone network and not public internet.

In case one of your goals was to secure access to the storage account, the above is not enough. Given that your clients have access to the storage account through the endpoint, you should continue with disabling the public endpoints or at least limit access to them to specific IPs.

Popular posts from this blog

Domain Controller Machine Password Reset

Configuring a Certificate on Exchange Receive Connector

Verbose Parameter Passing to cmdlet inside Function