Proveedor de configuración de Azure Key Vault en ASP.NET Core

En este documento se explica cómo usar el proveedor de Azure Key Vault para cargar valores de configuración de la aplicación desde Azure Key Vault secretos. Azure Key Vault es un servicio basado en la nube que ayuda a proteger las claves criptográficas y los secretos que usan las aplicaciones y los servicios. Los escenarios comunes para usar Azure Key Vault con ASP.NET Core aplicaciones incluyen:

  • Controlar el acceso a datos de configuración confidenciales.
  • Cumplir el requisito de módulos de seguridad de hardware (HSM) validados por FIPS 140-2 nivel 2 al almacenar datos de configuración.

Vea o descargue el código de ejemplo (cómo descargarlo)

Paquetes

Agregue referencias de paquete para los siguientes paquetes:

Aplicación de ejemplo

La aplicación de ejemplo se ejecuta en cualquiera de los dos modos determinados por la directiva #define de preprocesador en la parte superior de Program.cs:

  • Certificate: muestra cómo usar un identificador Azure Key Vault cliente y un certificado X.509 para acceder a los secretos almacenados en Azure Key Vault. Este ejemplo se puede ejecutar desde cualquier ubicación, ya sea implementada en Azure App Service o cualquier host que pueda servir una ASP.NET Core aplicación.
  • Managed: muestra cómo usar identidades administradas para recursos de Azure. La identidad administrada autentica la aplicación para Azure Key Vault autenticación Azure Active Directory (AD) sin credenciales almacenadas en el código o la configuración de la aplicación. Cuando se usan identidades administradas para autenticarse, no Azure AD identificador de aplicación y contraseña (secreto de cliente). La Managed versión del ejemplo debe implementarse en Azure. Siga las instrucciones de la sección Uso de identidades administradas para recursos de Azure.

