Announcing RUNWAY: The conference for teams securing what's nextRegister Now
RunReveal
SourcesSource Types

Snowflake

The Snowflake source requires a Pro plan subscription in RunReveal.

The Snowflake source collects audit and activity logs from your Snowflake account via the SNOWFLAKE.ACCOUNT_USAGE views. A single source instance polls three views automatically:

  • Login History -- authentication events including successful and failed login attempts, MFA usage, and client information.
  • Query History -- every query executed in your account, including the SQL text, execution status, user, role, warehouse, and performance metrics.
  • Access History -- data access patterns showing which objects (tables, views, columns) were read or modified by each query, plus any policies evaluated.

All three views use the same credentials, so no additional configuration is needed beyond the standard setup below.

Query History and Access History are available on all Snowflake editions. However, ACCESS_HISTORY requires Snowflake Enterprise Edition or higher. If your account does not support it, RunReveal will continue collecting login and query history without interruption.

Authentication methods

The source supports two ways to authenticate, chosen when you create it.

  • Key pair (recommended) -- you generate an RSA key pair, register the public key on your Snowflake service user, and give RunReveal the private key. RunReveal signs a short-lived JWT for each connection. Nothing expires, so the source keeps collecting indefinitely.
  • OAuth (legacy) -- RunReveal stores a Snowflake OAuth refresh token obtained through a browser consent flow.

Prefer key pair for new sources. Snowflake's OAUTH_REFRESH_TOKEN_VALIDITY defaults to 90 days, and 90 days is also the default maximum -- raising it requires your Snowflake admin to file a request with Snowflake Support. When the refresh token expires, every poll fails with invalid_grant until a person completes the browser consent flow again, which means log collection stops until someone notices. Key pair auth has no equivalent expiry.

If you already have an OAuth-configured Snowflake source, see Migrating from OAuth to key pair.

Setup

Step 1: Whitelist RunReveal IP addresses (if required)

If your Snowflake account has IP allowlisting enabled, you'll need to whitelist RunReveal's outbound IP addresses before the integration can connect. See Network Connectivity and IP Whitelisting for the IP addresses to add to your Snowflake network policy allowlist.

Step 2: Start RunReveal source creation

  1. Navigate to the RunReveal UI and go to the source creation page.
  2. Select "Snowflake" as your source type.
  3. Provide a descriptive name for your Snowflake source.
  4. Fill in your Snowflake Account Identifier. See the Snowflake docs on Account Identifiers for more information.
  5. Choose an Authentication Method. Leave this on Key pair unless you have a specific reason to use OAuth.

Leave this page open -- you'll come back to it to finish.

Step 3: Create a new Snowflake role

  1. Log into Snowflake and open a worksheet.
  2. Execute the following commands:
    CREATE ROLE runreveal_role;
    GRANT IMPORTED PRIVILEGES ON DATABASE SNOWFLAKE TO ROLE runreveal_role;
    GRANT USAGE ON WAREHOUSE COMPUTE_WH TO ROLE runreveal_role;

Note: You may use a different role name here, but be sure to use the same role in later commands, and change the default role on the Source settings page in RunReveal.

Step 4: Create a service user and configure authentication

Follow the tab matching the authentication method you selected in Step 2.

Generate an RSA key pair

Run these commands on your own machine. The first generates the private key RunReveal will use; the second derives the matching public key you'll register in Snowflake.

# Private key. -nocrypt is required: RunReveal cannot use a passphrase-protected key.
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt
 
# Public key, derived from the private key.
openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub

rsa_key.p8 is a credential -- treat it like a password. Store it somewhere safe and delete any extra copies once it's saved in RunReveal. If you omit -nocrypt, OpenSSL will prompt for a passphrase and produce an ENCRYPTED PRIVATE KEY that RunReveal will reject.

Create the service user

CREATE USER svc_runreveal
  DEFAULT_ROLE = runreveal_role
  DEFAULT_WAREHOUSE = COMPUTE_WH;
 
GRANT ROLE runreveal_role TO USER svc_runreveal;

No password is needed -- the key pair is the credential.

If your Snowflake account supports it, add TYPE = SERVICE to the CREATE USER statement. Service users cannot authenticate with a password or enroll in MFA, which is what you want for an unattended integration. See Snowflake's guidance on service users.

Register the public key on the user

Open rsa_key.pub and copy only the base64 body -- everything between the -----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY----- lines, joined into a single line with no line breaks. Then:

ALTER USER svc_runreveal SET RSA_PUBLIC_KEY = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...';

