Snowflake and Azure are incredibly capable of storing data securely. You can see all reports available to customers through their pages of security and compliance reports, for both Azure and Snowflake. This is fantastic for data stored in the platform; though, we must still consider how that data is accessed by end users and other systems from outside Snowflake’s network.
For example, consider the very simple situation of logging into Snowflake from your machine using a browser. Typically, you would access a URL such as https://organisation-account.snowflakecomputing.com
and arrive at Snowflake. This is already a potential security risk as this journey to Snowflake has travelled over the public internet. Of course, it would take somebody far more knowledgeable in networking and systems than myself to explain exactly how somebody could intercept this traffic. If I did know, I still wouldn’t think it was a good idea to share that here. Suffice it to say, somebody out there may be able to intercept this traffic and do something malicious with it.
So, how do we prevent this issue? How do we ensure our access to Snowflake remains secure when strict restrictions are in place, complying to frameworks such as HITRUST, PCI-DSS and ISO/IEC 27001? The answer is private connectivity, establishing a direct route between your virtual network and Snowflake. In this article, I will explain how to configure this for a Snowflake account that is hosted in an Azure region.
This article discusses how to configure private connectivity for an Azure-hosted Snowflake account. If you wish to view the AWS equivalent, please see my colleague Roger Garcia’s article: Configure AWS PrivateLink with Snowflake.
Architecture
Before discussing how to implement the solution, we first discuss the architecture.
Simple Architecture Diagram
This diagram shows a simple representation of how traffic from other resources inside a virtual network can interact with Snowflake using private connectivity:
This diagram shows a simple representation of how traffic from an end user can interact with Snowflake using private connectivity:
Naturally, you can use a combination of the two to facilitate traffic from both inside and outside your virtual network. You can also enjoy more complex models by peering other virtual networks and performing other networking feats, but they are outside the scope of this article.
Architecture Components
From the diagrams above, we can see the following key components are required:
- A Snowflake account deployed in Azure:
- All Snowflake accounts will already sit inside a relevant virtual network and have a private link service ready and waiting, so do not worry about this
- A virtual network in Azure to contain the private endpoint
- A private DNS zone in Azure that can route traffic inside the network to the private endpoint, if leveraging other resources from inside Azure:
- Configuration of any other resources inside Azure is not covered in this article, but this article does cover DNS routing for those resources using a private DNS zone
- A Virtual Private Network (VPN) that can route local traffic to the private endpoint, if connecting as an end user from outside the network:
- Configuration of the VPN is not covered in this article, but this article does cover local DNS routing for the end users
Requirements
To configure the architecture above, the following is required:
- Snowflake Business Critical Edition (or higher) deployed in Azure
- ACCOUNTADMIN access in your Snowflake account
- A resource group in Azure to work with
- The ability to create/modify the following objects inside the Azure resource group:
- Virtual network
- Private endpoint
- Private DNS zone (if routing traffic from inside your network)
- Azure CLI access
Step 1: Retrieve Details from Snowflake
The step is simple. Log in to your Snowflake account and execute the following command using the ACCOUNTADMIN role:
select SYSTEM$GET_PRIVATELINK_CONFIG();
This will return a dictionary object with all the relevant details for configuring your private connectivity:
This will take the following format, where I have masked any relevant information:
{ "privatelink-pls-id": "sf-pvlinksvc-azazureregion.a1b2cd34-ef5a-6b78-9c12-d3e4567890f0.azureregion.azure.privatelinkservice", "privatelink-account-name": "accountid.azure-region.privatelink", "regionless-snowsight-privatelink-url": "app-org-my_account.privatelink.snowflakecomputing.com", "snowsight-privatelink-url": "app.azure-region.privatelink.snowflakecomputing.com", "regionless-privatelink-ocsp-url": "ocsp.org-my_account.privatelink.snowflakecomputing.com", "privatelink-account-url": "accountid.azure-region.privatelink.snowflakecomputing.com", "regionless-privatelink-account-url": "org-my_account.privatelink.snowflakecomputing.com", "privatelink_ocsp-url": "ocsp.accountid.azure-region.privatelink.snowflakecomputing.com", "privatelink-connection-ocsp-urls": "[]", "privatelink-connection-urls": "[]" }
Step 2: Create a Virtual Network in Azure
This next step is to create a virtual network in Azure. You can do this directly within the Azure Portal by searching for the “Virtual networks” service then selecting “Create:”
On the “Basics” tab, decide which subscription, resource group and region you wish to deploy the virtual network into and give it an appropriate name. For our demonstration, the private endpoint is called SNOWFLAKE-PRIVATE-LINK-vnet
, where the vnet
suffix is our internal naming convention for denoting virtual networks:
You may wish to configure additional settings on the “Security” tab, or you can leave this as default.
On the “IP addresses” tab, you can determine a range of IP addresses that are allocated for your virtual network. To keep things simple, we can leave this as default for this article. Naturally, it is advised to agree a suitable range of IP addresses ahead of time that will fit with your wider Azure architecture:
Feel free to add any tags as relevant for your organisation’s methodology. Finally, review and create the virtual network:
Step 3: Create a Private Endpoint in Azure
Now that we have the details from the Snowflake account and a virtual network in Azure, we can begin creating the private endpoint in Azure. You can do this directly within the Azure Portal by searching for the “Private endpoints” service then selecting “Create:”
On the “Basics” tab, decide which subscription, resource group and region you wish to deploy the private endpoint into and give it an appropriate name. For our demonstration, the private endpoint is called pep-snowflake-private-link
, where the pep
suffix is our internal naming convention for denoting private endpoints:
On the “Resource” tab, select “Connect to an Azure resource by resource ID or alias” and paste the “privatelink-pls-id” value that you received from Snowflake. For our example, that value is as follows:
{ "privatelink-pls-id": "sf-pvlinksvc-azazureregion.a1b2cd34-ef5a-6b78-9c12-d3e4567890f0.azureregion.azure.privatelinkservice" }
On the “Virtual Network” tab, select your virtual network from the list. You may wish to change other settings or configure an application security group, depending on your preference and requirements:
You cannot configure DNS specifically for this type of resource so you can ignore the next tab. Feel free to add any tags as relevant for your organisation’s methodology. Finally, review and create the private endpoint:
Once the private endpoint has deployed, it can be found in the list of private endpoints in Azure. Notably, the connection state will be set to “Pending” until the endpoint is authorised in Snowflake.
Step 4: Authorise the Private Link in Snowflake
Now that the private endpoint exists, we can authorise it in Snowflake. To achieve this, we must first retrieve the resource id for the private endpoint and generate a temporary access token that Snowflake can leverage. This will require the Azure CLI as this step cannot be achieved in the Azure Portal.
Step 4a: Retrieve the Resource ID of the Private Endpoint
In Azure Portal, the resource ID for the private endpoint can be retrieved from its “Properties” pane:
This will take the following example format:
/subscriptions/a123bc45-67de-89f1-2345-ab6789cd1ef2/resourcegroups/my-resource-group-rg/providers/microsoft.network/privateendpoints/pep-snowflake-pas-private-link
Step 4b: Generate a Temporary Access Token That Snowflake Can Leverage
Be aware that the access token we are about to generate grants access to the entire Azure subscription temporarily, and thus should be handled carefuly and securely. Do not share this access token apart from when inserting it into Snowflake in the next step. According to the Azure documentation, the token will be valid for at least 5 minutes with the maximum at 60 minutes.
From the command line, log into Azure using the az login
command, then generate an access token with the following command:
az account get-access-token
You may need to specify your subscription if your private endpoint is not in your default subscription.
az account get-access-token --subscription <your-subscription-id>
This will output a lengthy access token, which can then be deployed into Snowflake.
Step 4c: Authorising the Private Link in Snowflake
These two values can now be submitted to Snowflake’s SYSTEM$AUTHORIZE_PRIVATELINK()
function as follows:
select SYSTEM$AUTHORIZE_PRIVATELINK( '/subscriptions/a123bc45-67de-89f1-2345-ab6789cd1ef2/resourcegroups/my-resource-group-rg/providers/microsoft.network/privateendpoints/pep-snowflake-pas-private-link' , 'eyJ...' ) ;
Entering this into Snowflake will inform us that the private link has been authorised:
Now all we need to do is sort out the DNS routing for our traffic and we’re good to go!
Step 5: DNS Routing
At this point, we have almost finished our journey. Traffic is now authorised to travel between our Azure virtual network and Snowflake’s, via our designated private endpoint. However, we cannot visit the private endpoint’s IP address directly Snowflake is expecting traffic to match a given format to meet the requirements of the SSL certificate. In short, we must ensure that we still attempt to access Snowflake using an appropriate URL.
Step 5a: Which URLs Need to Be Routed?
Fortunately, we already know which URLs we need to route as Snowflake is kind enough to tell us. Recall that back in step 1, we gathered the following information using Snowflake’s SYSTEM$GET_PRIVATELINK_CONFIG()
function:
{ "privatelink-pls-id": "sf-pvlinksvc-azazureregion.a1b2cd34-ef5a-6b78-9c12-d3e4567890f0.azureregion.azure.privatelinkservice", "privatelink-account-name": "accountid.azure-region.privatelink", "regionless-snowsight-privatelink-url": "app-org-my_account.privatelink.snowflakecomputing.com", "snowsight-privatelink-url": "app.azure-region.privatelink.snowflakecomputing.com", "regionless-privatelink-ocsp-url": "ocsp.org-my_account.privatelink.snowflakecomputing.com", "privatelink-account-url": "accountid.azure-region.privatelink.snowflakecomputing.com", "regionless-privatelink-account-url": "org-my_account.privatelink.snowflakecomputing.com", "privatelink_ocsp-url": "ocsp.accountid.azure-region.privatelink.snowflakecomputing.com", "privatelink-connection-ocsp-urls": "[]", "privatelink-connection-urls": "[]" }
As you can see, rows 4-9 of this output are all URLs. In fact, rows 10 and 11 may end up containing URLs too. These are the ones that need to be routed.
I would actually go a step further and suggest routing two versions of each of these URLs, the first as written and the second replacing any underscores with hyphens. This is because Snowflake actually supports connecting with both of those sets of URLs, since some drivers and third party tools don’t support underscores in connection strings.
This gives us the following set of URLs which need to be routed. The non-URL entries have also been removed from this list.
{ "regionless-snowsight-privatelink-url": "app-org-my_account.privatelink.snowflakecomputing.com", "regionless-snowsight-privatelink-url_with_hyphens": "app-org-my-account.privatelink.snowflakecomputing.com", "snowsight-privatelink-url": "app.azure-region.privatelink.snowflakecomputing.com", "regionless-privatelink-ocsp-url": "ocsp.org-my_account.privatelink.snowflakecomputing.com", "regionless-privatelink-ocsp-url_with_hyphens": "ocsp.org-my-account.privatelink.snowflakecomputing.com", "privatelink-account-url": "accountid.azure-region.privatelink.snowflakecomputing.com", "regionless-privatelink-account-url": "org-my_account.privatelink.snowflakecomputing.com", "regionless-privatelink-account-url_with_hyphens": "org-my-account.privatelink.snowflakecomputing.com", "privatelink_ocsp-url": "ocsp.accountid.azure-region.privatelink.snowflakecomputing.com", "privatelink-connection-ocsp-urls": "[]", "privatelink-connection-urls": "[]" }
Step 5b: Where Should Traffic Be Routed to?
This part is easy. In the Azure Portal, head back to your private endpoint and look at the “DNS configuration” tab. There, you will see an IP address listed for your private endpoint:
For demonstration purposes going forwards, lets assume our private endpoint as the IP address 10.0.0.10
.
Step 5c: Route Traffic From Other Resources Inside the Virtual Network
This step discussues how to route traffic from other resources inside your virtual network, such as virtual machines or functions apps that you are hosting in Azure. A common example of this is having a virtual machine within your network that users connect to when working, which they can then use to connect to Snowflake. The configuration of any such resource is not covered by this article, however this article will now cover the DNS routing for those resources using a private DNS zone.
If this is not relevant for you and you only wish to route traffic for an end user directly, without an interim virtual machine or similar, then feel free to skip to the next step.
Step 5c1: Create the Private DNS Zone
To begin setting this up within the Azure Portal, search for the “Private DNS zones” service then selecting “Create:”
On the “Basics” tab, decide which subscription and resource group you wish to deploy the private DNS zone into. The name must match the URL domain that will be routed, so enter the following value:
privatelink.snowflakecomputing.com
It is important to note that only one private DNS zone can exist for each domain per resource group. So, if you have multiple Snowflake accounts and deliberately want to keep the private DNS zone separate, these will need to sit in different resource groups and ideally not be exposed to the same resources/users.
Feel free to add any tags as relevant for your organisation’s methodology. Finally, review and create the private DNS zone:
The private DNS zone should not be visible in your list of private DNS zones:
Select the private DNS zone to view the list of record sets that are routed. At first, this will be empty:
Select “+ Record set” to add records for each of the URLs that we wish to route, acquired in step 5a. The “name” should be everything in the URL that takes place before the “.privatelink.snowflakecomputing.com”, and the IP address will be that of the private endpoint that you received in step 5b:
When you are finished, you will see something similar to this example:
Step 5c2: Link the Private DNS Zone to Your Virtual Network(s)
Now all that remains is to connect your private DNS zone to any virtual network(s) that will be leveraging the private endpoint to connect to Snowflake. This is configured using the “Virtual network links” pane within the private DNS zone. New links are created by select “Add:”
And there we have it. Any resource within your selected virtual networks will now be able to visit any of your “privatelink.snowflakecomputing.com” URLs. You won’t see anything on the surface, but underneath you will find that Azure is routing that traffic away from the original URL and to your private endpoint instead, securely connecting you to Snowflake.
Step 5d: Route Traffic for End Users From Outside the Virtual Network
This step discusses how to route traffic for an end user directly, without an interim virtual machine or similar. Of course, the user will still need to be able to access your virtual network in general through the use of a Virtual Private Network (VPN), the configuration of which is not covered in this article. However, this article will now cover the local DNS routing for the end users.
If this is not relevant for you and you only wish to route traffic from other resources inside your virtual network, such as virtual machines or functions apps that you are hosting in Azure, then this was covered in the previous step.
This step is simple to achieve; however, the process varies depending on your operating system. The objective is to update the local hosts file to override standard DNS routing for the local machine.
Since this article focuses on Azure, we will use the Microsoft operating system Windows 11 for our example. If you have another operating system, you should be able to find similar steps online if you search for how to modify your host file in that operating system.
This file is locked down and can only be modified with administrator access on the local machine. So we start by opening up a text editor, such as Notepad, as an administrator:
Within this administrator-level text editor, open the hosts file. In Windows, this is found in the directory “C:\Windows\System32\drivers\etc.” This assumes you have kept the standard of installing your operating system on the C drive; otherwise, you may need to change this to match the drive on which you have installed Windows:
When first accessed, it is likely that this file will still show the default content similar to the screenshot below; though, you may see other items there that are the result of other configurations. Do not change anything you are not familiar with as this may impact other applications and access on your local machine:
To add the bespoke routing, we must add records to this file for each of the URLs that we wish to route, acquired in step 5a, including the “.privatelink.snowflakecomputing.com” domain. The IP address is that of the private endpoint that you received in step 5b.
You should end up with something similar to the following, where each record is formed of the destination IP address, followed by the URL:
# Snowflake private link routing 10.0.0.10 app-org-my_account.privatelink.snowflakecomputing.com 10.0.0.10 app-org-my-account.privatelink.snowflakecomputing.com 10.0.0.10 app.azure-region.privatelink.snowflakecomputing.com 10.0.0.10 ocsp.org-my_account.privatelink.snowflakecomputing.com 10.0.0.10 ocsp.org-my-account.privatelink.snowflakecomputing.com 10.0.0.10 accountid.azure-region.privatelink.snowflakecomputing.com 10.0.0.10 org-my_account.privatelink.snowflakecomputing.com 10.0.0.10 org-my-account.privatelink.snowflakecomputing.com 10.0.0.10 ocsp.accountid.azure-region.privatelink.snowflakecomputing.com
The final piece should appear similarly to this screenshot:
This is all that’s required. As long as you are able to access the IP address from your local machine (meaning you should be using a VPN to access your Azure virtual network) then you should now be able to access any of those URLs through a browser or through any other tool. For completeness, here is a screenshot showing access to the main Snowsight area for private links in Azure UK South:
This brings us to the end of the article. I hope you found it useful. The above steps should enable you to visit any of your “privatelink.snowflakecomputing.com” URLs from both internal resources and from local end user machines. As mentioned before, you won’t see anything on the surface, but underneath you will find that Azure is routing that traffic away from the original URL and to your private endpoint instead, securely connecting you to Snowflake.
To make this fully secure, you may even wish to configure a network policy in your Snowflake account to block any access that does not come from your organization’s virtual network. This is not covered in this article, though, and I would advise caution with this approach as you always want to make sure you aren’t blocking yourself out before fully configuring your new route in!