snowflake-user
The snowflake-user
rotator enables you to rotate RSA keypairs for a Snowflake database user in your Environment. It automatically manages the key rotation process, ensuring that two keys remain valid at any point in time, which allows for seamless credential rotation without disrupting service availability. (See rotation concepts).
How Key Rotation Works
When the snowflake-user
rotator is executed:
- It connects to Snowflake using the provided login credentials.
- It generates a new 2048-bit RSA keypair.
- If a previous keypair exists in the state, it sets the user’s
RSA_PUBLIC_KEY_2
to the previous public key. - It sets the user’s
RSA_PUBLIC_KEY
to the new public key. - The new private key is stored securely in the environment state.
This two-key approach ensures that applications have time to update to the new key before the old one is completely removed, providing a smooth transition during rotation.
Configuring Snowflake for Key Rotation
Step 1: Create the Target User
Create the Snowflake user whose keys will be rotated:
CREATE USER ESC_ROTATION_DEMO_USER
DEFAULT_ROLE = 'PUBLIC'
TYPE = SERVICE;
Step 2: Create a Rotator Role
Create a role that has permission to alter the target user:
CREATE ROLE ESC_ROTATOR;
GRANT OWNERSHIP ON USER ESC_ROTATION_DEMO_USER TO ROLE ESC_ROTATOR;
Step 3: Create a Rotation Service User
Create a service user that will perform the rotation:
CREATE USER ESC_ROTATION_SERVICE_USER
DEFAULT_ROLE = 'ESC_ROTATOR'
TYPE = SERVICE;
GRANT ROLE ESC_ROTATOR TO USER ESC_ROTATION_SERVICE_USER;
The rotation service user should have minimal permissions, only enough to alter the target user.
Step 4: Set Up OIDC for the Rotation Service User
Follow the OIDC setup steps in the snowflake-login documentation to allow Pulumi ESC to authenticate as the rotation service user.
CREATE SECURITY INTEGRATION pulumi_oidc
TYPE = EXTERNAL_OAUTH
ENABLED = TRUE
EXTERNAL_OAUTH_TYPE = CUSTOM
EXTERNAL_OAUTH_ISSUER = 'https://api.pulumi.com/oidc'
EXTERNAL_OAUTH_JWS_KEYS_URL = 'https://api.pulumi.com/oidc/.well-known/jwks'
EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM = 'snowflake_user'
EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE = 'login_name'
EXTERNAL_OAUTH_AUDIENCE_LIST = ('snowflake:<pulumi-org>')
EXTERNAL_OAUTH_ALLOWED_ROLES_LIST = ('ESC_ROTATOR')
EXTERNAL_OAUTH_ANY_ROLE_MODE = 'ENABLE';
Replace <pulumi-org>
with your Pulumi organization name.
Step 5: Managing credentials
Set up an environment with Snowflake login credentials for the rotation service user:
# my-org/logins/snowflake
values:
snowflake:
account: myorganization-account
login:
fn::open::snowflake-login:
oidc:
account: myorganization-account
user: ESC_ROTATION_SERVICE_USER
role: ESC_ROTATOR
Step 6: Rotated environment
Then, create a separate environment for your rotated credentials:
# my-org/rotators/snowflake-keyrotator
values:
user:
fn::rotate::snowflake-user:
inputs:
login: ${environments.logins.snowflake.snowflake.login}
targetUser: ESC_ROTATION_DEMO_USER
If you have existing keys you want ESC to keep track of, you can optionally provide an initial state
:
# my-org/rotators/snowflake-keyrotator
values:
user:
fn::rotate::snowflake-user:
inputs:
login: ${environments.logins.snowflake.snowflake.login}
targetUser: ESC_ROTATION_DEMO_USER
state:
account: myorganization-account
privateKey:
fn::secret: |
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQE...
-----END PRIVATE KEY-----
createdAt: "2025-01-01T12:00:00Z"
Validation
Perform a manual rotation on the environment to provision a new private key. If successful, should see output similar to the following when opening the environment:
{
"user": {
"account": "myorganization-account",
"user": "ESC_ROTATION_DEMO_USER",
"privateKey": "[secret]",
"rotatedAt": "2025-04-24T10:00:00Z"
}
}
Inputs
Property | Type | Description |
---|---|---|
login | SnowflakeLogin | Required. Credentials used to connect to Snowflake and perform the rotation. |
targetUser | string | Required. The Snowflake user whose keypair will be rotated. |
SnowflakeLogin
The login
object must contain:
Property | Type | Description |
---|---|---|
account | string | Required. Snowflake account identifier. |
user | string | Required. Managing user to connect as. This user must have permission to alter the target user. |
And exactly one of:
Property | Type | Description |
---|---|---|
privateKey | string | Private key in PEM format. |
token | string | OAuth token (output of snowflake-login provider). |
State (Optional)
Property | Type | Description |
---|---|---|
account | string | Snowflake account identifier. |
privateKey | string | The private key in PEM format. |
createdAt | string | When the keypair was generated, in RFC3339 format. |
Outputs
Property | Type | Description |
---|---|---|
account | string | Snowflake account identifier. |
user | string | The rotated user. |
privateKey | string | Private key in PEM format (stored as a secret). |
rotatedAt | string | When the keypair was generated, in RFC3339 format. |
Thank you for your feedback!
If you have a question about how to use Pulumi, reach out in Community Slack.
Open an issue on GitHub to report a problem or suggest an improvement.