Snowflake encrypts everything: micro-partition files at rest, intermediate spill files on local SSD, all in-flight data over TLS, and metadata in the cloud services layer. The mechanism is a four-level hierarchical key model where each higher key wraps (encrypts) the keys at the level below. The root sits in a hardware security module and never leaves it in cleartext. Customer-managed keys are bolted on via Tri-Secret Secure (TSS), which composes the customer's KMS key with Snowflake's root so that revoking the customer key renders all data inaccessible — even to Snowflake operators.
Each level uses AES-256. A higher-level key never encrypts data directly; it only encrypts the keys at the level below. The narrower the scope of the key (file < table < account), the larger the rotation impact, so Snowflake rotates aggressively at the file level and rarely at the root.
┌──────────────────────────────────────────────────────────────────────┐
│ LEVEL 1: ROOT KEY (in HSM) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Hardware Security Module — never exported in cleartext │ │
│ │ (Snowflake-managed, or composed with CMK in TSS) │ │
│ └────────────────────────────┬─────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
│ wraps
▼
┌──────────────────────────────────────────────────────────────────────┐
│ LEVEL 2: ACCOUNT MASTER KEY (AMK) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ One per Snowflake account, rotated on schedule │ │
│ └────────────────────────────┬─────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
│ wraps
▼
┌──────────────────────────────────────────────────────────────────────┐
│ LEVEL 3: TABLE MASTER KEY (TMK) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ One per table, rotated when the table is altered or │ │
│ │ on the periodic rekey schedule (default 30 days) │ │
│ └────────────────────────────┬─────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
│ wraps
▼
┌──────────────────────────────────────────────────────────────────────┐
│ LEVEL 4: FILE KEYS (per micro-partition) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ AES-256 data key per encrypted file in cloud storage │ │
│ │ → used to decrypt the actual columnar data │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
A query that needs to read data from a file in cloud storage walks the hierarchy from the top down. Each unwrap is a small AES decrypt operation; the cost is dominated by the file read itself, not the key unwrap.
Critically, when Tri-Secret Secure is enabled, step 2's "root key" is the composition of Snowflake's root and the customer's KMS key — neither alone can unwrap the AMK. Removing the customer key from KMS at level 1 invalidates the entire chain.
Rekeying replaces an old key with a new one; existing data is re-wrapped under the new key without re-encrypting the underlying file contents. Enable account-level rekeying once and Snowflake handles the schedule.
USE ROLE ACCOUNTADMIN;
-- Enable annual rotation of the AMK and 30-day rotation of TMKs
ALTER ACCOUNT SET PERIODIC_DATA_REKEYING = TRUE;
-- Confirm
SHOW PARAMETERS LIKE 'PERIODIC_DATA_REKEYING' IN ACCOUNT;
-- Inspect the per-account encryption summary
SELECT * FROM TABLE(INFORMATION_SCHEMA.CURRENT_ACCOUNT_ENCRYPTION_KEY_TYPES());
Rekeying is invisible to queries — there is no downtime and no need to coordinate with running workloads. Old wrapped keys are retained for as long as Time Travel and Fail-safe windows might require reading historical files; they are destroyed only after the file itself is past Fail-safe.
Tri-Secret Secure introduces a customer key as a co-equal input to the wrapping function. It does not replace Snowflake's root — it composes with it. The customer key lives in the customer's KMS and is referenced by ARN or resource ID; Snowflake calls KMS each time it needs to unwrap.
kms:Encrypt, kms:Decrypt, and kms:GenerateDataKey.get, wrapKey, and unwrapKey permissions.cloudkms.cryptoKeyEncrypterDecrypter role.
# AWS — example KMS key policy fragment for Tri-Secret Secure
aws kms put-key-policy --key-id alias/snowflake-tss --policy '{
"Statement": [
{
"Sid": "Allow Snowflake account to use the key",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/snowflake-tss-role"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:GenerateDataKey",
"kms:DescribeKey"
],
"Resource": "*"
}
]
}'
-- Bind the customer key to the Snowflake account (run by Snowflake support
-- after the IAM/Key Vault grants are in place)
ALTER ACCOUNT SET TRI_SECRET_SECURE = TRUE;
Encryption events show up in SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY only as latency; explicit audit comes from the cloud KMS side (CloudTrail for AWS, Azure Activity Log, GCP Cloud Audit Logs). For TSS deployments, those logs are the authoritative record of who/what asked Snowflake's role to unwrap a key.
-- Confirm TSS is active
SELECT SYSTEM$GET_ACCOUNT_ENCRYPTION_INFO();
-- Force a manual rekey of an individual table (rare, but useful after a
-- suspected compromise of a long-lived TMK)
ALTER TABLE analytics.public.fct_orders SET DATA_RETENTION_TIME_IN_DAYS = 0;
ALTER TABLE analytics.public.fct_orders SET DATA_RETENTION_TIME_IN_DAYS = 7;
-- (any DDL that re-emits the file metadata triggers a TMK rotation on the
-- next periodic rekey cycle)
A common architectural pattern: keep production accounts on TSS with a customer key in a separate AWS account that has a much narrower set of administrators than the Snowflake account itself. This separation of duties means a rogue Snowflake admin cannot exfiltrate data without also compromising the KMS account.