Provedor de configuração do Azure Key Vault no ASP.NET Core

Este artigo explica como usar o provedor de configuração do Azure Key Vault para carregar valores de configuração de aplicativo dos segredos do Azure Key Vault. O Azure Key Vault é um serviço baseado em nuvem que ajuda a proteger chaves criptográficas e segredos usados por aplicativos e serviços. Cenários comuns para usar o Azure Key Vault com aplicativos ASP.NET Core incluem:

  • Controle de acesso a dados de configuração confidenciais.
  • Atendendo ao requisito de HSMs (Módulos de Segurança de Hardware) validados para FIPS 140-2 Nível 2 ao armazenar dados de configuração.

Pacotes

Adicione referências de pacote para os seguintes pacotes:

Aplicativo de exemplo

O aplicativo de exemplo é executado em um dos dois modos determinados pela diretiva de pré-processador #define na parte superior de Program.cs:

  • Certificate: demonstra como usar uma ID de cliente do Azure Key Vault e um certificado X.509 para acessar segredos armazenados no Azure Key Vault. Este exemplo pode ser executado de qualquer local, seja implantado em Serviço de Aplicativo do Azure ou em qualquer host que possa atender a um aplicativo ASP.NET Core.
  • Managed: demonstra como usar identidades gerenciadas para recursos do Azure. A identidade gerenciada autentica o aplicativo no Azure Key Vault com a autenticação do Azure Active Directory (AD) sem armazenar credenciais no código ou na configuração do aplicativo. A versão Managed do exemplo deve ser implantada no Azure. Siga as diretrizes na seção Usar as identidades gerenciadas para recursos do Azure .

