Implement Snowflake governance guardrails with network rules, session policies, authentication policies, and automated compliance checks. Use when enforcing security policies, implementing data governance, or configuring automated compliance for Snowflake. Trigger with phrases like "snowflake policy", "snowflake guardrails", "snowflake governance", "snowflake compliance", "snowflake enforce".
Automated policy enforcement and governance guardrails using Snowflake-native features: network rules, authentication policies, session policies, and object-level governance.
-- Network rules (more granular than legacy network policies)
CREATE OR REPLACE NETWORK RULE corp_vpn_rule
TYPE = IPV4
MODE = INGRESS
VALUE_LIST = ('203.0.113.0/24', '198.51.100.0/24');
CREATE OR REPLACE NETWORK RULE cloud_services_rule
TYPE = HOST_PORT
MODE = EGRESS
VALUE_LIST = ('api.company.com:443', 'events.company.com:443');
-- Create network policy using rules
CREATE OR REPLACE NETWORK POLICY prod_network_policy
ALLOWED_NETWORK_RULE_LIST = (corp_vpn_rule)
BLOCKED_NETWORK_RULE_LIST = ();
-- Apply at account level
ALTER ACCOUNT SET NETWORK_POLICY = prod_network_policy;
-- Or per-user (service accounts can have different rules)
ALTER USER svc_etl SET NETWORK_POLICY = prod_network_policy;
-- Require MFA for interactive users
CREATE OR REPLACE AUTHENTICATION POLICY interactive_auth
MFA_AUTHENTICATION_METHODS = ('TOTP')
CLIENT_TYPES = ('SNOWFLAKE_UI', 'SNOWSQL')
SECURITY_INTEGRATIONS = ('saml_sso');
-- Service accounts: key pair only, no password
CREATE OR REPLACE AUTHENTICATION POLICY service_auth
AUTHENTICATION_METHODS = ('KEYPAIR')
CLIENT_TYPES = ('SNOWFLAKE_DRIVER')
MFA_AUTHENTICATION_METHODS = ();
-- Apply policies
ALTER USER analyst_user SET AUTHENTICATION POLICY = interactive_auth;
ALTER USER svc_etl SET AUTHENTICATION POLICY = service_auth;
-- Enforce session timeout and idle limits
CREATE OR REPLACE SESSION POLICY prod_session_policy
SESSION_IDLE_TIMEOUT_MINS = 30
SESSION_UI_IDLE_TIMEOUT_MINS = 15;
-- Apply to account
ALTER ACCOUNT SET SESSION POLICY = prod_session_policy;
-- Prevent runaway queries
ALTER WAREHOUSE PROD_WH SET
STATEMENT_TIMEOUT_IN_SECONDS = 3600, -- 1 hour max
STATEMENT_QUEUED_TIMEOUT_IN_SECONDS = 600; -- 10 min max queue
-- Prevent accidental full table operations
-- Use row access policies + stored procedures instead of raw access
-- Example: Safe delete procedure with audit
CREATE OR REPLACE PROCEDURE safe_delete(
table_name VARCHAR, where_clause VARCHAR, max_rows INTEGER DEFAULT 10000
)
RETURNS VARCHAR
LANGUAGE SQL
AS
$$
BEGIN
-- Count affected rows first
LET count_sql VARCHAR := 'SELECT COUNT(*) FROM ' || :table_name || ' WHERE ' || :where_clause;
LET affected_rows INTEGER;
EXECUTE IMMEDIATE :count_sql INTO :affected_rows;
IF (:affected_rows > :max_rows) THEN
RETURN 'BLOCKED: Would delete ' || :affected_rows || ' rows (max: ' || :max_rows || ')';
END IF;
-- Audit log
INSERT INTO audit.delete_log (table_name, where_clause, row_count, executed_by, executed_at)
VALUES (:table_name, :where_clause, :affected_rows, CURRENT_USER(), CURRENT_TIMESTAMP());
-- Execute delete
EXECUTE IMMEDIATE 'DELETE FROM ' || :table_name || ' WHERE ' || :where_clause;
RETURN 'Deleted ' || :affected_rows || ' rows from ' || :table_name;
END;
$$;
-- Usage: CALL safe_delete('orders', 'order_date < ''2024-01-01''', 50000);
-- Create governance taxonomy
CREATE TAG IF NOT EXISTS data_domain ALLOWED_VALUES 'finance', 'marketing', 'engineering', 'hr';
CREATE TAG IF NOT EXISTS data_owner;
CREATE TAG IF NOT EXISTS retention_days;
-- Apply tags to databases/schemas
ALTER DATABASE PROD_DW SET TAG data_domain = 'finance';
ALTER SCHEMA PROD_DW.GOLD SET TAG data_owner = '[email protected]';
ALTER TABLE PROD_DW.GOLD.REVENUE SET TAG retention_days = '2555'; -- 7 years
-- Automated compliance report
SELECT
tag_name, tag_value, object_database, object_schema, object_name, column_name
FROM TABLE(INFORMATION_SCHEMA.TAG_REFERENCES_ALL_COLUMNS(
'PROD_DW.GOLD.REVENUE', 'TABLE'
));
-- Find untagged tables (governance gap)
SELECT t.table_catalog, t.table_schema, t.table_name, t.row_count
FROM INFORMATION_SCHEMA.TABLES t
LEFT JOIN TABLE(INFORMATION_SCHEMA.TAG_REFERENCES(
t.table_catalog || '.' || t.table_schema || '.' || t.table_name, 'TABLE'
)) tr ON TRUE
WHERE tr.tag_name IS NULL
AND t.table_schema NOT IN ('INFORMATION_SCHEMA')
ORDER BY t.row_count DESC NULLS LAST;
# .github/workflows/snowflake-governance.yml