Integraciones
26.1 25.2 25.1
26.1 25.2 25.1 Spanish English

Snowflake (API Nativa) - Configuración Infra

Antes de empezar

Esta página describe la infraestructura que hay que crear en Snowflake y en Microsoft Entra ID para que el plugin tot-plugin-snowflake funcione. No cubre la instalación del plugin ni su configuración funcional en Anjana: solo lo que debe existir antes.

Quién tiene que estar disponible. La configuración toca dos plataformas y exige dos permisos que rara vez coinciden en la misma persona.

Plataforma

Permiso

Para qué

Snowflake

ACCOUNTADMIN

Crear las security integrations, el rol y el usuario técnico

Entra ID

Global Administrator del tenant

Conceder el admin consent de los permisos de aplicación

Localice al administrador de Entra ID antes de empezar. Sin el admin consent la configuración queda a medias y no da error hasta el primer uso del plugin.

Qué se va a crear

  1. Tres app registrations en Entra ID y una Enterprise Application de galería.

  2. Una security integration OAuth en Snowflake y, si se aprovisiona por SCIM, una segunda integración SCIM.

  3. Un rol y un usuario técnico en Snowflake.

  4. Los valores resultantes, en el application.yaml del plugin.

Orden recomendado. Entra ID (app registrations) → Snowflake (integraciones, rol y usuario) → volver a Entra ID (Enterprise Application de SCIM, que necesita el token generado en Snowflake) → application.yaml → validación.

Los cuatro identificadores que se confunden. Casi todos los fallos de esta integración salen de intercambiar uno de estos valores, y los mensajes de error no lo delatan.

Identificador

De dónde sale

Dónde se usa

Application (client) ID de la app cliente OAuth

Overview de la app

oauth.client-id

Application (client) ID de la app recurso OAuth

Overview de la app

Application ID URI, EXTERNAL_OAUTH_AUDIENCE_LIST, oauth.scope

Object ID del service principal de la app cliente

az ad sp show

LOGIN_NAME del usuario de Snowflake

Object ID de la Enterprise Application de Snowflake

Overview de la Enterprise App

scim.service-principal-id

Autenticación y autorización de la identidad técnica del plugin

El plugin se autentica en Snowflake sin usuario ni contraseña: pide un token a Entra ID y lo presenta en cada llamada a la Snowflake SQL API. El montaje exige piezas coordinadas en las dos plataformas, y ninguna funciona sin su contraparte.

Este apartado cubre, en este orden:

  • Entra ID OAuth — las dos app registrations que emiten y validan el token.

  • Entra ID SCIM — la aplicación con la que el plugin lanza el aprovisionamiento y la Enterprise Application que lo ejecuta. Solo si va a aprovisionar por SCIM.

  • Snowflake — las security integrations que aceptan el token y las llamadas SCIM.

Nomenclatura usada en toda la página. Cuatro aplicaciones distintas, con nombre fijo para no confundirlas:

Nombre

Qué es

App cliente OAuth

App registration con la que el plugin pide el token para Snowflake

App recurso OAuth

App registration que representa a Snowflake como recurso protegido

App Graph

App registration con la que el plugin llama a Microsoft Graph (SCIM)

Enterprise App Snowflake

Aplicación de galería que ejecuta el aprovisionamiento SCIM


Entra ID OAuth

Qué es. El plugin se autentica contra la Snowflake SQL API con OAuth 2.0 y Entra ID como proveedor de identidad, mediante el flujo client_credentials: servidor a servidor, sin usuario interactivo y sin contraseña.

Qué hay que crear. Dos app registrations con papeles distintos, que no deben unificarse.

Aplicación

Papel

Qué aporta

App cliente OAuth

Quien pide el token

client_id, client_secret y el Object ID de su service principal

App recurso OAuth

Quien representa a Snowflake

El audience api://<resource-app-id> y el app-role session:role-any

Quién lo hace. Cualquiera con permiso para crear app registrations. El admin consent de la app cliente requiere Global Administrator.