Para obter mais informações sobre como configurar um aplicativo de exemplo usando diretivas de pré-processador (#define), consulte Visão geral de ASP.NET Core.

Exibir ou baixar código de exemplo (como baixar)

Armazenamento secreto no ambiente de desenvolvimento

Defina segredos localmente usando o Gerenciador de Segredos. Quando o aplicativo de exemplo é executado no computador local no ambiente de desenvolvimento, os segredos são carregados do repositório de segredos do usuário local.

O Gerenciador de Segredos requer uma propriedade <UserSecretsId> no arquivo de projeto do aplicativo. Defina o valor da propriedade ({GUID}) como qualquer GUID exclusivo:

<PropertyGroup>
  <UserSecretsId>{GUID}</UserSecretsId>
</PropertyGroup>

Os segredos são criados como pares nome-valor. Valores hierárquicos (seções de configuração) usam um : (dois-pontos) como separador em ASP.NET Core nomes de chave de configuração.

O Gerenciador de Segredos é usado de um shell de comando aberto para a raiz de conteúdo do projeto, em que {SECRET NAME} é o nome e {SECRET VALUE} é o valor:

dotnet user-secrets set "{SECRET NAME}" "{SECRET VALUE}"

Execute os seguintes comandos em um shell de comando da raiz de conteúdo do projeto para definir os segredos para o aplicativo de exemplo:

dotnet user-secrets set "SecretName" "secret_value_1_dev"
dotnet user-secrets set "Section:SecretName" "secret_value_2_dev"

Quando esses segredos são armazenados no Azure Key Vault no armazenamento secreto da seção Ambiente de produção com o Azure Key Vault, o _dev sufixo é alterado para _prod. O sufixo fornece uma indicação visual na saída do aplicativo que indica a origem dos valores de configuração.

Armazenamento secreto no ambiente de produção com o Azure Key Vault

Conclua as etapas a seguir para criar um Azure Key Vault e armazenar os segredos do aplicativo de exemplo nele. Para saber mais, confira Início Rápido: Definir e recuperar um segredo do Azure Key Vault usando a CLI do Azure.

  1. Abra o Azure Cloud Shell usando qualquer um dos seguintes métodos no portal do Azure:

    • Selecione Experimente no canto superior direito de um bloco de código. Use a cadeia de caracteres de pesquisa "CLI do Azure" na caixa de texto.
    • Abra o Cloud Shell no navegador com o botão Iniciar Cloud Shell.
    • Selecione o botão Cloud Shell no menu no canto superior direito do portal do Azure.

    Para obter mais informações, consulte CLI do Azure e Visão geral do Azure Cloud Shell.

  2. Se você ainda não estiver autenticado, entre com o comando az login.

  3. Crie um grupo de recursos com o seguinte comando, em que {RESOURCE GROUP NAME} é o nome do novo grupo de recursos e {LOCATION} é a região do Azure:

    az group create --name "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  4. Crie um Key Vault no grupo de recursos com o seguinte comando, em que {KEY VAULT NAME} é o nome do novo cofre e {LOCATION} é a região do Azure:

    az keyvault create --name {KEY VAULT NAME} --resource-group "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  5. Crie segredos no cofre como pares nome-valor.

    Os nomes de segredo do Azure Key Vault são limitados a caracteres alfanuméricos e traços. Valores hierárquicos (seções de configuração) usam -- (dois traços) como delimitador, pois dois-pontos não são permitidos em nomes de segredo do Key Vault. Dois-pontos delimitam uma seção de uma subchave na configuração do ASP.NET Core. A sequência de dois traços é substituída por dois-pontos quando os segredos são carregados na configuração do aplicativo.

    Os segredos a seguir são usados com o aplicativo de exemplo. Os valores incluem um sufixo _prod para distingui-los dos valores _dev de sufixo carregados no ambiente de desenvolvimento do Gerenciador de Segredos. Substitua {KEY VAULT NAME} pelo nome do Key Vault que você criou na etapa anterior:

    az keyvault secret set --vault-name {KEY VAULT NAME} --name "SecretName" --value "secret_value_1_prod"
    az keyvault secret set --vault-name {KEY VAULT NAME} --name "Section--SecretName" --value "secret_value_2_prod"
    

Usar a ID do Aplicativo e o certificado X.509 para aplicativos não hospedados no Azure

Configure o Azure AD, o Azure Key Vault, o aplicativo para usar uma ID do aplicativo do Azure AD e um certificado X.509 para autenticar em um cofre quando o aplicativo estiver hospedado fora do Azure. Para obter mais informações, consulte Sobre chaves, segredos e certificados.

Observação

Embora o uso de uma ID do Aplicativo e um certificado X.509 seja compatível com aplicativos hospedados no Azure, isso não é recomendado. Em vez disso, use Identidades gerenciadas para recursos do Azure ao hospedar um aplicativo no Azure. As identidades gerenciadas não exigem o armazenamento de um certificado no aplicativo ou no ambiente de desenvolvimento.

O aplicativo de exemplo usa uma ID do Aplicativo e um certificado X.509 quando a diretiva de pré-processador #define na parte superior do Program.cs é definida como Certificate.

  1. Crie um certificado de arquivo PKCS#12 (.pfx). As opções para criar certificados incluem New-SelfSignedCertificate no Windows e OpenSSL.
  2. Instale o certificado no repositório de certificados pessoal do usuário atual. Marcar a chave como exportável é opcional. Observe a impressão digital do certificado, que é usada posteriormente neste processo.
  3. Exporte o certificado do arquivo PKCS#12 (.pfx) como um certificado codificado em DER (.cer).
  4. Registre o aplicativo com Azure AD (Registros de aplicativo).
  5. Carregue o certificado codificado em DER (.cer) para Azure AD:
    1. Selecione o aplicativo no Azure AD.
    2. Navegue até Certificados e segredos.
    3. Selecione Carregar certificado para carregar o certificado, que contém a chave pública. Um certificado .cer, .pem ou .crt é aceitável.
  6. Armazene o nome do Key Vault, a ID do aplicativo e a impressão digital do certificado no arquivo appsettings.json do aplicativo.
  7. Navegue até Key Vaults no portal do Azure.
  8. Selecione o Key Vault que você criou no Armazenamento de segredos na seção Ambiente de produção com o Azure Key Vault.
  9. Selecione Políticas de acesso.
  10. Selecione Adicionar Política de Acesso.
  11. Abra Permissões de segredo e forneça ao aplicativo permissões Get e List .
  12. Selecione Selecionar entidade de segurança e selecione o aplicativo registrado pelo nome. Escolha o botão Selecionar.
  13. Selecione OK.
  14. Selecione Salvar.
  15. Implante o aplicativo.

O aplicativo de exemplo Certificate obtém seus valores de configuração de IConfigurationRoot com o mesmo nome que o nome do segredo:

  • Valores não hierárquicos: o valor de SecretName é obtido com config["SecretName"].
  • Valores hierárquicos (seções): use a notação : (dois-pontos) ou o método GetSection. Use uma dessas abordagens para obter o valor de configuração:
    • config["Section:SecretName"]
    • config.GetSection("Section")["SecretName"]

O certificado X.509 é gerenciado pelo sistema operacional. O aplicativo chama AddAzureKeyVault com valores fornecidos pelo arquivo appsettings.json:


using System.Security.Cryptography.X509Certificates;
using Azure.Identity;

var builder = WebApplication.CreateBuilder(args);

if (builder.Environment.IsProduction())
{
    using var x509Store = new X509Store(StoreLocation.CurrentUser);

    x509Store.Open(OpenFlags.ReadOnly);

    var x509Certificate = x509Store.Certificates
        .Find(
            X509FindType.FindByThumbprint,
            builder.Configuration["AzureADCertThumbprint"],
            validOnly: false)
        .OfType<X509Certificate2>()
        .Single();

    builder.Configuration.AddAzureKeyVault(
        new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
        new ClientCertificateCredential(
            builder.Configuration["AzureADDirectoryId"],
            builder.Configuration["AzureADApplicationId"],
            x509Certificate));
}

var app = builder.Build();

Valores de exemplo:

  • Nome do Key Vault: contosovault
  • ID do Aplicativo: 627e911e-43cc-61d4-992e-12db9c81b413
  • Impressão digital do certificado: fe14593dd66b2406c5269d742d04b6e1ab03adb1

appsettings.json:

{
  "KeyVaultName": "Key Vault Name",
  "AzureADApplicationId": "Azure AD Application ID",
  "AzureADCertThumbprint": "Azure AD Certificate Thumbprint",
  "AzureADDirectoryId": "Azure AD Directory ID"
}

Quando você executa o aplicativo, uma página da Web mostra os valores de segredo carregados. No ambiente de desenvolvimento, os valores secretos são carregados com o sufixo _dev. No ambiente de produção, os valores são carregados com o _prod sufixo .

Usar identidades gerenciadas para recursos do Azure

Um aplicativo implantado no Azure pode aproveitar as identidades gerenciadas para recursos do Azure. Uma identidade gerenciada permite que o aplicativo se autentique no Azure Key Vault usando a autenticação do Azure AD sem armazenar credenciais no código ou na configuração do aplicativo.

O aplicativo de exemplo usa uma identidade gerenciada atribuída pelo sistema quando a diretiva de pré-processador #define na parte superior do Program.cs é definida como Managed. Para criar uma identidade gerenciada para um aplicativo Serviço de Aplicativo do Azure, consulte Como usar identidades gerenciadas para Serviço de Aplicativo e Azure Functions. Depois que a identidade gerenciada tiver sido criada, observe a ID de Objeto do aplicativo mostrada no portal do Azure no painel Identity do Serviço de Aplicativo.

Insira o nome do cofre no arquivo do aplicativo appsettings.json. O aplicativo de exemplo não requer uma ID do Aplicativo e uma Senha (Segredo do Cliente) quando definido como a versão Managed, para que você possa ignorar essas entradas de configuração. O aplicativo é implantado no Azure e o Azure autentica o aplicativo para acessar o Azure Key Vault usando apenas o nome do cofre armazenado no arquivo appsettings.json.

Implantar o exemplo no Serviço de Aplicativo do Azure.

Usando a CLI do Azure e a ID de Objeto do aplicativo, forneça ao aplicativo permissões list e get para acessar o cofre:

az keyvault set-policy --name {KEY VAULT NAME} --object-id {OBJECT ID} --secret-permissions get list

Reinicie o aplicativo usando a CLI do Azure, o PowerShell ou o portal do Azure.

Esse exemplo cria uma instância da classe DefaultAzureCredential. A credencial tenta obter um token de acesso do ambiente para recursos do Azure:

using Azure.Identity;

var builder = WebApplication.CreateBuilder(args);

if (builder.Environment.IsProduction())
{
    builder.Configuration.AddAzureKeyVault(
        new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
        new DefaultAzureCredential());
}

Valor de exemplo do nome do Key Vault: contosovault

appsettings.json:

{
  "KeyVaultName": "Key Vault Name"
}

Para aplicativos que usam uma identidade gerenciada atribuída pelo usuário, configure a ID do Cliente da identidade gerenciada usando uma das seguintes abordagens:

  1. Defina a variável de ambiente AZURE_CLIENT_ID.

  2. Defina a propriedade DefaultAzureCredentialOptions.ManagedIdentityClientId ao chamar AddAzureKeyVault:

    builder.Configuration.AddAzureKeyVault(
        new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
        new DefaultAzureCredential(new DefaultAzureCredentialOptions
        {
            ManagedIdentityClientId = builder.Configuration["AzureADManagedIdentityClientId"]
        }));
    

Quando você executa o aplicativo, uma página da Web mostra os valores de segredo carregados. No ambiente de desenvolvimento, os valores secretos têm o sufixo _dev porque são fornecidos pelo Gerenciador de Segredos. No ambiente de produção, os valores são carregados com o sufixo _prod porque são fornecidos pelo Azure Key Vault.

Se você receber um erro Access denied, confirme se o aplicativo está registrado no Azure AD e se forneceu acesso ao cofre. Confirme se você reiniciou o serviço no Azure.

Para obter informações sobre como usar o provedor com uma identidade gerenciada e o Azure Pipelines, consulte Criar uma conexão de serviço no Resource Manager do Azure para uma VM com uma identidade de serviço gerenciada.

Opções de configuração

AddAzureKeyVault pode aceitar um objeto AzureKeyVaultConfigurationOptions:

// using Azure.Extensions.AspNetCore.Configuration.Secrets;

builder.Configuration.AddAzureKeyVault(
    new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
    new DefaultAzureCredential(),
    new AzureKeyVaultConfigurationOptions
    {
        // ...
    });

O objeto de AzureKeyVaultConfigurationOptions contém as seguintes propriedades:

Propriedade Descrição
Manager A instância KeyVaultSecretManager usada para controlar o carregamento de segredo.
ReloadInterval TimeSpan para aguardar entre tentativas de sondar alterações no cofre. O valor padrão é null (a configuração não é recarregada).

Usar um prefixo de nome de chave

AddAzureKeyVault fornece uma sobrecarga que aceita uma implementação de KeyVaultSecretManager, que permite controlar como os segredos do Key Vault são convertidos em chaves de configuração. Por exemplo, você pode implementar a interface para carregar valores secretos com base em um valor de prefixo fornecido na inicialização do aplicativo. Essa técnica permite, por exemplo, carregar segredos com base na versão do aplicativo.

Aviso

Não use prefixos em segredos do Key Vault para:

  • Colocar segredos para vários aplicativos no mesmo cofre.
  • Coloque segredos ambientais (por exemplo, desenvolvimento versus produção) no mesmo cofre.

Diferentes aplicativos e ambientes de desenvolvimento/produção devem usar Key Vaults separados para isolar ambientes de aplicativo a fim de obter o nível mais alto de segurança.

No exemplo a seguir, um segredo é estabelecido no Key Vault (e usando o Gerenciador de Segredos para o ambiente de desenvolvimento) para 5000-AppSecret (períodos não são permitidos em nomes de segredo do Key Vault). Esse segredo representa um segredo do aplicativo para a versão 5.0.0.0 do aplicativo. Para outra versão do aplicativo, 5.1.0.0, um segredo é adicionado ao cofre (e usando o Gerenciador de Segredos) para 5100-AppSecret. Cada versão do aplicativo carrega seu valor secreto com versão em sua configuração como AppSecret, removendo a versão à medida que carrega o segredo.

AddAzureKeyVault é chamado com uma implementação personalizada KeyVaultSecretManager :

// using Azure.Extensions.AspNetCore.Configuration.Secrets;

builder.Configuration.AddAzureKeyVault(
    new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
    new DefaultAzureCredential(),
    new SamplePrefixKeyVaultSecretManager("5000"));

A implementação reage aos prefixos de versão dos segredos para carregar o segredo adequado na configuração:

  • Load carrega um segredo quando seu nome começa com o prefixo . Outros segredos não são carregados.
  • GetKey:
    • Remove o prefixo do nome do segredo.
    • Substitui dois traços em qualquer nome pelo KeyDelimiter, que é o delimitador usado na configuração (geralmente dois-pontos). O Azure Key Vault não permite dois-pontos em nomes secretos.
public class SamplePrefixKeyVaultSecretManager : KeyVaultSecretManager
{
    private readonly string _prefix;

    public SamplePrefixKeyVaultSecretManager(string prefix)
        => _prefix = $"{prefix}-";

    public override bool Load(SecretProperties properties)
        => properties.Name.StartsWith(_prefix);

    public override string GetKey(KeyVaultSecret secret)
        => secret.Name[_prefix.Length..].Replace("--", ConfigurationPath.KeyDelimiter);
}

O método Load é chamado por um algoritmo de provedor que itera por meio dos segredos do cofre para encontrar os segredos prefixados por versão. Quando um prefixo de versão é encontrado com Load, o algoritmo usa o método GetKey para retornar o nome de configuração do nome do segredo. Ele remove o prefixo de versão do nome do segredo. O restante do nome do segredo é retornado para carregamento nos pares nome-valor da configuração do aplicativo.

Quando essa abordagem é implementada:

  1. A versão do aplicativo especificada no arquivo de projeto do aplicativo. No exemplo a seguir, a versão do aplicativo é definida como 5.0.0.0:

    <PropertyGroup>
      <Version>5.0.0.0</Version>
    </PropertyGroup>
    
  2. Confirme se uma propriedade <UserSecretsId> está presente no arquivo de projeto do aplicativo, em que {GUID} é um GUID fornecido pelo usuário:

    <PropertyGroup>
      <UserSecretsId>{GUID}</UserSecretsId>
    </PropertyGroup>
    

    Salve os seguintes segredos localmente com o Gerenciador de Segredos:

    dotnet user-secrets set "5000-AppSecret" "5.0.0.0_secret_value_dev"
    dotnet user-secrets set "5100-AppSecret" "5.1.0.0_secret_value_dev"
    
  3. Os segredos são salvos no Azure Key Vault usando os seguintes comandos da CLI do Azure:

    az keyvault secret set --vault-name {KEY VAULT NAME} --name "5000-AppSecret" --value "5.0.0.0_secret_value_prod"
    az keyvault secret set --vault-name {KEY VAULT NAME} --name "5100-AppSecret" --value "5.1.0.0_secret_value_prod"
    
  4. Quando o aplicativo é executado, os segredos do Key Vault são carregados. O segredo da cadeia de caracteres para 5000-AppSecret é correspondido à versão do aplicativo especificada no arquivo de projeto do aplicativo (5.0.0.0).

  5. A versão, 5000 (com o traço), é removida do nome da chave. Em todo o aplicativo, a configuração de leitura com a chave AppSecret carrega o valor do segredo.

  6. Se a versão do aplicativo for alterada no arquivo de projeto para 5.1.0.0 e o aplicativo for executado novamente, o valor secreto retornado será 5.1.0.0_secret_value_dev no ambiente de desenvolvimento e 5.1.0.0_secret_value_prod em Produção.

Observação

Você também pode criar sua própria implementação SecretClient do AddAzureKeyVault. Um cliente personalizado permite o compartilhamento de uma única instância do cliente no aplicativo.

Associar uma matriz a uma classe

O provedor pode ler valores de configuração em uma matriz para associação a uma matriz POCO.

Ao ler de uma fonte de configuração que permite que as chaves contenham separadores de dois-pontos (:), um segmento de chave numérica é usado para distinguir as chaves que compõem uma matriz (:0:, :1:, ... :{n}:). Para obter mais informações, consulte Configuração: associar uma matriz a uma classe.

As chaves de Azure Key Vault não podem usar dois-pontos como separador. A abordagem descrita neste artigo usa traços duplos (--) como separador para valores hierárquicos (seções). As chaves de matriz são armazenadas no Azure Key Vault com traços duplos e segmentos de chave numérica (--0--, --1--, ... --{n}--).

Examine a seguinte configuração do provedor de log do Serilog fornecida por um JSarquivo ON. Há dois literais de objeto definidos na matriz WriteTo que refletem dois coletores Serilog, que descrevem destinos para saída de registro em log:

"Serilog": {
  "WriteTo": [
    {
      "Name": "AzureTableStorage",
      "Args": {
        "storageTableName": "logs",
        "connectionString": "DefaultEnd...ountKey=Eby8...GMGw=="
      }
    },
    {
      "Name": "AzureDocumentDB",
      "Args": {
        "endpointUrl": "https://contoso.documents.azure.com:443",
        "authorizationKey": "Eby8...GMGw=="
      }
    }
  ]
}

A configuração mostrada no arquivo ON anterior JSé armazenada no Azure Key Vault usando notação de traço duplo (--) e segmentos numéricos:

Chave Valor
Serilog--WriteTo--0--Name AzureTableStorage
Serilog--WriteTo--0--Args--storageTableName logs
Serilog--WriteTo--0--Args--connectionString DefaultEnd...ountKey=Eby8...GMGw==
Serilog--WriteTo--1--Name AzureDocumentDB
Serilog--WriteTo--1--Args--endpointUrl https://contoso.documents.azure.com:443
Serilog--WriteTo--1--Args--authorizationKey Eby8...GMGw==

Recarregar segredos

Por padrão, os segredos são armazenados em cache pelo provedor de configuração para o tempo de vida do aplicativo. Os segredos que foram posteriormente desabilitados ou atualizados no cofre são ignorados pelo aplicativo.

Para recarregar segredos, chame IConfigurationRoot.Reload:

config.Reload();

Para recarregar segredos periodicamente, em um intervalo especificado, defina a propriedade AzureKeyVaultConfigurationOptions.ReloadInterval. Para mais informações, confira Opções de configuração.

Segredos desabilitados e expirados

Os segredos expirados são incluídos por padrão no provedor de configuração. Para excluir valores desses segredos na configuração do aplicativo, atualize o segredo expirado ou forneça a configuração usando um provedor de configuração personalizado:

class SampleKeyVaultSecretManager : KeyVaultSecretManager
{
  public override bool Load(SecretProperties properties) =>
    properties.ExpiresOn.HasValue &&
    properties.ExpiresOn.Value > DateTimeOffset.Now;
}

Passe esse KeyVaultSecretManager personalizado para AddAzureKeyVault:

// using Azure.Extensions.AspNetCore.Configuration.Secrets;

builder.Configuration.AddAzureKeyVault(
    new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
    new DefaultAzureCredential(),
    new SampleKeyVaultSecretManager());

Os segredos desabilitados não podem ser recuperados no Key Vault e nunca são incluídos.

Solucionar problemas

Quando o aplicativo falha ao carregar a configuração usando o provedor, uma mensagem de erro é gravada na infraestrutura de registro em log do ASP.NET Core. As seguintes condições impedirão o carregamento da configuração:

  • O aplicativo ou certificado não está configurado corretamente no Azure AD.
  • O cofre não existe no Azure Key Vault.
  • O aplicativo não está autorizado a acessar o cofre.
  • A política de acesso não inclui as permissões Get e List.
  • No cofre, os dados de configuração (par nome-valor) estão nomeados incorretamente, ausentes ou desabilitados.
  • O aplicativo tem o nome errado do Key Vault (KeyVaultName), da ID de aplicativo do Azure AD (AzureADApplicationId) ou da impressão digital do certificado do Azure AD (AzureADCertThumbprint) ou da ID do Diretório do Azure AD (AzureADDirectoryId).
  • Ao adicionar a política de acesso do Key Vault para o aplicativo, a política foi criada, mas o botão Salvar não foi selecionado na interface do usuário de políticas de acesso.

Recursos adicionais

Este artigo explica como usar o provedor de configuração do Azure Key Vault para carregar valores de configuração de aplicativo dos segredos do Azure Key Vault. O Azure Key Vault é um serviço baseado em nuvem que ajuda a proteger chaves criptográficas e segredos usados por aplicativos e serviços. Cenários comuns para usar o Azure Key Vault com aplicativos ASP.NET Core incluem:

  • Controle de acesso a dados de configuração confidenciais.
  • Atendendo ao requisito de HSMs (Módulos de Segurança de Hardware) validados para FIPS 140-2 Nível 2 ao armazenar dados de configuração.

Pacotes

Adicione referências de pacote para os seguintes pacotes:

Aplicativo de exemplo

O aplicativo de exemplo é executado em um dos dois modos determinados pela diretiva de pré-processador #define na parte superior de Program.cs:

  • Certificate: demonstra como usar uma ID de cliente do Azure Key Vault e um certificado X.509 para acessar segredos armazenados no Azure Key Vault. Este exemplo pode ser executado de qualquer local, seja implantado em Serviço de Aplicativo do Azure ou em qualquer host que possa atender a um aplicativo ASP.NET Core.
  • Managed: demonstra como usar identidades gerenciadas para recursos do Azure. A identidade gerenciada autentica o aplicativo no Azure Key Vault com a autenticação do Azure Active Directory (AD) sem credenciais armazenadas no código ou na configuração do aplicativo. Ao usar identidades gerenciadas para autenticar, uma ID do aplicativo Azure AD e senha (segredo do cliente) não são necessárias. A versão Managed do exemplo deve ser implantada no Azure. Siga as diretrizes na seção Usar as identidades gerenciadas para recursos do Azure .

Para obter mais informações sobre como configurar um aplicativo de exemplo usando diretivas de pré-processador (#define), consulte Visão geral de ASP.NET Core.

Exibir ou baixar código de exemplo (como baixar)

Armazenamento secreto no ambiente de desenvolvimento

Defina segredos localmente usando o Gerenciador de Segredos. Quando o aplicativo de exemplo é executado no computador local no ambiente de desenvolvimento, os segredos são carregados do repositório de segredos do usuário local.

O Gerenciador de Segredos requer uma propriedade <UserSecretsId> no arquivo de projeto do aplicativo. Defina o valor da propriedade ({GUID}) como qualquer GUID exclusivo:

<PropertyGroup>
  <UserSecretsId>{GUID}</UserSecretsId>
</PropertyGroup>

Os segredos são criados como pares nome-valor. Valores hierárquicos (seções de configuração) usam um : (dois-pontos) como separador em ASP.NET Core nomes de chave de configuração.

O Gerenciador de Segredos é usado de um shell de comando aberto para a raiz de conteúdo do projeto, em que {SECRET NAME} é o nome e {SECRET VALUE} é o valor:

dotnet user-secrets set "{SECRET NAME}" "{SECRET VALUE}"

Execute os seguintes comandos em um shell de comando da raiz de conteúdo do projeto para definir os segredos para o aplicativo de exemplo:

dotnet user-secrets set "SecretName" "secret_value_1_dev"
dotnet user-secrets set "Section:SecretName" "secret_value_2_dev"

Quando esses segredos são armazenados no Azure Key Vault no armazenamento secreto da seção Ambiente de produção com o Azure Key Vault, o _dev sufixo é alterado para _prod. O sufixo fornece uma indicação visual na saída do aplicativo que indica a origem dos valores de configuração.

Armazenamento secreto no ambiente de produção com o Azure Key Vault

Conclua as etapas a seguir para criar um Azure Key Vault e armazenar os segredos do aplicativo de exemplo nele. Para saber mais, confira Início Rápido: Definir e recuperar um segredo do Azure Key Vault usando a CLI do Azure.

  1. Abra o Azure Cloud Shell usando qualquer um dos seguintes métodos no portal do Azure:

    • Selecione Experimente no canto superior direito de um bloco de código. Use a cadeia de caracteres de pesquisa "CLI do Azure" na caixa de texto.
    • Abra o Cloud Shell no navegador com o botão Iniciar Cloud Shell.
    • Selecione o botão Cloud Shell no menu no canto superior direito do portal do Azure.

    Para obter mais informações, consulte CLI do Azure e Visão geral do Azure Cloud Shell.

  2. Se você ainda não estiver autenticado, entre com o comando az login.

  3. Crie um grupo de recursos com o seguinte comando, em que {RESOURCE GROUP NAME} é o nome do novo grupo de recursos e {LOCATION} é a região do Azure:

    az group create --name "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  4. Crie um Key Vault no grupo de recursos com o seguinte comando, em que {KEY VAULT NAME} é o nome do novo cofre e {LOCATION} é a região do Azure:

    az keyvault create --name {KEY VAULT NAME} --resource-group "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  5. Crie segredos no cofre como pares nome-valor.

    Os nomes de segredo do Azure Key Vault são limitados a caracteres alfanuméricos e traços. Valores hierárquicos (seções de configuração) usam -- (dois traços) como delimitador, pois dois-pontos não são permitidos em nomes de segredo do Key Vault. Dois-pontos delimitam uma seção de uma subchave na configuração do ASP.NET Core. A sequência de dois traços é substituída por dois-pontos quando os segredos são carregados na configuração do aplicativo.

    Os segredos a seguir são usados com o aplicativo de exemplo. Os valores incluem um sufixo _prod para distingui-los dos valores _dev de sufixo carregados no ambiente de desenvolvimento do Gerenciador de Segredos. Substitua {KEY VAULT NAME} pelo nome do Key Vault que você criou na etapa anterior:

    az keyvault secret set --vault-name {KEY VAULT NAME} --name "SecretName" --value "secret_value_1_prod"
    az keyvault secret set --vault-name {KEY VAULT NAME} --name "Section--SecretName" --value "secret_value_2_prod"
    

Usar a ID do Aplicativo e o certificado X.509 para aplicativos não hospedados no Azure

Configure o Azure AD, o Azure Key Vault, o aplicativo para usar uma ID do aplicativo do Azure AD e um certificado X.509 para autenticar em um cofre quando o aplicativo estiver hospedado fora do Azure. Para obter mais informações, consulte Sobre chaves, segredos e certificados.

Observação

Embora o uso de uma ID do Aplicativo e um certificado X.509 seja compatível com aplicativos hospedados no Azure, isso não é recomendado. Em vez disso, use Identidades gerenciadas para recursos do Azure ao hospedar um aplicativo no Azure. As identidades gerenciadas não exigem o armazenamento de um certificado no aplicativo ou no ambiente de desenvolvimento.

O aplicativo de exemplo usa uma ID do Aplicativo e um certificado X.509 quando a diretiva de pré-processador #define na parte superior do Program.cs é definida como Certificate.

  1. Crie um certificado de arquivo PKCS#12 (.pfx). As opções para criar certificados incluem New-SelfSignedCertificate no Windows e OpenSSL.
  2. Instale o certificado no repositório de certificados pessoal do usuário atual. Marcar a chave como exportável é opcional. Observe a impressão digital do certificado, que é usada posteriormente neste processo.
  3. Exporte o certificado do arquivo PKCS#12 (.pfx) como um certificado codificado em DER (.cer).
  4. Registre o aplicativo com Azure AD (Registros de aplicativo).
  5. Carregue o certificado codificado em DER (.cer) para Azure AD:
    1. Selecione o aplicativo no Azure AD.
    2. Navegue até Certificados e segredos.
    3. Selecione Carregar certificado para carregar o certificado, que contém a chave pública. Um certificado .cer, .pem ou .crt é aceitável.
  6. Armazene o nome do Key Vault, a ID do aplicativo e a impressão digital do certificado no arquivo appsettings.json do aplicativo.
  7. Navegue até Key Vaults no portal do Azure.
  8. Selecione o Key Vault que você criou no Armazenamento de segredos na seção Ambiente de produção com o Azure Key Vault.
  9. Selecione Políticas de acesso.
  10. Selecione Adicionar Política de Acesso.
  11. Abra Permissões de segredo e forneça ao aplicativo permissões Get e List .
  12. Selecione Selecionar entidade de segurança e selecione o aplicativo registrado pelo nome. Escolha o botão Selecionar.
  13. Selecione OK.
  14. Selecione Salvar.
  15. Implante o aplicativo.

O aplicativo de exemplo Certificate obtém seus valores de configuração de IConfigurationRoot com o mesmo nome que o nome do segredo:

  • Valores não hierárquicos: o valor de SecretName é obtido com config["SecretName"].
  • Valores hierárquicos (seções): use a notação : (dois-pontos) ou o método GetSection. Use uma dessas abordagens para obter o valor de configuração:
    • config["Section:SecretName"]
    • config.GetSection("Section")["SecretName"]

O certificado X.509 é gerenciado pelo sistema operacional. O aplicativo chama AddAzureKeyVault com valores fornecidos pelo arquivo appsettings.json:

// using System.Linq;
// using System.Security.Cryptography.X509Certificates;
// using Azure.Extensions.AspNetCore.Configuration.Secrets;
// using Azure.Identity;

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((context, config) =>
        {
            if (context.HostingEnvironment.IsProduction())
            {
                var builtConfig = config.Build();

                using var store = new X509Store(StoreLocation.CurrentUser);
                store.Open(OpenFlags.ReadOnly);
                var certs = store.Certificates.Find(
                    X509FindType.FindByThumbprint,
                    builtConfig["AzureADCertThumbprint"], false);

                config.AddAzureKeyVault(new Uri($"https://{builtConfig["KeyVaultName"]}.vault.azure.net/"),
                                        new ClientCertificateCredential(builtConfig["AzureADDirectoryId"], builtConfig["AzureADApplicationId"], certs.OfType<X509Certificate2>().Single()),
                                        new KeyVaultSecretManager());

                store.Close();
            }
        })
        .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());

Valores de exemplo:

  • Nome do Key Vault: contosovault
  • ID do Aplicativo: 627e911e-43cc-61d4-992e-12db9c81b413
  • Impressão digital do certificado: fe14593dd66b2406c5269d742d04b6e1ab03adb1

appsettings.json:

{
  "KeyVaultName": "Key Vault Name",
  "AzureADApplicationId": "Azure AD Application ID",
  "AzureADCertThumbprint": "Azure AD Certificate Thumbprint",
  "AzureADDirectoryId": "Azure AD Directory ID"
}

Quando você executa o aplicativo, uma página da Web mostra os valores de segredo carregados. No ambiente de desenvolvimento, os valores secretos são carregados com o sufixo _dev. No ambiente de produção, os valores são carregados com o _prod sufixo .

Usar identidades gerenciadas para recursos do Azure

Um aplicativo implantado no Azure pode aproveitar as identidades gerenciadas para recursos do Azure. Uma identidade gerenciada permite que o aplicativo se autentique com o Azure Key Vault usando a autenticação do Azure AD sem credenciais (ID do Aplicativo e Senha/Segredo do Cliente) armazenadas no aplicativo.

O aplicativo de exemplo usa identidades gerenciadas para recursos do Azure quando a diretiva de pré-processador #define na parte superior do Program.cs é definida como Managed.

Insira o nome do cofre no arquivo do aplicativo appsettings.json. O aplicativo de exemplo não requer uma ID do Aplicativo e uma Senha (Segredo do Cliente) quando definido como a versão Managed, para que você possa ignorar essas entradas de configuração. O aplicativo é implantado no Azure e o Azure autentica o aplicativo para acessar o Azure Key Vault usando apenas o nome do cofre armazenado no arquivo appsettings.json.

Implantar o exemplo no Serviço de Aplicativo do Azure.

Um aplicativo implantado no Serviço de Aplicativo do Azure é registrado automaticamente com Azure AD quando o serviço é criado. Obtenha a ID do Objeto da implantação para uso no comando a seguir. A ID do objeto é mostrada no portal do Azure no painel Identity do Serviço de Aplicativo.

Usando a CLI do Azure e a ID de Objeto do aplicativo, forneça ao aplicativo permissões list e get para acessar o cofre:

az keyvault set-policy --name {KEY VAULT NAME} --object-id {OBJECT ID} --secret-permissions get list

Reinicie o aplicativo usando a CLI do Azure, o PowerShell ou o portal do Azure.

O aplicativo de exemplo:

  • Cria uma instância de DefaultAzureCredential classe. A credencial tenta obter um token de acesso do ambiente para recursos do Azure.
  • Um novo SecretClient é criado com a instância DefaultAzureCredential.
  • A instância SecretClient é usada com uma instância KeyVaultSecretManager, que carrega valores secretos e substitui traços duplos (--) por dois-pontos (:) em nomes de chave.
// using Azure.Security.KeyVault.Secrets;
// using Azure.Identity;
// using Azure.Extensions.AspNetCore.Configuration.Secrets;

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((context, config) =>
        {
            if (context.HostingEnvironment.IsProduction())
            {
                var builtConfig = config.Build();
                var secretClient = new SecretClient(
                    new Uri($"https://{builtConfig["KeyVaultName"]}.vault.azure.net/"),
                    new DefaultAzureCredential());
                config.AddAzureKeyVault(secretClient, new KeyVaultSecretManager());
            }
        })
        .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());

