Utilizar referências de Key Vault como definições da aplicação no Serviço de Aplicações do Azure e no Funções do Azure

Este artigo mostra-lhe como utilizar segredos do Azure Key Vault como valores de definições de aplicações ou cadeias de ligação nas suas aplicações Serviço de Aplicações ou Funções do Azure.

O Azure Key Vault é um serviço que fornece gestão de segredos centralizada, com controlo total sobre as políticas de acesso e o histórico de auditorias. Quando uma definição de aplicação ou cadeia de ligação é uma referência do cofre de chaves, o código da aplicação pode utilizá-lo como qualquer outra definição de aplicação ou cadeia de ligação. Desta forma, pode manter segredos para além da configuração da sua aplicação. As definições da aplicação são encriptadas em segurança quando inativos, mas se precisar de capacidades de gestão de segredos, estas devem entrar num cofre de chaves.

Conceder acesso à sua aplicação a um cofre de chaves

Para ler segredos de um cofre de chaves, tem de ter um cofre criado e dar permissão à sua aplicação para aceder ao mesmo.

  1. Crie um cofre de chaves ao seguir o início rápido Key Vault.

  2. Crie uma identidade gerida para a sua aplicação.

    Por predefinição, as referências do cofre de chaves utilizam a identidade atribuída pelo sistema da aplicação, mas pode especificar uma identidade atribuída pelo utilizador.

  3. Autorizar o acesso de leitura aos segredos do cofre de chaves para a identidade gerida que criou anteriormente. A forma como o faz depende do modelo de permissões do cofre de chaves:

Aceder a cofres restritos à rede

Se o cofre estiver configurado com restrições de rede, certifique-se de que a aplicação tem acesso à rede. Os cofres não devem depender dos IPs de saída públicos da aplicação porque o IP de origem do pedido secreto pode ser diferente. Em vez disso, o cofre deve ser configurado para aceitar o tráfego de uma rede virtual utilizada pela aplicação.

  1. Certifique-se de que a aplicação tem capacidades de rede de saída configuradas, conforme descrito em Serviço de Aplicações funcionalidades de rede e Funções do Azure opções de rede.

    As aplicações Linux que se ligam a pontos finais privados têm de ser explicitamente configuradas para encaminhar todo o tráfego através da rede virtual. Este requisito será removido numa próxima atualização. Para configurar esta definição, execute o seguinte comando:

    az webapp config set --subscription <sub> -g <group-name> -n <app-name> --generic-configurations '{"vnetRouteAllEnabled": true}'
    
  2. Certifique-se de que a configuração do cofre permite a rede ou sub-rede que a sua aplicação utiliza para aceder à mesma.

Aceder a cofres com uma identidade atribuída pelo utilizador

Algumas aplicações precisam de referenciar segredos no momento da criação, quando uma identidade atribuída pelo sistema ainda não está disponível. Nestes casos, uma identidade atribuída pelo utilizador pode ser criada e ter acesso ao cofre com antecedência.

Depois de conceder permissões à identidade atribuída pelo utilizador, siga estes passos:

  1. Atribua a identidade à sua aplicação, caso ainda não o tenha feito.

  2. Configure a aplicação para utilizar esta identidade para operações de referência do cofre de chaves ao definir a keyVaultReferenceIdentity propriedade para o ID de recurso da identidade atribuída pelo utilizador.

    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 definição aplica-se a todas as referências do cofre de chaves para a aplicação.

Rotação

Se a versão secreta não for especificada na referência, a aplicação utiliza a versão mais recente que existe no cofre de chaves. Quando as versões mais recentes ficam disponíveis, como com um evento de rotação, a aplicação é atualizada automaticamente e começa a utilizar a versão mais recente dentro de 24 horas. O atraso deve-se ao facto de o Serviço de Aplicações colocar em cache os valores das referências do cofre de chaves e voltar a obtê-los a cada 24 horas. Qualquer alteração de configuração na aplicação causa um reinício da aplicação e um reinício imediato de todos os segredos referenciados.

Definições da aplicação de origem do cofre de chaves

Para utilizar uma referência do cofre de chaves, defina a referência como o valor da definição. A sua aplicação pode referenciar o segredo através da respetiva chave normalmente. Não são necessárias alterações de código.

Dica

A maioria das definições de aplicações que utilizam referências do cofre de chaves deve ser marcada como definições de bloco, uma vez que deve ter cofres separados para cada ambiente.

Uma referência do cofre de chaves é do formulário @Microsoft.KeyVault({referenceString}), em que {referenceString} se encontra num dos seguintes formatos:

Cadeia de referência Description
SecretUri=secretUri O SecretUri deve ser o URI completo do plano de dados de um segredo no cofre, opcionalmente incluindo uma versão, por exemplo, https://myvault.vault.azure.net/secrets/mysecret/ ou https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931
VaultName=vaultName; SecretName=secretName; SecretVersion=secretVersion O VaultName é obrigatório e é o nome do cofre. O SecretName é obrigatório e é o nome do segredo. A SecretVersion é opcional, mas se presente indicar a versão do segredo a utilizar.

Por exemplo, uma referência completa seria semelhante à seguinte cadeia:

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

Em alternativa:

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

Considerações para a montagem de Ficheiros do Azure