App cliente OAuth

Identidad del plugin frente a la Snowflake SQL API.

Pasos

  1. Cree una app registration. Anote su Application (client) IDoauth.client-id.

  2. Genere un client secret y copie el Secret Value en ese momento: después no se vuelve a mostrar → oauth.client-secret.

  3. En API permissions, añada el app-role session:role-any de la app recurso OAuth como Application permission, y pida a un Global Administrator que conceda el admin consent.

  4. Elimine el permiso delegado User.Read que Azure añade por defecto: no interviene.

  5. Obtenga el Object ID de su service principal, que será el LOGIN_NAME del usuario técnico de Snowflake:

az ad sp show --id <application-client-id> --query id -o tsv

Datos que salen de aquí: oauth.client-id, oauth.client-secret y el Object ID del service principal.

Tres GUID distintos, no los intercambie: Application (client) ID ≠ Object ID del app registration ≠ Object ID del service principal. El que necesita Snowflake es el tercero.

Por qué

  • El app-role session:role-any es lo que permite al plugin indicar el rol de Snowflake en cada petición. Su mitad obligatoria en Snowflake es EXTERNAL_OAUTH_ANY_ROLE_MODE = 'ENABLE'; sin ella el token se valida pero el rol se rechaza.

  • No hacen falta permisos delegados: en client_credentials el token lleva el claim roles y nunca scp.

App recurso OAuth (Oauth Resource)

Representa a Snowflake como recurso protegido. No tiene secreto y nadie se autentica con ella: solo declara el audience que valida la security integration y el app-role que usará la app cliente.

Pasos

  1. Cree una app registration. Su Application (client) ID es el <resource-app-id>; anótelo.

  2. En Expose an API, fije el Application ID URI a api://<resource-app-id>.

  3. En App roles, cree un rol con valor session:role-any y Allowed member types = Applications.

El error más frecuente de toda la página. El valor por defecto de Allowed member types es Users/Groups. Con ese tipo el rol no se puede asignar a la app cliente, el token se emite sin ese valor en el claim roles y Snowflake rechaza el rol con un error que apunta a la integración, no al origen real.

El mismo valor en tres sitios. El <resource-app-id> aparece en el Application ID URI de esta app, en EXTERNAL_OAUTH_AUDIENCE_LIST de la security integration y en oauth.scope del plugin (allí, con el sufijo /.default). Si los tres no coinciden, el token no valida.

Entra ID SCIM

Aplica solo si va a aprovisionar por SCIM (scim.enabled: true). Con false, sáltese este apartado entero: el plugin gestiona los roles por SQL directo.

Qué hace SCIM aquí. Entra ID sincroniza usuarios y grupos hacia Snowflake, y cada grupo de Entra ID se materializa como un rol de Snowflake. El plugin no llama al endpoint SCIM de Snowflake: llama a Microsoft Graph para lanzar bajo demanda el job de provisioning de la Enterprise Application y comprobar su resultado.

Los grupos no los crea este plugin. Los crea el plugin de Entra ID que gestiona usuarios y grupos para el gobierno, o se reutilizan grupos existentes indicando el physicalName en el DSA. Aquí solo se monta el transporte. El detalle está en Snowflake (API nativa) .

Qué hay que crear

Elemento

Papel

App Graph

Identidad del plugin frente a Microsoft Graph, para lanzar y consultar el job

Enterprise App Snowflake

Aplicación de galería que ejecuta el aprovisionamiento contra Snowflake

Dependencia de orden. La Enterprise Application necesita el token SCIM que se genera en Snowflake (apartado Integración SCIM en Snowflake). Haga primero la parte de Snowflake y vuelva aquí después.


App Graph (cliente SCIM)

Identidad del plugin frente a Microsoft Graph, no frente a Snowflake. Debe ser una app registration distinta de la app cliente OAuth.