Para obtener más información sobre cómo configurar una aplicación de ejemplo mediante directivas de preprocesador ( #define ), vea Introducción a ASP.NET Core .

Almacenamiento de secretos en el entorno de desarrollo

Establezca los secretos localmente mediante el Administrador de secretos. Cuando la aplicación de ejemplo se ejecuta en el equipo local en el entorno de desarrollo, los secretos se cargan desde el almacén de secretos de usuario local.

Secret Manager requiere una <UserSecretsId> propiedad en el archivo de proyecto de la aplicación. Establezca el valor de propiedad ( {GUID} ) en cualquier GUID único:

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

Los secretos se crean como pares nombre-valor. Los valores jerárquicos (secciones de configuración) usan (dos puntos) como separador en ASP.NET Core : de clave de configuración.

Secret Manager se usa desde un shell de comandos abierto en la raíz de contenido del proyecto,donde {SECRET NAME} es el nombre y es el {SECRET VALUE} valor:

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

Ejecute los siguientes comandos en un shell de comandos desde la raíz de contenido del proyecto para establecer los secretos de la aplicación de ejemplo:

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

Cuando estos secretos se almacenan en Azure Key Vault almacenamiento secreto en el entorno de producción con Azure Key Vault, el _dev sufijo se cambia a _prod . El sufijo proporciona una indicación visual en la salida de la aplicación que indica el origen de los valores de configuración.

Almacenamiento de secretos en el entorno de producción con Azure Key Vault

Complete los pasos siguientes para crear un Azure Key Vault almacenar los secretos de la aplicación de ejemplo en él. Para más información, consulte Inicio rápido: Establecimiento y recuperación de un secreto desde Azure Key Vault mediante la CLI de Azure.

  1. Abra Azure Cloud Shell mediante cualquiera de los métodos siguientes en el Azure Portal:

    • Seleccione Pruébelo en la esquina superior derecha de un bloque de código. Use la cadena de búsqueda "CLI de Azure" en el cuadro de texto.
    • Abra Cloud Shell en el explorador con el botón Iniciar Cloud Shell inicio.
    • Seleccione el Cloud Shell en el menú de la esquina superior derecha de la Azure Portal.

    Para obtener más información, vea CLI de Azure overview of Azure Cloud Shell.

  2. Si aún no está autenticado, inicie sesión con el az login comando .

  3. Cree un grupo de recursos con el siguiente comando, donde es el nombre del nuevo grupo de recursos {RESOURCE GROUP NAME} y es la región de {LOCATION} Azure:

    az group create --name "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  4. Cree un almacén de claves en el grupo de recursos con el siguiente comando, donde es el nombre del nuevo almacén de claves {KEY VAULT NAME} y es la región de {LOCATION} Azure:

    az keyvault create --name {KEY VAULT NAME} --resource-group "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  5. Cree secretos en el almacén de claves como pares nombre-valor.

    Azure Key Vault secretos se limitan a caracteres alfanuméricos y guiones. Los valores jerárquicos (secciones de configuración) usan (dos guiones) como delimitador, ya que no se permiten dos puntos en los nombres de -- secretos del almacén de claves. Dos puntos delimitan una sección de una subclave en ASP.NET Core configuración. La secuencia de dos guiones se reemplaza por dos puntos cuando los secretos se cargan en la configuración de la aplicación.

    Los siguientes secretos se usan con la aplicación de ejemplo. Los valores incluyen un sufijo para distinguirlos de los valores de _prod sufijo _dev cargados en el entorno de desarrollo del Administrador de secretos. Reemplace {KEY VAULT NAME} por el nombre del almacén de claves que creó en el paso 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"
    

Uso del identificador de aplicación y el certificado X.509 para aplicaciones no hospedadas en Azure

Configure Azure AD, Azure Key Vault y la aplicación para usar un identificador de aplicación de Azure AD y un certificado X.509 para autenticarse en un almacén de claves cuando la aplicación se hospeda fuera de Azure. Para más información, consulte el artículo About keys, secrets, and certificates (Claves, secretos y certificados).

Nota

Aunque se admite el uso de un identificador de aplicación y un certificado X.509 para las aplicaciones hospedadas en Azure, no se recomienda. En su lugar, use Identidades administradas para recursos de Azure al hospedar una aplicación en Azure. Las identidades administradas no requieren almacenar un certificado en la aplicación o en el entorno de desarrollo.

La aplicación de ejemplo usa un identificador de aplicación y un certificado X.509 cuando la directiva de preprocesador de la parte superior #define de Program.cs está establecida en Certificate .

  1. Cree un certificado PKCS #12 archive (.pfx). Las opciones para crear certificados incluyen MakeCert en Windows y OpenSSL.
  2. Instale el certificado en el almacén de certificados personal del usuario actual. Marcar la clave como exportable es opcional. Tenga en cuenta la huella digital del certificado, que se usa más adelante en este proceso.
  3. Exporte el certificado PKCS #12 archive (.pfx) como un certificado codificado con DER (.cer).
  4. Registre la aplicación con Azure AD (Registros de aplicaciones).
  5. Upload certificado codificado con DER (.cer) para Azure AD:
    1. Seleccione la aplicación en Azure AD.
    2. Vaya a Certificados & secretos.
    3. Seleccione Upload certificado para cargar el certificado, que contiene la clave pública. Un certificado .cer, .pem o .crt es aceptable.
  6. Almacene el nombre del almacén de claves, el identificador de aplicación y la huella digital del certificado en el archivo de la appsettings.json aplicación.
  7. Vaya a Almacenes de claves en la Azure Portal.
  8. Seleccione el almacén de claves que creó en el almacenamiento secreto en el entorno de producción con Azure Key Vault sección.
  9. Seleccione Directivas de acceso.
  10. Seleccione Agregar directiva de acceso.
  11. Abra permisos secretos y proporcione a la aplicación los permisos Get y List.
  12. Seleccione Seleccionar entidad de seguridad y seleccione la aplicación registrada por nombre. Seleccione el botón Seleccionar.
  13. Seleccione Aceptar.
  14. Seleccione Guardar.
  15. Implemente la aplicación.

La Certificate aplicación de ejemplo obtiene sus valores de configuración de con el mismo nombre que el nombre del IConfigurationRoot secreto:

  • Valores no jerárquicos: el valor de SecretName se obtiene con config["SecretName"] .
  • Valores jerárquicos (secciones): use : la notación (dos puntos) o el GetSection método de extensión. Use cualquiera de estos enfoques para obtener el valor de configuración:
    • config["Section:SecretName"]
    • config.GetSection("Section")["SecretName"]

El sistema operativo administra el certificado X.509. La aplicación llama AddAzureKeyVault a con valores proporcionados por el archivo 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 ejemplo:

  • Nombre del almacén de claves: contosovault
  • Id. de aplicación: 627e911e-43cc-61d4-992e-12db9c81b413
  • Huella digital del certificado: fe14593dd66b2406c5269d742d04b6e1ab03adb1

appsettings.json:

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

Al ejecutar la aplicación, una página web muestra los valores de secreto cargados. En el entorno de desarrollo, los valores secretos se cargan con el _dev sufijo . En el entorno de producción, los valores se cargan con el _prod sufijo .

Uso de identidades administradas para recursos de Azure

Una aplicación implementada en Azure puede aprovechar las identidades administradas para los recursos de Azure. Una identidad administrada permite que la aplicación se autentique con Azure Key Vault mediante Azure AD autenticación sin credenciales (id. de aplicación y contraseña/secreto de cliente) almacenadas en la aplicación.

La aplicación de ejemplo usa identidades administradas para los recursos de Azure cuando la directiva de preprocesador de la parte superior #define de Program.cs está establecida en Managed .

Escriba el nombre del almacén en el archivo de la appsettings.json aplicación. La aplicación de ejemplo no requiere un identificador de aplicación y una contraseña (secreto de cliente) cuando se establece en la versión, por lo que puede omitir Managed esas entradas de configuración. La aplicación se implementa en Azure y Azure la autentica para acceder a Azure Key Vault solo con el nombre del almacén almacenado en el appsettings.json archivo.

Implemente la aplicación de ejemplo en Azure App Service.

Una aplicación implementada en Azure App Service se registra automáticamente con Azure AD cuando se crea el servicio. Obtenga el identificador de objeto de la implementación para usarlo en el siguiente comando. El identificador de objeto se muestra en la Azure Portal del Identity panel de la App Service.

Con CLI de Azure y el identificador de objeto de la aplicación, proporcione a la aplicación los permisos y list para acceder al almacén de get claves:

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

Reinicie la aplicación mediante CLI de Azure, PowerShell o el Azure Portal.

La aplicación de ejemplo:

  • Crea una instancia de la clase DefaultAzureCredential. La credencial intenta obtener un token de acceso del entorno para los recursos de Azure.
  • Se crea SecretClient un nuevo con la instancia de DefaultAzureCredential .
  • La instancia se usa con una instancia de , que carga los valores secretos y reemplaza los dos guiones ( ) por dos puntos SecretClient ( ) en los nombres de KeyVaultSecretManager -- : clave.
// 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 ejemplo del nombre del almacén de claves: contosovault

appsettings.json:

{
  "KeyVaultName": "Key Vault Name"
}

Al ejecutar la aplicación, una página web muestra los valores de secreto cargados. En el entorno de desarrollo, los valores secretos tienen el _dev sufijo porque los proporciona el Administrador de secretos. En el entorno de producción, los valores se cargan con el sufijo porque los proporciona _prod Azure Key Vault.

Si recibe un error, confirme que la aplicación está registrada con Azure AD Access denied acceso al almacén de claves. Confirme que ha reiniciado el servicio en Azure.

Para obtener información sobre el uso del proveedor con una identidad administrada Azure Pipelines, consulte Creación de una conexión de servicio Azure Resource Manager a una máquina virtual con una identidad de servicio administrada.

Opciones de configuración

AddAzureKeyVault puede aceptar un AzureKeyVaultConfigurationOptions objeto :

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

El AzureKeyVaultConfigurationOptions objeto contiene las siguientes propiedades.

Propiedad Descripción
Manager IKeyVaultSecretManager instancia de utilizada para controlar la carga de secretos.
ReloadInterval TimeSpan para esperar entre intentos de sondeo del almacén de claves en busca de cambios. El valor predeterminado es null (la configuración no se vuelve a cargar).

Usar un prefijo de nombre de clave

AddAzureKeyVault proporciona una sobrecarga que acepta una implementación de , que permite controlar cómo se convierten los secretos del almacén de claves IKeyVaultSecretManager en claves de configuración. Por ejemplo, puede implementar la interfaz para cargar valores secretos en función de un valor de prefijo que proporcione al iniciar la aplicación. Esta técnica permite, por ejemplo, cargar secretos en función de la versión de la aplicación.

Advertencia

No use prefijos en los secretos del almacén de claves para:

  • Coloque los secretos de varias aplicaciones en el mismo almacén.
  • Coloque secretos de entorno (por ejemplo, de desarrollo frente a secretos de producción) en el mismo almacén.

Las distintas aplicaciones y entornos de desarrollo y producción deben usar almacenes de claves independientes para aislar los entornos de aplicación para el mayor nivel de seguridad.

En el ejemplo siguiente, se establece un secreto en el almacén de claves (y se usa el Administrador de secretos para el entorno de desarrollo) para (no se permiten períodos en los nombres de secretos del almacén 5000-AppSecret de claves). Este secreto representa un secreto de aplicación para la versión 5.0.0.0 de la aplicación. Para otra versión de la aplicación, 5.1.0.0, se agrega un secreto al almacén de claves (y se usa el Administrador de secretos) para 5100-AppSecret . Cada versión de la aplicación carga su valor de secreto con versiones en su configuración como , quitando AppSecret la versión a medida que carga el secreto.

AddAzureKeyVault Se llama a con una implementación IKeyVaultSecretManager personalizada:

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

La implementación reacciona a los prefijos de versión de los secretos para cargar el secreto adecuado en la configuración:

  • Load carga un secreto cuando su nombre comienza con el prefijo . No se cargan otros secretos.
  • GetKey:
    • Quita el prefijo del nombre del secreto.
    • Reemplaza dos guiones de cualquier nombre por , que es el delimitador utilizado en la KeyDelimiter configuración (normalmente dos puntos). Azure Key Vault no permite dos puntos en los nombres de secreto.
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);
    }
}

