Configurar conexões sem senha entre vários aplicativos e serviços do Azure
Artigo
Os aplicativos geralmente exigem conexões seguras entre vários serviços do Azure simultaneamente. Por exemplo, uma instância de Serviço de Aplicativo do Azure empresarial pode se conectar a várias contas de armazenamento diferentes, uma instância de banco de dados SQL do Azure, um barramento de serviço e muito mais.
As identidades gerenciadas são a opção de autenticação recomendada para conexões seguras e sem senha entre recursos do Azure. Os desenvolvedores não precisam controlar e gerenciar manualmente muitos segredos diferentes para identidades gerenciadas, já que a maioria dessas tarefas é tratada internamente pelo Azure. Este tutorial explora como gerenciar conexões entre vários serviços usando identidades gerenciadas e a biblioteca de clientes do Azure Identity.
Compare os tipos de identidades gerenciadas
O Azure fornece os seguintes tipos de identidades gerenciadas:
As identidades gerenciadas atribuídas pelo sistema estão diretamente vinculadas a um único recurso do Azure. Quando você habilita uma identidade gerenciada atribuída pelo sistema em um serviço, o Azure criará uma identidade vinculada e tratará tarefas administrativas para essa identidade internamente. Quando o recurso do Azure é excluído, a identidade também é.
As identidades gerenciadas atribuídas pelo usuário são identidades independentes criadas por um administrador e podem ser associadas a um ou mais recursos do Azure. O ciclo de vida da identidade é independente desses recursos.
Você pode ler mais sobre as práticas recomendadas e quando usar identidades atribuídas pelo sistema versus identidades atribuídas pelo usuário nas práticas recomendadas de identidades.
Explorar DefaultAzureCredential
As identidades gerenciadas geralmente são implementadas no código do aplicativo por meio de uma classe chamada DefaultAzureCredential da biblioteca de clientes Azure.Identity. DefaultAzureCredential dá suporte a vários métodos de autenticação e determina automaticamente quais devem ser usados no runtime. Você pode ler mais sobre essa abordagem na visão geral defaultAzureCredential.
Conectar um aplicativo hospedado do Azure a vários serviços do Azure
Você foi encarregado de conectar um aplicativo existente a vários serviços e bancos de dados do Azure usando conexões sem senha. O aplicativo é uma API Web ASP.NET Core hospedada no Serviço de Aplicativo do Azure, embora as etapas abaixo se apliquem a outros ambientes de hospedagem do Azure, como Azure Spring Apps, Máquinas Virtuais, Aplicativos de Contêiner e AKS.
Este tutorial se aplica às arquiteturas a seguir, embora possa ser adaptado a muitos outros cenários também por meio de alterações mínimas de configuração.
As etapas a seguir demonstram como configurar um aplicativo para usar uma identidade gerenciada atribuída pelo sistema e sua conta de desenvolvimento local para se conectar a vários Serviços do Azure.
Criar uma identidade gerenciada atribuída pelo sistema
No portal do Azure, navegue até o aplicativo hospedado que você deseja conectar a outros serviços.
Na página visão geral de serviço, selecione Identidade.
Alterne a configuração Status para Ativar para habilitar uma identidade gerenciada atribuída pelo sistema para o serviço.
Atribuir funções à identidade gerenciada para cada serviço conectado
Navegue até a página de visão geral da conta de armazenamento à qual você deseja conceder acesso à sua identidade.
Selecione Controle de Acesso (IAM) na navegação da conta de armazenamento.
Escolha Adicionar e, em seguida, Adicionar atribuição de função.
Na caixa de pesquisa Função, pesquise o Colaborador de Dados de Blob de Armazenamento, que concede permissões para executar operações de leitura e gravação em dados de blob. Você pode atribuir qualquer função apropriada para seu caso de uso. Selecione o Colaborador de Dados do Blob de Armazenamento na lista e escolha Avançar.
Na tela Adicionar atribuição de função, para a opção Atribuir acesso à, selecione Identidade gerenciada. Em seguida, escolha +Selecionar membros.
No submenu, pesquise a identidade gerenciada que você criou inserindo o nome do serviço de aplicativo. Selecione a identidade atribuída pelo sistema e escolha Selecionar para fechar o menu de submenu.
Selecione Avançar algumas vezes até que você possa selecionar Revisão + atribuir para concluir a atribuição de função.
Repita esse processo para os outros serviços aos quais você deseja se conectar.
Considerações de desenvolvimento local
Você também pode habilitar o acesso aos recursos do Azure para desenvolvimento local atribuindo funções a uma conta de usuário da mesma forma que atribuiu funções à sua identidade gerenciada.
Depois de atribuir a função Colaborador de Dados de Blob de Armazenamento à sua identidade gerenciada, em Atribuir acesso, desta vez selecione Usuário, grupo ou entidade de serviço. Escolha + Selecionar membros para abrir o menu de submenu novamente.
Pesquise a conta user@domain ou o grupo de segurança do Microsoft Entra ao qual você deseja conceder acesso por endereço de email ou nome e selecione-a. Essa deve ser a mesma conta que você usa para entrar em suas ferramentas de desenvolvimento locais, como o Visual Studio ou a CLI do Azure.
Observação
Também poderá atribuir essas funções a um grupo de segurança do Microsoft Entra se estiver trabalhando em uma equipe com vários desenvolvedores. Em seguida, você pode colocar qualquer desenvolvedor dentro desse grupo que precise de acesso para desenvolver o aplicativo localmente.
Dentro do projeto, adicione uma referência ao pacote NuGet Azure.Identity. Esta biblioteca contém todas as entidades necessárias para implementar DefaultAzureCredential. Você também pode adicionar outras bibliotecas do Azure relevantes ao seu aplicativo. Para este exemplo, os pacotes Azure.Storage.Blobs e Azure.KeyVault.Keys são adicionados para se conectar ao Armazenamento de Blobs e Key Vault.
Na parte superior do arquivo Program.cs, adicione o seguinte usando as instruções:
using Azure.Identity;
using Azure.Storage.Blobs;
using Azure.Security.KeyVault.Keys;
No arquivo Program.cs do código do projeto, crie instâncias dos serviços necessários aos quais seu aplicativo se conectará. Os exemplos a seguir se conectam ao Armazenamento de Blobs e ao barramento de serviço usando as classes de SDK correspondentes.
var blobServiceClient = new BlobServiceClient(
new Uri("https://<your-storage-account>.blob.core.windows.net"),
new DefaultAzureCredential(credOptions));
var serviceBusClient = new ServiceBusClient("<your-namespace>", new DefaultAzureCredential());
var sender = serviceBusClient.CreateSender("producttracking");
Dentro do projeto, adicione a dependência azure-identity ao arquivo pom.xml. Essa biblioteca contém todas as entidades necessárias para implementar DefaultAzureCredential. Você também pode adicionar outras dependências do Azure relevantes ao seu aplicativo. Para esse exemplo, as dependências azure-storage-blob e azure-messaging-servicebus são adicionadas para se conectar ao Armazenamento de Blobs e Key Vault.
No código do projeto, crie instâncias dos serviços necessários aos quais seu aplicativo se conectará. Os exemplos a seguir se conectam ao Armazenamento de Blobs e ao barramento de serviço usando as classes de SDK correspondentes.
class Demo {
public static void main(String[] args) {
DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilder().build();
BlobServiceClient blobServiceClient = new BlobServiceClientBuilder()
.endpoint("https://<your-storage-account>.blob.core.windows.net")
.credential(defaultAzureCredential)
.buildClient();
ServiceBusClientBuilder clientBuilder = new ServiceBusClientBuilder().credential(defaultAzureCredential);
ServiceBusSenderClient serviceBusSenderClient = clientBuilder.sender()
.queueName("producttracking")
.buildClient();
}
}
Dentro do projeto, só é preciso adicionar dependências de serviço que você usa. Para esse exemplo, as dependências spring-cloud-azure-starter-storage-blob e spring-cloud-azure-starter-servicebus são adicionadas para se conectar ao Armazenamento de Blobs e Key Vault.
No código do projeto, crie instâncias dos serviços necessários aos quais seu aplicativo se conectará. Os exemplos a seguir se conectam ao Armazenamento de Blobs e ao barramento de serviço usando as classes de SDK correspondentes.
@Service
public class ExampleService {
@Autowired
private BlobServiceClient blobServiceClient;
@Autowired
private ServiceBusSenderClient serviceBusSenderClient;
}
Dentro do projeto, use npm para adicionar uma referência ao pacote @azure/identity. Esta biblioteca contém todas as entidades necessárias para implementar DefaultAzureCredential. Instale outras bibliotecas do SDK do Azure relevantes para seu aplicativo.
Na parte superior do arquivo index.js, adicione as seguintes instruções import para importar as classes de cliente necessárias para os serviços aos quais o aplicativo vai se conectar:
import { DefaultAzureCredential } from "@azure/identity";
import { BlobServiceClient } from "@azure/storage-blob";
import { KeyClient } from "@azure/keyvault-keys";
No arquivo index.js, crie objetos de cliente para os serviços do Azure aos quais o aplicativo vai se conectar. Os exemplos a seguir se conectam ao Armazenamento de Blobs e ao Key Vault usando as classes de SDK correspondentes.
// Azure resource names
const storageAccount = process.env.AZURE_STORAGE_ACCOUNT_NAME;
const keyVaultName = process.env.AZURE_KEYVAULT_NAME;
// Create client for Blob Storage using managed identity
const blobServiceClient = new BlobServiceClient(
`https://${storageAccount}.blob.core.windows.net`,
new DefaultAzureCredential()
);
// Create client for Key Vault using managed identity
const keyClient = new KeyClient(`https://${keyVaultName}.vault.azure.net`, new DefaultAzureCredential());
// Create a new key in Key Vault
const result = await keyClient.createKey(keyVaultName, "RSA");
Quando esse código de aplicativo for executado localmente, DefaultAzureCredential pesquisará uma cadeia de credenciais para obter as primeiras credenciais disponíveis. Se Managed_Identity_Client_ID for nulo localmente, ele usará automaticamente as credenciais da CLI local do Azure ou da entrada do Visual Studio. Você pode ler mais sobre esse processo na visão geral da biblioteca de Identidades do Azure.
Quando o aplicativo for implantado no Azure, DefaultAzureCredential recuperará automaticamente a variável Managed_Identity_Client_ID do ambiente do serviço de aplicativo. Esse valor fica disponível quando uma identidade gerenciada está associada ao seu aplicativo.
Esse processo geral garante que seu aplicativo possa ser executado com segurança localmente e no Azure sem a necessidade de alterações de código.
Conectar vários aplicativos usando várias identidades gerenciadas
Embora os aplicativos no exemplo anterior tenham compartilhado todos os mesmos requisitos de acesso ao serviço, ambientes reais geralmente são mais nuances. Considere um cenário em que vários aplicativos se conectam às mesmas contas de armazenamento, mas dois dos aplicativos também acessam serviços ou bancos de dados diferentes.
Para configurar essa configuração em seu código, verifique se seu aplicativo registra serviços separados para se conectar a cada conta de armazenamento ou banco de dados. Certifique-se de efetuar pull das IDs corretas do cliente de identidade gerenciada para cada serviço ao configurar DefaultAzureCredential. O exemplo de código a seguir configura as seguintes conexões de serviço:
Duas conexões com contas de armazenamento separadas usando uma identidade gerenciada atribuída pelo usuário compartilhado
Uma conexão com o Azure Cosmos DB e SQL do Azure serviços usando uma segunda identidade gerenciada atribuída pelo usuário compartilhado
// Get the first user-assigned managed identity ID to connect to shared storage
const clientIdStorage = Environment.GetEnvironmentVariable("Managed_Identity_Client_ID_Storage");
// First blob storage client that using a managed identity
BlobServiceClient blobServiceClient = new BlobServiceClient(
new Uri("https://<receipt-storage-account>.blob.core.windows.net"),
new DefaultAzureCredential()
{
ManagedIdentityClientId = clientIDstorage
});
// Second blob storage client that using a managed identity
BlobServiceClient blobServiceClient2 = new BlobServiceClient(
new Uri("https://<contract-storage-account>.blob.core.windows.net"),
new DefaultAzureCredential()
{
ManagedIdentityClientId = clientIDstorage
});
// Get the second user-assigned managed identity ID to connect to shared databases
var clientIDdatabases = Environment.GetEnvironmentVariable("Managed_Identity_Client_ID_Databases");
// Create an Azure Cosmos DB client
CosmosClient client = new CosmosClient(
accountEndpoint: Environment.GetEnvironmentVariable("COSMOS_ENDPOINT", EnvironmentVariableTarget.Process),
new DefaultAzureCredential()
{
ManagedIdentityClientId = clientIDdatabases
});
// Open a connection to Azure SQL using a managed identity
string ConnectionString1 = @"Server=<azure-sql-hostname>.database.windows.net; User Id=ClientIDOfTheManagedIdentity; Authentication=Active Directory Default; Database=<database-name>";
using (SqlConnection conn = new SqlConnection(ConnectionString1))
{
conn.Open();
}
class Demo {
public static void main(String[] args) {
// Get the first user-assigned managed identity ID to connect to shared storage
String clientIdStorage = System.getenv("Managed_Identity_Client_ID_Storage");
// Get the DefaultAzureCredential from clientIdStorage
DefaultAzureCredential storageCredential =
new DefaultAzureCredentialBuilder().managedIdentityClientId(clientIdStorage).build();
// First blob storage client that using a managed identity
BlobServiceClient blobServiceClient = new BlobServiceClientBuilder()
.endpoint("https://<receipt-storage-account>.blob.core.windows.net")
.credential(storageCredential)
.buildClient();
// Second blob storage client that using a managed identity
BlobServiceClient blobServiceClient2 = new BlobServiceClientBuilder()
.endpoint("https://<contract-storage-account>.blob.core.windows.net")
.credential(storageCredential)
.buildClient();
// Get the second user-assigned managed identity ID to connect to shared databases
String clientIdDatabase = System.getenv("Managed_Identity_Client_ID_Databases");
// Create an Azure Cosmos DB client
CosmosClient cosmosClient = new CosmosClientBuilder()
.endpoint("https://<cosmos-db-account>.documents.azure.com:443/")
.credential(new DefaultAzureCredentialBuilder().managedIdentityClientId(clientIdDatabase).build())
.buildClient();
// Open a connection to Azure SQL using a managed identity
String connectionUrl = "jdbc:sqlserver://<azure-sql-hostname>.database.windows.net:1433;"
+ "database=<database-name>;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database"
+ ".windows.net;loginTimeout=30;Authentication=ActiveDirectoryMSI;";
try {
Connection connection = DriverManager.getConnection(connectionUrl);
Statement statement = connection.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Dentro do projeto, use npm para adicionar uma referência ao pacote @azure/identity. Esta biblioteca contém todas as entidades necessárias para implementar DefaultAzureCredential. Instale outras bibliotecas do SDK do Azure relevantes para seu aplicativo.
Na parte superior do arquivo index.js, adicione as seguintes instruções import para importar as classes de cliente necessárias para os serviços aos quais o aplicativo vai se conectar:
import { DefaultAzureCredential } from "@azure/identity";
import { BlobServiceClient } from "@azure/storage-blob";
import { KeyClient } from "@azure/keyvault-keys";
No arquivo index.js, crie objetos de cliente para os serviços do Azure aos quais o aplicativo vai se conectar. Os exemplos a seguir se conectam ao Armazenamento de Blobs, Cosmos DB e SQL do Azure usando as classes de SDK correspondentes.
// Get the first user-assigned managed identity ID to connect to shared storage
const clientIdStorage = process.env.MANAGED_IDENTITY_CLIENT_ID_STORAGE;
// Storage account names
const storageAccountName1 = process.env.AZURE_STORAGE_ACCOUNT_NAME_1;
const storageAccountName2 = process.env.AZURE_STORAGE_ACCOUNT_NAME_2;
// First blob storage client that using a managed identity
const blobServiceClient = new BlobServiceClient(
`https://${storageAccountName1}.blob.core.windows.net`,
new DefaultAzureCredential({
managedIdentityClientId: clientIdStorage
})
);
// Second blob storage client that using a managed identity
const blobServiceClient2 = new BlobServiceClient(
`https://${storageAccountName2}.blob.core.windows.net`,
new DefaultAzureCredential({
managedIdentityClientId: clientIdStorage
})
);
// Get the second user-assigned managed identity ID to connect to shared databases
const clientIdDatabases = process.env.MANAGED_IDENTITY_CLIENT_ID_DATABASES;
// Cosmos DB Account endpoint
const cosmosDbAccountEndpoint = process.env.COSMOS_ENDPOINT;
// Create an Azure Cosmos DB client
const client = new CosmosClient({
endpoint: cosmosDbAccountEndpoint,
credential: new DefaultAzureCredential({
managedIdentityClientId: clientIdDatabases
})
});
// Open a connection to Azure SQL using a managed identity with mssql package
// mssql reads the environment variables to get the managed identity
const server = process.env.AZURE_SQL_SERVER;
const database = process.env.AZURE_SQL_DATABASE;
const port = parseInt(process.env.AZURE_SQL_PORT);
const type = process.env.AZURE_SQL_AUTHENTICATIONTYPE;
const config = {
server,
port,
database,
authentication: {
type // <---- Passwordless connection
},
options: {
encrypt: true
}
};
await sql.connect(sqlConfig);
Você também pode associar uma identidade gerenciada atribuída pelo usuário, bem como uma identidade gerenciada atribuída pelo sistema a um recurso simultaneamente. Isso pode ser útil em cenários em que todos os aplicativos exigem acesso aos mesmos serviços compartilhados, mas um dos aplicativos também tem uma dependência muito específica de um serviço adicional. O uso de uma identidade atribuída pelo sistema também garante que a identidade vinculada a esse aplicativo específico seja excluída quando o aplicativo é excluído, o que pode ajudar a manter seu ambiente limpo.
Neste tutorial, você aprendeu a migrar um aplicativo para conexões sem senha. Você pode ler os seguintes recursos para explorar os conceitos discutidos neste artigo com mais detalhes: