Partekatu honen bidez:


Uso de referencias de Key Vault como configuración de la aplicación en Azure App Service y Azure Functions

En este artículo se muestra cómo usar secretos de Azure Key Vault como valores de la configuración de la aplicación o cadenas de conexión en las aplicaciones de Azure App Service o Azure Functions.

Key Vault es un servicio que proporciona administración centralizada de secretos, con control total sobre las directivas de acceso y el historial de auditoría. Cuando una configuración de aplicación o una cadena de conexión es una referencia de Key Vault, el código de la aplicación puede usarlo como cualquier otra configuración de aplicación o cadena de conexión. De este modo, puede mantener los secretos separados de la configuración de la aplicación. La configuración de la aplicación se cifra de forma segura cuando está en reposo, pero si necesita capacidades para administrar secretos, se deben almacenar en un almacén de claves.

Conceder a la aplicación acceso a un almacén de claves

Para leer secretos desde un almacén de claves, primero debe crear un almacén y conceder permiso a la aplicación para acceder a él:

  1. Para crear un almacén de claves, siga la guía de inicio rápido de Key Vault.

  2. Cree una identidad administrada para la aplicación.

    Las referencias del almacén de claves usan la identidad asignada por el sistema de la aplicación de forma predeterminada, pero puede especificar una identidad asignada por el usuario.

  3. Autorice acceso de lectura a los secretos del almacén de claves para la identidad administrada que ha creado. La forma de hacerlo depende del modelo de permisos del almacén de claves:

Acceso a almacenes restringidos de red

Si el almacén está configurado con restricciones de red, asegúrese de que la aplicación tenga acceso a la red. Los almacenes no deberían depender de las direcciones IP de salida públicas de la aplicación porque la dirección IP de origen de la solicitud secreta podría ser diferente. En su lugar, el almacén debería configurarse para aceptar tráfico de una red virtual que usa la aplicación.

  1. Asegúrese de que la aplicación tiene configuradas las funcionalidades de red salientes, como se describe en Características de red de App Service y opciones de red de Azure Functions.

    Actualmente, las aplicaciones Linux que se conectan a puntos de conexión privados deben configurarse explícitamente para enrutar todo el tráfico a través de la red virtual. Para establecer esta configuración, ejecute el siguiente comando:

    az webapp config set --resource-group <group-name>  --subscription <subscription> --name <app-name> --generic-configurations '{"vnetRouteAllEnabled": true}'
    
  2. Asegúrese de que la configuración del almacén permita a la red o la subred que la aplicación usa acceder al almacén.

Tenga en cuenta que, incluso si ha configurado correctamente el almacén para aceptar el tráfico de la red virtual, los registros de auditoría del almacén pueden seguir mostrando un evento SecretGet con errores (403 - Prohibido) desde la dirección IP de salida pública de la aplicación. Esto va seguido de un evento SecretGet correcto desde la dirección IP privada de la aplicación y es por diseño.

Acceso a los almacenes con una identidad asignada por el usuario

Algunas aplicaciones necesitan hacer referencia a secretos en el momento de la creación, cuando una identidad asignada por el sistema aún no está disponible. En estos casos, cree una identidad asignada por el usuario y concédale acceso al almacén de antemano.

Después de conceder permisos a la identidad asignada por el usuario, siga estos pasos:

  1. Asigne la identidad a la aplicación.

  2. Configure la aplicación para que use esta identidad para las operaciones de referencia de Key Vault estableciendo la keyVaultReferenceIdentity propiedad en el identificador de recurso de la identidad asignada por el usuario:

    identityResourceId=$(az identity show --resource-group <group-name> --name <identity-name> --query id -o tsv)
    az webapp update --resource-group <group-name> --name <app-name> --set keyVaultReferenceIdentity=${identityResourceId}
    

Esta configuración se aplica a todas las referencias de Key Vault para la aplicación.

Descripción de la rotación

Si no se especifica la versión del secreto en la referencia, la aplicación usa la versión más reciente que exista en el almacén de claves. Cuando las versiones más recientes estén disponibles, como con la rotación, la aplicación se actualiza automáticamente y comienza a usar la versión más reciente en un plazo de 24 horas.

El retraso se debe a que App Service almacena en caché los valores de las referencias de Key Vault y los vuelve a capturar cada 24 horas. Cualquier cambio de configuración en la aplicación hace que la aplicación se reinicie y que se vuelvan a recuperar inmediatamente todos los secretos a los que se hace referencia.

Para forzar la resolución de las referencias de Key Vault de la aplicación, realice una solicitud POST autenticada al punto de conexión de API https://management.azure.com/[Resource ID]/config/configreferences/appsettings/refresh?api-version=2022-03-01.

Descripción de la configuración de la aplicación de origen de Key Vault

Para usar una referencia de Key Vault, establezca la referencia como el valor de la configuración. La aplicación puede hacer referencia al secreto mediante su clave de la forma habitual. No se requiere ningún cambio de código.