Un algoritmo de proveedor llama al método que recorre en iteración los secretos del almacén para buscar los secretos Load con prefijo de versión. Cuando se encuentra un prefijo de versión con , el algoritmo usa el método para devolver el Load nombre de configuración del nombre del GetKey secreto. Quita el prefijo de versión del nombre del secreto. El resto del nombre del secreto se devuelve para cargarlo en los pares nombre-valor de configuración de la aplicación.

Cuando se implementa este enfoque:

  1. Versión de la aplicación especificada en el archivo de proyecto de la aplicación. En el ejemplo siguiente, la versión de la aplicación se establece en 5.0.0.0 :

    <PropertyGroup>
      <Version>5.0.0.0</Version>
    </PropertyGroup>
    
  2. Confirme que una propiedad está presente en el archivo de proyecto de la <UserSecretsId> aplicación, donde {GUID} es un GUID proporcionado por el usuario:

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

    Guarde los siguientes secretos localmente con el Administrador de secretos:

    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. Los secretos se guardan Azure Key Vault mediante los siguientes CLI de Azure comandos:

    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. Cuando se ejecuta la aplicación, se cargan los secretos del almacén de claves. El secreto de cadena de coincide con la versión de la aplicación especificada en el 5000-AppSecret archivo de proyecto de la aplicación ( 5.0.0.0 ).

  5. La versión 5000 (con el guión) se quita del nombre de clave. En toda la aplicación, la lectura de la configuración con la AppSecret clave carga el valor del secreto.

  6. Si la versión de la aplicación cambia en el archivo de proyecto a y la aplicación se vuelve a ejecutar, el valor secreto devuelto se encuentra en el entorno de desarrollo y 5.1.0.0 5.1.0.0_secret_value_dev en 5.1.0.0_secret_value_prod producción.

