Back to changelog
New
2 minute read

Snowflake: Secrets

Atlas now manages Snowflake secrets, the schema-level objects that store credentials used by UDFs, procedures, and external access integrations.

A secret holds a credential: a password, an OAuth token, a generic string, or a key. An external access integration names the secrets its code may use. Atlas manages their full lifecycle with CREATE, ALTER, and DROP SECRET.

Declaring a Secret

The new secret block requires schema and type. The rest of its attributes depend on the type:

TypeAttributes
OAUTH2api_authentication, comment, and either oauth_scopes or oauth_refresh_token with oauth_refresh_token_expiry_time. The two are mutually exclusive.
PASSWORDusername, password, comment.
GENERIC_STRINGsecret_string, comment.
SYMMETRIC_KEYalgorithm, currently GENERIC, and comment.
CLOUD_PROVIDER_TOKENapi_authentication, comment. Snowflake rejects api_authentication in ALTER SECRET, so it is applied on create and cannot be changed afterwards.
WORKLOAD_IDENTITY_FEDERATIONcomment, nothing else beyond schema and type.

One secret of each type:

schema.hcl
secret "S_OAUTH" {  schema             = schema.PUBLIC  type               = OAUTH2  api_authentication = "ATLAS_SECRET_INT"  oauth_scopes       = ["scope_a", "scope_b"]  comment            = "client credentials flow"}
secret "S_PASSWORD" {  schema   = schema.PUBLIC  type     = PASSWORD  username = "your_user"  password = "dummy-password"  comment  = "password secret"}
secret "S_GENERIC" {  schema        = schema.PUBLIC  type          = GENERIC_STRING  secret_string = "dummy-value"  comment       = "generic string secret"}
secret "S_SYMMETRIC" {  schema    = schema.PUBLIC  type      = SYMMETRIC_KEY  algorithm = GENERIC}
secret "S_CLOUD" {  schema             = schema.PUBLIC  type               = CLOUD_PROVIDER_TOKEN  api_authentication = "SEC_IN30"}
secret "S_WIF" {  schema = schema.PUBLIC  type   = WORKLOAD_IDENTITY_FEDERATION}

Planning and Applying Changes

atlas schema apply
atlas schema apply --env local --skip-lint
Planning migration statements (6 in total):
  -- create secret "s_oauth":    -> CREATE SECRET "PUBLIC"."S_OAUTH" TYPE = OAUTH2 API_AUTHENTICATION = ATLAS_SECRET_INT OAUTH_SCOPES = ('scope_a', 'scope_b') COMMENT = 'client credentials flow';  -- create secret "s_password":  -- atlas:sensitive:    -> CREATE SECRET (sensitive).(sensitive) TYPE = PASSWORD USERNAME = (sensitive) PASSWORD = (sensitive) COMMENT = (sensitive);  -- create secret "s_generic":  -- atlas:sensitive:    -> CREATE SECRET (sensitive).(sensitive) TYPE = GENERIC_STRING SECRET_STRING = (sensitive) COMMENT = (sensitive);  -- create secret "s_symmetric":    -> CREATE SECRET "PUBLIC"."S_SYMMETRIC" TYPE = SYMMETRIC_KEY ALGORITHM = GENERIC;  -- create secret "s_cloud":    -> CREATE SECRET "PUBLIC"."S_CLOUD" TYPE = CLOUD_PROVIDER_TOKEN API_AUTHENTICATION = SEC_IN30;  -- create secret "s_wif":    -> CREATE SECRET "PUBLIC"."S_WIF" TYPE = WORKLOAD_IDENTITY_FEDERATION;

A statement that carries a password, a secret string, or a refresh token is printed with (sensitive) in their place. The real values are still used during execution.

Inspecting Applied Secrets

Atlas keeps credentials out of its output. Inspection writes <sensitive> in place of a password, a secret string, or a refresh token, and the api_authentication of a CLOUD_PROVIDER_TOKEN secret is not part of the inspected state:

atlas schema inspect
secret "S_CLOUD" {  schema = schema.PUBLIC  type   = CLOUD_PROVIDER_TOKEN}secret "S_GENERIC" {  schema        = schema.PUBLIC  type          = GENERIC_STRING  secret_string = "<sensitive>"  comment       = "generic string secret"}secret "S_OAUTH" {  schema             = schema.PUBLIC  type               = OAUTH2  api_authentication = "ATLAS_SECRET_INT"  oauth_scopes       = ["scope_a", "scope_b"]  comment            = "client credentials flow"}secret "S_PASSWORD" {  schema   = schema.PUBLIC  type     = PASSWORD  username = "your_user"  password = "<sensitive>"  comment  = "password secret"}secret "S_SYMMETRIC" {  schema    = schema.PUBLIC  type      = SYMMETRIC_KEY  algorithm = GENERIC}secret "S_WIF" {  schema = schema.PUBLIC  type   = WORKLOAD_IDENTITY_FEDERATION}

Versioned and Declarative Workflows

To keep credentials safe, the versioned workflow does not support a secret that carries a password, a secret string, or a refresh token. Apply those in the declarative workflow with atlas schema apply --skip-lint. Secrets that carry none of those, SYMMETRIC_KEY, CLOUD_PROVIDER_TOKEN, WORKLOAD_IDENTITY_FEDERATION, and OAUTH2 with oauth_scopes, are unaffected.

Getting Started

Secrets are opt-in. Set secrets = true in the mode "snowflake" block of your env to manage them. Add sensitive = ALLOW only when Atlas should plan the sensitive information a secret carries, such as a password or a secret string:

atlas.hcl
env "local" {  url = "snowflake://user:pass@account_identifier/database"  dev = "snowflake://user:pass@dev_account_identifier/database"  schema {    src = "file://schema.hcl"    mode "snowflake" {      secrets   = true      sensitive = ALLOW    }  }}

The secret block is documented in the Snowflake HCL reference. Snowflake support is part of Atlas Pro. Run atlas login to get started.

featuresnowflakesecretsecuritydeclarative