Snowflake: Network Policies

A slightly more in-depth and guided approach to setting up Snowflake network rules and network policies... Basically, the stuff I wish I'd known when I started trying to secure my Snowflake account.

Avoid Footguns: a Backdoor User

Snowflake lets you apply network policies at the account, security integration and user level. The smaller the audience (e.g. user) the higher the precedence.

It is possible to lock yourself out of your Snowflake instance with Network Policies. In that case, you may need help from Snowflake Support to get back in.

When I'm going to do a lot of experimentation with Network Policies, I either test the policies by using them on one user, or I create a user that is exempt from the Account level policy. That way, if a bad policy gets applied, that user can get in a fix it.

-- Because network rules are schema objects, create a schema to hold them
CREATE DATABASE BLOG;
CREATE SCHEMA NETPOLICY;

-- Create a network rule which matches all IPv4 addresses
CREATE OR REPLACE NETWORK RULE zero_ingress_ipv4_rule
  MODE = INGRESS
  TYPE = IPV4
  COMMENT = 'All IPv4 Addresses'
  VALUE_LIST = ('0.0.0.0/0');

-- Create a network policy using the rule
CREATE NETWORK POLICY open_network_policy
  COMMENT = 'Open policy, access from anywhere'
  ALLOWED_NETWORK_RULE_LIST = ('zero_ingress_ipv4_rule');

-- Apply that network policy to a user with ACCCOUNTADMIN
-- You should clear this after testing!
ALTER USER backdoor SET NETWORK_POLICY = open_network_policy;

Network Rules

One of the most confusing things for me, is that network rules are schema objects:

USE SCHEMA NETPOLICY;
CREATE OR REPLACE NETWORK RULE an_ingress_ipv4_rule
  MODE = INGRESS
  TYPE = IPV4
  COMMENT = 'Network rule in first schema'
  VALUE_LIST = ('1.2.3.4/32');

SHOW NETWORK RULES;

Here you can see the new rule you just created, along with the zero rule you created before. After creating a new rule in a different schema:

CREATE SCHEMA NETPOLICY2;
CREATE OR REPLACE NETWORK RULE an_ingress_ipv4_rule
  MODE = INGRESS
  TYPE = IPV4
  COMMENT = 'Network rule in second schema'
  VALUE_LIST = ('5.6.7.8/32');

SHOW NETWORK RULES;

If you use the UI, you can see all of the rules together, but the format isn't that useful:

When you create a new policy, it's going to use rules from whatever your current schema is. You can see how that context could be critical.

Network Policies

Network policies, unlike rules, are account objects.

USE SCHEMA NETPOLICY;
CREATE OR REPLACE NETWORK POLICY a_network_policy
  COMMENT = "Primary Network Policy for Account"
  ALLOWED_NETWORK_RULE_LIST = ('an_ingress_ipv4_rule');

SHOW NETWORK POLICIES;

Unless your IP address is 1.2.3.4, applying this policy to your account will lock you out. Update the network rule to your IP address.

ALTER NETWORK RULE an_ingress_ipv4_rule SET VALUE_LIST = ('31.212.55.117/32');

With the network rule updated, you can apply the network policy to your account:

ALTER ACCOUNT SET NETWORK_POLICY = a_network_policy;

Clean Up

Once the network policy looks good, you can reset the security policy on the user that you used, so that the account policy will take effect:

ALTER USER backdoor UNSET NETWORK_POLICY;

-- To delete everything created in this post:
ALTER ACCOUNT UNSET NETWORK_POLICY;
ALTER USER backdoor UNSET NETWORK_POLICY;
DROP NETWORK POLICY a_network_policy;
DROP NETWORK POLICY open_network_policy;
DROP SCHEMA NETPOLICY;
DROP SCHEMA NETPOLICY2;

See Also

Not directly related to network rules and policies, but something that I ended up using a lot while developing and refining my own policies where the LOGIN_HISTORY, SESSIONS, and QUERY_HISTORY views. Combining those together (filter by date range on each object, and be prepared to wait) you can figure out who is logging in, from where, and what objects they are using.