Como vocês devem ter visto nos links que passei no post “Configurando Autenticação Kerberos” (obviamente para aqueles que leram), a configuração de autenticação trusted (Windows authentication) no SQL Server requer a utilização de autenticação KERBEROS.
A partir deste ponto o negócio é super sensível e qualquer erro de configuração pode gerar problemas de autenticação no SQL Server fazendo com que você receba a mensagem de erro “Cannot generate SSPI context” ao tentar se conectar a um servidor SQL Server ou ainda o erro abaixo ao tentar utilizar um linked server entre dois servidores SQL Server.
Msg 18456, Level 14, State 1, Line 1
Login failed for user ‘NT AUTHORITY/ANONYMOUS LOGON’.
Ontem passei por estes dois problemas e para que vocês tenham uma idéia dos detallhes que devemos ficar atendo ao utilizar autenticação Kerberos, vou relatar aqui (usando um cenário fictício) o que foi feito para solucionar.
O cenário:
Para que vocês possam entender melhor, vou utilizar um cenário onde tenho 4 instâncias de SQL, portas tcp/ip usada pelo SQL Server e a respectiva conta de serviço utilizada para subir o serviço do SQL Server:
Servidor SRV01: possui três instâncias de SQL Server 2005
Instância Porta TCP Conta de Serviço
========= ======= ================
SQL01 1433 contoso/sqlservice_des
SQL02 3218 contoso/sqlservice_des
SQL03 2927 contoso/sqlservice_des
Servidor SRV02: possui 1 instância de SQL Server 2005
Instância Porta TCP Conta de Serviço
========= ======= ================
SQL04 1377 contoso/sqlservice_des
Obs: Fique atendo à barra que separa o domínio da conta! Devido a uma limitação estou usando o formato domínio/conta.
Os Problemas:
Ok, a partir deste ponto o primeiro problema que tive foi que ao tentar estabelecer qualquer conexão com a instância SQL01 no servidor SRV01 a mensagem de erro “Cannot generate SSPI context” era apresentada. Há, vale lembrar que este erro somente ocorria quando se usava conexão trusted, ou seja, usando uma conta do windows. Conexão usando login standard (do próprio SQL) funcionavam normalmente.
Bom, tentei então estabelecer uma conexão usando o utilitário de linha de comando SQLCMD, isso porque, ele usa SQL Native Client e na maioria das vezes este utilitário apresenta mensagem de erro com um pouco mais de detalhe. Ao usar o SQLCMD a mensagem era a seguinte:
HResult 0x80090322, Level 16, State 1
SQL Network Interfaces: The target principal name is incorrect.
Sqlcmd: Error: Microsoft SQL Native Client : Cannot generate SSPI context.
Hummm.. note que agora temos o seguinte “SQL Network Interfaces: The target principal name is incorrect.” Isso me levou a crer que tinha algo de errado com meus registros SPN (veja o post anterior) para a instância de SQL Server que eu estava tentando acessar, a SQL01.
Verificando a porta TCP que a instância SQL01 estava usando constatei que era a porta 1433 e então fiz uma consulta dos registros de SPN para a conta sqlservice_des. Como podemos observar no output abaixo, tudo parecia normal, ou seja, eu tinha a entrada para a instância SQL01 e sua respectiva porta 1433.
C:/temp>setspn -L contoso/sqlservice_des
Registered ServicePrincipalNames for …
.
.
.
MSSQLSvc/SQL01.contoso.com.br:1433
MSSQLSvc/SQL02.contoso.com.br:3218
MSSQLSvc/SQL04.contoso.com.br:1377
Aparentemente tudo ok, parti então para uma pesquisa na net onde caí no post “Cannot generate SSPI context error message, when connect to local SQL Server outside domain no blog do SQL Server Protocol Team. Lendo o post, encontrei o seguinte já no último parágrafo:
“From the error message reported by SNAC ODBC/OLEDB, you can differentiated the issue described by this post from another case of Cannot generate SSPI context, in which the root cause is because, in Active Directory, the Service Principle Name (SPN) of SQL Server is registered for a domain account different from the SQL Server is actually running under. The error message for the other case is [SQL Native Client]SQL Network Interfaces: The target principal name is incorrect.[SQL Native Client]Cannot generate SSPI context”
Hummm… isso fazia sentido uma vez que tenho contas de serviço diferentes para cada ambiente (desenvolvimento/produção/homologação)! Então poderia sim ser possível que o registro de SPN existente no AD estivesse como outra conta que não a que estava sendo usada pelo serviço do SQL Server naquele momento.
Executei então outras consultas dos SPN registrados para as outras contas e em uma delas encontrei a seguinte saída…
C:/temp>setspn -L contoso/sqlservice_prod
Registered ServicePrincipalNames for …
.
.
.
MSSQLSvc/SQL01.contoso.com.br:1433
MSSQLSvc/SQL06.contoso.com.br:1433
MSSQLSvc/SQL010.contoso.com.br:2515
Opa… encontrei então um outro registro para a instância SQL01 e mesma porta! Note que a primeira entrada da saída acima é exatamente igual à saída que obtive para a conta de serviço sqlservice_des.
Bom, com isso o problema estava esclarecido! Ao tentar me conectar à instância SQL01 o SPN que estava sendo usado era o SPN que estava registrado no AD para a conta sqlservice_prod, porém, como o serviço do SQL Server estava subindo com a conta sqlservice_des o SPN não batia e a autenticação Kerberos falhava. Para resolver o problema eu simplesmente removí os dois SPN e cadastrei novamente o SPN correto (não requer parada do SQL Server!!)…
— Remove SPN da instância SQL01 na porta 1433 para as contas sqlservice_prod e sqlservice_des
setspn -D MSSQLSvc/SQL01.contoso.com.br:1433 contoso/sqlservice_prod
setspn -D MSSQLSvc/SQL01.contoso.com.br:1433 contoso/sqlservice_des
— Registra SPN da instância SQL01 na porta 1433 para a conta sqlservice_des
setspn -A MSSQLSvc/SQL01.contoso.com.br:1433 contoso/sqlservice_des
Legal, isso resolveu meu primeiro problema! Vamos então para o segundo…
O segundo problema estava relacionado ao uso de linked server entre a instância SQL04 e uma outra instância que vou chamar aqui de SQL05. A Instância SQL04 possui um linked server para a instância SQL05, no entanto, quando a procedure de um analista tentava usar um linked server ele recebia a mensagem de erro abaixo:
Msg 18456, Level 14, State 1, Line 1
Login failed for user ‘NT AUTHORITY/ANONYMOUS LOGON’.
O problema era facilmente reproduzido abrindo um sesão no Query Editor com meu usuário de domínio e executando uma query como esta…
SELECT TOP 10 * FROM LS_SQL05.master.dbo.sysobjects
Por skill, a causa mais comum deste erro também esta relacionada a problemas de autenticação Kerberos, ou seja, registro de SPN incorreto ou que não existe.
Verifiquei então a instância SQL04 e constatei que ela estava usando a conta de serviço sqlservice_des com a porta 1377. A instância SQL05, usava a mesma conta de serviço com a porta 2927.
Consultando mais uma vez os SPNs registrados para a conta sqlservice_des obtive o seguinte output…
C:/temp>setspn -L contoso/sqlservice_des
Registered ServicePrincipalNames for …
.
.
.
MSSQLSvc/SQL01.contoso.com.br:1433
MSSQLSvc/SQL02.contoso.com.br:3218
MSSQLSvc/SQL04.contoso.com.br:1377
Hummm.. se as instâncias usam a mesma conta de serviço, cadê a entrada para a instância SQL05 na porta 2927?
Estava aí o problema! A autenticação Kerberos estava falhando porque não existia no AD um SPN registrado para a instância SQL05. Após registrar o SPN usando o comando abaixo o linked server passou a funcionar normalmente.
setspn -A MSSQLSvc/SQL05.contoso.com.br:1433 contoso/sqlservice_des
Ao final acabei com os seguintes SPN regsitrados para a conta sqlservice_des
C:/temp>setspn -L contoso/sqlservice_des
Registered ServicePrincipalNames for …
.
.
.
MSSQLSvc/SQL01.contoso.com.br:1433
MSSQLSvc/SQL02.contoso.com.br:3218
MSSQLSvc/SQL04.contoso.com.br:1377
MSSQLSvc/SQL05.contoso.com.br:2927
É isso pessoal, se você pretende utilizar ou utiliza o método de autenticação “Windows Authentication”, fique sempre atendo a estes problemas de Kerberos, nomes de computador no DNS, registros de SPN e não deixem de ler tudo que puder sobre autenticação Kerberos com SQL Server. Tenha ainda em mente que quando trabalhamos com autenticação Kerberos vários requisitos de configuração precisam ser satisfeitos e a correta configuração do SPN é apenas uma delas.
abraços e até
Nilton Pinheiro