Claude-code-plugins-plus-skills snowflake-policy-guardrails

install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/snowflake-pack/skills/snowflake-policy-guardrails" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-snowflake-policy-guardrails && rm -rf "$T"
manifest: plugins/saas-packs/snowflake-pack/skills/snowflake-policy-guardrails/SKILL.md
source content

Snowflake Policy & Guardrails

Overview

Automated policy enforcement and governance guardrails using Snowflake-native features: network rules, authentication policies, session policies, and object-level governance.

Instructions

Step 1: Network Rules and Policies

-- 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;

Step 2: Authentication Policies

-- 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;

Step 3: Session Policies

-- 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;

Step 4: Statement-Level Guardrails

-- 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);

Step 5: Data Governance Tags and Policies

-- 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 = 'analytics-team@company.com';
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;

Step 6: CI/CD Policy Checks

# .github/workflows/snowflake-governance.yml
name: Snowflake Governance Check

on:
  pull_request:
    paths: ['sql/**', 'migrations/**']

jobs:
  policy-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Check for dangerous SQL patterns
        run: |
          # No DROP DATABASE/SCHEMA without IF EXISTS
          if grep -rn "DROP DATABASE\|DROP SCHEMA" sql/ | grep -v "IF EXISTS"; then
            echo "ERROR: DROP without IF EXISTS detected"
            exit 1
          fi

          # No GRANT ... TO PUBLIC
          if grep -rn "TO ROLE PUBLIC\|TO PUBLIC" sql/; then
            echo "ERROR: Granting to PUBLIC role is not allowed"
            exit 1
          fi

          # No hardcoded passwords
          if grep -rn "PASSWORD = " sql/ | grep -v "PASSWORD = \$"; then
            echo "ERROR: Hardcoded password detected"
            exit 1
          fi

          # All tables must have DATA_RETENTION_TIME_IN_DAYS
          for f in $(grep -rl "CREATE TABLE\|CREATE OR REPLACE TABLE" sql/); do
            if ! grep -q "DATA_RETENTION_TIME_IN_DAYS" "$f"; then
              echo "WARNING: $f missing explicit retention policy"
            fi
          done

          echo "All governance checks passed"

      - name: Validate SchemaChange naming
        run: |
          # Ensure migration files follow V{version}__{description}.sql
          for f in migrations/V*.sql; do
            if ! echo "$f" | grep -qE 'V[0-9]+\.[0-9]+\.[0-9]+__[a-z_]+\.sql'; then
              echo "ERROR: Invalid migration filename: $f"
              echo "Expected: V{major}.{minor}.{patch}__{description}.sql"
              exit 1
            fi
          done

Step 7: Automated Compliance Audit

-- Weekly compliance audit stored procedure
CREATE OR REPLACE PROCEDURE run_compliance_audit()
  RETURNS TABLE (check_name VARCHAR, status VARCHAR, details VARCHAR)
  LANGUAGE SQL
AS
$$
  -- Check 1: No users with ACCOUNTADMIN default role
  SELECT 'accountadmin_check' AS check_name,
    CASE WHEN COUNT(*) = 0 THEN 'PASS' ELSE 'FAIL' END AS status,
    COUNT(*) || ' users with ACCOUNTADMIN default' AS details
  FROM SNOWFLAKE.ACCOUNT_USAGE.USERS
  WHERE default_role = 'ACCOUNTADMIN' AND disabled = 'false'

  UNION ALL

  -- Check 2: Network policy active
  SELECT 'network_policy_check',
    CASE WHEN value != '' THEN 'PASS' ELSE 'FAIL' END,
    'Account network policy: ' || COALESCE(value, 'NONE')
  FROM TABLE(FLATTEN(INPUT => PARSE_JSON(
    SYSTEM$GET_SNOWFLAKE_PLATFORM_INFO()
  )))
  WHERE key = 'network_policy'

  UNION ALL

  -- Check 3: MFA adoption
  SELECT 'mfa_check',
    CASE WHEN COUNT_IF(has_mfa = 'true') * 100 / COUNT(*) >= 90 THEN 'PASS' ELSE 'WARN' END,
    COUNT_IF(has_mfa = 'true') || '/' || COUNT(*) || ' users have MFA'
  FROM SNOWFLAKE.ACCOUNT_USAGE.USERS
  WHERE disabled = 'false';
$$;

Error Handling

IssueCauseSolution
Network policy blocks legitimate userIP not in allowlistAdd IP range to network rule
Auth policy prevents loginWrong client type in policyAdjust CLIENT_TYPES
Session timeout too aggressiveShort idle timeoutIncrease SESSION_IDLE_TIMEOUT_MINS
CI check false positiveSQL pattern too broadRefine regex pattern

Resources

Next Steps

For architecture blueprints, see

snowflake-architecture-variants
.