As aplicações podem utilizar a definição da aplicação WEBSITE_CONTENTAZUREFILECONNECTIONSTRING para montar Ficheiros do Azure como o sistema de ficheiros. Esta definição tem verificações de validação para garantir que a aplicação pode ser iniciada corretamente. A plataforma depende de ter uma partilha de conteúdos dentro de Ficheiros do Azure e assume um nome predefinido, a menos que seja especificado através da WEBSITE_CONTENTSHARE definição. Para quaisquer pedidos que modifiquem estas definições, a plataforma valida se esta partilha de conteúdos existe e tenta criá-la se não existir. Se não conseguir localizar ou criar a partilha de conteúdos, bloqueia o pedido.

Quando utiliza referências do cofre de chaves nesta definição, a verificação de validação falha por predefinição, porque o segredo em si não pode ser resolvido durante o processamento do pedido recebido. Para evitar este problema, pode ignorar a validação ao definir WEBSITE_SKIP_CONTENTSHARE_VALIDATION como "1". Esta definição indica Serviço de Aplicações ignorar todas as verificações e não cria a partilha de conteúdos automaticamente. Deve certificar-se de que é criado com antecedência.

Atenção

Se ignorar a validação e a cadeia de ligação ou a partilha de conteúdos forem inválidas, a aplicação não poderá iniciar corretamente e apenas irá apresentar erros HTTP 500.

Como parte da criação da aplicação, a tentativa de montagem da partilha de conteúdos pode falhar devido à propagação das permissões de identidade gerida ou à integração da rede virtual não estar a ser configurada. Pode adiar a configuração Ficheiros do Azure até mais tarde no modelo de implementação para acomodar esta situação. Veja Implementação do Azure Resource Manager para saber mais. Neste caso, Serviço de Aplicações utiliza um sistema de ficheiros predefinido até Ficheiros do Azure ser configurado e os ficheiros não são copiados. Tem de garantir que não ocorrem tentativas de implementação durante o período provisório antes de a Ficheiros do Azure ser montada.

Considerações sobre a instrumentação do Application Insights

As aplicações podem utilizar as definições da aplicação APPINSIGHTS_INSTRUMENTATIONKEY ou APPLICATIONINSIGHTS_CONNECTION_STRING para integrar com o Application Insights. As experiências do portal para Serviço de Aplicações e Funções do Azure também utilizam estas definições para ver dados telemétricos do recurso. Se estes valores forem referenciados a partir de Key Vault, estas experiências não estão disponíveis e, em vez disso, tem de trabalhar diretamente com o recurso do Application Insights para ver a telemetria. No entanto, estes valores não são considerados segredos, pelo que, em alternativa, poderá considerar configurá-los diretamente em vez de utilizar referências do cofre de chaves.

Implementação do Azure Resource Manager

Ao automatizar implementações de recursos através do Azure Resource Manager modelos, poderá ter de sequenciar as suas dependências para que esta funcionalidade funcione. Certifique-se de que define as definições da aplicação como o seu próprio recurso, em vez de utilizar uma siteConfig propriedade na definição da aplicação. Isto deve-se ao facto de a aplicação ter de ser definida primeiro para que a identidade atribuída pelo sistema seja criada com a mesma e possa ser utilizada na política de acesso.

O seguinte pseudo-modelo é um exemplo do aspeto que uma aplicação de funções pode ter:

{
    //...
    "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

Neste exemplo, a implementação do controlo de origem depende das definições da aplicação. Normalmente, este comportamento não é seguro, uma vez que a atualização da definição da aplicação se comporta de forma assíncrona. No entanto, como incluímos a definição da aplicação WEBSITE_ENABLE_SYNC_UPDATE_SITE , a atualização é síncrona. Isto significa que a implementação do controlo de origem só começará depois de as definições da aplicação terem sido totalmente atualizadas. Para obter mais definições da aplicação, veja Variáveis de ambiente e definições da aplicação no Serviço de Aplicações do Azure.

Resolução de problemas de referências do cofre de chaves

Se uma referência não for resolvida corretamente, é utilizada a cadeia de referência (por exemplo, @Microsoft.KeyVault(...)). Pode fazer com que a aplicação deite erros, porque está à espera de um segredo de um valor diferente.

A falha na resolução deve-se normalmente a uma configuração incorreta da política de acesso Key Vault. No entanto, também pode dever-se a um segredo que já não existe ou a um erro de sintaxe na própria referência.

Se a sintaxe estiver correta, pode ver outras causas de erro ao verificar o estado de resolução atual no portal. Navegue para Definições da Aplicação e selecione "Editar" para a referência em questão. A caixa de diálogo editar mostra informações de estado, incluindo quaisquer erros. Se não vir a mensagem de estado, significa que a sintaxe é inválida e não é reconhecida como uma referência do cofre de chaves.

Também pode utilizar um dos detetores incorporados para obter informações adicionais.

Utilizar o detetor para Serviço de Aplicações

  1. No portal, navegue para a sua aplicação.
  2. Selecione Diagnosticar e resolver problemas.
  3. Selecione Disponibilidade e Desempenho e selecione Aplicação Web inativa.
  4. Na caixa de pesquisa, procure e selecione Key Vault Diagnóstico de Definições da Aplicação.

Utilizar o detetor para Funções do Azure

  1. No portal, navegue para a sua aplicação.
  2. Navegue para Funcionalidades da plataforma.
  3. Selecione Diagnosticar e resolver problemas.
  4. Selecione Disponibilidade e Desempenho e selecione Aplicação de funções inativa ou comunicar erros.
  5. Selecione Key Vault Diagnóstico de Definições da Aplicação.