The Azure services used when delivering integrations within the Azure platform provide many options when it comes to security. The Azure documentation includes references to public and private endpoints, virtual networks (VNets), VNet peering and the use of ExpressRoute. While the simplest and most widely adopted approach (judging by the amount of information available online) to integration within the Azure ecosystem often involves utilising public endpoints, it’s important to acknowledge that some clients may not be able to adopt this strategy.
Despite strong arguments centred around secure communication over HTTPS and adherence to the Zero Trust principle (never trust, always verify, and enforce the principle of least privilege from both inside and outside the network), certain clients insist on a stringent requirement: all communication between on-premises systems and the Azure cloud must exclusively pass through an existing ExpressRoute, with no usage of public endpoints permitted.
In addition to this, enterprises frequently dictate the choice of specific Azure regions for resource deployment. This can lead to restrictions in terms of approach used to connect to the storage account (which are not particularly well documented).
This post serves as a useful reference point of applied approaches, notes and article links to support your work in these scenarios.
Azure Private Endpoints
While there is an abundance of information within the Azure documentation regarding Private Endpoints, the simplest explanation I have come across can be found here: Understanding Private Endpoints. At a high level:
- When not using private endpoints:
- All communication with Azure services (regardless of whether from on-premise and an ExpressRoute / Site-to-Site VPN connection exists or from within a VNet within Azure) will be via the public internet
- When using private endpoints:
- A private endpoint is created within a VNet thereby allowing traffic from the VNet to connect to the service without traversing the public internet
The following diagram (1) illustrates the concept.
For the purposes of this post, we will be looking to create a storage account with a private endpoint which can be accessed by a Logic App.
High level steps
At a high level, the steps which are required are:
- Creation of virtual network (VNet) and associated subnets
- Creation of storage account with private endpoint and DNS private zone
- Creation of Standard Logic App, associated app service plan and storage account
Virtual network (VNet) creation
When creating virtual networks, it is important to consider the desired address space prior to creation. For the purposes of this blog, we’ll only be using allocating a small number of IP addresses in order to demonstrate the concepts.
Create a VNet having an address space of 10.0.0.0/26 (which will allocate 64 addresses) and allocate the following subnets:
- snet-logicapp-outbound – 10.0.0.0/28
- snet-private-endpoints – 10.0.0.16/28
Each of these subnets will have 11 available IP addresses (as Azure retains some for internal use).
Storage Account and Private Endpoint Creation
For the purposes of this example, we will be creating a general purpose V2 storage account. This disables public access and instead exposes a private endpoint for the storage account’s blob sub-resource. Once the storage account has been created, within the ‘Networking’ blade, ensure that public network access is disabled:
Select the ‘Private endpoint connections’ tab and create a private endpoint with the following configuration:
- Target sub-resource: blob
- Virtual network: select the virtual network created in the previous step
- Subnet: snet-private-endpoints
- Private IP configuration: Dynamically allocate IP address
Integrate with private DNS zone: Yes
This will result in a few additional resources being created. Namely:
- A private endpoint for the blob sub-resource of the storage account
- A network interface card associated with the private endpoint
- A private DNS zone for use by the private endpoint
Note that in enterprise environments, there may be a preference to manage the DNS entries using an alternative approach as outlined here: https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/private-link-and-dns-integration-at-scale. If this approach is used, it removes the need to create the private DNS zone. Instead, it relies on Azure policies to detect and configure the DNS configuration dynamically. This results in less concerns from a devops perspective but care should be taken (especially when automating deployments through ARM templates as the Azure policies can take some time to run and therefore the DNS resolutions take some time to become effective).
At this point, we should have a storage account which is accessible only from within the VNet and we will perform an additional optional step just to validate this is the case.
Private Endpoint Validation (optional)
In order to verify that the private endpoint has been configured correctly, within the Azure portal, view the DNS configuration blade of the private endpoint resource and you should see that there is a FQDN associated with the blob sub-resource of the storage account which has an IP address from the VNet’s snet-private-endpoint subnet.
You can also navigate to the Subnets blade of the VNet resource and verify that the number of available IPs within the snet-private-endpoint subnet has decreased by 1 (and should now be 10).
The final step in the validation process involves creating a virtual machine which uses the same VNet created above. Once the virtual machine has been created, from within the virtual machine, it should be possible to resolve the public FQDN to the private IP address associated with the private endpoint. For example, if our storage account was named ‘saae768’, then we could issue the following nslookup command and validate that the private IP address associated with the private endpoint is returned:
Which should result in output similar to the following:
An important point to note is that even though a private endpoint exists and has a FQDN which contains ‘privatelink’, you should continue to utilise the public FQDN and rely on the DNS to resolve it to a private IP address. This ensures that no additional code changes are required when enabling private endpoints.
Just as a final point, it should be noted that there is no need for the virtual machine to be part of the same subnet as the private endpoint of the storage account – just that it be part of the same VNet.
Standard Logic App Connecting to Private Endpoint of Storage Account
When creating a Logic App, it should be noted that one of the limitations of consumption based Logic Apps is that they cannot connect to private endpoints. This means that in our scenario of utilising a storage account with a private endpoint, we need to use a standard (rather than consumption) Logic App.
When creating a standard Logic App, there is a need to create a storage account and app service plan associated with the Logic App. In the interests of brevity, we will not cover these steps here but please note that for the purposes of this blog, we will be using a separate storage account which is accessible via the public internet. This is in order to keep things simple and it is certainly possible to use a storage account which only has access provided via private endpoints, it is just a bit more involved than what we want to cover here.
Once the standard Logic App (and dependent storage account and app service plan have been created), we need to set up the Logic App to be integrated with the VNet. This basically means that all outbound communication from within the Logic App will be via the VNet. In order to do this, navigate to the Networking blade of the Logic App and within the ‘Outbound traffic’ section, click VNet integration. On the resulting page, click ‘Add VNet’ and provide the details of the VNet and subnet (which will be snet-logicapp-outbound).
Once the VNet integration has been configured, the final step is to connect to the storage account from within the Logic App. Since the Logic App has been configured with VNet integration and there is a private endpoint associated with the blob service of the storage account, you may be thinking that it’s simply a matter of utilising any blob connector, but there are a few caveats which should be considered.
In general, there are three connectors which can be used within a Logic App to interact with blobs within a storage account:
- In-App Azure blob storage connector – which runs natively on the Azure Logic Apps runtime
- Shared Azure blob storage connector – which is managed by Microsoft and hosted in Azure
- HTTP connector – which can be used to interact with the Blob REST APIs
and deciding which to use requires taking the use of private endpoints and also the resource regions into consideration.
For example, if the Logic App and storage account reside within the same region, then the In-App Azure blob storage connector should be used. Attempting to use the Shared Azure blob storage connector in this scenario simply will not work and the error messages are not helpful (trust me – I’ve spent way too much time trying to figure out why the connection couldn’t be established)!
In general, if the Logic App and storage account reside within the same region, just use the In-App Azure blob storage connector. I don’t believe that Microsoft have published a detailed article regarding which connectors to use in each scenario, but the following can be used as a summary: https://techcommunity.microsoft.com/t5/azure-integration-services-blog/access-azure-blob-using-logic-app/ba-p/1451573
In the world of cloud integration, security is paramount. This post has explored Azure security features including public and private endpoints, virtual networks and their interplay with Logic Apps. Standard Logic Apps are required to utilise secure private endpoint connections, streamlining data integration and as you journey through Azure integration, remember that security choices and endpoint configuration can impact the approach you need to take to implement solutions. Stay informed and use private endpoints for adaptable, secure integrations tailored to your clients’ needs.
For more information or questions on how to leverage private endpoints for secure Azure integration, don’t hesitate to reach out.
Henshall, K. (2023). Notes regarding VNets, Logic Apps and Private Endpoints. Retrieved from https://intelligentpathways.atlassian.net/wiki/spaces/IMCC/pages/7309656065/Notes+regarding+VNets+Logic+Apps+and+Private+Endpoints