Verify it took effect:

DESC USER svc_runreveal;

RSA_PUBLIC_KEY_FP should now show a SHA256: fingerprint. If it's empty, the key was not set.

Finish in RunReveal

  1. Return to the RunReveal source page.
  2. Enter the Snowflake User Name (svc_runreveal above) and confirm the Snowflake Role matches the role from Step 3.
  3. Paste the contents of rsa_key.p8 into Private Key, or use Upload key file to select it.
  4. Click Test. RunReveal connects to Snowflake and returns sample events, so you can confirm the credentials work before saving.
  5. Click Connect to save.

Rotating the key. Snowflake keeps two public key slots, RSA_PUBLIC_KEY and RSA_PUBLIC_KEY_2, so you can rotate without downtime: register the new public key in the unused slot, update the private key in RunReveal, confirm with Test, then ALTER USER svc_runreveal UNSET the old slot. See Snowflake's key rotation docs.

Migrating from OAuth to key pair

An existing OAuth source can be switched in place. Polling resumes from where it left off, so there's no gap or duplication in your logs.

  1. Follow Generate an RSA key pair and Register the public key on the user, using the service user the source already authenticates as. You do not need to create a new user or role.
  2. In RunReveal, open the existing Snowflake source and click Edit.
  3. Change the Authentication Method to Key pair.
  4. Enter the Snowflake User Name for the existing service user and provide the private key.
  5. Click Test to confirm the new credentials work, then save.

Once saved, the source no longer uses the refresh token, and you can drop the OAuth security integration in Snowflake if nothing else depends on it:

DROP SECURITY INTEGRATION RUNREVEAL;

Verify It's Working

Once added, the source logs should begin flowing within a few minutes. Login history events appear first (up to 2-hour latency from Snowflake), followed by query history (up to 1 hour) and access history (up to 3 hours).

You can validate that logs are flowing by running the following SQL query:

SELECT * FROM runreveal.logs WHERE sourceType = 'snowflake' LIMIT 10

To check each event type specifically, use the serviceName field:

-- Login events
SELECT * FROM runreveal.logs
WHERE sourceType = 'snowflake' AND serviceName = 'login_history'
LIMIT 5
 
-- Query history events
SELECT * FROM runreveal.logs
WHERE sourceType = 'snowflake' AND serviceName = 'query_history'
LIMIT 5
 
-- Access history events
SELECT * FROM runreveal.logs
WHERE sourceType = 'snowflake' AND serviceName = 'access_history'
LIMIT 5

What's Collected

Login History

Sourced from SNOWFLAKE.ACCOUNT_USAGE.LOGIN_HISTORY. Captures every authentication attempt to your Snowflake account, including:

  • User identity and client IP address
  • Authentication factors (password, MFA, SSO)
  • Success or failure status with error codes
  • Client type and version (Snowflake UI, JDBC driver, SnowSQL, etc.)

Query History

Sourced from SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY. Captures every query executed in your account, including:

  • Full SQL query text
  • Database, schema, and warehouse context
  • User and role that executed the query
  • Execution status, error codes, and performance metrics (elapsed time, bytes scanned, rows produced)
  • Query tags for custom attribution

Access History

Sourced from SNOWFLAKE.ACCOUNT_USAGE.ACCESS_HISTORY. Tracks which data objects each query touched, including:

  • Direct and base objects accessed (tables, views, columns)
  • Objects modified (inserts, updates, DDL changes)
  • Policies evaluated during query execution (masking, row access)

Access History requires Snowflake Enterprise Edition or higher. If your account does not support it, this view is automatically skipped and the other two views continue to be polled.

Schema

The following columns are exposed for this source. RunReveal applies schema normalization across all sources, ensuring uniform field names and data types for cross-source queries and reusable detection logic.

Table: snowflake_logs (35 columns)

ColumnType
sourceIDString
sourceTypeLowCardinality(String)
sourceTTLUInt32
receivedAtDateTime
idString
eventTimeDateTime
eventNameString
eventIDString
srcIPString
srcASCountryCodeString
srcASNumberUInt32
srcASOrganizationString
srcCityString
srcConnectionTypeString
srcISPString
srcLatitudeFloat64
srcLongitudeFloat64
srcUserTypeString
ColumnType
dstIPString
dstASCountryCodeString
dstASNumberUInt32
dstASOrganizationString
dstCityString
dstConnectionTypeString
dstISPString
dstLatitudeFloat64
dstLongitudeFloat64
dstUserTypeString
actorMap(String, String)
tagsMap(String, String)
resourcesArray(String)
serviceNameString
enrichmentsArray(Tuple(data Map(String, String), name String, provider String, type String, value String))
readOnlyBool
rawLogString