Pasos

  1. Cree una app registration → scim.client-id, y genere un client secret → scim.client-secret.

  2. En API permissions, añada de Microsoft Graph, como Application permissions (no delegados): Synchronization.ReadWrite.All y Group.Read.All.

  3. Un Global Administrator concede el admin consent de ambos.

Para qué sirve cada permiso

Permiso

Habilita

Si falta

Synchronization.ReadWrite.All

Leer y lanzar bajo demanda el job de provisioning

El plugin no puede forzar ni verificar sincronizaciones

Group.Read.All

Localizar en Entra ID el grupo que se va a aprovisionar

403 Insufficient privileges: no resuelve el identificador del grupo

El token se pide con el scope https://graph.microsoft.com/.default (scim.scope).

No la unifique con la app cliente OAuth. Synchronization.ReadWrite.All es un permiso de ámbito de tenant: un único secreto comprometido abriría a la vez el acceso a Snowflake y el motor de aprovisionamiento del directorio.

Datos que salen de aquí: scim.tenant-id, scim.client-id, scim.client-secret.

Enterprise Application de Snowflake (SCIM Snowflake)

Aplicación de galería que sincroniza usuarios y grupos de Entra ID hacia Snowflake.

Requisito previo: el token SCIM de Snowflake, que se genera en Integración SCIM en Snowflake.

Pasos

  1. Añádala desde la galería de aplicaciones de Entra ID, buscando el conector SCIM de Snowflake.

  2. En Provisioning, indique Tenant URL https://<account>.snowflakecomputing.com/scim/v2/ y, como Secret Token, el token de la integración SCIM de Snowflake.

  3. Pruebe la conexión y guarde.

  4. Defina el alcance y los scoping filters antes de activar (bloque siguiente).

  5. Ponga el Provisioning Status en On.

No toque el Provisioning Mode. Pasarlo de Automatic a Manual borra la configuración de aprovisionamiento completa: Tenant URL, token y mappings. Para detener el aprovisionamiento temporalmente use el Provisioning Status, que es un ajuste distinto.

Datos que salen de aquí

Propiedad

De dónde

scim.snowflake-app-name

Display name exacto de la Enterprise Application

scim.service-principal-id

Object ID de la Enterprise Application, en su pantalla de Overview

scim.job-id

Microsoft Graph (llamadas de abajo)

scim.user-rule-id / scim.group-rule-id

Esquema del job

scim.service-principal-id no es el de la app Graph. Usar el equivocado devuelve 401 UnknownError con el mensaje vacío, que parece un problema de token o de permisos.

El job-id y los identificadores de regla no están en el portal. Se obtienen con Microsoft Graph, usando un token de la app Graph:

GET https://graph.microsoft.com/v1.0/servicePrincipals/{service-principal-id}/synchronization/jobs
GET https://graph.microsoft.com/v1.0/servicePrincipals/{service-principal-id}/synchronization/jobs/{job-id}/schema

La primera devuelve el job-id. En el esquema de la segunda están user-rule-id y group-rule-id; en el conector de Snowflake pueden coincidir si hay una única regla que cubre ambos objetos.

Alcance del aprovisionamiento

Un grupo que no esté dentro del alcance nunca llega a Snowflake: Entra ID lo descarta en la fase de scoping con el motivo NotEffectivelyEntitled.

Qué alcance puede usar depende del plan del tenant, porque asignar grupos a una Enterprise Application es una funcionalidad de Entra ID P1. Con un plan inferior el portal solo permite asignar usuarios individuales, y no hay rodeo por API ni por PowerShell: la comprobación la hace el servicio, no la interfaz. Y asignar usuarios sueltos no resuelve nada, porque lo que se convierte en rol de Snowflake es el grupo.

Plan

Alcance

Qué hay que hacer

Con P1

Sync only assigned users and groups

Asignar explícitamente cada grupo. El plugin genera un grupo por DSA y versión, así que conviene usar el physicalName del DSA para reutilizar grupos ya asignados y no asignar uno nuevo en cada versión.

Sin P1

Sync all users and groups