Nota

También puede proporcionar su propia SecretClient implementación a AddAzureKeyVault . Un cliente personalizado permite compartir una única instancia del cliente entre la aplicación.

Enlace de una matriz a una clase

El proveedor puede leer los valores de configuración en una matriz para enlazar a una matriz POCO.

Al leer desde un origen de configuración que permite que las claves contengan separadores de dos puntos ( ), se usa un segmento de clave numérica para distinguir las claves que consten una matriz : ( :0: , , :1::{n}: ). Para obtener más información, vea Configuración: Enlazar una matriz a una clase.

Azure Key Vault claves no pueden usar dos puntos como separador. El enfoque descrito en este documento usa guiones dobles ( -- ) como separador para los valores jerárquicos (secciones). Las claves de matriz se almacenan Azure Key Vault con guiones dobles y segmentos de clave numéricos ( --0-- , --1-- , … --{n}-- ).

Examine la siguiente configuración del proveedor de registro de Serilog proporcionada por un archivo JSON. Hay dos literales de objeto definidos en la matriz que reflejan dos receptores Serilog , que describen los WriteTo destinos para registrar la salida:

"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=="
      }
    }
  ]
}

La configuración que se muestra en el archivo JSON anterior se almacena en Azure Key Vault con la notación de doble guion ( ) y -- segmentos numéricos:

Clave Value
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==

Recarga de secretos

Los secretos se almacenan en caché IConfigurationRoot.Reload() hasta que se llama a . La aplicación no respeta los secretos expirados, deshabilitados y actualizados del almacén de claves hasta que Reload se ejecuta.

Configuration.Reload();

Secretos deshabilitados y expirados

Los secretos deshabilitados y expirados inician RequestFailedException una excepción . Para evitar que la aplicación se inicia, proporcione la configuración con un proveedor de configuración diferente o actualice el secreto deshabilitado o expirado.

Solución de problemas

Cuando la aplicación no puede cargar la configuración mediante el proveedor, se escribe un mensaje de error en la infraestructura ASP.NET Core Logging. Las siguientes condiciones impedirán que se cargue la configuración:

  • La aplicación o el certificado no están configurados correctamente en Azure AD.
  • El almacén de claves no existe en Azure Key Vault.
  • La aplicación no está autorizada para acceder al almacén de claves.
  • La directiva de acceso no incluye Get los List permisos y .
  • En el almacén de claves, los datos de configuración (par nombre-valor) se denominan incorrectamente, faltan, deshabilitan o expiran.
  • La aplicación tiene el nombre de almacén de claves incorrecto ( ), Azure AD Id. de aplicación ( ) o Azure AD huella digital del certificado ( ) o Azure AD KeyVaultName AzureADApplicationId Directory ID ( AzureADCertThumbprint AzureADDirectoryId ).
  • La clave de configuración (nombre) es incorrecta en la aplicación para el valor que está intentando cargar.
  • Al agregar la directiva de acceso del almacén de claves para la aplicación, se creó la directiva, pero el botón Guardar no se seleccionó en la interfaz de usuario directivas de acceso.

Recursos adicionales

En este documento se explica cómo usar el proveedor Microsoft Azure Key Vault configuración de aplicaciones para cargar valores de configuración de aplicaciones desde Azure Key Vault secretos. Azure Key Vault es un servicio basado en la nube que ayuda a proteger las claves criptográficas y los secretos usados por aplicaciones y servicios. Los escenarios comunes para usar Azure Key Vault con ASP.NET Core aplicaciones incluyen:

  • Controlar el acceso a los datos de configuración confidenciales.
  • Cumplir el requisito de módulos de seguridad de hardware (HSM) validados por FIPS 140-2 nivel 2 al almacenar datos de configuración.