Valor de exemplo do nome do Key Vault: contosovault

appsettings.json:

{
  "KeyVaultName": "Key Vault Name"
}

Quando você executa o aplicativo, uma página da Web mostra os valores de segredo carregados. No ambiente de desenvolvimento, os valores secretos têm o sufixo _dev porque são fornecidos pelo Gerenciador de Segredos. No ambiente de produção, os valores são carregados com o sufixo _prod porque são fornecidos pelo Azure Key Vault.

Se você receber um erro Access denied, confirme se o aplicativo está registrado no Azure AD e se forneceu acesso ao cofre. Confirme se você reiniciou o serviço no Azure.

Para obter informações sobre como usar o provedor com uma identidade gerenciada e o Azure Pipelines, consulte Criar uma conexão de serviço no Resource Manager do Azure para uma VM com uma identidade de serviço gerenciada.

Opções de configuração

AddAzureKeyVault pode aceitar um objeto AzureKeyVaultConfigurationOptions:

config.AddAzureKeyVault(
    new SecretClient(
        new Uri("Your Key Vault Endpoint"),
        new DefaultAzureCredential(),
        new AzureKeyVaultConfigurationOptions())
    {
        ...
    });

O objeto de AzureKeyVaultConfigurationOptions contém as seguintes propriedades.