Obligatorio acotar con scoping filters en las reglas de usuarios y de grupos, definidos antes de activar el aprovisionamiento.

Sin filtros, "Sync all users and groups" exporta el directorio completo a Snowflake: cada usuario del tenant como usuario y cada grupo de seguridad como rol. Los scoping filters son la frontera de seguridad real de la integración, no el desplegable del alcance.

Dos consecuencias a tener en cuenta al definirlos:

  • Las reglas de usuarios y de grupos son independientes, y no existe ningún filtro del tipo "miembros del grupo X". Filtrar el grupo sin incluir a sus miembros en la regla de usuarios crea el rol vacío en Snowflake.

  • Reducir el alcance más adelante desaprovisiona. Estrechar un filtro o volver a "Sync only assigned users and groups" deshabilita usuarios y elimina roles en Snowflake.


Snowflake: security integration OAuth

Crea la integración que acepta los tokens de Entra ID. Requiere ACCOUNTADMIN.

Tenga a mano antes de ejecutar: {tenant-id} (Directory ID del tenant) y {resource-app-id} (Application (client) ID de la app recurso OAuth).

SQL
CREATE SECURITY INTEGRATION anjana_oauth_azure
    TYPE = external_oauth
    ENABLED = true
    EXTERNAL_OAUTH_TYPE = azure
    EXTERNAL_OAUTH_ISSUER = 'https://sts.windows.net/{tenant-id}/'
    EXTERNAL_OAUTH_AUDIENCE_LIST = ('api://{resource-app-id}')
    EXTERNAL_OAUTH_JWS_KEYS_URL = 'https://login.microsoftonline.com/{tenant-id}/discovery/v2.0/keys'
    EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM = 'sub'
    EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE = 'login_name'
    EXTERNAL_OAUTH_ANY_ROLE_MODE = 'ENABLE'
    EXTERNAL_OAUTH_BLOCKED_ROLES_LIST = ('ACCOUNTADMIN', 'ORGADMIN', 'SECURITYADMIN');

Los cuatro parámetros que hay que entender

Parámetro

Qué hay que saber

EXTERNAL_OAUTH_AUDIENCE_LIST

{resource-app-id} es el Application (client) ID de la app recurso: no el de la app cliente ni el de la Enterprise Application de SCIM. Un audience distinto del que emite Entra ID produce HTTP 401, sin mencionar el audience en ningún momento.

EXTERNAL_OAUTH_ANY_ROLE_MODE

Contrapartida del app-role session:role-any. Sin él, el rol que el plugin envía en el cuerpo de la petición se rechaza.

EXTERNAL_OAUTH_BLOCKED_ROLES_LIST

Reproduce de forma explícita el valor por defecto de Snowflake. Se declara porque, con el modo de roles habilitado, es el cliente quien elige el rol, y conviene dejar escrito que los roles administrativos quedan fuera del alcance de cualquier token externo.

EXTERNAL_OAUTH_ISSUER

https://sts.windows.net/{tenant-id}/ corresponde a tokens de versión 1.0, que es lo que emite Entra ID mientras accessTokenAcceptedVersion del manifest de la app recurso no se fije a 2. Si se cambia a 2, el issuer pasa a https://login.microsoftonline.com/{tenant-id}/v2.0.


Integración SCIM en Snowflake

Solo con scim.enabled: true. Crea tres cosas: el rol con el que Entra ID actúa dentro de Snowflake, la integración que recibe las llamadas SCIM y el token con el que se autentican.

SQL
USE ROLE ACCOUNTADMIN;

CREATE ROLE aad_provisioner;
GRANT CREATE USER ON ACCOUNT TO ROLE aad_provisioner;
GRANT CREATE ROLE ON ACCOUNT TO ROLE aad_provisioner;
GRANT ROLE aad_provisioner TO ROLE accountadmin;

CREATE SECURITY INTEGRATION anjana_scim_azure
    TYPE = scim
    SCIM_CLIENT = 'AZURE'
    RUN_AS_ROLE = 'AAD_PROVISIONER';

