Cannot Generate SSPI context es uno de los errores que más me ha costado diagnosticar y corregir en todos los años que llevo trabajando con SQL Server y con el resto de tecnologías de Microsoft. Debo de ser algo cortito, pero al final lo he pillado (y yo sólo, jeje).
Por eso, a través de este artículo, me gustaría conseguir aclarar las principales dudas relacionadas con el error Cannot Generate SSPI context, un error en SQL Server por desgracia algo habitual y de resolución bastante desconocida, mágica cuanto menos. Confío conseguir este objetivo, y a quienes se les produzca el error Cannot Generate SSPI context, puedan llegar a está página fácilmente buscando en Internet, y con la misma solucionar este problema. Espero francamente que os sirva, y os ayude a conocer un poquito más a SQL Server.
Cannot Generate SSPI context: Descripción del Error
¿Por qué se produce el error de conexión Cannot generate SSPI context de SQL Server? Mi realidad en los últimos años, estaba muy clara: Ni puta idea, pa que mentir. Lo cierto, es que es un error real, un error que todo consultor o administrador de SQL Server ha sufrido alguna vez, y un error, que para mí siempre ha sido una espinita, pues no lo conseguía resolver (de una forma elegante, con ñapas sí...), y me lo he encontrado ya en varios clientes distintos. Pero no tenía ni idea, de porqué en algunas instalaciones se materializaba este error, mientras que en otras no ocurre ¿Quizás sea la maqueta de los equipos sobre los que se instala SQL Server? ¿Quizás sea tema de configuración de Directorio Activo? ¿Quizás sea por permisos o derechos en políticas referentes a la cuenta de equipo de las máquinas SQL Server o de la cuenta de servicio de SQL Server? ¿Quizás sea un tema de parcheado? ¿Quizás sea un poco de todo?
Pues me ha vuelto a ocurrir. Fruto de la desesperación, he tenido que volver a googlear, en esta ocasión parece que con más éxito que en otros intentos del pasado (y empleando mucho menos tiempo ¿será que Google indexa mejor?). Lo primero, es tener claro que el error Cannot Generate SSPI context, parece estar relacionado (a priori) con:
- Autenticación Integrada, utilizando Kerberos. Esta claro. Con atenticación SQL Server, va como la seda.
- Conexiones a una instancia SQL Server utilizando el protocolo TCP/IP. Esta claro. Con el protocolo Named Pipes, el error Cannot Generate SSPI context, ni lo hueles.
- Una instancia de SQL Server que se inicia con una cuenta de Dominio. Esto con el tiempo, se empieza a sospechar, pero vamos, muy claro no está.
Por otro lado, desde el punto de vista de la teoría, deberíamos saber que Security Support Provider Interface (SSPI) es una API que facilita la Delegación y Autenticación Mutua sobre una capa de transporte de datos (ej: TCP/IP). Además, el Driver de SQL Server, al utilizar Autenticación Integrada, utiliza la delegación, pudiendo utilizar diferentes mecanismos:
- NTLM sobre Named Pipes sin SSPI.
- NTLM sobre TCP/IP con SSPI.
- Kerberos sobre TCP/IP con SSPI.
Sin profundizar demasiado, llegados a este punto, con lo que nos debemos quedar, es con que el error Cannot Generate SSPI context se produce al utilizar Kerberos sobre TCP/IP con SSPI como mecanismo de delegación y/o autenticación.
Con esto, ya se puede empezar a intuir una posible solución fácil (Workaround o ñapa): utilizar Named Pipes como protocolo (en vez de TCP/IP), para así esquivar la utilización de Kerberos.
Sin embargo, surge una nueva duda: Al utilizar el protoco TCP/IP para conectar con SQL Server con Autenticación Integrada ¿Cuándo se utiliza NTLM o cuando se utiliza Kerberos? Lo primero, tendremos que saber qué es un Service Principal Name (SPN), bueno, que nos suene.
Un Service Principal Name (SPN) es un identificador único en un bosque o dominio de Directorio Activo, una forma de identificar o direccionar un Servicio o Recurso de Red en el Directorio Activo (vaya con el Directorio Activo de los cojones... y yo que pensaba que sólo valía para hacer Logon ;-). También debemos de saber, que todos los Service Principal Name (SPN) se registran en Directorio Activo (bueno, yo he llegado a esta conclusión, espero no estar confundido).
Un Service Principal Name (SPN) está formado por:
- Una clase de servicio (ServiceClass). Ej: MSSQLSvc, HTTP, HOST, etc.
- Un Host. Ej: vsql01.guillesql.local.
- Un Puerto: Ej: 1433.
Así, un ejemplo de un Service Principal Name (SPN) para una instancia de SQL Server escuchando en el puerto 1433 en un servidor cuyo FQDN es vsql01.guillesql.local, sería el siguiente: MSSQLSvc/vsql01.guillesql.local:1433
Además, un Service Principal Name (SPN) se asocia a un equipo o a un usuario (mejor dicho, a una cuenta de equipo o a una cuenta de usuario de Directorio Activo). A esto volveremos más tarde, de momento que nos suene.
Es importante tener en cuenta, la disponibilidad de la utilidad setspn.exe a través del Kit de Recursos de Windows 2000 o a través de las Windows Support Tools de Windows Server 2003. La utilidad setspn.exe permite la manipulación manual de los Service Principal Name (SPN). Aunque habitualmente no necesitaremos utilizar setspn.exe (siendo la aplicación que corresponda, como sería el caso de SQL Server, quien realice este trabajo automáticamente), en ocasiones es necesario utilizar setspn.exe para dejar correctamente configurados los Service Principal Name (SPN). A continuación mostramos algunos ejemplos de uso de setspn.exe:
- Es posible ver los Service Principal Name (SPN) asociados a un contenedor (sea una cuenta de equipo o una cuenta de usuario), ejecutando el comando setspn.exe -L, y especificando el contenedor deseado. Por ejemplo, para ver los Service Principal Name (SPN) asociados a la cuenta de equipo VSQL01, ejecutaríamos setspn -L VSQL01. Del mismo modo, para ver los Service Principal Name (SPN) asociados a la cuenta de usuario SQLSvc, ejecutaríamos setspn -L SQLSvc.
- Es posible agregar un Service Principal Name (SPN) asociado a un contenedor (sea una cuenta de equipo o una cuenta de usuario), ejecutando el comando setspn.exe -A. Por ejemplo, para agregar el Service Principal Name (SPN) de MSSQLSvc/SQL01, y asociarlo con la cuenta de servicio GUILLESQL\SQLSvc, podría ejecutarse el comando setspn -A MSSQLSvc/VSQL01 GUILLESQL\SQLSvc.
- Es posible eliminar un Service Principal Name (SPN) asociado a un contenedor (sea una cuenta de equipo o una cuenta de usuario), ejecutando el comando setspn.exe -R. Por ejemplo, para eliminar el Service Principal Name (SPN) de MSSQLSvc/SQL01 asociardo a la cuenta de servicio GUILLESQL\SQLSvc, podría ejecutarse el comando setspn -D MSSQLSvc/VSQL01 GUILLESQL\SQLSvc.
- Es posible crear los Service Principal Name (SPN) por defecto utilizando setspn.exe -R. Por ejemplo, para crear los Service Principal Name (SPN) por defecto de un servidor VSQL01, podría ejecutarse el comando setspn -R VSQL01. Esto creará al menos, los Service Principal Name (SPN) de la Clase de Servicio HOST (ej: HOST/VSQL01, HOST/VSQL01.guillesql.local, etc.).
Siguiendo con lo nuestro. Cuando un cliente intenta conectarse a una instancia SQL Server con Autenticación Integrada utilizando TCP/IP, el Driver de SQL Server intenta resolver el nombre completo (FQDN) del servidor SQL, y lo utiliza para formar el Service Principal Name (SPN) con el que intentar realizar la Autenticación. Si el intento de Autenticación con el Service Principal Name (SPN) generado en el cliente es fallido, SSPI intenta buscar en Directorio Activo un Service Principal Name (SPN) válido. Si NO se encuentra ningún Service Principal Name (SPN), la Autenticación con Kerberos no puede realizarse, por lo que se intentará realizar la Autencación NTLM.
Hasta aquí bien (bueno, cuesta pillarlo, pero más o menos). Sin embargo, la eterna duda, sigue sin resolverse. ¿Cuándo se produce el error Cannot Generate SSPI context? Pues cuando se utiliza un Service Principal Name (SPN) válido, pero que no está asignado a un contenedor apropiado.
Vaya, que bien. Ahora tenemos otra duda nueva. ¿A que se refiere lo de Contenedor apropiado? Hablando en la jerga de Directorio Activo (ese servicio que sólo sirve para hacer Logon ;-), el contenedor puede ser una cuenta de equipo o una cuenta de usuario (la que inicia el servicio de SQL Server), depende del caso, y de aquí, lo de Contenedor apropiado:
- Si la cuenta de usuario utilizada para iniciar el servicio de SQL Server es LocalSystem, el contenedor apropiado es la Cuenta de Equipo.
- En cualquier otro caso, el contenedor apropiado es la Cuenta de Usuario utilizada para iniciar el Servicio de SQL Server.
Bueno, ya hemos encontrado varios posibles motivos del error Cannot Generate SSPI context (joder, yo pensaba que era imposible):
- Problemas o errores de resolución de nombres DNS, siendo recomendable disponer de una correcta resolución directa y resolución inversa. Este no ha sido mi caso, no sé si quizás, lo habrá sido en alguna de las ocasiones anteriores en que me ha ocurrido.
- Existencia de Directorio Activo de Service Principal Name (SPN) inválidos o asociados a Contenedores erróneos. Este ha sido mi caso, al menos, el caso base de este artículo. Seguro.
Los problemas de resolución de nombres DNS, quedan fuera del alcance de este artículo, entre otras cosas por su fácil diagnóstico y resolución (con ping y ping -a, nos será suficiente).
Sin embargo, nos surge una nueva duda, para examinar la alternativa relacionada con los problemas asociados al Service Principal Name (SPN): ¿Cómo se crea un Service Principal Name (SPN)? En el caso de SQL Server, cuando una instancia de SQL Server se inicia, ella misma intenta registrar en Directorio Activo su propio Service Principal Name (SPN), llamando a la función API DsWriteAccountSpn, de tal modo, que si no lo consigue registrará un error en el Registro de Sucesos del Sistema (Source: MSSQLServer EventID: 19011 Description: SuperSocket info: (SpnRegister) : Error 8344).
Entonces, ¿Cuándo se crear el Service Principal Name (SPN) con éxito y cuando se produce error en su creación?
- Si el servicio de SQL Server se ejecuta con Local System, el Service Principal Name (SPN) se registrará correctamente en Directorio Activo.
- En el resto de casos, la creación del Service Principal Name (SPN) fallará excepto que el servicio de SQL Server de inicie con una cuenta que sea administradora del dominio.
Volviendo a recapitular, parece que los posibles motivos del error Cannot Generate SSPI context son:
- Problemas o errores de resolución de nombres DNS, siendo recomendable disponer de una correcta resolución directa y resolución inversa.
- Existencia de Directorio Activo de Service Principal Name (SPN) inválidos o asociados a Contenedores erróneos. Cabe destacar, el caso particular de las instancias de SQL Server que se inician con una cuenta de Directorio Activo que no sea Administrador de Dominio, las cuales, pueden no conseguir registrar correctamente su Service Principal Name (SPN) en Directorio Activo. Este es mi caso.
Con todo esto, antes de continuar, quiero aportar una descripción del último escenario en el que me he encontrado el error Cannot Generate SSPI context. Se trata de un Dominio de Directorio Activo, formado por un Controlador de Dominio ejecutando Windows Server 2003 R2 SP2 Enterprise x86 (corriendo sobre Virtual Server 2005 R2 SP1). La resolución de nombres DNS es correcta, existiendo tanto las zonas de resolución directa como las zonas de resolución inversa necesarias, todas integradas en Directorio Activo. El servidor de base de datos, es un Windows Server 2003 R2 SP2 Enterprise x86 miembro del anterior dominio, también virtualizado con Virtual Server 2005 R2 SP1, sobre el cual está instalado SQL Server 2005 Developer SP3. El servicio de SQL Server se está corriendo utilizando una cuenta de Directorio Activo, la cual es Administrador Local de la máquina, pero no tiene privilegios elevados en Directorio Activo (no el Administrador del Dominio).
Vaya. Con que el servicio SQL Server está corriendo utilizando una cuenta de Directorio Activo que no el Administrador del Dominio. Perfecto. Parece que tenemos el problema identificado, cogido by the webs.
Cannot Generate SSPI context: La solución rápida (no recomendable)
Ahora que tenemos una pequeña base para la identificación y diagnóstico del error Cannot Generate SSPI context ¿Cómo hacemos para solucionar el error Cannot generate SSPI context de SQL Server?
Hasta hace muy poco (que coño, hasta ayer), lo que yo hacía, es lo que creo que hacían muchos: Jugar con los protocolos de SQL Server. El problema lo tenía claramente acotado (o eso creía, hasta ayer…): cuando se produce, es relativo a intentos de conexión a una instancia de SQL Server utilizando el protocolo TCP/IP con Inicios de Sesión de Windows (correspondientes a cuentas de Directorio Activo). Con esto, lo que quiero decir, es que con el protocolo Named Pipes no ocurre, y de aquí tenemos varias alternativas (Workaround o ñapas, es español):
- Habilitar Named Pipes como protocolo de Servidor y deshabilitar TCP/IP. Con esto, los equipos cliente sólo podrán conectarse a través de Named Pipes (o eso, o nada). Un poco radical, pero funciona.
- Cambiar el orden de los protocolos de Cliente, de tal modo, que prevalezca el protocolo Named Pipes frente al protocolo TCP/IP. Esto hay que hacerlo en cada equipo cliente, por lo cual, es un poco laborioso (también depende del número de clientes, claro).
- Utilizar Inicios de Sesión de SQL Server. Vamos a ver, esto lo pongo porque cierto es que evitamos el problema, pero ni es elegante, ni es mi recomendación. Ahora, es posible, claro que sí.
Creo recordar, que en alguna ocasión me he encontrado este problema con algún equipo cliente en particular, de tal modo que el resto de equipos clientes funcionaban correctamente. En este escenario particular, si mal no recuerdo, conseguía solucionar el error subiendo la versión de MDAC o reinstalando MDAC (al menos, en algunos casos). En cualquier caso, el error al que me refiero en este artículo, es cuando se produce el mensaje Cannot generate SSPI context desde cualquier máquina cliente, incluso desde el propio servidor de base de datos al intentar conectar por TCP/IP (ojo, por Shared Memory o por Names Pipes no se produce el error Cannot generate SSPI context).
Cannot Generate SSPI context: La solución buena (setspn.exe)
Evidentemente, utilizar otro protocolo (en este caso, Named Pipes), o cambiar el modo de autenticación, son alternativas que, aunque nos ayudan a esquivar el problema, la realidad es que el problema sigue estando ahí.
La forma de corregir el problema, es configurar correctamente los Service Principal Name (SPN) correspondientes a SQL Server, ese gran desconocido, para lo cual utilizaremos la utilidad setspn.exe. No es la primera vez que me enfrento a este tipo de configuraciones, ya que también es muy típico en aplicaciones Web para conseguir hacer funcionar la Autenticación Integrada y Delegación de Kerberos en IIS, una incidencia de Soporte Microsoft, sobre todo en entornos de IIS sobre Cluster NLB.
A continuación, describo paso a paso las tareas que he realizado en esta máquina de laboratorio, para resolver el error Cannot Generate SSPI context:
- En Directorio Activo, utilizando la herramienta administrativa Active Directory User and Computers (ADUC), habilitar la opción Trust computer for delegation, sobre la cuenta de equipo correspondiente al servidor SQL Server.
No tengo claro la necesidad de este paso, pero como lo hice, lo pongo. Tras realizarlo, probé la autenticación (con un fichero UDL) y el error Cannot Generate SSPI context seguía produciéndose.
- Descargar la herramienta setspn.exe desde la Web de Microsoft, descargable desde aquí. Recordar, que la utilidad setspn.exe, está disponible a través del Kit de Recursos de Windows 2000 y también a través de las Windows Support Tools de Windows Server 2003.
- Ejecutar los siguientes comandos en una ventana de símbolo de sistema, desde la propia máquina SQL Server (instalar previamente setspn.exe), para registrar los correspondientes Service Principal Name (SPN) en Directorio Activo:
setspn -A MSSQLSvc/VSQL01 GUILLESQL\SQLSvc
setspn -A MSSQLSvc/VSQL01.guillesql.local GUILLESQL\SQLSvc
setspn -A MSSQLSvc/VSQL01:1433 GUILLESQL\SQLSvc
setspn -A MSSQLSvc/VSQL01.guillesql.local:1433 GUILLESQL\SQLSvc
Tras la ejecución de cada una de las anteriores líneas, volví a probar la autenticación (con el fichero UDL) y el error Cannot Generate SSPI context seguía produciéndose. Aquí perdí un poco la esperanza, todo sea dicho.
- Reiniciar el Servicio de SQL Server (primero Detener, y luego Iniciar).
Volví a probar la autenticación (con el fichero UDL) y el error Cannot Generate SSPI context ha dejado de producirse. Hice la prueba desde varias máquinas, y todo OK, ya no hay más error Cannot Generate SSPI context.
Me surge la duda de que alguno de los pasos anteriores no fuese necesario, y si hubiese reiniciado el servicio antes, habría funcionado (vamos, que es vinculante el reinicio del servicio, pero quizás no todos los pasos previos). Principalmente, tengo duda sobre la necesidad de activar la opción Trust computer for Delegation sobre la cuenta de equipo en Directorio Activo, y además, no tengo claro si todos los Service Principal Name (SPN) registrados son estrictamente necesarios. Lo que más me preocupa, es quitar la opción Trust computer for Delegation, así que continúo.
- En Directorio Activo, utilizando la herramienta administrativa Active Directory User and Computers (ADUC), Deshabilitar la opción Trust computer for delegation, sobre la cuenta de equipo correspondiente al servidor SQL Server.
- Reiniciar el Servicio de SQL Server (primero Detener, y luego Iniciar). Tras esto, sigue funcionando correctamente (el error Cannot Generate SSPI context no ha vuelto a aparecer), por lo que parece, que la opción Trust computer for delegation no era necesaria (o una vez reiniciado el servicio SQL Server, ya da igual quitarla que no, la verdad que no lo sé).
Como conclusión de todo esto, si bien tengo alguna duda sobre si todos los pasos realizados son estrictamente necesarios, la realiadad es que una vez ejecutados, todo funciona correctamente, y el error Cannot Generate SSPI context desaparece, que era el principal objetivo. Y además, sin necesidad de hacer al usuario que inicia el servicio de SQL Server, miembro del grupo de Administradores del Dominio (algo con lo que me he pegado en muchas ocasiones, en diferentes clientes). Es más, no es necesario ni recomendable que sea Administrador Local de la máquina, como ya comenté en mi Manual de Instalación de SQL Server.
Utilizar Kerberos con SQL Server de verdad [Actualizado 13 de Julio de 2009]
He sacado algún otro hueco para continuar con mis pruebas de Kerberos y los Service Principal Name (SPN) de SQL Server. Por un lado, me ha surgido una duda, que entiendo que a más de uno le surgirá ¿Cómo comprobar que método de autenticación a utilizado una conexión de SQL Server?
En SQL Server 2000, no sabría responderlo (tampoco me he preocupado en buscarlo, seamos sinceros ;-). Por el contrario, en SQL Server 2005 y SQL Server 2008 es posible consultar sys.dm_exec_connections, una dynamic management view que nos mostrará las conexiones existentes, los protocolos de red que utilizan, el método de autenticación (campo auth_scheme), etc.
En mi caso, al ejecutar una consulta sobre sys.dm_exec_connections, me encontré que todas mis conexiones estaban utilizando NTLM como protocolo de autenticación. Mierda. No puede ser. Después de currarme todo el artículo con las pantallas y todo, y de Kerberos, na de na. Esto tenemos que arreglarlo, ya que aunque efectivamente hemos corregido el error Cannot Generate SSPI context, ha sido pagando el precio de NTLM, y lo suyo es poder utilizar Kerberos.
Finalmente, revisé los Service Principal Name (SPN) de la cuentas de equipo y de la cuenta del usuario que inicia el servicio SQL Server. Realizado esto, la configuración de los Service Principal Name (SPN) de mi entorno de laboratorio queda como se muestra en la siguiente pantalla capturada:
Por último, ahora al consultar el contenido de sys.dm_exec_connections, ya existen conexiones TCP autenticadas por Kerberos, como se puede mostrar en la siguiente imagen:
Para conseguir llegar a este punto, me fue de utilidad el siguiente Artículo de Soporte de Microsoft:
How to make sure that you are using Kerberos authentication when you create a remote connection to an instance of SQL Server 2005 http://support.microsoft.com/kb/909801/en-us
Despedida y Cierre
Pues todo lo que hemos visto, está muy bien, pero también tengo que adminitir que he estado en instalaciones de SQL Server, en las que se inicia el servicio de SQL Server con una cuenta de domino que no es Administrador de Dominio, y no se ha producido el error Cannot Generate SSPI context. Así que nada, si no nos ocurre este error y todo funciona, genial, y si se produce el error Cannot Generate SSPI context, pos ya sabemos como curarlo.
Para acabar, quería incluir como referencia un Artículo de Microsoft donde ampliar la información de este error. Para la resolución del error Cannot Generate SSPI context, me he basado en cosillas sueltas que he encontrado por Internet (Foros y Blogs, nada oficial) y en este artículo de Soporte de Microsoft, la KB 811889:
How to troubleshoot the "Cannot generate SSPI context" error message
Este artículo de soporte, es bastante espesito (si lo queréis leer, empezar cuando tengáis un buen hueco). De hecho, me lo he empezado a leer varias veces, y no lo he acabado ninguna. Pereza la mía. Pero bueno, que lo tengáis. El resto de fragmentos que he encontrado entre Foros y Blogs, no me parecen lo suficientemente claros o interesantes para incluirlos aquí (de hecho, ni me los apunté en su momento).
Y ahora, si que me despido. Espero que os guste, y sobretodo, que os sirva como a mí me ha servido. Enjoy your SQL Server ;-)
Actualización 21/02/2010: Recientemente me he encontrado un caso de configuración de Kerberos, en particular, configurar la Autenticación y Delegación de Kerberos con MOSS y Analysis Services, que puede resultar una lectura de interés en relación con el tema del presente artículo.