-
Notifications
You must be signed in to change notification settings - Fork 0
Machine‐to‐Machine Authentication Using Snowflake
This project demonstrates how to implement secure Machine-to-Machine (M2M) authentication in Snowflake using a dedicated service account, RSA key-pair authentication, and Role-Based Access Control (RBAC).
The lab follows enterprise security best practices by eliminating shared administrator credentials, enforcing the Principle of Least Privilege, validating authorization boundaries, and demonstrating key rotation.
- Snowflake
- Python
- Snowflake Connector for Python
- OpenSSL
- SQL
- RSA Key Pair Authentication
- RBAC
- Identity & Access Management (IAM)
Build a complete Machine-to-Machine (M2M) authentication lab using Snowflake.
Provision a Snowflake environment to build and test Machine-to-Machine (M2M) authentication.
- Registered for a Snowflake Trial account.
- Logged into the Snowsight interface.
- Verified access as the ACCOUNTADMIN role.
- Confirmed the default compute warehouse (COMPUTE_WH) was automatically provisioned.
Snowflake provisioned a secure cloud environment containing:
- Identity and Access Management (IAM)
- Compute resources
- Storage
- SQL execution engine
- Administrative interface
Authentication begins at the Snowflake account level. All users, service accounts, roles, and authentication methods are managed from this account.
Verify compute resources are available to execute SQL queries.
Verified that the default warehouse COMPUTE_WH exists and is available.
A warehouse is Snowflake's compute layer. Unlike traditional databases, compute is separated from storage, allowing independent scaling and automatic suspension when not in use.
Authentication grants access to Snowflake, but queries cannot execute without authorized compute resources.
Create an isolated database for the authentication lab.
CREATE DATABASE IAM_LAB;
USE DATABASE IAM_LAB;
CREATE SCHEMA DEMO;
USE SCHEMA DEMO;Created a dedicated database and schema that will store the sample application data used throughout this lab.
The lab now has its own isolated workspace separate from system databases.
Applications should access only the databases required for their function. Isolating application data simplifies permission management and supports the principle of least privilege.
Create a sample table that represents customer data an enterprise application will access after successfully authenticating to Snowflake.
Machine-to-Machine authentication is only meaningful if an application has a protected resource to access.
- The Python application will authenticate to Snowflake.
- Snowflake will verify its identity.
- If authorized, the application will read data from the CUSTOMERS table.
This simulates a common enterprise scenario where a backend service retrieves customer information without any human interaction.
Run the following SQL:
A table named CUSTOMERS is created inside:
IAM_LAB
└── DEMO
└── CUSTOMERSThe database now contains a protected resource that can later be secured using roles and permissions.
Authentication answers:
Who are you?
Authorization answers:
What are you allowed to access?
The CUSTOMERS table is the resource we'll protect with authorization.
Run:
INSERT INTO CUSTOMERS
VALUES
(1,'Nicole','nicole@test.com'),
(2,'Alice','alice@test.com'),
(3,'Bob','bob@test.com');Three sample customer records are inserted into the table.
The table now contains data that our future machine-to-machine application will retrieve after authenticating successfully.
Run:
SELECT * FROM CUSTOMERS;
The query confirms:
- The table was created successfully.
- The records were inserted successfully.
- The environment is ready for RBAC configuration.
At the moment, you're logged in as ACCOUNTADMIN, which has broad privileges.
In a production environment, applications should never use an administrative account. Instead, they'll use a dedicated service identity with only the permissions it needs. That's what we'll build next.
Create a dedicated application role that has permission to access only the resources required by the application.
This demonstrates the Principle of Least Privilege, one of the most important security concepts in enterprise IAM.
Right now, you're using: ACCOUNTADMIN
That role can do almost anything:
- Create users
- Delete databases
- Create warehouses
- Change security settings
- Read all data
No production application should ever run with these permissions.
Instead, applications should use a dedicated role with only the permissions required.
Today your environment looks like this:
ACCOUNTADMIN
│
▼
IAM_LAB
│
▼
CUSTOMERSAfter this section it will look like:
Application
│
▼
Service User
│
▼
LAB_APP_ROLE
│
▼
CUSTOMERS tableNotice that the application does not connect as ACCOUNTADMIN.
Run:
CREATE ROLE LAB_APP_ROLE;A new security role named LAB_APP_ROLE is created.
Roles are collections of permissions.
Instead of assigning permissions directly to users, Snowflake recommends assigning permissions to roles and then assigning roles to users.
This makes permission management much easier.
This is Role-Based Access Control (RBAC).
Instead of:
User
├── Permission
├── Permission
├── PermissionEnterprise systems use:
User
│
Role
│
PermissionsRun:
GRANT USAGE
ON WAREHOUSE COMPUTE_WH
TO ROLE LAB_APP_ROLE;The role is now allowed to use the compute resources.
Without this permission, the application could authenticate successfully but still wouldn't be able to execute queries.
Authentication does not automatically grant access to compute resources.
Authorization determines what authenticated identities can actually use.
Run:
GRANT USAGE
ON DATABASE IAM_LAB
TO ROLE LAB_APP_ROLE;The role can now locate the database.
Run:
GRANT USAGE
ON SCHEMA IAM_LAB.DEMO
TO ROLE LAB_APP_ROLE;The role can now access objects inside the schema.
Run:
GRANT SELECT
ON TABLE IAM_LAB.DEMO.CUSTOMERS
TO ROLE LAB_APP_ROLE;The role can read data from the CUSTOMERS table.
Notice what we didn't grant: ❌ INSERT ❌ UPDATE ❌ DELETE ❌ OWNERSHIP
This is the Principle of Least Privilege in action.
The future application only needs to read customer information.
Therefore, we grant only: SELECT
Nothing else.
Run: SHOW GRANTS TO ROLE LAB_APP_ROLE;
You have now created an enterprise RBAC model.
Create a dedicated service user that represents a non-human application. This service account will eventually authenticate using an RSA key pair instead of a password.
Your Python application should never connect using your personal administrator account.
Instead, enterprise applications use service accounts (also called service users or non-human identities).
For example:
This is the identity your Python application will use.
Run:
CREATE USER LAB_SERVICE_USER
PASSWORD = 'TempPassword123!'
DEFAULT_ROLE = LAB_APP_ROLE
DEFAULT_WAREHOUSE = COMPUTE_WH
DEFAULT_NAMESPACE = IAM_LAB.DEMO
MUST_CHANGE_PASSWORD = FALSE;A new user named LAB_SERVICE_USER is created.
You've created a dedicated identity that applications can use instead of sharing a personal administrator account.
At the moment, it still has no effective permissions because it hasn't been assigned the application role.
Identity and Permissions are separate.
Creating a user only establishes who the identity is. Permissions come later by assigning roles.
Run:
GRANT ROLE LAB_APP_ROLE
TO USER LAB_SERVICE_USER;The service user now inherits all permissions assigned to LAB_APP_ROLE.
Those permissions are limited to:
- Using COMPUTE_WH
- Accessing IAM_LAB
- Accessing the DEMO schema
- Reading the CUSTOMERS table
Nothing more.
Run:
SHOW GRANTS TO USER LAB_SERVICE_USER;You should see LAB_APP_ROLE in the results.
Your security model now looks like this:
LAB_SERVICE_USER
│
▼
LAB_APP_ROLE
│
├── USAGE on COMPUTE_WH
├── USAGE on IAM_LAB
├── USAGE on DEMO
└── SELECT on CUSTOMERSThis is a common RBAC design in enterprise Snowflake deployments.
We need the user object to exist before we can configure key-pair authentication. Right now the password is simply a placeholder so the user can be created.
In the next section, we'll configure RSA key-pair authentication, and the Python application will authenticate using a private key instead of relying on that password.
Create a dedicated service account for machine-to-machine authentication.
CREATE USER LAB_SERVICE_USER
PASSWORD='TempPassword123!'
DEFAULT_ROLE=LAB_APP_ROLE
DEFAULT_WAREHOUSE=COMPUTE_WH
DEFAULT_NAMESPACE=IAM_LAB.DEMO
MUST_CHANGE_PASSWORD=FALSE;
GRANT ROLE LAB_APP_ROLE
TO USER LAB_SERVICE_USER;A non-human service account was created and assigned the least-privilege application role.
Instead of allowing applications to authenticate with an administrator account, a dedicated service identity was created. The service user inherits only the permissions granted through LAB_APP_ROLE, following Snowflake's RBAC model.
Service accounts isolate application access from human users, improving security, auditability, and credential management. This approach supports the Principle of Least Privilege and is the recommended pattern for enterprise machine-to-machine authentication.
##Objective
Create a private/public key pair so the service user can authenticate without a password.
On your computer, open Terminal.
Run:
mkdir snowflake_m2m_lab
cd snowflake_m2m_labopenssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocryptopenssl rsa -in rsa_key.p8 -pubout -out rsa_key.pubcat rsa_key.pubCopy the key, we'll need it for Snowflake.
In Snowflake worksheet, run this using your copied public key:
ALTER USER LAB_SERVICE_USER
SET RSA_PUBLIC_KEY = 'PASTE_PUBLIC_KEY_HERE';Then verify:
DESC USER LAB_SERVICE_USER;
Configure Snowflake to trust the service user’s RSA public key.
Snowflake stored the public key on the service identity. The private key stays on your machine and will be used by the Python application to prove its identity.
This enables password-less machine-to-machine authentication using asymmetric cryptography.
In Terminal, inside your lab folder, run:
python3 -m venv venv
source venv/bin/activate
pip install snowflake-connector-python cryptographyThen create your app file:
touch app.pyOpen app.py and type this:
import snowflake.connector
conn = snowflake.connector.connect(
user="LAB_SERVICE_USER",
account="YOUR_ACCOUNT_IDENTIFIER",
private_key_file="rsa_key.p8",
warehouse="COMPUTE_WH",
database="IAM_LAB",
schema="DEMO",
role="LAB_APP_ROLE"
)
cur = conn.cursor()
cur.execute("SELECT * FROM CUSTOMERS")
for row in cur:
print(row)
cur.close()
conn.close()Replace:
YOUR_ACCOUNT_IDENTIFIER
with your Snowflake account identifier.
Then run:
python app.py
Use a Python application to authenticate to Snowflake as LAB_SERVICE_USER using RSA key-pair authentication.
The Python app connected to Snowflake and returned the three customer records from IAM_LAB.DEMO.CUSTOMERS.
The application authenticated without using a human admin account or password. Access was controlled through LAB_APP_ROLE, enforcing least privilege.
Remove password reliance and make the service account more secure.
Run in Snowflake:
ALTER USER LAB_SERVICE_USER
SET PASSWORD = NULL;DESC USER LAB_SERVICE_USER;Confirm RSA_PUBLIC_KEY is still populated.
In Terminal:
python app.py
Harden the service account by removing password-based authentication.
The service account can still authenticate using RSA key-pair authentication, but no longer relies on a password.
This reduces credential risk by preventing password-based login and enforcing machine authentication through asymmetric keys.
Confirm the service user can read data but cannot modify it.
Add this under your successful SELECT query:
print("\nTesting unauthorized INSERT...")
try:
cur.execute("INSERT INTO CUSTOMERS VALUES (4, 'Eve', 'eve@test.com')")
except Exception as e:
print("INSERT failed as expected:")
print(e)
python app.py
The service account successfully read from CUSTOMERS but failed when attempting to insert a new record.
This proves least privilege. The service role has SELECT access only, not INSERT, UPDATE, or DELETE.
Show how a service account key can be rotated without changing the application role or permissions.
In Terminal:
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key_2.p8 -nocrypt
openssl rsa -in rsa_key_2.p8 -pubout -out rsa_key_2.pub
cat rsa_key_2.pubCopy only the Base64 text between the BEGIN and END lines.
Run:
ls -l
Run:
cat rsa_key_2.pubCopy the key.
In your Snowflake worksheet:
ALTER USER LAB_SERVICE_USER
SET RSA_PUBLIC_KEY_2 = 'PASTE_SECOND_PUBLIC_KEY_HERE';Then verify:
DESC USER LAB_SERVICE_USER;
Verify that the application can authenticate using the new private key before retiring the old one.
Find:
private_key_file="rsa_key.p8",Replace it with:
private_key_file="rsa_key_2.p8",
python app.pyThe Python application authenticated successfully using RSA key-pair authentication and retrieved customer data from Snowflake. When the application attempted an unauthorized INSERT, Snowflake denied the request with an SQL access control error because the service role was granted only SELECT privileges.
This test confirmed that: ✅ Machine-to-machine authentication is functioning correctly. ✅ RBAC is correctly configured. ✅ Least privilege is enforced. ✅ Unauthorized write operations are blocked.
✅ Snowflake account provisioning ✅ Warehouse usage ✅ Database and schema creation ✅ RBAC design ✅ Least privilege ✅ Service account creation ✅ RSA key-pair authentication ✅ Passwordless machine-to-machine authentication ✅ Python integration ✅ Permission validation ✅ Key rotation
Python Application
│
▼
RSA Private Key (.p8)
│
▼
Snowflake Authentication
│
▼
LAB_SERVICE_USER
│
▼
LAB_APP_ROLE
│
┌─────────────────┴─────────────────┐
│ │
Warehouse: COMPUTE_WH Database: IAM_LAB
│
▼
Schema: DEMO
│
▼
CUSTOMERS Table
After successfully authenticating, the application intentionally attempted an unauthorized INSERT operation.
Snowflake denied the request because the service role had only SELECT permissions.
This validates:
- RBAC
- Principle of Least Privilege
- Authorization Enforcement
- Authentication and authorization are separate security controls.
- RBAC is easier to manage than assigning permissions directly to users.
- Service accounts should replace administrator accounts for application access.
- RSA key-pair authentication reduces the risks associated with password-based authentication.
- Snowflake supports seamless key rotation through dual public keys.