SELECT SYSTEM$GENERATE_SCIM_ACCESS_TOKEN('ANJANA_SCIM_AZURE');

Después de ejecutar

  • La última sentencia devuelve el token SCIM: es el Secret Token de la Enterprise Application. Cópielo ahora.

  • El Tenant URL que pedirá la Enterprise Application es https://<account>.snowflakecomputing.com/scim/v2/.

El token SCIM caduca a los seis meses. Se regenera con la misma función y hay que actualizarlo después en Entra ID. Anote la fecha de vencimiento junto a las credenciales.

Dos puntos que se olvidan

  • CREATE USER y CREATE ROLE sobre la cuenta son imprescindibles. Sin ellos la integración se crea sin ningún error y el aprovisionamiento falla más tarde, cuando ya se está buscando el problema en otro sitio.

  • Los usuarios y roles que crea el aprovisionamiento son propiedad del rol indicado en RUN_AS_ROLE, no del rol del plugin. Para que el plugin pueda conceder, revocar y eliminar esos roles necesita su propiedad. Dos salidas: transferirla de forma explícita, o usar el propio rol del plugin como RUN_AS_ROLE —concediéndole además CREATE USER ON ACCOUNT—, con lo que los roles aprovisionados nacen siendo suyos.

Identidad técnica del plugin

Las aplicaciones de Entra ID resuelven quién es el plugin. Los privilegios con los que se ejecuta cada sentencia son otra cosa: los del rol de Snowflake asociado a la identidad técnica.

Este apartado crea los dos objetos que la componen —un rol y un usuario—, explica qué se concede a cada uno y cómo quedan unidos entre sí y con la app cliente OAuth. Todo requiere ACCOUNTADMIN.

Rol: anjana_plugin_role

Concentra todos los privilegios del plugin.

Criterio de alcance. Los privilegios se acotan a las bases de datos que se vayan a gobernar, en lugar de conceder MANAGE GRANTS a nivel de cuenta. WITH GRANT OPTION sobre esas bases es precisamente lo que permite al plugin reconceder los privilegios a los roles de consumo sin ese permiso global.

SQL
USE ROLE ACCOUNTADMIN;

CREATE ROLE anjana_plugin_role;

-- Computo para las sentencias enviadas por la SQL API
GRANT USAGE ON WAREHOUSE <warehouse> TO ROLE anjana_plugin_role;

-- Creacion de los roles que representan los grupos de cada DSA.
-- Snowflake no permite acotar este privilegio a una base de datos.
GRANT CREATE ROLE ON ACCOUNT TO ROLE anjana_plugin_role;

-- Lectura de metadatos y muestreo sobre las bases a gobernar.
-- WITH GRANT OPTION es lo que permite al plugin reconceder estos privilegios
-- a los roles de consumo sin necesidad de MANAGE GRANTS a nivel de cuenta.
GRANT USAGE ON DATABASE <db> TO ROLE anjana_plugin_role WITH GRANT OPTION;
GRANT USAGE ON ALL SCHEMAS IN DATABASE <db> TO ROLE anjana_plugin_role WITH GRANT OPTION;
GRANT USAGE ON FUTURE SCHEMAS IN DATABASE <db> TO ROLE anjana_plugin_role WITH GRANT OPTION;
GRANT SELECT ON ALL TABLES IN DATABASE <db> TO ROLE anjana_plugin_role WITH GRANT OPTION;
GRANT SELECT ON FUTURE TABLES IN DATABASE <db> TO ROLE anjana_plugin_role WITH GRANT OPTION;
GRANT SELECT ON ALL VIEWS IN DATABASE <db> TO ROLE anjana_plugin_role WITH GRANT OPTION;
GRANT SELECT ON FUTURE VIEWS IN DATABASE <db> TO ROLE anjana_plugin_role WITH GRANT OPTION;
GRANT REFERENCES ON ALL TABLES IN DATABASE <db> TO ROLE anjana_plugin_role;
GRANT REFERENCES ON FUTURE TABLES IN DATABASE <db> TO ROLE anjana_plugin_role;
GRANT REFERENCES ON ALL VIEWS IN DATABASE <db> TO ROLE anjana_plugin_role;
GRANT REFERENCES ON FUTURE VIEWS IN DATABASE <db> TO ROLE anjana_plugin_role;