Vea o descargue el código de ejemplo (cómo descargarlo)

Paquetes

Agregue una referencia de paquete al paquete Microsoft.Extensions.Configuration.AzureKeyVault.

Aplicación de ejemplo

La aplicación de ejemplo se ejecuta en cualquiera de los dos modos determinados por la directiva #define de preprocesador en la parte superior de Program.cs:

  • Certificate: muestra cómo usar un identificador Azure Key Vault cliente y un certificado X.509 para acceder a los secretos almacenados en Azure Key Vault. Este ejemplo se puede ejecutar desde cualquier ubicación, ya sea implementada en Azure App Service o cualquier host que pueda servir una ASP.NET Core aplicación.
  • Managed: muestra el uso de identidades administradas para recursos de Azure para autenticar la aplicación Azure Key Vault con autenticación de Azure Active Directory (AD) sin credenciales almacenadas en el código o la configuración de la aplicación. Cuando se usan identidades administradas para autenticarse, Azure AD identificador de aplicación y contraseña (secreto de cliente) no son necesarios. La Managed versión del ejemplo debe implementarse en Azure. Siga las instrucciones de la sección Uso de identidades administradas para recursos de Azure.

Para obtener más información sobre cómo configurar una aplicación de ejemplo mediante directivas de preprocesador ( #define ), vea Introducción a ASP.NET Core .

Almacenamiento de secretos en el entorno de desarrollo

Establezca los secretos localmente mediante el Administrador de secretos. Cuando la aplicación de ejemplo se ejecuta en el equipo local en el entorno de desarrollo, los secretos se cargan desde el almacén de secretos de usuario local.

Secret Manager requiere una <UserSecretsId> propiedad en el archivo de proyecto de la aplicación. Establezca el valor de propiedad ( {GUID} ) en cualquier GUID único:

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

Los secretos se crean como pares nombre-valor. Los valores jerárquicos (secciones de configuración) usan (dos puntos) como separador en los : ASP.NET Core clave de configuración.

Secret Manager se usa desde un shell de comandos abierto a la raíz de contenido del proyecto,donde {SECRET NAME} es el nombre y es el {SECRET VALUE} valor:

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

Ejecute los siguientes comandos en un shell de comandos desde la raíz de contenido del proyecto para establecer los secretos de la aplicación de ejemplo:

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

Cuando estos secretos se almacenan en Azure Key Vault almacenamiento secreto en el entorno de producción con Azure Key Vault, el _dev sufijo se cambia a _prod . El sufijo proporciona una indicación visual en la salida de la aplicación que indica el origen de los valores de configuración.

Almacenamiento de secretos en el entorno de producción con Azure Key Vault

Las instrucciones proporcionadas por Inicio rápido: Establecer y recuperar un secreto de Azure Key Vault mediante CLI de Azure se resumen aquí para crear un Azure Key Vault y almacenar secretos usados por la aplicación de ejemplo.

  1. Abra Azure Cloud Shell mediante cualquiera de los métodos siguientes en el Azure Portal:

    • Seleccione Pruébelo en la esquina superior derecha de un bloque de código. Use la cadena de búsqueda "CLI de Azure" en el cuadro de texto.
    • Abra Cloud Shell en el explorador con el botón Iniciar Cloud Shell inicio.
    • Seleccione el Cloud Shell en el menú de la esquina superior derecha de la Azure Portal.

    Para obtener más información, vea CLI de Azure información general de Azure Cloud Shell.

  2. Si aún no está autenticado, inicie sesión con el az login comando .

  3. Cree un grupo de recursos con el siguiente comando, donde es el nombre del nuevo grupo de recursos {RESOURCE GROUP NAME} y es la región de {LOCATION} Azure:

    az group create --name "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  4. Cree un almacén de claves en el grupo de recursos con el siguiente comando, donde es el nombre del nuevo almacén de claves {KEY VAULT NAME} y es la región de {LOCATION} Azure:

    az keyvault create --name {KEY VAULT NAME} --resource-group "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  5. Cree secretos en el almacén de claves como pares nombre-valor.

    Azure Key Vault secretos se limitan a caracteres alfanuméricos y guiones. Los valores jerárquicos (secciones de configuración) usan (dos guiones) como delimitador, ya que no se permiten dos puntos en los nombres de secretos -- del almacén de claves. Los dos puntos delimitan una sección de una subclave en ASP.NET Core configuración . La secuencia de dos guiones se reemplaza por dos puntos cuando los secretos se cargan en la configuración de la aplicación.

    Los siguientes secretos se usan con la aplicación de ejemplo. Los valores incluyen un sufijo para distinguirlos de los valores de _prod sufijo _dev cargados en el entorno de desarrollo del Administrador de secretos. Reemplace {KEY VAULT NAME} por el nombre del almacén de claves que creó en el paso 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"
    

Uso del identificador de aplicación y el certificado X.509 para aplicaciones no hospedadas en Azure

Configure Azure AD, Azure Key Vault y la aplicación para usar un identificador de aplicación de Azure AD y un certificado X.509 para autenticarse en un almacén de claves cuando la aplicación se hospeda fuera de Azure. Para más información, consulte el artículo About keys, secrets, and certificates (Claves, secretos y certificados).

Nota

Aunque se admite el uso de un identificador de aplicación y un certificado X.509 para las aplicaciones hospedadas en Azure, no se recomienda. En su lugar, use Identidades administradas para los recursos de Azure al hospedar una aplicación en Azure. Las identidades administradas no requieren almacenar un certificado en la aplicación o en el entorno de desarrollo.

La aplicación de ejemplo usa un identificador de aplicación y un certificado X.509 cuando la instrucción de la parte superior del #define archivo Program.cs se establece en Certificate .

  1. Cree un PKCS #12 archive (.pfx). Las opciones para crear certificados incluyen MakeCert en Windows y OpenSSL.
  2. Instale el certificado en el almacén de certificados personal del usuario actual. Marcar la clave como exportable es opcional. Tenga en cuenta la huella digital del certificado, que se usa más adelante en este proceso.
  3. Exporte el PKCS #12 archive (.pfx) como un certificado codificado con DER (.cer).
  4. Registre la aplicación con Azure AD (Registros de aplicaciones).
  5. Upload certificado codificado con DER (.cer) para Azure AD:
    1. Seleccione la aplicación en Azure AD.
    2. Vaya a Certificados & secretos.
    3. Seleccione Upload certificado para cargar el certificado, que contiene la clave pública. Un certificado .cer, .pem o .crt es aceptable.
  6. Almacene el nombre del almacén de claves, el identificador de aplicación y la huella digital del certificado en el archivo de la appsettings.json aplicación.
  7. Vaya a Almacenes de claves en la Azure Portal.
  8. Seleccione el almacén de claves que creó en el almacenamiento secreto en el entorno de producción con Azure Key Vault sección.
  9. Seleccione Directivas de acceso.
  10. Seleccione Agregar directiva de acceso.
  11. Abra permisos secretos y proporcione a la aplicación los permisos Obtener y Enumerar.
  12. Seleccione Seleccionar entidad de seguridad y seleccione la aplicación registrada por nombre. Seleccione el botón Seleccionar.
  13. Seleccione Aceptar.
  14. Seleccione Guardar.
  15. Implemente la aplicación.

La Certificate aplicación de ejemplo obtiene sus valores de configuración de con el mismo nombre que el nombre del IConfigurationRoot secreto:

  • Valores no jerárquicos: el valor SecretName de se obtiene con config["SecretName"] .
  • Valores jerárquicos (secciones): use : la notación (dos puntos) o el GetSection método de extensión. Use cualquiera de estos enfoques para obtener el valor de configuración:
    • config["Section:SecretName"]
    • config.GetSection("Section")["SecretName"]

El sistema operativo administra el certificado X.509. La aplicación llama AddAzureKeyVault a con valores proporcionados por el archivo appsettings.json :

// using System.Linq;
// using System.Security.Cryptography.X509Certificates;
// using Microsoft.Extensions.Configuration;

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.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(
                        $"https://{builtConfig["KeyVaultName"]}.vault.azure.net/",
                        builtConfig["AzureADApplicationId"],
                        certs.OfType<X509Certificate2>().Single());

                    store.Close();
                }
            }
        })
        .UseStartup<Startup>();