Propriedade Descrição
Manager A instância KeyVaultSecretManager usada para controlar o carregamento de segredo.
ReloadInterval TimeSpan para aguardar entre tentativas de sondar alterações no cofre. O valor padrão é null (a configuração não é recarregada).

Usar um prefixo de nome de chave

AddAzureKeyVault fornece uma sobrecarga que aceita uma implementação de KeyVaultSecretManager, que permite controlar como os segredos do Key Vault são convertidos em chaves de configuração. Por exemplo, você pode implementar a interface para carregar valores secretos com base em um valor de prefixo fornecido na inicialização do aplicativo. Essa técnica permite, por exemplo, carregar segredos com base na versão do aplicativo.

Aviso

Não use prefixos em segredos do Key Vault para:

  • Colocar segredos para vários aplicativos no mesmo cofre.
  • Coloque segredos ambientais (por exemplo, desenvolvimento versus produção) no mesmo cofre.

Diferentes aplicativos e ambientes de desenvolvimento/produção devem usar Key Vaults separados para isolar ambientes de aplicativo a fim de obter o nível mais alto de segurança.

No exemplo a seguir, um segredo é estabelecido no Key Vault (e usando o Gerenciador de Segredos para o ambiente de desenvolvimento) para 5000-AppSecret (períodos não são permitidos em nomes de segredo do Key Vault). Esse segredo representa um segredo do aplicativo para a versão 5.0.0.0 do aplicativo. Para outra versão do aplicativo, 5.1.0.0, um segredo é adicionado ao cofre (e usando o Gerenciador de Segredos) para 5100-AppSecret. Cada versão do aplicativo carrega seu valor secreto com versão em sua configuração como AppSecret, removendo a versão à medida que carrega o segredo.

