Snowflake workload identity federation lets a workload sign in as a Snowflake service user by presenting the cloud identity it already has. On AWS that identity is an IAM role. Snowflake checks the role and opens the session. There is no password and no private key in the connection. Snowflake documents the method in workload identity federation, including the AWS role path and the service-user properties the account has to store.
Rutagon builds the cutover from key-pair authentication to that path for pipelines that already run as an AWS role: an ECS task, a Lambda function, a job on an instance profile. Key-pair auth was an improvement over a password. It still leaves an RSA private key in a secret, a public key on the Snowflake user, and a rotation task that has to update both without breaking the nightly load. Federation deletes that secret. Who may query which tables is a separate problem, already covered in Snowflake access review automation. This article is only the credential the loader uses to connect.
Why the private key is still a credential
Key-pair authentication, documented by Snowflake under key-pair auth, registers a public key on the user. The job signs a JWT with the private key. The private key has to live somewhere the job can read. In practice that is Secrets Manager, an encrypted file on the image, or a CI variable passed into a container. Rotation generates a new pair, sets the public key on the user, deploys the private key, and hopes no worker is still on the old one. Teams often keep RSA_PUBLIC_KEY_2 populated so both keys work during the overlap. That overlap is two valid long-lived secrets.
The key does not expire on its own. A copy taken during a debug session works until the public key is unset. CloudTrail will not show the Snowflake login, because the secret never asked AWS to vouch for the caller. The login shows up in Snowflake, and the credential shows up wherever the file was copied. Secrets sprawl is the search for those copies. Federation makes the search short: after the cutover the private key is not required, so a remaining copy is a finding to delete, not a backup path.
A programmatic access token has the same shape at a smaller size. It is a bearer secret stored for the job. Replacing a key pair with a token that lives for months moves the secret. It does not remove it. The federation path is the one that uses the role the compute platform already minted.
Snowflake workload identity federation for an AWS role
Snowflake's AWS path binds a service user to the role's ARN. The user type is SERVICE. The workload identity type is AWS. The connector sends an attestation from the role, and Snowflake matches it to that user. The published minimum driver versions matter. Snowflake's documentation lists a Python connector minimum for workload identity federation, and a higher minimum when you switch the AWS path to the JWT attestation from GetWebIdentityToken. We pin the connector at or above the version the doc requires for the path we enable. An older connector that only understands key-pair will fail the connection or, worse, get pointed back at the key by a fallback in the config.
The user we create looks like this. The account id in the ARN is a placeholder. The role name is the role the task already uses.
CREATE USER pipeline_loader
WORKLOAD_IDENTITY = (
TYPE = AWS
ARN = 'arn:aws:iam::123456789012:role/pipeline-loader'
)
TYPE = SERVICE
DEFAULT_ROLE = loader;
-- connector: authenticator=WORKLOAD_IDENTITY, workload_identity_provider=AWS
-- no private_key_file on the connection The connection on the workload sets the authenticator to WORKLOAD_IDENTITY and the provider to AWS. It does not set a private key path.
Snowflake also documents a JWT-based AWS method that uses GetWebIdentityToken, with an issuer URL stored on the user and a connector flag that turns the outbound token on. The role then needs sts:GetWebIdentityToken. We prefer that path when the connector version in production meets Snowflake's stated minimum for it, because the attestation is a token Snowflake can check without a callback pattern. We do not flip the flag before the issuer is set on the user. Snowflake's doc is explicit that the connection fails if the flag is on and the issuer is missing. Order is: set the issuer, deploy the connector flag, watch a successful login, then remove the key.
The role in the ARN has to be the role the task receives, not a human's admin role and not a wildcard. One service user per pipeline role keeps the Snowflake grants understandable. Snowflake's doc also describes mapping several workloads through impersonation to one identity. We use that only when the role design on AWS already has a shared impersonated role with a clear name. A single Snowflake user bound to an account-root pattern is not a configuration we ship.
OIDC elimination of secrets into AWS is the same idea aimed at AWS APIs. Here AWS is the issuer side and Snowflake is the relying party. Workload identity federation migration is the checklist we already use for CI tokens. The Snowflake user properties are the new step. The habit to break is the same: stop storing a long-lived secret for a machine that already has a role.
Cutover, then remove the key
The cutover is one pipeline at a time. We add the workload identity on the service user while the public key is still set, deploy the connector change to one environment, and read LOGIN_HISTORY for that user. A success row whose first authentication factor is workload identity is the proof. A success row that is still key-pair means the config did not take and the key is still in use. We do not unset the public key on the strength of a deploy.
After the proof login, we remove the private key from the secret store and unset the public key material on the user so a stolen copy cannot sign in. The next scheduled run has to succeed on federation alone. If it fails, the fix is the role ARN, the connector version, or the issuer, not a restore of the key into the image. A break-glass copy of the private key, if the data owner insists, sits in a vault with an expiry and an owner, and it is not mounted on the task. The expiry is short. The steady state is no mounted key.
Grants stay on the role the service user uses. Federation does not widen them. If the loader's role can read schemas it should not, that is a grant review, and it belongs in the access-review article linked above. Mixing the two projects is how the credential cutover stalls behind a warehouse argument. We change the authenticator first. The grants are the next change, with their own decider.
Network policy and authentication policy still apply. Snowflake lets you restrict which providers a service user may use. We set that so the loader's user cannot fall back to a password. A user that accepts both a key and workload identity will keep accepting the key until the key is unset. The policy makes the intended method explicit. The unset key makes the old method impossible.
Evidence for the credential control is small. The user definition shows WORKLOAD_IDENTITY and no public key. The secret inventory shows no secret tagged for that user's private key. LOGIN_HISTORY for the last 30 days shows workload identity for that user. Those three artifacts go to the evidence bucket the GRC platform already points at. We regenerate them. A ticket that says "migrated to keyless" is not one of the three.
Rutagon's deliverable is the service user bound to the AWS role ARN, the connector configuration without a key path, the proof row in login history, and the removal of the private key from the runtime. The warehouse grants stay a review. The connection stops being a secret.
Frequently Asked Questions
Does key-pair authentication already solve this?
It removes the password. The job still holds a private key, and Snowflake still holds the matching public key. That key works until it is unset, including from any copy taken while it was valid. Workload identity federation uses the AWS role attestation instead, and the private key can be deleted.
What has to be true on the AWS side?
The workload needs the IAM role whose ARN is stored on the Snowflake service user. The connector reads that role from the environment the same way any AWS SDK would. For the JWT path Snowflake documents, the role also needs permission to call sts:GetWebIdentityToken, and the user needs the issuer set before the connector flag is enabled.
Which connector version should we pin?
Pin at or above the minimum Snowflake publishes for workload identity federation on that driver, and at or above the higher minimum if you enable the AWS JWT attestation. An older driver that only supports key-pair will keep you on the private key. We read the current minimums from Snowflake's driver table at cutover time rather than copying a version from memory.
Can one Snowflake user cover many pipelines?
Yes, if those pipelines assume one role, or if they impersonate one role and the user is bound to that role's ARN. We do not bind a service user to every role in the account. A shared user still receives only the grants that user has. Federation does not add grants.
What do we keep for the auditor?
The service user showing workload identity and no public key, the secret inventory showing no private key for that user, and login history showing workload identity factor on the recent sessions. Those are regenerated from Snowflake and from the secret store. A migration ticket is not the artifact.
Ask for a credential diagnostic of Snowflake service users that still have a private key mounted on an AWS workload. Contact Rutagon at rutagon.com/contact, 907-841-8407, or contact@rutagon.com.