Valores de ejemplo:

  • Nombre del almacén de claves: contosovault
  • Id. de aplicación: 627e911e-43cc-61d4-992e-12db9c81b413
  • Huella digital del certificado: fe14593dd66b2406c5269d742d04b6e1ab03adb1

appsettings.json:

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

Al ejecutar la aplicación, una página web muestra los valores de secreto cargados. En el entorno de desarrollo, los valores secretos se cargan con el _dev sufijo . En el entorno de producción, los valores se cargan con el _prod sufijo .

Uso de identidades administradas para recursos de Azure

Una aplicación implementada en Azure puede aprovechar las identidades administradas de los recursos de Azure. Una identidad administrada permite que la aplicación se autentique con Azure Key Vault mediante Azure AD sin credenciales (id. de aplicación y contraseña/secreto de cliente) almacenadas en la aplicación.

La aplicación de ejemplo usa identidades administradas para los recursos de Azure cuando la instrucción de la parte superior del #define archivo Program.cs está establecida en Managed .

Escriba el nombre del almacén en el archivo de la appsettings.json aplicación. La aplicación de ejemplo no requiere un identificador de aplicación y una contraseña (secreto de cliente) cuando se establece en la versión, por lo que puede omitir Managed esas entradas de configuración. La aplicación se implementa en Azure y Azure autentica la aplicación para acceder a Azure Key Vault solo con el nombre del almacén almacenado en el appsettings.json archivo.

