Utilização de Kerberos para cenários de delegação em .Net

Introdução
Quando trabalhamos com aplicações distribuídas, muitas vezes torna-se necessário “repassar” o contexto de segurança do usuário por cada camada da aplicação até o banco de dados.
Este processo pode se tornar mais complicado na medida em que mais camadas estão envolvidas no processo, principalmente se estas camadas estão fisicamente separadas em computadores diferentes.
Descrição do Problema
Quando um sistema Windows Forms faz um acesso ao SQL Server utilizando segurança integrada, este sistema utiliza o contexto de usuário que está executando o processo (o executável Windows Forms) para tentar se autenticar no banco de dados. A implementação deste cenário é relativamente simples, pois o usuário já se autenticou ao efetuar o logon no Windows, e não é necessário que sejam efetuadas maiores configurações para suportar o “repasse” dessas credenciais para o banco de dados.
Figura 1: Aplicação Windows Forms efetuando acesso ao SQL Server.
 
Mas quando trabalhamos com uma aplicação Web no lugar de Windows Forms, a complexidade aumenta, pois agora teremos que efetuar uma primeira autenticação do browser com o IIS, e depois uma segunda autenticação do IIS para o SQL Server. Para este cenário, teremos que utilizar o Kerberos, pois o NTLM não suporta o que chamamos de “delegação”, ou seja, repasse de autenticação entre máquinas sucessivamente (a menos que tenhamos conhecimento, via código, das variáveis usuário e senha e efetuemos um logon manual em cada camada do processo via programação, utilizando, por exmeplo, a API LogonUser). Poderíamos também trabalhar com Basic/Clear text, mas como este recurso não oferece nenhuma criptografia, teríamos que utilizar SSL, tanto entre o browser e o servidor web, quanto entre o servidor web e o de web services, caso exista.
Como sabemos que SSL não é uma boa solução quando se trabalha com web services, e que basic/clear da acesso, via código, à senha do usuário, acreditamos que a solução ideal seja realmente o Kerberos.
 
Figura 2: Aplicação Asp.Net efetuando acesso ao SQL Server.
 
Neste tipo de cenário, a configuração do Kerberos pode vir a se tornar extremamente complexa, dependendo do ambiente e tipo de aplicação. 
Um exemplo disto seria supormos que provavelmente a camada ASP.Net poderia ser dividida entre um projeto web, um web service e algumas dll’s que fariam o acesso ao banco de dados, gerando o cenário ilustrado no próximo exemplo:  
 
Figura 3: Aplicação distribuída, com n camadas, efetuando acesso ao SQL Server..
 
