Olá amigos, há um tempo atrás enfrentei o famoso problema SSPI atípico e sempre adiava este post, bom finalmente decidi escrever o artigo. Espere que o ajude.
Problema
Um usuário sempre conectou ao SQL Server sem problemas, mas um dia ao tentar conectar-se ao mesmo serviço de SQL ele recebeu a seguinte mensagem:
Não houve nenhuma mudança por parte de infraestrutura e DBAs no servidor, o usuário simplesmente não consegue conectar mais, e o mais intrigante é que alguns usuários conseguem conectar-se e outros não.
Bom, na grande maioria das vezes o erro SSPI Context é gerado por falta de SPN em uma tentativa de conexão via kerberos com o SQL Server e para resolver este problema basta criar o SPN.
Listando os SPN atuais:
No prompt de comando digite o seguinte comando
SETSPN –L <domínio\conta_de_serviço_do_SQL>
Nota: Se ao executar o comando setspn –L você não receber o SPN para a sua instância de SQL Server, você deve criar o SPN e você está recebendo o erro de SSPI Context, possivelmente o seu problema será resolvido com a criação manual do SPN com o seguinte comando:
SETSPN – A MSSQLSvc/fqdn <domínio>\<conta de serviço do SQL>
SETSPN – A MSSQLSvc/fqdn:1433 <domínio>\<conta de serviço do SQL>
Ex. SETSPN –A MSSLSvc/sqlproducao.contoso.com contoso\sqlServiceAcc
Maiores informações no artigo: https://msdn.microsoft.com/pt-br/library/ms191153.aspx
Como podemos observar no resultado do SETSPN –L no meu ambiente eu tenho os SPNs corretamente criados!
O que justifica algumas conexões conseguirem conectar-se, pois o SPN está ok, e então por que algumas conexões recebem o SSPI?
Para responder esta questão precisamos analisar o ticket do kerberos, executando a ferramenta tokensz você poderá evidenciar o problema de token bloat com a seguinte sintaxe
tokensz.exe /compute_tokensize /user:<usuário_com_erro_sspi>
Como podemos notar na imagem acima, o tamanho máximo do Token é 12000 (12K) e o token do usuário contoso\usuarioSQL que estou tentando conectar-se ao SQL e estou recebendo o erro SSPI contexto ultrapassou o limite.
Um token basicamente contém os grupos e permissões de um usuário e é criado no momento do logon e este token é repassado aos outros serviços/servidores conforme o usuário necessita autenticar-se para consumir os serviços (para maiores detalhes sobre kerberos consulte o artigo https://msdn.microsoft.com/en-us/library/bb742516.aspx)
Pois bem, se em um token temos a ACL (Access control List) vamos investigar os usuários criados:
Os dois usuários são membros do grupo SQLacesso o qual foi criado o login no SQL Server, mas o segundo usuário é membro de mais algumas centenas de grupos.
Até o Windows 2008 R2 o tamanho máximo default de um token é de 12K a partir do Windows 2012 este valor foi alterado para 48K
Dependendo do tamanho de seu ambiente este limite de 12K é facilmente alcançado com um usuário pertencendo a aproximadamente 150 grupos.
Em uma empresa multinacional onde como boa prática são criados diversos grupos para controlar acessos a diversos compartilhamentos, servidores, aplicações etc. este limite é alcançado muito rapidamente.
Qual o tamanho de cada grupo?
Para calcular o tamanho do token utilizamos a seguinte formula:
TokenSize = 1200 + 40d + 8s
Onde:
D = (grupos domínio local + grupos universais externos)
S = (grupos globais + Universal)
Existem diversos scripts que automatizam este cálculo, abaixo um bem simples que encontrei no artigo http://www.cluberti.com/blog/2014/05/26/getting-kerberos-token-size-with-powershell/
# Always credit where due - this was found via # http://jacob.ludriks.com/getting-kerberos-token-size-with-powershell/ #Gets max token size #Run with .\get_tokensize.ps1 -Username "domain\username" #Reference: http://support.microsoft.com/kb/327825 #tokensize = 1200 + 40d + 8s Param( [Parameter(Mandatory=$True)] [String]$Username ) $domain = ($username.split("\"))[0] $user = ($username.split("\"))[1] Import-Module ActiveDirectory $rootdse = (Get-ADDomain $domain).distinguishedname $server = (Get-ADDomain $domain).pdcemulator $usergroups = Get-ADPrincipalGroupMembership -server $server $user | select distinguishedname,groupcategory,groupscope,name $domainlocal = [int]@($usergroups | where {$_.groupscope -eq "DomainLocal"}).count $global = [int]@($usergroups | where {$_.groupscope -eq "Global"}).count $universaloutside = [int]@($usergroups | where {$_.distinguishedname -notlike "*$rootdse" -and $_.groupscope -eq "Universal"}).count $universalinside = [int]@($usergroups | where {$_.distinguishedname -like "*$rootdse" -and $_.groupscope -eq "Universal"}).count $tokensize = 1200 + (40 * ($domainlocal + $universaloutside)) + (8 * ($global + $universalinside)) Write-Host " Domain local groups: $domainlocal Global groups: $global Universal groups outside the domain: $universaloutside Universal groups inside the domain: $universalinside Kerberos token size: $tokensize"
Outros scripts úteis
http://www.jhouseconsulting.com/2013/12/20/script-to-create-a-kerberos-token-size-report-1041
https://gallery.technet.microsoft.com/scriptcenter/Check-for-MaxTokenSize-520e51e5
Como Resolver
Você tem duas maneiras de resolver o problema, aumentando o default do token size ou excluindo grupos desnecessários.
Para aumentar o token size, você pode seguir as etapas do KB http://support.microsoft.com/kb/938118
Em cada estação:
- Inicie Regedt32.exe
- Localize a chave (HKLM\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters)
- No menu Edit clique em NEW / DWORD e utilize os parâmetros abaixo:
Nome: MaxTokenSize
tipo: REG_DWORD
Base: Decimal
Valor: 48000
- Feche o Editor de Registro
Se executarmos novamente a ferramenta Tokensz teremos o seguinte resultado:
Leituras adicionais
http://support.microsoft.com/kb/938118
http://support.microsoft.com/kb/327825/en-us
http://blogs.technet.com/b/askds/archive/2012/07/27/kerberos-errors-in-network-captures.aspx
http://blogs.technet.com/b/askds/archive/2007/11/02/what-s-in-a-token.aspx
http://support.microsoft.com/kb/327825/en-us