Implemente la aplicación de ejemplo en Azure App Service.

Una aplicación implementada en Azure App Service se registra automáticamente con Azure AD cuando se crea el servicio. Obtenga el identificador de objeto de la implementación para usarlo en el siguiente comando. El identificador de objeto se muestra en la Azure Portal en el Identity panel de la App Service.

Con CLI de Azure y el identificador de objeto de la aplicación, proporcione a la aplicación los permisos y list para acceder al almacén de get claves:

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

Reinicie la aplicación mediante CLI de Azure, PowerShell o el Azure Portal.

La aplicación de ejemplo:

  • Crea una instancia de la AzureServiceTokenProvider clase sin una cadena de conexión. Cuando no se proporciona una cadena de conexión, el proveedor intenta obtener un token de acceso de identidades administradas para recursos de Azure.
  • Se crea un KeyVaultClient nuevo con la devolución de llamada del AzureServiceTokenProvider token de instancia.
  • La instancia se usa con una implementación predeterminada de que carga todos los valores secretos y reemplaza los dos guiones ( ) por dos puntos KeyVaultClient ( ) en los nombres de IKeyVaultSecretManager -- : clave.
// using Microsoft.Azure.KeyVault;
// using Microsoft.Azure.Services.AppAuthentication;
// using Microsoft.Extensions.Configuration.AzureKeyVault;

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

                var azureServiceTokenProvider = new AzureServiceTokenProvider();
                var keyVaultClient = new KeyVaultClient(
                    new KeyVaultClient.AuthenticationCallback(
                        azureServiceTokenProvider.KeyVaultTokenCallback));

                config.AddAzureKeyVault(
                    $"https://{builtConfig["KeyVaultName"]}.vault.azure.net/",
                    keyVaultClient,
                    new DefaultKeyVaultSecretManager());
            }
        })
        .UseStartup<Startup>();

Valor de ejemplo del nombre del almacén de claves: contosovault

appsettings.json:

{
  "KeyVaultName": "Key Vault Name"
}

Al ejecutar la aplicación, una página web muestra los valores de secreto cargados. En el entorno de desarrollo, los valores secretos tienen el _dev sufijo porque los proporciona el Administrador de secretos. En el entorno de producción, los valores se cargan con el sufijo porque los proporciona _prod Azure Key Vault.

Si recibe un error, confirme que la aplicación está registrada con Azure AD Access denied acceso al almacén de claves. Confirme que ha reiniciado el servicio en Azure.

Para obtener información sobre el uso del proveedor con una identidad administrada Azure Pipelines, consulte Creación de una conexión de servicio Azure Resource Manager a una máquina virtual con una identidad de servicio administrada.

Usar un prefijo de nombre de clave

AddAzureKeyVault proporciona una sobrecarga que acepta una implementación de IKeyVaultSecretManager . Esta sobrecarga permite controlar cómo se convierten los secretos del almacén de claves en claves de configuración. Por ejemplo, puede implementar la interfaz para cargar valores secretos en función de un valor de prefijo que proporcione al iniciar la aplicación. Esta técnica permite, por ejemplo, cargar secretos en función de la versión de la aplicación.

Advertencia

No use prefijos en los secretos del almacén de claves para colocar secretos de varias aplicaciones en el mismo almacén de claves ni para colocar secretos de entorno (por ejemplo, de desarrollo frente a secretos de producción) en el mismo almacén. Se recomienda que las distintas aplicaciones y entornos de desarrollo y producción usen almacenes de claves independientes para aislar los entornos de aplicación para el mayor nivel de seguridad.

En el ejemplo siguiente, se establece un secreto en el almacén de claves (y se usa el Administrador de secretos para el entorno de desarrollo) para (no se permiten períodos en los nombres de secretos del almacén 5000-AppSecret de claves). Este secreto representa un secreto de aplicación para la versión 5.0.0.0 de la aplicación. Para otra versión de la aplicación, 5.1.0.0, se agrega un secreto al almacén de claves (y se usa el Administrador de secretos) para 5100-AppSecret . Cada versión de la aplicación carga su valor de secreto con versiones en su configuración como , quitando AppSecret la versión a medida que carga el secreto.

AddAzureKeyVault Se llama a con un IKeyVaultSecretManager personalizado:

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

La implementación reacciona a los prefijos de versión de IKeyVaultSecretManager los secretos para cargar el secreto adecuado en la configuración:

  • Load carga un secreto cuando su nombre comienza con el prefijo . No se cargan otros secretos.
  • GetKey:
    • Quita el prefijo del nombre del secreto.
    • Reemplaza dos guiones de cualquier nombre por , que es el delimitador utilizado en la configuración KeyDelimiter (normalmente dos puntos). Azure Key Vault no permite dos puntos en los nombres de secreto.
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);
    }
}