Para simplificar o processo de configuração do Kerberos para atender a tais situações, enumeramos os passos necessários no tópico a seguir.
Possíveis Soluções
Segue abaixo um guia prático para a configuração do Kerberos:
Passo 1: Configurando contas de usuário e máquinas no Active Directory para que sejam “trusted for delegation”:
Abrir o Active Directory Users and Computers, escolher os usuários que precisarão se utilizar deste recurso, abrir as propriedades e fazer as seguintes modificações:
-Desmarcar o item “Account is sensitive and cannot be delegated”, caso esteja marcado.
-Marcar o item “Account is trusted for delegation”, caso esteja desmarcado.
Escolher agora os computadores envolvidos no processo de delegação, abrir as propriedades e marcar o checkbox “Trust computer for delegation”.
Passo 2: Sincronizando relógios:
Para o correto funcionamento do Kerberos, é necessário que a data/hora dos computadores esteja perfeitamente sincronizada. O Kerberos suporta uma diferença de apenas 5 minutos (valor default, pode ser modificado via policy de domínio) na data/hora dos computadores. Sendo assim, sincronize todos os computadores para ter certeza de que a data e hora estão compatíveis. Tome cuidado com configuração de horário de verão e fuso horário.
Passo 3: Serviço MSSQLSERVER
Caso o seu cenário de delegação chegue ao SQL Server, ou a algum outro serviço em especial, verifique qual o usuário com o qual este serviço está executando (Ferramentas Administrativas/Serviços). Lembre-se que:
-A conta de usuário não pode ser uma conta local da máquina, pois isto impedirá o cenário de delegação de funcionar corretamente.
-A conta de usuário poderá ser configurada como System Account, isto não impedirá a delegação de ocorrer.
-Caso a conta de usuário seja uma conta de domínio, verifique se o Passo 1 foi efetuado para esta conta, e se ela possui as devidas permissões para que o serviço execute normalmente.
Passo 4: String de conexão
Se estivermos acessando o SQL Server e desejarmos que o cenário de delegação se aplique até o nível do banco de dados, devemos nos lembrar de configurar a string de conexão com o banco de dados incluindo os seguintes dados: "Integrated Security=SSPI;Network Library=dbmssocn". O primeiro informa que estamos trabalhando com segurança integrada, e o segundo pede para que se use TCP/IP, necessário para o funcionamento do Kerberos.
Passo 5: Service Pack
Não insista em problemas que poderiam já estar resolvidos, instale a última versão do Service Pack do Windows em todas as máquinas. Muitos problemas relacionados a este cenário são corrigidos em Service Packs. O mesmo vale para correções de Internet Explorer, SQL Server, e demais serviços envolvidos.
Passo 6: Internet Explorer
Procure trabalhar com a última versão do Internet Explorer (para os nossos testes de Kerberos, utilizamos a versão 5.5 ou superior). Lembre-se de de marcar a opção “Enable Integrated Authentication (requires restart)”, em Tools, Options, Advanced (Esta opção pode ter sido desabilitada caso tenha sido feito um upgrade para o Internet Explorer 6.0). Caso esta opção não apareça nas opções do seu browser, provavelmente ele é muito antigo e não suporta Kerberos desta forma.
O Kerberos não é suportado via proxy servers, sendo assim, temos duas opções: Desabilitar a configuração de proxy no browser ou incluir os servidores que estaremos acessando na opção de endereços locais para efetuar bypass.
Lembre-se: Só é possível utilizar Kerberos com Windows XP, 2000, 2003 ou superiores. Os Windows 9x e Me não são suportados neste cenário (apesar de termos visto drivers de terceiros que prometem resolver isto para estas plataformas, não chegamos a testa-los).
Caso, no processo de autenticação, uma janela esteja abrindo no browser para entrada de usuário e senha, é sinal de que por algum motivo o browser e o servidor web estão tentando se autenticar em clear text, e não em kerberos. Reveja as configurações de ambos para que isto não ocorra.
Passo 7: Web Services
O arquivo web.config do projeto deve ter os elementos de segurança modificados para que se force a integração entre a autenticação do usuário e o contexto de segurança, da seguinte forma:
<identity impersonate="true"></identity>
<authorization>
<allow users="*"/>
<deny users="?"/>
</authorization>

O elemento “identity” está habilitando a personificação de usuário, enquanto o “authorization” está permitindo o acesso de todos os usuários, exceto o anonymous.
Passo 8: Site Asp.Net
Para o site Asp.Net, devemos efetuar a mesma configuração de web.config que fizemos para os web services:
<identity impersonate="true"></identity>
<authorization>
<allow users="*"/>
<deny users="?"/>
</authorization>
 
