Securing External Stages
Hardening your data ingestion pathways: Storage Integrations, Private Link, and IAM best practices.
External stages (S3, Azure Blob, GCS) are the most common way data enters Snowflake. However, they are also a common attack vector if misconfigured. Hardcoding AWS Access Keys into stage definitions is a practice from 2018—in 2025, we have better tools.
1. Storage Integrations are Mandatory#
Never use credentials (AWS_KEY_ID, AWS_SECRET_KEY) in a CREATE STAGE command. Instead, use a Storage Integration.
This object establishes a trust relationship between Snowflake and your Cloud Provider (using IAM Roles in AWS or
Service Principals in Azure).
CREATE STORAGE INTEGRATION s3_int
TYPE = EXTERNAL_STAGE
STORAGE_PROVIDER = 'S3'
ENABLED = TRUE
STORAGE_AWS_ROLE_ARN = 'arn:aws:iam::123456789012:role/my-snowflake-role'
STORAGE_ALLOWED_LOCATIONS = ('s3://my-bucket/data/');sqlThis ensures that:
- Credentials are not exposed in DDL.
- You can rotate keys/roles on the cloud side without breaking Snowflake objects.
- You can strictly limit which buckets Snowflake can access.
2. Network Isolation (Private Link)#
If you are on an Enterprise edition or higher, use Private Link (AWS) or Private Endpoints (Azure). This ensures that traffic between your VPC/VNet and Snowflake never traverses the public internet. It significantly reduces the surface area for man-in-the-middle attacks.
3. Encryption#
Ensure your external buckets have Server-Side Encryption (SSE) enabled. Snowflake handles the decryption transparently using the permissions granted to the integration.
4. Directory Tables for Observability#
Turn on highly convenient Directory Tables on your stages.
CREATE STAGE my_stage
URL='s3://bucket/path'
STORAGE_INTEGRATION = s3_int
DIRECTORY = (ENABLE = TRUE);sqlThis allows you to query the stage contents (SELECT * FROM DIRECTORY(@my_stage)) to audit what files are present,
their sizes, and last modified timestamps effectively.
5. Least Privilege#
When configuring the Cloud IAM Role:
- Grant
GetObjectonly for loading. - Grant
PutObjectonly for unloading. - Restrict the
Resourcescope to specific prefixes, not the whole bucket.
Conclusion#
Securing your connection to the outside world is step one in a robust security posture. By forcing the use of Storage Integrations and implementing Private Connectivity, you close the biggest doors to potential data exfiltration.