AddAzureKeyVault é chamado com uma implementação personalizada KeyVaultSecretManager :

config.AddAzureKeyVault(
    $"https://{builtConfig["KeyVaultName"]}.vault.azure.net/",
    builtConfig["AzureADApplicationId"],
    certs.OfType<X509Certificate2>().Single(),
    new PrefixKeyVaultSecretManager(versionPrefix));

A implementação reage aos prefixos de versão dos segredos para carregar o segredo adequado na configuração:

  • Load carrega um segredo quando seu nome começa com o prefixo . Outros segredos não são carregados.
  • GetKey:
    • Remove o prefixo do nome do segredo.
    • Substitui dois traços em qualquer nome pelo KeyDelimiter, que é o delimitador usado na configuração (geralmente dois-pontos). O Azure Key Vault não permite dois-pontos em nomes secretos.
public class PrefixKeyVaultSecretManager : KeyVaultSecretManager
{
    private readonly string _prefix;

    public PrefixKeyVaultSecretManager(string prefix)
    {
        _prefix = $"{prefix}-";
    }

    public override bool Load(SecretProperties secret)
    {
        return secret.Name.StartsWith(_prefix);
    }

    public override string GetKey(KeyVaultSecret secret)
    {
        return secret.Name
            .Substring(_prefix.Length)
            .Replace("--", ConfigurationPath.KeyDelimiter);
    }
}

