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 |
|
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
-
Tres app registrations en Entra ID y una Enterprise Application de galería.
-
Una security integration OAuth en Snowflake y, si se aprovisiona por SCIM, una segunda integración SCIM.
-
Un rol y un usuario técnico en Snowflake.
-
Los valores resultantes, en el
application.yamldel 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 |
|
|
Application (client) ID de la app recurso OAuth |
Overview de la app |
Application ID URI, |
|
Object ID del service principal de la app cliente |
|
|
|
Object ID de la Enterprise Application de Snowflake |
Overview de la Enterprise App |
|
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 |
|
|
App recurso OAuth |
Quien representa a Snowflake |
El audience |
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
-
Cree una app registration. Anote su Application (client) ID →
oauth.client-id. -
Genere un client secret y copie el Secret Value en ese momento: después no se vuelve a mostrar →
oauth.client-secret. -
En API permissions, añada el app-role
session:role-anyde la app recurso OAuth como Application permission, y pida a un Global Administrator que conceda el admin consent. -
Elimine el permiso delegado
User.Readque Azure añade por defecto: no interviene. -
Obtenga el Object ID de su service principal, que será el
LOGIN_NAMEdel 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-anyes lo que permite al plugin indicar el rol de Snowflake en cada petición. Su mitad obligatoria en Snowflake esEXTERNAL_OAUTH_ANY_ROLE_MODE = 'ENABLE'; sin ella el token se valida pero el rol se rechaza. -
No hacen falta permisos delegados: en
client_credentialsel token lleva el claimrolesy nuncascp.
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
-
Cree una app registration. Su Application (client) ID es el
<resource-app-id>; anótelo. -
En Expose an API, fije el Application ID URI a
api://<resource-app-id>. -
En App roles, cree un rol con valor
session:role-anyy 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
-
Cree una app registration →
scim.client-id, y genere un client secret →scim.client-secret. -
En API permissions, añada de Microsoft Graph, como Application permissions (no delegados):
Synchronization.ReadWrite.AllyGroup.Read.All. -
Un Global Administrator concede el admin consent de ambos.
Para qué sirve cada permiso
|
Permiso |
Habilita |
Si falta |
|---|---|---|
|
|
Leer y lanzar bajo demanda el job de provisioning |
El plugin no puede forzar ni verificar sincronizaciones |
|
|
Localizar en Entra ID el grupo que se va a aprovisionar |
|
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
-
Añádala desde la galería de aplicaciones de Entra ID, buscando el conector SCIM de Snowflake.
-
En Provisioning, indique Tenant URL
https://<account>.snowflakecomputing.com/scim/v2/y, como Secret Token, el token de la integración SCIM de Snowflake. -
Pruebe la conexión y guarde.
-
Defina el alcance y los scoping filters antes de activar (bloque siguiente).
-
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 |
|---|---|
|
|
Display name exacto de la Enterprise Application |
|
|
Object ID de la Enterprise Application, en su pantalla de Overview |
|
|
Microsoft Graph (llamadas de abajo) |
|
|
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 |
|
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).
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 |
|---|---|
|
|
|
|
|
Contrapartida del app-role |
|
|
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. |
|
|
|
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.
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 USERyCREATE ROLEsobre 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 comoRUN_AS_ROLE—concediéndole ademásCREATE 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.
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.
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_ROLEes solo una preferencia de sesión y no concede nada: elGRANT ROLEfinal es imprescindible. -
No se preocupe por las mayúsculas del GUID. Snowflake normaliza
LOGIN_NAMEa 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.
-
El plugin pide un token a Entra ID con
grant_type=client_credentialsyscope=api://<resource-app-id>/.default, usando elclient-idy elclient-secretde la aplicación cliente de OAuth. -
Entra ID emite un token cuyo
audesapi://<resource-app-id>, cuyoisses el tenant y cuyosubes el Object ID del service principal de esa aplicación cliente. El app-rolesession:role-anyviaja en el claimroles. -
El plugin llama a la Snowflake SQL API con ese token en la cabecera
Authorizationy con la cabeceraX-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. -
Snowflake localiza la security integration por issuer y audience, valida la firma contra el JWKS, extrae el claim
suby lo busca en ellogin_namede sus usuarios: obtieneANJANA_PLUGIN_SVC. -
Acepta el rol indicado en el cuerpo de la petición porque
EXTERNAL_OAUTH_ANY_ROLE_MODEestá habilitado, comprueba que está concedido al usuario y ejecuta la sentencia con los privilegios deANJANA_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 |
|
Secret Value incorrecto o caducado. Compruebe que no envió el Secret ID |
|
2 |
El token sale sin |
App role con Allowed member types = Users/Groups, o admin consent sin conceder |
|
3 |
Errores que no cuadran con la causa |
Falta la cabecera |
|
4 |
|
|
|
4 |
|
|
|
5 |
|
Identificador en minúsculas, o |
|
SCIM |
|
Falta |
|
SCIM |
|
|
|
SCIM |
El rol no llega nunca a Snowflake |
Grupo fuera de alcance: descartado en scoping con |
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 |
|---|---|---|
|
|
|
Cuenta de Snowflake |
|
|
Warehouse con |
Rol |
|
|
|
Rol |
|
|
|
Directory (tenant) ID |
|
|
Application (client) ID |
App cliente OAuth |
|
|
Secret Value |
App cliente OAuth |
|
|
|
Fijo |
|
|
|
App recurso OAuth. Mismo valor que el audience de la security integration, con el sufijo |
|
|
|
Decisión de diseño. Con |
|
|
Directory (tenant) ID |
Tenant de Entra ID |
|
|
Application (client) ID |
App Graph |
|
|
Secret Value |
App Graph |
|
|
|
Fijo |
|
|
|
Fijo |
|
|
Display name exacto |
Enterprise App Snowflake |
|
|
Object ID de la Enterprise Application, no el de la app Graph |
Enterprise App Snowflake, Overview |
|
|
Job de provisioning |
Microsoft Graph, |
|
|
Regla de sincronización de usuarios |
Esquema del job |
|
|
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 |
|
|
Client secret de la app Graph |
Entra ID |
|
|
Token SCIM |
Snowflake ( |
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 (client) ID. Va en |
|
|
Directory (tenant) ID. Va dentro de |
|
|
Valor del client secret. Va en |
|
|
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.scopey 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.
-
¿El token se valida y resuelve al usuario y al rol esperados?
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_SVCcon el rol autorizado. -
Falla: si no aparece el usuario de servicio, el
LOGIN_NAMEno es el Object ID del service principal de la app cliente OAuth.
-
¿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_SVCyANJANA_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.