Além disso, é preciso que, na chamada aos web services, o código Asp.Net “repasse” a autenticação que recebeu para que os web services a recebam. Isto pode ser feito da seguinte forma:
WebServiceProxy.Service1  MeuServico;
MeuServico =new WebServiceProxy.Service1();
MeuServico.Proxy=null;
MeuServico.Credentials=System.Net.CredentialCache.DefaultCredentials;
MeuServico.ExecutarMetodoWeb();
A linha que altera a propriedade Credentials é fundamental nesse contexto, pois ela busca no CredentialCache a credencial usada para autenticação na página e faz a associação desta com o proxy do Web Service a ser executado.
Já a linha que altera a propriedade Proxy para null não é essencial, mas serve para nos lembrar que o servidor Asp.Net não pode se valer de um web proxy para acessar o web service, sob pena de perder o ticket Kerberos.
Passo 9: IIS
As configurações de IIS feitas no servidor Asp.Net devem ser as mesmas feitas no servidor de Web Services.
Basicamente, devemos abrir o IIS Manager, acessar as propriedades das SubWebs envolvidas (tanto a do site quanto a do web service) entrar na aba “Directory Security”, em “Authentication and access control”, clicar em “Edit”, e desmarcar todos os check-boxes, deixando apenas o de “Integrated Windows authentication” marcado.
É importante que apenas esse check-box esteja marcado, caso contrário o IIS poderá decidir por tentar outro tipo de autenticação no lugar do Kerberos.
Os servidores IIS também devem permitir que o tipo de autenticação chamado “Negotiate” esteja habilitado. Esta é a configuração default, mas pode ser confirmada executando-se o comando script abaixo:
cscript adsutil.vbs set w3svc/1/NTAuthenticationProviders "Negotiate,NTLM"
Não é necessário remover o NTLM, isto impediria qualquer Windows 9x de acessar o IIS. Como o Negotiate vem primeiro, esta será a primeira tentativa, e só não irá ocorrer caso exista algum outro problema.
Passo 10: Setspn
Um utilitário praticamente indispensável quando se trabalha com o Kerberos é o setspn (“SPN” vem de “Service Principal Name”).
O download pode ser feito no endereço abaixo:
http://www.microsoft.com/windows2000/techinfo/reskit/tools/existing/setspn-o.asp
Service Principal Names são usados para suportar autenticação mutua entre uma aplicação cliente e um serviço.
O setspn tem o objetivo de auxiliar na configuração do Active Directory (a resolução de nomes tem um papel fundamental para que o Kerberos funcione). A idéia principal é a seguinte: Não basta que se consiga resolver o nome da máquina para o IP, mas também o IP para o nome da máquina (e se um nome chega a um IP, esse IP tem que resolver exatamente para o mesmo nome original). Além disso, precisamos cadastrar alguns serviços no Active Directory, e é aí que o setspn entra.
Para ilustrar o uso do setspn, instalei este utilitário no meu computador e executei o seguinte comando no DOS:
setspn -L nome_da_maquina
O comando gerou o seguinte retorno:
Registered ServicePrincipalNames for CN=nome_da_maquina,CN=Computers,DC=flag,DC=com,DC=br:
MSSQLSvc/nome_da_maquina.flag.com.br:1433
HOST/NOME_DA_MAQUINA
HOST/nome_da_maquina.flag.com.br
C:\>
O parâmetro –L listou os Service Principal Names registrados para a minha máquina. É interessante observar que automaticamente eu já tenho o serviço do SQL Server informado no Active Directory. Ele sabe inclusive que o meu SQL Server está na porta 1433.
Executei este comando para mostrar que, muitas vezes, podemos descobrir que o serviço que estamos usando não está registrado como deveria, e nesse caso, teremos que registra-lo manualmente.
Por exemplo, suponhamos que eu tenha uma segunda instância do SQL Server ouvindo a porta 9000. Como este serviço não apareceu quando eu executei o parâmetro –L, terei que cadastra-lo manualmente (caso o serviço não tenha se registrado automaticamente, pode ser um sinal de que algo errado está acontecendo com este serviço. Se o serviço estiver rodando com uma conta local, provavelmente ele não conseguirá efetuar o registro, e também não irá funcionar, mesmo que eu faça o registro manualmente).
O comando para registrar o serviço do SQL Server seria assim:
setspn -A MSSQLSvc/nome_da_maquina.flag.com.br:9000 nome_da_maquina
Verifique se o comando executou e nenhuma mensagem de erro foi retornada. Caso uma mensagem de erro tenha ocorrido, pode ser que a conta de usuário que esteja sendo usada não tem permissão suficiente para fazer este registro.
Pode ser que você queira fazer o registro do serviço sem o nome FQDN também, para garantir que a resolução ocorra tanto com o nome FQDN quanto com o hostname, e o resultado então seria:
Registered ServicePrincipalNames for CN=nome_da_maquina,CN=Computers,DC=flag,DC=com,DC=br:
MSSQLSvc/nome_da_maquina.flag.com.br:1433
HOST/NOME_DA_MAQUINA
HOST/nome_da_maquina.flag.com.br
MSSQLSvc/nome_da_maquina.flag.com.br:9000
MSSQLSvc/nome_da_maquina:9000
C:\>
Devemos nos lembrar que pode ser necessário o cadastro de outros serviços também, como por exemplo:
Para Olap Server:
MSOLAPSvc/nome_da_maquina.dominio
MSOLAPSvc/nome_da_maquina
Para servidores IIS (página e web services):
HTTP/nome_da_maquina.dominio nome_da_maquina
HTTP/nome_da_maquina nome_da_maquina
É importante lembrar também que deve haver cuidado com a replicação dos dados. Por exemplo, posso fazer este cadastro em um servidor KDC, mas enquanto a replicação não ocorre, os outros ficam desatualizados, podendo impedir o funcionamento do cenário de Delegação.
Como a resolução máquina/IP e IP/máquina devem estar em sintonia, devemos também fazer um teste simples: “ping nome_da_maquina” e “ping –a IP”. Ambos devem funcionar com sucesso, e o nome retornado pelo segundo deve ser igual ao nome que usamos no primeiro. Da mesma forma, o IP retornado pelo primeiro deve ser igual ao IP usado no segundo. Pode parecer um teste sem maior importância, mas uma configuração incorreta neste ponto pode impedir totalmente o kerberos de funcionar.
Passo 11: Se tudo mais falhar
Vivenciamos um problema real onde, mesmo seguindo todos os itens citados anteriormente, ainda não conseguíamos fazer com que o cenário de delegação funcionasse. Deduzimos então que deveria estar ocorrendo alguma restrição de policy que nos impedia de fazer este cenário funcionar.
Para resolver o problema, efetuamos o seguinte teste, que nos permitiu resolver o problema:
-Abrir o Local Security Policy do servidor SQL Server.
-Em Local Policy/User Rights Assignment, abrir as permissões para Everyone nos itens: Access this computer from the network, Act as part of the operating system, Create a token object, Enable computer and user accounts to be trusted for delegation, Impersonate a client after authentication, Log on as a service, Replace a process level token.
-Efetuar novo teste no sistema.
Após os testes funcionarem, desfazer uma a uma as alterações efetuadas na policy, até encontrar o ponto que estava impedindo o funcionamento do cenário de delegação.
Recomendações Finais
O cenário de delegação pode ser extremamente útil numa intranet, mas deve ser usado com cautela. Isto porque de certa forma ele torna a segurança do ambiente menos restritiva.
Caso um código malicioso execute em uma máquina, ele agora poderá causar danos não só locais, mas também reutilizar o contexto de permissão do usuário para causar danos em cascata, em uma seqüência de máquinas, se valendo do cenário de delegação.
Algumas restrições citadas para este cenário nas documentações do MSDN podem ser contornadas ou sequer existir, dependendo de como configurarmos nosso ambiente, por exemplo:
-Não é necessário fazer todo acesso às máquinas pelo FQDN (nome.domínio). Caso as entradas no SPN estejam corretas, podemos utilizar apenas o nome da máquina, ou até nomes fictícios, cadastrados no hosts.
-Não é necessário fazer alterações no machine.config, colocando o processo do IIS para rodar com uma conta específica de usuário.
-Podemos manter as configurações de proxy habilitadas no browser, contanto que as máquinas que estejamos acessando estejam na lista de bypass da configuração de proxy.