Repita el bloque de la base de datos por cada base que se vaya a gobernar. CREATE ROLE ON ACCOUNT es la única concesión que no se puede acotar a una base de datos: Snowflake no lo permite.

Nota de redacción: los comentarios del bloque SQL van sin tildes (Computo, Creacion). Si el fichero se guarda en UTF-8, conviene acentuarlos para que casen con el resto de la página.

Usuario: anjana_plugin_svc

Identidad con la que Snowflake resuelve el token. Sin contraseña: la única vía de autenticación es el token de Entra ID.

SQL
USE ROLE ACCOUNTADMIN;

CREATE USER anjana_plugin_svc
    LOGIN_NAME = '<object-id-del-service-principal-del-cliente-oauth>'
    DEFAULT_ROLE = anjana_plugin_role
    DEFAULT_WAREHOUSE = <warehouse>
    DEFAULT_SECONDARY_ROLES = ('ALL')
    COMMENT = 'Identidad tecnica del plugin tot-plugin-snowflake';

GRANT ROLE anjana_plugin_role TO USER anjana_plugin_svc;

El dato crítico es el LOGIN_NAME: el Object ID del service principal de la app cliente OAuth. Es el punto de unión entre las dos plataformas —Entra ID emite un token cuyo claim sub es ese GUID, y la security integration lo busca en el login_name de los usuarios de Snowflake—. Si se omite, LOGIN_NAME toma por defecto el nombre del usuario y la autenticación falla con HTTP 401 y 390100 Incorrect username or password, un mensaje que apunta a credenciales incorrectas cuando lo que falla es el mapeo.

  • DEFAULT_ROLE es solo una preferencia de sesión y no concede nada: el GRANT ROLE final es imprescindible.

  • No se preocupe por las mayúsculas del GUID. Snowflake normaliza LOGIN_NAME a mayúsculas y la comparación en el login no distingue, así que el valor copiado de Entra ID casa igual.

Cómo quedan conectados

Recorrido completo de una llamada. Sirve para situar en qué paso falla cuando algo no funciona.

  1. El plugin pide un token a Entra ID con grant_type=client_credentials y scope=api://<resource-app-id>/.default, usando el client-id y el client-secret de la aplicación cliente de OAuth.

  2. Entra ID emite un token cuyo aud es api://<resource-app-id>, cuyo iss es el tenant y cuyo sub es el Object ID del service principal de esa aplicación cliente. El app-role session:role-any viaja en el claim roles.

  3. El plugin llama a la Snowflake SQL API con ese token en la cabecera Authorization y con la cabecera X-Snowflake-Authorization-Token-Type: OAUTH. Sin esta última, Snowflake interpreta el bearer como un token de sesión propio y devuelve errores que no corresponden a la causa real.

  4. Snowflake localiza la security integration por issuer y audience, valida la firma contra el JWKS, extrae el claim sub y lo busca en el login_name de sus usuarios: obtiene ANJANA_PLUGIN_SVC.

  5. Acepta el rol indicado en el cuerpo de la petición porque EXTERNAL_OAUTH_ANY_ROLE_MODE está habilitado, comprueba que está concedido al usuario y ejecuta la sentencia con los privilegios de ANJANA_PLUGIN_ROLE.

Dónde falla cada paso. Tabla propuesta como añadido: hoy esta información existe, pero está repartida por ocho puntos distintos de la página, y quien está depurando no la encuentra.

Paso

Síntoma

Causa habitual

1

AADSTS7000215

Secret Value incorrecto o caducado. Compruebe que no envió el Secret ID

2

El token sale sin session:role-any en el claim roles

App role con Allowed member types = Users/Groups, o admin consent sin conceder