Sugerencia

Dado que debe tener almacenes independientes para cada entorno, la mayoría de los ajustes de la aplicación que usan referencias de Key Vault deben marcarse como ajustes de ranura, porque requieren tener almacenes independientes para cada entorno.

Una referencia de Key Vault tiene el formato @Microsoft.KeyVault({referenceString}), donde {referenceString} tiene uno de los siguientes formatos:

Cadena de referencia Descripción
SecretUri=<secretUri> El SecretUri debe ser el URI completo del plano de datos de un secreto en el almacén. Por ejemplo: https://myvault.vault.azure.net/secrets/mysecret. Opcionalmente, incluya una versión, como https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931.
VaultName=<vaultName>;SecretName=<secretName>;SecretVersion=<secretVersion> El valor VaultName es necesario y es el nombre del almacén. El valor SecretName es obligatorio y es el nombre del secreto. El SecretVersion valor es opcional, pero, si está presente, indica la versión del secreto que se va a usar.

Por ejemplo, una referencia completa sin una versión específica tendría el siguiente aspecto:

@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret)

O bien:

@Microsoft.KeyVault(VaultName=myvault;SecretName=mysecret)

Consideraciones para el montaje de Azure Files

Las aplicaciones pueden usar la configuración de la aplicación WEBSITE_CONTENTAZUREFILECONNECTIONSTRING para montar Azure Files como el sistema de archivos. Esta configuración tiene comprobaciones de validación para garantizar que la aplicación se puede iniciar correctamente.

La plataforma se basa en compartir contenido dentro de Azure Files. La plataforma supone un nombre predeterminado a menos que se especifique uno mediante la WEBSITE_CONTENTSHARE configuración . En el caso de las solicitudes que modifiquen esta configuración, la plataforma valida que existe este recurso compartido de contenido. Si el recurso compartido de contenido no existe, la plataforma intenta crearlo. Si la plataforma no puede encontrar ni crear el recurso compartido de contenido, bloquea la solicitud.

Cuando se usan referencias de Key Vault en esta configuración, se produce un error en la comprobación de validación de forma predeterminada, ya que el secreto no se puede resolver durante el procesamiento de la solicitud entrante. Para evitar este problema, puede omitir la validación configurando WEBSITE_SKIP_CONTENTSHARE_VALIDATION como 1. Esta configuración indica a App Service que omita todas las comprobaciones y no cree el recurso compartido de contenido automáticamente. Debe asegurarse de que el recurso compartido de contenido se crea de antemano.

Precaución

Si omite la validación y la cadena de conexión o el recurso compartido de contenido no son válidos, la aplicación no se inicia correctamente y crea errores HTTP 500.

Como parte de la creación de la aplicación, se podría producir un error al intentar montar el recurso compartido de contenido porque los permisos de identidad administrada no se propagan o la integración de red virtual no está configurada. Puede aplazar la configuración de Azure Files hasta más adelante en la plantilla de implementación para dar cabida a este comportamiento. Para más información, consulte Implementación de Azure Resource Manager más adelante en este artículo.

En este caso, App Service usa un sistema de archivos predeterminado hasta que se configura Azure Files, y los archivos no se copian. Debe asegurarse de que no se produzca ningún intento de implementación durante el período provisional antes de montar Azure Files.

Consideraciones sobre la instrumentación de Application Insights

Las aplicaciones pueden usar la configuración de la aplicación APPINSIGHTS_INSTRUMENTATIONKEY o APPLICATIONINSIGHTS_CONNECTION_STRING para integrarse con Application Insights.

Para App Service y Azure Functions, Azure Portal también usa esta configuración para exponer los datos de telemetría del recurso. Si se hace referencia a estos valores desde Key Vault, este enfoque no está disponible. En su lugar, debe trabajar directamente con el recurso de Application Insights para ver la telemetría. Sin embargo, estos valores no se consideran secretos, por lo que puede considerar la posibilidad de configurarlos directamente en lugar de usar referencias de Key Vault.

Implementación de Azure Resource Manager

Al automatizar las implementaciones de recursos a través de plantillas de Azure Resource Manager, es posible que tenga que secuenciar las dependencias en un orden determinado. Asegúrese de definir la configuración de la aplicación como su propio recurso en lugar de usar una propiedad siteConfig en la definición de la aplicación. La aplicación debe definirse primero para que la identidad asignada por el sistema se cree con ella y se pueda usar en la directiva de acceso.

La siguiente pseudoplantilla es un ejemplo de cómo podría ser una aplicación de funciones:

