Aumentando a segurança das suas aplicações no Azure com Managed Identities

Eliminando credenciais do seu código.

Wilson Santos
8 min readSep 8, 2021

A evolução dos mecanismos de segurança para gerenciar credenciais no desenvolvimento de software percorreu um longo caminho. Começamos com encriptação em arquivos de configuração, passamos pela automação de deploys em pipelines de CI/CD e pelo uso de User Secrets. Depois, os cofres de chaves como o Azure Key Vault ajudaram a centralizar e proteger as credenciais. Uma abordagem interessante é o uso de Azure Managed Identities, que elimina a necessidade de gerenciar diretamente as credenciais, permitindo a autenticação e autorização entre serviços de forma segura. A escolha do melhor mecanismo depende das necessidades e requisitos específicos do projeto

Considere o cenário abaixo

O cenário descrito envolve o Azure API Management (APIM) na camada de borda e um serviço de aplicativo (App Service) como API que acessa um banco de dados Azure SQL Server.

No cenário acima, é necessário pelo menos uma credencial no código para acessar o banco de dados, conhecida como “connection string”. Além disso, dependendo das ações a serem realizadas com o APIM (Azure API Management), também é necessário uma credencial para negociar tokens com o AAD (Azure Active Directory) e repassá-los para a API. Se você quiser saber mais sobre esse cenário, recomendo dar uma olhada neste artigo. Azure AD B2C / Azure AD, usando Client Credencial

Modelo Convencional de registro de Aplicações no Azure Active Directory

O modelo clássico de registro de aplicações no Azure Active Directory

Normalmente, é necessário ter uma aplicação que representa o servidor e outra que representa o cliente. Em seguida, expomos uma URI na aplicação do servidor e concedemos permissões nessa URI para a aplicação cliente.

No caso de fluxo de usuário, usamos escopos para definir as permissões. Já no caso de fluxo de aplicação, utilizamos roles (funções) para definir as permissões.

Com as identidades gerenciadas, o processo é semelhante, mas as aplicações serão criadas automaticamente quando habilitarmos o serviço de Identidade Gerenciada no recurso correspondente. Portanto, o primeiro passo para utilizar as Managed Identities no cenário mencionado é habilitar esse recurso no Azure para a instância do App Service e, em seguida, realizar algumas configurações no Azure SQL Server.

No App Services

No menu Settings Identity

System assigned

Uma identidade gerenciada atribuída ao sistema é restrita a uma por recurso e está vinculada ao ciclo de vida desse recurso. Você pode conceder permissões à identidade gerenciada usando o controle de acesso baseado em função do Azure (Azure RBAC). A identidade gerenciada é autenticada com o Azure AD, portanto, você não precisa armazenar nenhuma credencial no código.

User assigned

As identidades gerenciadas atribuídas pelo usuário permitem que os recursos do Azure se autentiquem em serviços de nuvem (por exemplo, Azure Key Vault) sem armazenar credenciais no código. Esse tipo de identidades gerenciadas são criadas como recursos autônomos do Azure e têm seu próprio ciclo de vida. Um único recurso (por exemplo, máquina virtual) pode utilizar identidades gerenciadas atribuídas a vários usuários. Da mesma forma, uma única identidade gerenciada atribuída ao usuário pode ser compartilhada entre vários recursos (por exemplo, máquina virtual).

saiba mais

Depois disso podemos começar com nossa Connectionstring direto no código, ela vai mudar disso

Data Source=seed-srv.database.windows.net;Initial Catalog=seeddb;user id=seed-app;password=123456;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False;MultipleActiveResultSets=True

Para isso

Server=seed-srv.database.windows.net; Authentication=Active Directory Managed Identity; Database=seeddb

Perceba que não há mais credenciais na connection string e não foi necessário fazer nenhuma alteração no código. Essa implementação funciona bem no dotnet core 3.1 e 5.0. No entanto, é importante notar que você precisa atualizar ou instalar o pacote Microsoft.Data.SqlClient para a versão 3.0.0. Recomendo dar uma olhada aqui para obter mais informações sobre essa questão, pois pode variar dependendo da versão do framework da sua aplicação.

Na versão Full framework 4.7.2 ≥ não foi bem assim

Foi necessário obter o token manualmente e passá-lo para a conexão. O código para Entity Framework (E.F.) é mais ou menos o mesmo, porém, no caso do E.F., precisamos fazer isso na classe de contexto, no construtor.

Install-Package Microsoft.Azure.Services.AppAuthentication

A connectionstring também ficou diferente.

Server=seed-srv.database.windows.net; Database=seeddb

OBS: Aqui fica um ponto de estudo para verificar se realmente é necessário intervir no código para usar a identidade gerenciada.

Do lado do Azure Sql Server também tem alguns ajustes

Primeiramente, no seu servidor do Azure SQL Server, vá até as configurações de segurança e selecione a opção “Firewalls and Virtual Networks”. Em seguida, marque a opção “Allow Azure services and resources to access this server”. Isso permitirá que qualquer recurso dentro da infraestrutura do Azure acesse o banco de dados, eliminando a necessidade de liberar manualmente endereços IP.

Servidor Azure SQl Server Firewalls and virtual networks habilitar a flag “Allow Azure services and resources to access this server”

Outro ponto importante é que precisaremos criar um usuário no Azure SQL Server para o banco de dados desejado. No entanto, para fazer isso, é necessário fazer login com um usuário do Azure Active Directory (AD). Portanto, é necessário configurar um usuário administrador do Azure SQL Server que esteja vinculado ao Azure Active Directory. Para fazer isso, vá até o menu “Settings” e, em seguida, selecione o submenu “Azure Active Directory” no servidor do Azure SQL Server. Você pode criar esse usuário no Azure Active Directory e associá-lo aqui sem enfrentar maiores problemas.

