Minimum Permissions for Scan Accounts
Forcepoint DSPM scans Snowflake data sources for cataloging and classification. This topic describes the minimum Snowflake privileges required for a scan account, so customers can provision a
least-privilege role instead of using ACCOUNTADMIN or a full IMPORTED PRIVILEGES grant on the SNOWFLAKE share.
| Requirement | Reason |
|---|---|
Network reachability to <account>.snowflakecomputing.com (443) |
Establish the JDBC connection |
A Snowflake user for the scanner (a TYPE = SERVICE user is recommended) |
SERVICE users authenticate with a PAT or key-pair only—never a password - so they bypass MFA, which suits an unattended scanner |
| A Programmatic Access Token (PAT) or key-pair for that user | The connector passes the PAT as the JDBC password |
| A network policy bound to the user | Snowflake requires a network policy on the user for PAT authentication |
| The target database name | Required - the connector rejects a connection with no database |
The connector uses the official Snowflake JDBC driver. No
ACCOUNTADMIN role is required.
How Snowflake handles catalog visibility
Snowflake's per-database INFORMATION_SCHEMA shows only objects the active role has at least one privilege on. USAGE on a schema does not cascade to its tables - the role
needs both schema USAGE and explicit SELECT on the tables/views for them to appear in INFORMATION_SCHEMA.TABLES and to be sampled. Account-wide identity metadata (users, roles,
grants) lives in the SNOWFLAKE.ACCOUNT_USAGE share, which is reachable through the granular SNOWFLAKE.OBJECT_VIEWER + SNOWFLAKE.SECURITY_VIEWER
database roles.
- Connection test & database metadata
Operation Objects read Minimum grant Test connection / run queries — USAGEon warehouse +USAGEon databaseSchema enumeration ( getSchemas)Database schemas USAGEon schemaTable / view listing SHOW TABLES IN SCHEMA,SHOW VIEWS IN SCHEMAUSAGEon schemaColumn / PK / FK metadata SHOW COLUMNS/PRIMARY KEYS/IMPORTED KEYS IN SCHEMAUSAGEon schemaApproximate row count & table size INFORMATION_SCHEMA.TABLES(row_count, bytes)USAGEon schema +SELECTon the tables (INFORMATION_SCHEMA is privilege-filtered) - Data sampling
Operation Objects read Minimum grant SAMPLE BERNOULLIrow sampleTarget user table/view USAGEon schema +SELECTon table/viewColumn payload sampling Target user table/view Same as above - Trustee (users & roles) extraction
Operation Objects read Minimum grant List users SNOWFLAKE.ACCOUNT_USAGE.USERSSNOWFLAKE.OBJECT_VIEWER+SNOWFLAKE.SECURITY_VIEWERdatabase rolesList roles (groups) SNOWFLAKE.ACCOUNT_USAGE.ROLESSame as above Recursive role membership SNOWFLAKE.ACCOUNT_USAGE.GRANTS_TO_USERS,GRANTS_TO_ROLESSame as above Users are classified as users; roles are classified as groups. ACCOUNTADMIN, SECURITYADMIN, SYSADMIN, and USERADMIN are flagged as top-level admins.
The two viewer database roles are a tighter substitute for
GRANT IMPORTED PRIVILEGES ON DATABASE SNOWFLAKE- they give the scanner the same read access to the ACCOUNT_USAGE views it needs but keepSHOW GRANTSon the scanner role at a couple of rows instead of expanding to hundreds. Note ACCOUNT_USAGE views have a 45 - 90 minute data latency. - Permissions extraction
Operation Objects read Minimum grant Database-level grants SHOW GRANTS ON DATABASEUSAGEon databaseSchema-level grants SHOW GRANTS ON SCHEMA/ACCOUNT_USAGE.GRANTS_TO_ROLESUSAGEon schema (+ viewer roles for the ACCOUNT_USAGE fast path)Table-level grants SHOW GRANTS ON TABLEUSAGEon schema +SELECTon tableTop-level admin holders ACCOUNT_USAGE.ROLESviewer roles Column-level grants — Not supported by the Snowflake connector
Granting scan access
Attach all grants to a custom role, not directly to the user - that keeps the permission set auditable and revocable as a unit. USAGE on a schema does not reach its
tables, so the role needs schema USAGE plus SELECT on current and future tables/views.
-- Run as ACCOUNTADMIN. Edit the SET values first.
SET USER_NAME = 'FP_SCANNER';
SET ROLE_NAME = 'FP_SCANNER_ROLE';
SET NETWORK_POLICY_NAME = 'FP_SCANNER_NETWORK_POLICY';
SET PAT_NAME = 'FP_SCANNER_PAT';
SET WAREHOUSE_NAME = 'COMPUTE_WH';
SET DATABASE_NAME = '<TARGET_DATABASE>';
SET SCHEMAS = '<SCHEMA_1>,<SCHEMA_2>'; -- comma-separated
USE ROLE ACCOUNTADMIN;
-- Network policy (required for PAT auth) — replace with the scanner's CIDRs
CREATE NETWORK POLICY IF NOT EXISTS IDENTIFIER($NETWORK_POLICY_NAME)
ALLOWED_IP_LIST = ('0.0.0.0/0');
-- Custom role
CREATE ROLE IF NOT EXISTS IDENTIFIER($ROLE_NAME);
-- Service user (no password; PAT only)
CREATE USER IF NOT EXISTS IDENTIFIER($USER_NAME)
TYPE = SERVICE
DEFAULT_ROLE = $ROLE_NAME
DEFAULT_WAREHOUSE = $WAREHOUSE_NAME;
GRANT ROLE IDENTIFIER($ROLE_NAME) TO USER IDENTIFIER($USER_NAME);
ALTER USER IDENTIFIER($USER_NAME) SET NETWORK_POLICY = $NETWORK_POLICY_NAME;
-- Account- and database-level grants
GRANT USAGE ON WAREHOUSE IDENTIFIER($WAREHOUSE_NAME) TO ROLE IDENTIFIER($ROLE_NAME);
GRANT DATABASE ROLE SNOWFLAKE.OBJECT_VIEWER TO ROLE IDENTIFIER($ROLE_NAME);
GRANT DATABASE ROLE SNOWFLAKE.SECURITY_VIEWER TO ROLE IDENTIFIER($ROLE_NAME);
GRANT USAGE ON DATABASE IDENTIFIER($DATABASE_NAME) TO ROLE IDENTIFIER($ROLE_NAME);
-- Per-schema grants (loops over $SCHEMAS)
EXECUTE IMMEDIATE $$
BEGIN
LET schemas ARRAY := SPLIT($SCHEMAS, ',');
FOR i IN 0 TO ARRAY_SIZE(schemas) - 1 DO
LET qualified VARCHAR := '"' || $DATABASE_NAME || '"."' || TRIM(GET(schemas, i)::VARCHAR) || '"';
EXECUTE IMMEDIATE 'GRANT USAGE ON SCHEMA ' || qualified || ' TO ROLE "' || $ROLE_NAME || '"';
EXECUTE IMMEDIATE 'GRANT SELECT ON ALL TABLES IN SCHEMA ' || qualified || ' TO ROLE "' || $ROLE_NAME || '"';
EXECUTE IMMEDIATE 'GRANT SELECT ON ALL VIEWS IN SCHEMA ' || qualified || ' TO ROLE "' || $ROLE_NAME || '"';
EXECUTE IMMEDIATE 'GRANT SELECT ON FUTURE TABLES IN SCHEMA ' || qualified || ' TO ROLE "' || $ROLE_NAME || '"';
EXECUTE IMMEDIATE 'GRANT SELECT ON FUTURE VIEWS IN SCHEMA ' || qualified || ' TO ROLE "' || $ROLE_NAME || '"';
END FOR;
RETURN 'done';
END;
$$;
-- Generate the PAT — token_secret is shown ONCE; copy it into your secret manager
ALTER USER IDENTIFIER($USER_NAME) ADD PROGRAMMATIC ACCESS TOKEN IDENTIFIER($PAT_NAME)
ROLE_RESTRICTION = $ROLE_NAME
DAYS_TO_EXPIRY = 90;Scope variants: to scan the whole datasource, list every user schema in $SCHEMAS; to scan a single schema or table, grant USAGE/SELECT only on that schema
(and, for a single table, SELECT on just that table).
Verification
FP_SCANNER_ROLE) and
run:SELECT CURRENT_USER(), CURRENT_ROLE(), CURRENT_DATABASE();
SHOW TABLES IN SCHEMA "<DATABASE>"."<SCHEMA>";
SELECT * FROM "<DATABASE>"."<SCHEMA>"."<TABLE>" SAMPLE BERNOULLI (1) LIMIT 10;
SELECT COUNT(*) FROM SNOWFLAKE.ACCOUNT_USAGE.USERS WHERE DELETED_ON IS NULL;
SELECT COUNT(*) FROM SNOWFLAKE.ACCOUNT_USAGE.ROLES WHERE DELETED_ON IS NULL;
SHOW GRANTS ON DATABASE "<DATABASE>";All queries should return without an access error. Empty result sets are fine when the underlying object has no matching rows. (Remember ACCOUNT_USAGE latency of up to ~90 minutes for brand-new users/roles.)
What is not required
-
The
ACCOUNTADMIN,SECURITYADMIN,SYSADMIN, orUSERADMINroles. -
GRANT IMPORTED PRIVILEGES ON DATABASE SNOWFLAKE(the two granular viewer database roles replace it). -
OWNERSHIPon any object. -
INSERT,UPDATE,DELETE,TRUNCATE, or any write/DDL privilege. -
Any
MODIFY/OPERATEon the warehouse beyondUSAGE.