O método Load é chamado por um algoritmo de provedor que itera por meio dos segredos do cofre para encontrar os segredos prefixados por versão. Quando um prefixo de versão é encontrado com Load, o algoritmo usa o método GetKey para retornar o nome de configuração do nome do segredo. Ele remove o prefixo de versão do nome do segredo. O restante do nome do segredo é retornado para carregamento nos pares nome-valor da configuração do aplicativo.

Quando essa abordagem é implementada:

  1. A versão do aplicativo especificada no arquivo de projeto do aplicativo. No exemplo a seguir, a versão do aplicativo é definida como 5.0.0.0:

    <PropertyGroup>
      <Version>5.0.0.0</Version>
    </PropertyGroup>
    
  2. Confirme se uma propriedade <UserSecretsId> está presente no arquivo de projeto do aplicativo, em que {GUID} é um GUID fornecido pelo usuário:

    <PropertyGroup>
      <UserSecretsId>{GUID}</UserSecretsId>
    </PropertyGroup>
    

    Salve os seguintes segredos localmente com o Gerenciador de Segredos:

    dotnet user-secrets set "5000-AppSecret" "5.0.0.0_secret_value_dev"
    dotnet user-secrets set "5100-AppSecret" "5.1.0.0_secret_value_dev"
    
  3. Os segredos são salvos no Azure Key Vault usando os seguintes comandos da CLI do Azure:

    az keyvault secret set --vault-name {KEY VAULT NAME} --name "5000-AppSecret" --value "5.0.0.0_secret_value_prod"
    az keyvault secret set --vault-name {KEY VAULT NAME} --name "5100-AppSecret" --value "5.1.0.0_secret_value_prod"
    
  4. Quando o aplicativo é executado, os segredos do Key Vault são carregados. O segredo da cadeia de caracteres para 5000-AppSecret é correspondido à versão do aplicativo especificada no arquivo de projeto do aplicativo (5.0.0.0).

  5. A versão, 5000 (com o traço), é removida do nome da chave. Em todo o aplicativo, a configuração de leitura com a chave AppSecret carrega o valor do segredo.

  6. Se a versão do aplicativo for alterada no arquivo de projeto para 5.1.0.0 e o aplicativo for executado novamente, o valor secreto retornado será 5.1.0.0_secret_value_dev no ambiente de desenvolvimento e 5.1.0.0_secret_value_prod em Produção.