3

Errores que no cuadran con la causa

Falta la cabecera X-Snowflake-Authorization-Token-Type: OAUTH

4

HTTP 401, sin mención al audience

EXTERNAL_OAUTH_AUDIENCE_LIST distinto del que emite Entra ID

4

HTTP 401 / 390100 Incorrect username or password

LOGIN_NAME no es el Object ID del service principal

5

HTTP 400 / 390186 Role ... is not granted to this user

Identificador en minúsculas, o EXTERNAL_OAUTH_ANY_ROLE_MODE sin habilitar

SCIM

403 Insufficient privileges

Falta Group.Read.All en la app Graph

SCIM

401 UnknownError con mensaje vacío

scim.service-principal-id es el de la app Graph y no el de la Enterprise Application

SCIM

El rol no llega nunca a Snowflake

Grupo fuera de alcance: descartado en scoping con NotEffectivelyEntitled

Los identificadores del application.yaml van en MAYÚSCULAS

Regla. Cree los objetos de Snowflake sin comillas dobles y escriba en mayúsculas technology.role, technology.warehouse, technology.database y technology.schema del application.yaml.

Por qué. La Snowflake SQL API toma los identificadores del cuerpo de la petición de forma literal, al contrario que el parser SQL, que los normaliza. Los objetos creados sin comillas dobles viven en mayúsculas, así que un valor en minúsculas produce HTTP 400 con 390186 Role ... is not granted to this user, un mensaje que induce a buscar un grant que en realidad existe.

Colocación. Esta regla se aplica al rellenar el application.yaml, no al crear la identidad técnica. Gana leída justo antes de la tabla de propiedades del apartado siguiente, o repetida allí como aviso.

Datos de configuración del plugin

Todos los valores van en el application.yaml del plugin, bajo totplugin.connection[].technology, .oauth y .scim. El detalle de cada propiedad está en YAML de ejemplo - Plugin Snowflake (API nativa) .

Use esta tabla como lista de comprobación final: si tiene los diecinueve valores, la infraestructura está completa. Las filas de scim solo aplican con scim.enabled: true.

Sobre la tabla actual se proponen dos cambios: una columna De dónde sale, con el apartado de esta página que produce el dato, para que el lector pueda volver atrás sin buscar; y separar visualmente el bloque scim, que hoy se mezcla con el resto.

Propiedad

Valor

De dónde sale

technology.host

<account>.snowflakecomputing.com

Cuenta de Snowflake

technology.warehouse

Warehouse con USAGE concedido, en MAYÚSCULAS

Rol anjana_plugin_role

technology.role

ANJANA_PLUGIN_ROLE, en MAYÚSCULAS

Rol anjana_plugin_role

oauth.token-url

https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token

Directory (tenant) ID

oauth.client-id

Application (client) ID

App cliente OAuth

oauth.client-secret

Secret Value

App cliente OAuth

oauth.grant-type

client_credentials

Fijo

oauth.scope

api://<resource-app-id>/.default

App recurso OAuth. Mismo valor que el audience de la security integration, con el sufijo /.default

scim.enabled

true para aprovisionar por SCIM; false para gestionar los roles por SQL directo

Decisión de diseño. Con false, ignore el resto de filas

scim.tenant-id

Directory (tenant) ID

Tenant de Entra ID

scim.client-id

Application (client) ID

App Graph

scim.client-secret

Secret Value

App Graph

scim.scope

https://graph.microsoft.com/.default

Fijo

scim.graph-base-url

https://graph.microsoft.com/v1.0

Fijo

scim.snowflake-app-name

Display name exacto

Enterprise App Snowflake

scim.service-principal-id

Object ID de la Enterprise Application, no el de la app Graph

Enterprise App Snowflake, Overview

scim.job-id

Job de provisioning

Microsoft Graph, /synchronization/jobs

scim.user-rule-id

Regla de sincronización de usuarios

Esquema del job

scim.group-rule-id

Regla de sincronización de grupos