{
    //...
    "resources": [
        {
            "type": "Microsoft.Storage/storageAccounts",
            "name": "[variables('storageAccountName')]",
            //...
        },
        {
            "type": "Microsoft.Insights/components",
            "name": "[variables('appInsightsName')]",
            //...
        },
        {
            "type": "Microsoft.Web/sites",
            "name": "[variables('functionAppName')]",
            "identity": {
                "type": "SystemAssigned"
            },
            //...
            "resources": [
                {
                    "type": "config",
                    "name": "appsettings",
                    //...
                    "dependsOn": [
                        "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]",
                        "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]",
                        "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('storageConnectionStringName'))]",
                        "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('appInsightsKeyName'))]"
                    ],
                    "properties": {
                        "AzureWebJobsStorage": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('storageConnectionStringName')).secretUriWithVersion, ')')]",
                        "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('storageConnectionStringName')).secretUriWithVersion, ')')]",
                        "APPINSIGHTS_INSTRUMENTATIONKEY": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('appInsightsKeyName')).secretUriWithVersion, ')')]",
                        "WEBSITE_ENABLE_SYNC_UPDATE_SITE": "true"
                        //...
                    }
                },
                {
                    "type": "sourcecontrols",
                    "name": "web",
                    //...
                    "dependsOn": [
                        "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]",
                        "[resourceId('Microsoft.Web/sites/config', variables('functionAppName'), 'appsettings')]"
                    ],
                }
            ]
        },
        {
            "type": "Microsoft.KeyVault/vaults",
            "name": "[variables('keyVaultName')]",
            //...
            "dependsOn": [
                "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]"
            ],
            "properties": {
                //...
                "accessPolicies": [
                    {
                        "tenantId": "[reference(resourceId('Microsoft.Web/sites/', variables('functionAppName')), '2020-12-01', 'Full').identity.tenantId]",
                        "objectId": "[reference(resourceId('Microsoft.Web/sites/', variables('functionAppName')), '2020-12-01', 'Full').identity.principalId]",
                        "permissions": {
                            "secrets": [ "get" ]
                        }
                    }
                ]
            },
            "resources": [
                {
                    "type": "secrets",
                    "name": "[variables('storageConnectionStringName')]",
                    //...
                    "dependsOn": [
                        "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]",
                        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
                    ],
                    "properties": {
                        "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountResourceId'),'2019-09-01').key1)]"
                    }
                },
                {
                    "type": "secrets",
                    "name": "[variables('appInsightsKeyName')]",
                    //...
                    "dependsOn": [
                        "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]",
                        "[resourceId('Microsoft.Insights/components', variables('appInsightsName'))]"
                    ],
                    "properties": {
                        "value": "[reference(resourceId('microsoft.insights/components/', variables('appInsightsName')), '2019-09-01').InstrumentationKey]"
                    }
                }
            ]
        }
    ]
}

Nota:

En este ejemplo, la implementación del control de código fuente depende de la configuración de la aplicación. Esta dependencia suele ser un comportamiento no seguro, ya que la actualización de configuración de la aplicación se comporta de forma asincrónica. Sin embargo, dado que incluyó la configuración de la WEBSITE_ENABLE_SYNC_UPDATE_SITE aplicación, la actualización es sincrónica. La implementación del control de código fuente comienza solo después de que la configuración de la aplicación se actualice por completo. Para conocer más opciones de configuración de la aplicación, vea Variables de entorno y configuración de la aplicación en Azure App Service.

Solución de problemas de las referencias de Key Vault

Si una referencia no se resuelve correctamente, la cadena de referencia se usa en su lugar, por ejemplo, @Microsoft.KeyVault(...). Esta situación puede hacer que la aplicación produzca errores, ya que espera un secreto de un valor diferente.

Habitualmente, el error al resolver se debe a una configuración incorrecta de la directiva de acceso de Key Vault. Sin embargo, el motivo también podría ser que un secreto ya no existe o que la referencia contiene un error de sintaxis.

Si la sintaxis es correcta, puede ver otras causas de un error comprobando el estado de resolución actual en Azure Portal. Vaya a Configuración de la aplicación y seleccione Editar para la referencia en cuestión. El cuadro de diálogo de edición muestra información de estado, incluidos los errores. Si no ve el mensaje de estado, significa que la sintaxis no es válida y no se reconoce como referencia de Key Vault.

También puede usar uno de los detectores integrados para obtener más información.

Para usar el detector para App Service:

  1. En el portal de Azure, vaya a tu aplicación.
  2. Seleccione Diagnóstico y solución de problemas.
  3. Seleccione Disponibilidad y rendimiento>Aplicación web fuera de servicio.
  4. En el cuadro de búsqueda, busque y seleccione Diagnóstico de configuración de la aplicación de Key Vault.

Para usar el detector para Azure Functions:

  1. En el portal de Azure, vaya a tu aplicación.
  2. Vaya a Características de la plataforma.
  3. Seleccione Diagnóstico y solución de problemas.
  4. Seleccione Disponibilidad y rendimiento>Aplicación de funciones fuera de servicio o que informa de errores.
  5. Seleccione Diagnóstico de configuración de la aplicación de Key Vault.