Observação

Você também pode criar sua própria implementação SecretClient do AddAzureKeyVault. Um cliente personalizado permite o compartilhamento de uma única instância do cliente no aplicativo.

Associar uma matriz a uma classe

O provedor pode ler valores de configuração em uma matriz para associação a uma matriz POCO.

Ao ler de uma fonte de configuração que permite que as chaves contenham separadores de dois-pontos (:), um segmento de chave numérica é usado para distinguir as chaves que compõem uma matriz (:0:, :1:, ... :{n}:). Para obter mais informações, consulte Configuração: associar uma matriz a uma classe.

As chaves de Azure Key Vault não podem usar dois-pontos como separador. A abordagem descrita neste artigo usa traços duplos (--) como separador para valores hierárquicos (seções). As chaves de matriz são armazenadas no Azure Key Vault com traços duplos e segmentos de chave numérica (--0--, --1--, ... --{n}--).

Examine a seguinte configuração do provedor de log do Serilog fornecida por um JSarquivo ON. Há dois literais de objeto definidos na matriz WriteTo que refletem dois coletores Serilog, que descrevem destinos para saída de registro em log:

"Serilog": {
  "WriteTo": [
    {
      "Name": "AzureTableStorage",
      "Args": {
        "storageTableName": "logs",
        "connectionString": "DefaultEnd...ountKey=Eby8...GMGw=="
      }
    },
    {
      "Name": "AzureDocumentDB",
      "Args": {
        "endpointUrl": "https://contoso.documents.azure.com:443",
        "authorizationKey": "Eby8...GMGw=="
      }
    }
  ]
}