ervidor do Azure SQl Server Azure Active Directory admin

Pelo CLI

az sql server ad-admin create --resource-group <ResourceGroupName> --server-name <ServerName> --display-name ADMIN --object-id <ObjectId>

Agora podemos logar no SSME utilizando a opção MFA,

perceba que precisamos usar o nome qualificado do usuário com o domínio do seu AD

Depois de conectar rode o script a seguir contra o banco desejado.

CREATE USER [seed-api-windows] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [seed-api-windows];
ALTER ROLE db_datawriter ADD MEMBER [seed-api-windows];
ALTER ROLE db_ddladmin ADD MEMBER [seed-api-windows];
GO

Caso precise dar grant em alguma procedure use algo como.

GRANT EXECUTE TO [seed-api-windows]

Esse usuário precisa ter o nome da Identidade gerenciada criada na aplicação acima, normalmente é o mesmo nome do recurso.

No menu Settings Identity podemos ver o nome da Identidade Gerenciada

Mas e o APIM?

Vamos considerar como requisito que nossa API, descrita no diagrama acima, esteja protegida pelo Azure Active Directory (AAD) e, portanto, requer um token para acesso. No entanto, os usuários que consomem o Azure API Management (APIM) fornecerão apenas uma chave de assinatura (subscription key). Nesse caso, é responsabilidade do APIM negociar um token com o AAD e repassá-lo para a API.

No artigo “Azure AD B2C / Azure AD, usando Client Credential”, esse cenário é detalhado de forma mais abrangente. Nele, podemos ver que a política “send-request” utilizada requer as credenciais de aplicação para obter o token usando o fluxo de credenciais do cliente. Nosso objetivo é substituir essa política por uma solução mais adequada.

authentication-managed-identity

O primeiro passo é habilitar a Identidade Gerenciada no Azure API Management (APIM). Para fazer isso, siga estas etapas:

  1. Acesse sua instância do APIM no portal do Azure.
  2. Vá para o menu “Security” (Segurança).
  3. Selecione o subitem “Managed Identities” (Identidades Gerenciadas).
  4. Ative a opção para ligar a identidade gerenciada, definindo a flag como “On”.

Ao habilitar a identidade gerenciada no APIM, você permite que ele tenha uma identidade exclusiva e gerenciada pelo Azure. Isso permite que o APIM faça autenticação e autorização em outros serviços do Azure de forma segura e simplificada

tela do APIM menu Security , sub item Managed identities flag on

No modelo padrão de registro de aplicações, temos uma aplicação servidor e uma aplicação cliente. A aplicação servidor expõe uma URI e, por meio de roles ou escopos, solicitamos um token de autenticação. O Azure API Management (APIM), nesse caso, desempenha o papel de cliente, solicitando um token à aplicação servidor.

A sequência típica de interações seria a seguinte:

  1. A aplicação cliente (APIM) envia uma solicitação de token para a aplicação servidor, especificando as roles ou escopos necessários.
  2. A aplicação servidor, por meio de integração com o Azure AD, autentica a solicitação e emite um token válido com as permissões adequadas.
  3. A aplicação cliente (APIM) recebe o token de autenticação da aplicação servidor.
  4. O APIM pode então usar esse token para autenticar e autorizar as solicitações de API vindas de seus consumidores (clientes).

Esse modelo permite que o APIM, como intermediário entre a aplicação cliente e a aplicação servidor, solicite um token de autenticação para obter acesso seguro aos recursos da aplicação servidor.

OBS: O que fiz aqui foi registrar mais uma aplicação para representar a API, então expor uma URI e cadastrar uma Role de permissionamento. Atenção essa aplicação é diferente da gerada como Enterprise Application no processo de identidade gerenciada pois preciso utilizar os recursos de Exposição de URI e Roles que não existem nas aplicações Enterprise.

Aqui fica outro ponto de estudo para verificar se é possível utilizar a mesma aplicação gerada no processo de ativação da identidade do wep app.

Com essa aplicação devidamente configurada, a API foi protegida usando o seguinte código adicionado ao método ConfigureServices da classe Startup.cs em uma aplicação web dotnet core 3.1 (e também válido para versões superiores).

services.AddMicrosoftIdentityWebApiAuthentication(Configuration, "AzureAd");

No appsettings.json temos algo assim

"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "7a3837da-8577-4677-9fcd-e66362b054c1",
"TenantId": "779811d8-5862-4c34-baeb-6b53957d52e7",
"Audience": "7a3837da-8577-4677-9fcd-e66362b054c1"
},

A audiência é representada pelo ClientId, que é usado para restringir o acesso apenas a essa aplicação específica. No entanto, no caso do Azure API Management (APIM), a aplicação gerada durante o processo de ativação da Identidade Gerenciada é uma “Enterprise Application” que não possui uma interface de usuário para configurar permissões. Portanto, para lidar com essa situação, precisaremos fazer isso por meio do módulo PowerShell do AzureAD.

Na política temos isso

O parâmetro “resource” corresponde ao ClientId da Aplicação Servidora. Após obtermos o token por meio da política “authentication-managed-identity”, utilizamos o “set-header” para repassar o token para o backend da API.

Referências

  1. Using Azure Active Directory authentication with SqlClient — ADO.NET Provider for SQL Server | Microsoft Docs
  2. Tutorial: Access data with managed identity — Azure App Service | Microsoft Docs
  3. az sql server ad-admin | Microsoft Docs

--

--

Wilson Santos
Wilson Santos

Written by Wilson Santos

Nos últimos 15 anos, venho desenvolvendo , aperfeiçoando e integrando sistemas, sou apaixonado por desenvolver e ensinar, nem tanto por escrever!.

No responses yet