Esquema del job

Qué guarda el gestor de secretos

Tres secretos en toda la integración, y solo tres. Empezar por este inventario evita la duda de si falta alguno.

Secreto

Se genera en

Se usa en

Client secret de la app cliente OAuth

Entra ID

oauth.client-secret

Client secret de la app Graph

Entra ID

scim.client-secret

Token SCIM

Snowflake (SYSTEM$GENERATE_SCIM_ACCESS_TOKEN)

Secret Token de la Enterprise Application. No es una propiedad del plugin

Los dos primeros van al gestor de secretos: una entrada por aplicación, con cuatro campos.

Campo

Uso

application id

Application (client) ID. Va en oauth.client-id o scim.client-id

tenant id

Directory (tenant) ID. Va dentro de oauth.token-url y en scim.tenant-id

secret value

Valor del client secret. Va en oauth.client-secret o scim.client-secret

secret id

No se usa en la configuración. Solo identifica el secreto en Azure, para saber cuál rotar

Dos trampas de este apartado. Enviar el secret id en lugar del secret value produce AADSTS7000215, el mismo error que da un secreto caducado. Y el Secret Value solo se muestra en Azure en el momento de crearlo: si se pierde no se recupera, hay que generar uno nuevo.

Guarde también, aunque no sean secretos. Sin ellos, la credencial no sirve.

  • El Application (client) ID de la app recurso OAuth: es la base del oauth.scope y el audience de la security integration. Pertenece a una aplicación distinta de las dos que tienen secreto, y por eso es el dato que se pierde con más facilidad.

  • La fecha de caducidad de cada secreto. Los client secrets de Entra ID caducan según lo fijado al crearlos; el token SCIM, a los seis meses. El vencimiento de cualquiera detiene la integración sin que haya habido ningún cambio de configuración.

No hace falta custodiar el Object ID del service principal (el LOGIN_NAME del usuario de Snowflake): se deriva del application id con az ad sp show.

Si el despliegue lo permite, inyecte los secretos por variable de entorno en lugar de escribirlos en claro en el application.yaml, y limite la lectura del fichero al usuario del servicio.

Validación de la conexión

Dos comprobaciones, un minuto, antes de que el plugin use la integración por primera vez. Detectan los dos fallos más habituales —el LOGIN_NAME y las mayúsculas—, cuyos mensajes de error apuntan a causas que no son la real.

Paso previo. Obtenga un token contra el token-url con grant_type=client_credentials y scope=api://<resource-app-id>/.default.

  1. ¿El token se valida y resuelve al usuario y al rol esperados?

SQL
SELECT SYSTEM$VERIFY_EXTERNAL_OAUTH_TOKEN('<token>');

Devuelve qué security integration valida el token, a qué usuario se mapea y qué roles quedan autorizados.

  • Correcto: aparece ANJANA_PLUGIN_SVC con el rol autorizado.

  • Falla: si no aparece el usuario de servicio, el LOGIN_NAME no es el Object ID del service principal de la app cliente OAuth.

  1. ¿La Snowflake SQL API responde con esa identidad?

POST https://<account>.snowflakecomputing.com/api/v2/statements
Authorization: Bearer <token>
X-Snowflake-Authorization-Token-Type: OAUTH
Content-Type: application/json

{
  "statement": "select current_user(), current_role()",
  "warehouse": "<WAREHOUSE>",
  "role": "ANJANA_PLUGIN_ROLE"
}
  • Correcto: devuelve ANJANA_PLUGIN_SVC y ANJANA_PLUGIN_ROLE.

  • Falla con 390186: repita la llamada con el rol en mayúsculas. Si entonces funciona, la causa era esa y no una concesión que falte.

Falta una tercera comprobación. Con scim.enabled: true, la validación actual cubre solo la vía OAuth. Añadir un paso que lance el job por Graph y verifique que el grupo aparece como rol en Snowflake cerraría la otra mitad de la infraestructura, que es justamente la que más puntos de fallo silencioso tiene.