A configuração mostrada no arquivo ON anterior JSé armazenada no Azure Key Vault usando notação de traço duplo (--) e segmentos numéricos:

Chave Valor
Serilog--WriteTo--0--Name AzureTableStorage
Serilog--WriteTo--0--Args--storageTableName logs
Serilog--WriteTo--0--Args--connectionString DefaultEnd...ountKey=Eby8...GMGw==
Serilog--WriteTo--1--Name AzureDocumentDB
Serilog--WriteTo--1--Args--endpointUrl https://contoso.documents.azure.com:443
Serilog--WriteTo--1--Args--authorizationKey Eby8...GMGw==

Recarregar segredos

Os segredos são armazenados em cache até que IConfigurationRoot.Reload seja chamado. Os segredos desabilitados ou atualizados subsequentemente no cofre não são respeitados pelo aplicativo até que Reload seja executado.

Configuration.Reload();

Segredos desabilitados e expirados

Os segredos expirados são incluídos por padrão no provedor de configuração. Para excluir valores desses segredos na configuração do aplicativo, atualize o segredo expirado ou forneça a configuração usando um provedor de configuração personalizado:

class SampleKeyVaultSecretManager : KeyVaultSecretManager
{
  public override bool Load(SecretProperties properties) =>
    properties.ExpiresOn.HasValue &&
    properties.ExpiresOn.Value > DateTimeOffset.Now;
}

Passe esse KeyVaultSecretManager personalizado para AddAzureKeyVault:

// using Azure.Extensions.AspNetCore.Configuration.Secrets;

config.AddAzureKeyVault(
    new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
    new DefaultAzureCredential(),
    new SampleKeyVaultSecretManager());

Os segredos desabilitados não podem ser recuperados no Key Vault e nunca são incluídos.

Solucionar problemas

Quando o aplicativo falha ao carregar a configuração usando o provedor, uma mensagem de erro é gravada na infraestrutura de registro em log do ASP.NET Core. As seguintes condições impedirão o carregamento da configuração:

  • O aplicativo ou certificado não está configurado corretamente no Azure AD.
  • O cofre não existe no Azure Key Vault.
  • O aplicativo não está autorizado a acessar o cofre.
  • A política de acesso não inclui as permissões Get e List.
  • No cofre, os dados de configuração (par nome-valor) estão nomeados incorretamente, ausentes ou desabilitados.
  • O aplicativo tem o nome errado do Key Vault (KeyVaultName), da ID de aplicativo do Azure AD (AzureADApplicationId) ou da impressão digital do certificado do Azure AD (AzureADCertThumbprint) ou da ID do Diretório do Azure AD (AzureADDirectoryId).
  • Ao adicionar a política de acesso do Key Vault para o aplicativo, a política foi criada, mas o botão Salvar não foi selecionado na interface do usuário de políticas de acesso.

Recursos adicionais