Troubleshooting

Key pair: JWT token is invalid

Snowflake rejected the signed token. Usually one of:

  • The public key isn't registered, or doesn't match the private key. Run DESC USER svc_runreveal; and confirm RSA_PUBLIC_KEY_FP is set. If you regenerated the key pair, re-run the ALTER USER ... SET RSA_PUBLIC_KEY step -- the private key in RunReveal must be the one matching the registered public key.
  • The public key was pasted with its PEM header/footer or line breaks. RSA_PUBLIC_KEY takes only the base64 body, on a single line.
  • The Snowflake User Name doesn't match. The JWT identifies the user, so a typo here fails even with a correctly registered key. It must be the login name of the user the public key is set on.

Key pair: private key is passphrase protected

The key was exported with encryption. RunReveal can't decrypt it. Re-export it without a passphrase:

openssl pkcs8 -topk8 -inform PEM -in rsa_key.p8 -out rsa_key_unencrypted.p8 -nocrypt

Then upload rsa_key_unencrypted.p8. The public key on the Snowflake user does not change -- it's the same key pair, just stored without encryption.

Key pair: private key is not PEM encoded

RunReveal expects the full PEM text, including the -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- lines. Paste the file's entire contents (or use Upload key file), not just the base64 body -- that's the format RSA_PUBLIC_KEY wants in Snowflake, not the format the private key field wants here.

OAuth: invalid_grant, or the source stops collecting after ~90 days

The OAuth refresh token expired. Snowflake's OAUTH_REFRESH_TOKEN_VALIDITY defaults to 90 days, and recovering requires a person to repeat the browser consent flow -- so collection stays broken until someone notices.

Re-authorizing the source restarts the 90-day clock but doesn't fix the underlying problem. Migrate the source to key pair instead.

OAuth: Invalid Client

If you see this source error:

failed to get oauth token using refresh token: oauth2: "invalid_client"

it indicates trouble with the OAuth integration in Snowflake. Check that the Client ID and Client Secret you entered in RunReveal match the values from Snowflake.

If you get the error "Invalid consent request" when attempting to log into Snowflake as part of the OAuth flow in adding the source to RunReveal, check the following:

  • make sure you're logging in with the correct service user credentials
  • make sure that user has been granted the correct role. (This will be runreveal_role if you followed the instructions above.)
  • make sure that role is mentioned in the CREATE SECURITY INTEGRATION statement you issued as part of the setup.

OAuth: no refresh token available

If you see the source error no refresh token available, make sure you included OAUTH_ISSUE_REFRESH_TOKENS = TRUE when creating the integration.

User's configured default role 'OTHER_ROLE' is not granted to this user.

If you see this source error, be sure you've granted the correct role (usually runreveal_role) to the service user, and that the Snowflake Role on the source matches it. On OAuth sources, also confirm you logged in as that service user during the consent flow.

'SNOWFLAKE.ACCOUNT_USAGE' does not exist or not authorized

If you see this source error, double check the runreveal_role (or other role, if you specified a different one in the Source setup page) was created properly, and that the role was granted to the service user.

you must specify the warehouse....

If you see this source error

snowflake API returned status code 422: Unable to run the command. You must specify the warehouse to use by either setting the warehouse field in the body of the request or by setting the DEFAULT_NAMESPACE property for the current user.

make sure to set DEFAULT_WAREHOUSE when creating the service user.

Query History falling behind on high-volume accounts

By default RunReveal fetches up to 10,000 rows per view on each poll. Accounts that execute more queries than that between polls will see query history fall behind and slowly accumulate a backlog.

Raise the Batch Limit on the source's settings page to let it catch up -- it accepts values up to 100,000. Leave it blank to use the default. Larger batches make each poll query heavier on your warehouse, so raise it only while a source is behind.

Query History or Access History not appearing

If you only see login events but not query or access history events:

  • Query History: Events have up to 1-hour latency in Snowflake. Wait at least 1 hour after setup before investigating.
  • Access History: Events have up to 3-hour latency. This view also requires Snowflake Enterprise Edition or higher. Check your Snowflake edition if access history events never appear.
  • Verify the service user's role has IMPORTED PRIVILEGES ON DATABASE SNOWFLAKE granted, which provides access to all ACCOUNT_USAGE views.