This series takes you from zero to hero with the latest and greatest cloud data warehousing platform, Snowflake.
An important step towards ensuring the security of your Snowflake account(s) is the appropriate use of network rules and policies to prevent unauthorised access. These policies are leveraged to ensure that access is only allowed through restricted methods and to/from exclusive sources.
Without this protection, you have one less wall to prevent potential bad actors from accessing your environment. Whilst it may be easy to think that MFA is enough to secure an environment, this is certainly not enough as there are plenty of situations where this can be defeated when it is the only line of defence. What if the bad actor has managed to get hold of an employee’s phone? Or the bad actor is a recent ex-employee who has not yet turned in their phone? What if the access is for a service principal instead of a human user, such as an automated process orchestrated by Matillion or an automated extract refresh in Tableau, where MFA simply is not appropriate as no human will be approving the MFA request when the process runs at 2 a.m. or every 15 minutes?
In all of the above scenarios, reliance on MFA does not ensure your account is secure. Network rules and policies are an excellent way to harden your security and help keep your data safe.
Here are a few example scenarios where network rules and policies are useful:
- A user should only be able to log in from their home office, which has an explicit IP address.
- All users who work from the head office should only be able to log in from within the head office, which has a few public-facing IP addresses all within a precise range.
- A dedicated service principal for a third party (Matillion, Atlan, etc.) should only be able to log in from that third party’s IP address range.
- SCIM requests via Entra (Active Directory) should only be allowed if they come from the appropriate subnet in the Azure network.
- OAuth integrations with a third party (dbt Cloud, Dataiku, Thoughtspot, Tableau, etc.) should only be allowed to leverage OAuth tokens from the appropriate third-party network.
- For a highly secure account leveraging private connectivity with Azure/AWS, all users should only be able to authenticate through an exclusive set of private endpoints, and all traffic over the public internet should be blocked.
- This example is actually covered in more detail in this more targeted article: Snowflake Network Rules: Restrict Access to Specific Private Endpoints.
This article walks through how to configure your Snowflake account(s) appropriately to handle the situations such as those above. To achieve this, we will cover the following:
- What are network rules?
- What are network policies?
- How to leverage network policies to secure authentication requests and security integrations.
- A tip for mapping login history to known network rules.
What are Network Rules?
In short, network rules are objects that store information on a type of network traffic for Snowflake. This traffic can be one of two categories:
- Ingress — Traffic from outside of Snowflake that is coming in to Snowflake.
- Egress — Traffic that is leaving Snowflake and travelling outside.
This article focuses on the ingress category, and how we can leverage this to restrict inbound traffic to Snowflake to exclusive private endpoints. Note that in Snowflake’s terminology, the category (ingress/egress) is referred to as the “mode,” and this terminology will be used for the rest of this article. If you are interested in the egress mode instead, see our series on Snowflake External Access.
Ingress Mode — Traffic Types
There are three types of inbound traffic that Snowflake can leverage for network rules:
IPV4
— The standard internet.AWSVPCEID
— Private endpoints established via AWS PrivateLink.AZURELINKID
— Private endpoints established via Azure Private Link.
As stated above, this article focuses on the IPv4 category to handle traffic across the standard internet. For guidance on further securing private endpoints, see this more targeted article: Snowflake Network Rules: Restrict Access to Specific Private Endpoints.
When creating a network rule, the type is paired with a list of values. For example, if the type is IPV4
then each value in the list must either be an IP address or a range of addresses provided as a CIDR block. When creating a network rule for private endpoints via AWS or Azure, then each value in the values list must be Snowflake’s internal ID for that private endpoint.
An Important Note
An important piece of information to note is that network rules will only ever act on traffic within their distinctive traffic type. So if a network rule is created for IPv4 that matches a certain IP range, then traffic coming through a different type but in that same IP range will not be matched.
For example, consider a network rule of type IPV4
that matches the IP address 10.10.10.10
. Any inbound traffic that travels via the public internet using IPv4 from the IP address 10.10.10.10
will be matched. However, this IP address may belong to a user that is connecting to Snowflake using private connectivity. In that case, the type of their connection would be AZURELINKID
or AWSVPCEID
, not IPV4
. In this scenario, even though the connection comes from the IP address of 10.10.10.10
, the traffic does not match against the the IPV4
rule as the traffic is not of that type.
Example Network Rule – IPv4
Here is a simple example for creating an IPV4
network rule:
create network rule if not exists "NET_RULE__ALL_IPV4" type = IPV4 mode = INGRESS value_list = ('0.0.0.0/0') comment = 'Network rule that can match against the full range of IPv4 addresses, i.e. all public network traffic. This can be included in blocked lists for private connectivity policies' ;
This network rule uses CIDR notation to span the full range of IP addresses. This means that any connection to Snowflake that comes across the public internet would match against this rule. Of course, it is unlikely that you will want to apply this network rule to any allowed lists as it fully open, however this may be leveraged as part of a blocked list to ensure traffic for a given process can only leverage another type (AZURELINKID
or AWSVPCEID
).
If you are not sure what a CIDR block is, the simplest and quickest description is that a CIDR block is a quick notation for a range of IP addresses. For example, the CIDR block
123.123.123.32/29
covers all IP addresses in the range123.123.123.32
to123.123.123.39
. If you are not sure about CIDR blocks, all functionality here can be achieved by either listing IP addresses one-by-one, or by using an IP range to CIDR conversion tool to quickly find the ranges you need.
A Best Practice Recommendation
Network rules are schema-level objects. This means that each network rule must sit within a schema, within a database. This can make things much harder to manage if network rules are created sporadically without a structure in place. It is highly recommended to agree beforehand on a central location or set of locations for network rules and only ever create them there. A very simple example could be having a database called “ACCOUNT_ADMIN” that contains a schema called “NETWORK_RULES,” then granting the “CREATE NETWORK RULE” privilege on this schema to the “SECURITYADMIN” role. This makes it far easier for anybody managing network rules/policies to understand what is already there.
What are Network Policies?
In short, network policies are a mechanism for allowing/blocking specific traffic. These can be thought of as a bridge between a set of network rules and a particular user, integration or account. There is no limit to the number of network rules that can be linked to a network policy, however an individual user/integration/account can only leverage a single network policy at any time.
The following diagram demonstrates how multiple network rules can be leveraged by a network policy, and yet only a single network policy can be leveraged by any particular user/integration/account.
Example Network Policies
Here is a simple example for creating a network policy that only allows traffic for two specific network rules:
create network policy "NET_POL__PRIVATE_ENDPOINT_ONLY" allowed_network_rule_list = ('NET_RULE__HEAD_OFFICE', 'NET_RULE__INTERNAL_VPN') comment = 'Allows access to traffic originating from either the company head office or the company Virtual Private Network (VPN)' ;
Similarly, here is an example of a network rule that only allows access via an exclusive private endpoint and blocks all access that comes through the public internet:
create network policy "NET_POL__PRIVATE_ENDPOINT_ONLY" allowed_network_rule_list = ('NET_RULE__MY_PRIVATE_ENDPOINT') blocked_network_rule_list = ('NET_RULE__ALL_IPV4') comment = 'Allows user access through the private endpoint. Blocks any access that comes through the public internet.' ;
Why Bother with Network Rules?
If you look at the documentation for network policies in Snowflake, you can see that it is possible to directly block/allow IP addresses and CIDR blocks within a network policy, instead of relying on network rules. This is the legacy mechanism that Snowflake provided for managing network security, before network rules were available. Whilst this legacy functionality is still available, I would highly recommend leveraging network rules instead. This has multiple benefits, including:
- Network rules can be attached to multiple network policies, so you only need to define/maintain the information in a single network rule instead of in multiple network policies.
- For example, there could be many network policies that involve an internal VPN. For whatever reason, the outbound IP address of this internal VPN could change. If using network rules, this new outbound IP address only needs to be changed in one location instead of in every network policy.
- Network rules provide a better mechanism for clearly explaining what each IP address or CIDR block is.
- For example, consider a network policy that allows traffic from multiple locations, including the head office, an internal VPN and two other offices. This could easily result in 4 or more different IP addresses or CIDR blocks within a single policy. When a network administrator is reviewing these 3 months later, it is much harder to tell that
123.123.123.10
is the head office and123.45.67.89
is one of the other offices. Depending on the maturity of the networking team, they may not have this information easily on hand and might have to investigate more deeply in other resources to determine which is the appropriate IP address for which office. This problem goes away if each office has its own network rule, as it is easier to match an IP address against a network rule.
- For example, consider a network policy that allows traffic from multiple locations, including the head office, an internal VPN and two other offices. This could easily result in 4 or more different IP addresses or CIDR blocks within a single policy. When a network administrator is reviewing these 3 months later, it is much harder to tell that
How to Leverage Network Policies To Secure Authentication Requests and Security Integrations
Once a network policy has been created, leveraging it to secure a user/integration/account is very simple. All that is required is an alter statement, such as the following examples:
-- Apply a network policy to an individual user alter user "MY_USER" set network_policy = "NET_POL__MY_NETWORK_POLICY" ; -- Apply a network policy to a security integration alter security integration "INT__MY_INTEGRATION" set network_policy = "NET_POL__MY_NETWORK_POLICY" ; -- Apply a network policy to an entire account. alter account set network_policy = "NET_POL__MY_NETWORK_POLICY" ;
Important Notes
It is important to keep the following things in mind when applying network policies:
- As stated above, only one network policy can be applied to an individual user/integration/account at any time. If you need to apply the rules for two network policies to a single user, the only option is to create a new network policy that combines the required properties.
- To apply a network policy to a whole account, the user must either use the “SECURITYADMIN” role (or higher), or use a role with the global ATTACH POLICY privilege.
- Snowflake will only leverage the most granular network policy when authenticating a user or service.
- For example, if a user attempts to authenticate:
- Snowflake will first check to see if there is a user-level network policy for that user. If one exists, only this user-level network policy will be leveraged for authentication.
- If no user-level network policy exists, Snowflake will then check to see if there is an integration-level network policy against the authentication method being leveraged. If one exists, only this integration-level network policy will be leveraged for authentication.
- If no integration-level network policy exists either, Snowflake will then check to see if there is an account-level network policy for the account. If one exists, only this account-level network policy will be leveraged for authentication.
- If no account-level network policy exists either, Snowflake will not perform any network-level validation and will simply allow the access
- More plainly, the order is:
- User-level
- Integration-level
- Account-level
- For example, if a user attempts to authenticate:
Viewing Active Network Policies for an Object
Snowflake have provided a simple view that greatly simplifies viewing any and all policies that are active against an object. Beyond network policies, this also includes other policies such as authentication policies and password policies.
To quickly see what policies are active against a user/integration/account, you can query the “POLICY_REFERENCES” table function with the following options:
-- View current account-level network policy select "POLICY_NAME" from table( "SNOWFLAKE"."INFORMATION_SCHEMA"."POLICY_REFERENCES"( REF_ENTITY_DOMAIN => 'ACCOUNT' , REF_ENTITY_NAME => current_account() ) ) where "POLICY_KIND" = 'NETWORK_POLICY' ; -- View current integration-level network policy select "POLICY_NAME" from table( "SNOWFLAKE"."INFORMATION_SCHEMA"."POLICY_REFERENCES"( REF_ENTITY_DOMAIN => 'INTEGRATION' , REF_ENTITY_NAME => 'INT_OAUTH__MY_INTEGRATION' ) ) where "POLICY_KIND" = 'NETWORK_POLICY' ; -- View current user-level network policy select "POLICY_NAME" from table( "SNOWFLAKE"."INFORMATION_SCHEMA"."POLICY_REFERENCES"( REF_ENTITY_DOMAIN => 'USER' , REF_ENTITY_NAME => 'MY_USER' ) ) where "POLICY_KIND" = 'NETWORK_POLICY' ;
Each of these statements will return the name of the active network policy should one exist.
Viewing Where a Specific Network Policy is Leveraged
Similar to the above, it is also possible to query this information for a specific network policy, and therefore view all users/integrations/accounts where the network policy is leveraged:
-- View where a specific network policy is leveraged select "REF_ENTITY_DOMAIN", "REF_ENTITY_NAME" from table( "SNOWFLAKE"."INFORMATION_SCHEMA"."POLICY_REFERENCES"( POLICY_NAME => 'NET_POL__MY_NETWORK_POLICY' , POLICY_KIND => 'NETWORK_POLICY' ) ) ;
This statement will show all users/integrations/accounts where the network policy is being leveraged, with the “REF_ENTITY_DOMAIN” field showing whether this is applied to a user, integration or account.
For full details, check out Snowflake’s documentation on the POLICY_REFERENCES table function and view.
A Tip for Mapping Login History to Known Network Rules
Through the joy of Snowpark, it is not too difficult to create a process that retrieves the IP addresses and CIDR blocks for all network rules in a schema/database/account and store this information in a table. Through Snowflake’s parse_ip function, this information can be joined to the “CLIENT_ID” field in Snowflake’s LOGIN_HISTORY table function and view to assist with identifying access requests and their sources. I think you’ll have a hard time finding anybody who actually knows all appropriate IP addresses for their network without having to look them up, and this approach can drastically simplify any investigations or analytics taking place.
There is also the added benefit of potentially finding out that you already know the IP address for traffic that you thought was unknown, and that you can actually use an existing network rule/policy for something that you did not previously realise. For example, you may be trying to identify how traffic for a service principal called “MY_SERVICE_PRINCIPAL” should be secured, only to realise from this login history that the traffic always comes from “NET_POL__MY_TABLEAU_SERVER” and is actually a service principal for a Tableau workload.
I have provided the full code for this tip here for anybody to leverage.
Wrap up
To finish this article, I would like to simply reiterate what I said at the start. Network rules and policies are a critical component in any secure Snowflake environment. Without this protection, you have one less wall to prevent potential bad actors from accessing your environment. Whilst it may be easy to think that MFA is enough to secure an environment, this is certainly not enough and you should not rely on MFA alone to keep accounts secure. In fact, I would not rely on the combination of MFA and network rules/policies alone either, as there’s also a great benefit from using authentication policies, password policies and security integrations.
In short, the best way to ensure that your Snowflake accounts are secure is to remain vigilant and put up as many walls as you can, whilst of course being mindful not to introduce unnecessary roadblocks that get in the way of actual users being able to use the environment without a security benefit. It’s better to be overcautious than to have a breach.
If you like what you have seen here and would like some hands-on support and guidance, I strongly recommend checking out our Snowflake Security and Cost Management Health Checks. If you are interested in this or any of our services, then contact us here.