Un algoritmo de proveedor llama al método que recorre en iteración los secretos del almacén para buscar los que Load tienen el prefijo de versión. Cuando se encuentra un prefijo de versión con , el algoritmo usa el método para devolver el nombre Load de configuración del nombre del GetKey secreto. Quita el prefijo de versión del nombre del secreto. El resto del nombre del secreto se devuelve para cargarlo en los pares nombre-valor de configuración de la aplicación.

Cuando se implementa este enfoque:

  1. Versión de la aplicación especificada en el archivo de proyecto de la aplicación. En el ejemplo siguiente, la versión de la aplicación se establece en 5.0.0.0 :

    <PropertyGroup>
      <Version>5.0.0.0</Version>
    </PropertyGroup>
    
  2. Confirme que una propiedad está presente en el archivo de proyecto de la <UserSecretsId> aplicación, donde {GUID} es un GUID proporcionado por el usuario:

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

    Guarde los siguientes secretos localmente con el Administrador de secretos:

    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. Los secretos se guardan Azure Key Vault mediante los siguientes CLI de Azure comandos:

    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. Cuando se ejecuta la aplicación, se cargan los secretos del almacén de claves. El secreto de cadena de coincide con la versión de la aplicación especificada en el archivo de proyecto de 5000-AppSecret la aplicación ( 5.0.0.0 ).

  5. La versión 5000 (con el guion) se quita del nombre de clave. En toda la aplicación, la lectura de la configuración con la AppSecret clave carga el valor del secreto.

  6. Si la versión de la aplicación cambia en el archivo de proyecto a y la aplicación se vuelve a ejecutar, el valor secreto devuelto se encuentra en el entorno de desarrollo y 5.1.0.0 5.1.0.0_secret_value_dev en 5.1.0.0_secret_value_prod producción.

Nota

También puede proporcionar su propia KeyVaultClient implementación a AddAzureKeyVault . Un cliente personalizado permite compartir una única instancia del cliente entre la aplicación.

Enlace de una matriz a una clase

El proveedor puede leer los valores de configuración en una matriz para enlazar a una matriz POCO.

Al leer desde un origen de configuración que permite que las claves contengan separadores de dos puntos ( ), se usa un segmento de clave numérica para distinguir las claves que consten una matriz : ( :0: , , :1::{n}: ). Para obtener más información, vea Configuración: Enlazar una matriz a una clase.

Azure Key Vault claves no pueden usar dos puntos como separador. El enfoque descrito en este documento usa guiones dobles ( -- ) como separador para los valores jerárquicos (secciones). Las claves de matriz se almacenan Azure Key Vault con guiones dobles y segmentos de clave numéricos ( --0-- , --1-- , … --{n}-- ).

Examine la siguiente configuración del proveedor de registro de Serilog proporcionada por un archivo JSON. Hay dos literales de objeto definidos en la matriz que reflejan dos receptores Serilog , que describen los WriteTo destinos para registrar la salida:

"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=="
      }
    }
  ]
}

La configuración que se muestra en el archivo JSON anterior se almacena en Azure Key Vault con la notación de doble guion ( ) y -- segmentos numéricos:

Clave Value
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==

Recarga de secretos

Los secretos se almacenan en caché IConfigurationRoot.Reload() hasta que se llama a . La aplicación no respeta los secretos expirados, deshabilitados y actualizados del almacén de claves hasta que Reload se ejecuta.

Configuration.Reload();

Secretos deshabilitados y expirados

Los secretos deshabilitados y expirados inician una KeyVaultErrorException excepción . Para evitar que la aplicación se inicia, proporcione la configuración con un proveedor de configuración diferente o actualice el secreto deshabilitado o expirado.

Solución de problemas

Cuando la aplicación no puede cargar la configuración mediante el proveedor, se escribe un mensaje de error en la infraestructura ASP.NET Core Logging. Las siguientes condiciones impedirán que se cargue la configuración:

  • La aplicación o el certificado no están configurados correctamente en Azure AD.
  • El almacén de claves no existe en Azure Key Vault.
  • La aplicación no está autorizada para acceder al almacén de claves.
  • La directiva de acceso no incluye Get los List permisos y .
  • En el almacén de claves, los datos de configuración (par nombre-valor) se denominan incorrectamente, faltan, deshabilitan o expiran.
  • La aplicación tiene el nombre de almacén de claves incorrecto ( ), Azure AD id. de aplicación ( ) o Azure AD huella digital KeyVaultName AzureADApplicationId del certificado ( AzureADCertThumbprint ).
  • La clave de configuración (nombre) es incorrecta en la aplicación para el valor que está intentando cargar.
  • Al agregar la directiva de acceso de la aplicación al almacén de claves, se creó la directiva, pero el botón Guardar no se seleccionó en la interfaz de usuario directivas de acceso.

Recursos adicionales