Usar referências do Key Vault como configurações de aplicativo no Serviço de Aplicativo do Azure e Azure Functions

Este artigo mostra como usar segredos do Azure Key Vault como valores de configurações de aplicativo ou cadeias de conexão em aplicativos do Azure Functions ou Serviço de Aplicativo.

Azure Key Vault é um serviço que fornece gerenciamento centralizado de segredos, com controle total sobre políticas de acesso e histórico de auditoria. Quando uma configuração de aplicativo ou cadeia de conexão é uma referência do cofre de chaves, o código do aplicativo pode usá-la como qualquer outra configuração de aplicativo ou cadeia de conexão. Dessa forma, você pode manter segredos além da configuração do aplicativo. As configurações do aplicativo são criptografadas com segurança em repouso, mas se você precisar de recursos de gerenciamento de segredo, elas devem entrar em um cofre de chaves.

Permitir ao aplicativo acesso a um cofre de chaves

Para ler os segredos de um cofre de chaves, você precisa criar um cofre e conceder permissão ao aplicativo para acessá-lo.

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

  2. Crie uma Identidade gerenciada para seu aplicativo.

    Referências ao Key Vault usam a identidade atribuída pelo sistema do aplicativo por padrão, mas você pode especificar uma identidade atribuída pelo usuário.

  3. Autorize o acesso de leitura aos segredos do cofre de chaves para a identidade gerenciada que você criou anteriormente. Como fazer isso depende do modelo de permissões do cofre de chaves:

Acessar cofres restritos à rede

Se o cofre estiver configurado com restrições de rede, garanta que o aplicativo tenha acesso à rede. Os cofres não devem depender dos IPs de saída públicos do aplicativo porque o IP de origem da solicitação secreta pode ser diferente. Em vez disso, o cofre deve ser configurado para aceitar o tráfego de uma rede virtual usada pelo aplicativo.

  1. Verifique se o aplicativo tem os recursos de rede de saída configurados, conforme descrito em Recursos de rede do Serviço de Aplicativo e Opções de rede do Azure Functions.

    Aplicativos Linux que se conectam a pontos de extremidade privados devem ser configurados explicitamente para rotear todo o tráfego através da rede virtual. Esse requisito será removido em uma atualização futura. Para definir essa configuração, execute o seguinte comando:

    az webapp config set --subscription <sub> -g <group-name> -n <app-name> --generic-configurations '{"vnetRouteAllEnabled": true}'
    
  2. Garanta que a configuração do cofre dá permissão à rede ou à sub-rede que seu aplicativo usa para acessá-lo.

Acessar cofres com uma identidade atribuída pelo usuário

Alguns aplicativos precisam referenciar segredos no momento da criação, quando uma identidade atribuída pelo sistema ainda não está disponível. Nesses casos, uma identidade atribuída ao usuário pode ser criada e ter acesso ao cofre com antecedência.

Depois de conceder permissões à identidade atribuída pelo usuário, siga estas etapas:

  1. Atribua a identidade ao seu aplicativo, caso ainda não tenha feito isso.

  2. Configure o aplicativo para usar essa identidade para operações de referência do cofre de chaves configurando a propriedade keyVaultReferenceIdentity como a ID do recurso da identidade atribuída pelo usuário.

    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}
    

Essa configuração se aplica a todas as referências do cofre de chaves para o aplicativo.

Rotação

Se uma versão de segredo não for especificada na referência, o aplicativo usará a versão mais recente no cofre de chaves. Quando versões mais recentes estiverem disponíveis, como com um evento de rotação, o aplicativo atualiza automaticamente e começa a usar a versão mais recente dentro de 24 horas. O atraso é devido ao fato de o Serviço de Aplicativo armazenar em cache os valores das referências do cofre de chaves e os busca a cada 24 horas. Qualquer alteração de configuração no aplicativo causa o reinício do aplicativo e uma busca imediata de todos os segredos referenciados.

Configurações do aplicativo de origem do cofre de chaves

Para usar uma referência do cofre de chaves, defina a referência como o valor da configuração. Seu aplicativo pode fazer referência ao segredo por meio de sua chave normalmente. Nenhuma alteração de código é necessária.

Dica

A maioria das configurações de aplicativos que usam referências do cofre de chaves deve ser marcada como configurações de slot, pois você deve ter cofres separados para cada ambiente.

Uma referência do cofre de chaves é da forma @Microsoft.KeyVault({referenceString}), em que {referenceString} está em um dos seguintes formatos:

Cadeia de caracteres de referência Descrição
SecretUri = secretUri O SecretUri deve ser o URI do plano de dados completo 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. O SecretVersion é opcional, mas, se presente, indica a versão do segredo a ser usada.

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

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

Como alternativa:

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

Considerações sobre montagem de Arquivos do Azure

Os aplicativos podem usar a configuração de aplicativo WEBSITE_CONTENTAZUREFILECONNECTIONSTRING para montar os Arquivos do Azure como o sistema de arquivos. Essa configuração tem verificações de validação para garantir que o aplicativo possa ser iniciado corretamente. A plataforma depende de ter um compartilhamento de conteúdo nos Arquivos do Azure e assume um nome padrão, a menos que um seja especificado por meio da configuração WEBSITE_CONTENTSHARE. Para todas as solicitações que modificam essas configurações, a plataforma valida se esse compartilhamento de conteúdo existe e tenta criá-lo se não existir. Se ela não puder localizar nem criar o compartilhamento de conteúdo, a solicitação será bloqueada.

Quando você usa referências do cofre de chaves nessa configuração, a validação verifica falha por padrão, porque o segredo em si não pode ser resolvido durante o processamento da solicitação de entrada. Para evitar esse problema, você pode ignorar a validação definindo WEBSITE_SKIP_CONTENTSHARE_VALIDATION como "1". Essa configuração informa Serviço de Aplicativo para ignorar todas as verificações e não cria o compartilhamento de conteúdo para você. Você deve garantir que ele seja criado com antecedência.

Cuidado

Se você ignorar a validação e a cadeia de conexão ou o compartilhamento de conteúdo for inválido, o aplicativo não poderá iniciar corretamente e só atenderá a erros HTTP 500.

Como parte da criação do aplicativo, a tentativa de montagem do compartilhamento de conteúdo falha porque as permissões de identidade gerenciada não foram propagadas ou a integração de rede virtual não foi configurada. Você pode adiar a configuração de Arquivos do Azure até mais tarde no modelo de implantação para acomodar isso. Confira Modos de implantação do Azure Resource Manager para saber mais. Nesse caso, o Serviço de Aplicativo usa um sistema de arquivos padrão até que Arquivos do Azure seja configurado e os arquivos não sejam copiados. Você deve garantir que nenhuma tentativa de implantação ocorra durante o período provisório antes que os Arquivos do Azure seja montado.

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

Os aplicativos podem usar as configurações de aplicativo APPINSIGHTS_INSTRUMENTATIONKEY ou APPLICATIONINSIGHTS_CONNECTION_STRING para serem integrados ao Application Insights. As experiências do portal para o Serviço de Aplicativo e o Azure Functions também usam essas configurações para exibir os dados telemétricos do recurso. Se esses valores forem referenciados do Key Vault, essas experiências não estarão disponíveis e, em vez disso, você precisará trabalhar diretamente com o recurso do Application Insights para ver a telemetria. No entanto, esses valores não são considerados segredos, ou seja, você pode, alternativamente, considerar configurá-los diretamente em vez de usar as referências do cofre de chaves.

Implantação do Azure Resource Manager

Ao automatizar implantações de recursos por meio dos modelos do Azure Resource Manager, talvez seja necessário sequenciar suas dependências em uma ordem específica para que esse recurso funcione. Defina as configurações do aplicativo como um recurso próprio, em vez de usar uma propriedade siteConfig na definição do aplicativo. Isso ocorre porque o aplicativo precisa ser definido primeiro para que a identidade atribuída pelo sistema seja criada com ele e possa ser usada na política de acesso.

O pseudo-modelo a seguir é um exemplo de como um aplicativo de funções pode ser:

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

Observação

Neste exemplo, a implantação do controle de origem depende das configurações do aplicativo. Esse comportamento normalmente é inseguro, pois a atualização da configuração do aplicativo se comporta de maneira assíncrona. No entanto, como incluímos a configuração do aplicativo WEBSITE_ENABLE_SYNC_UPDATE_SITE, a atualização é síncrona. Isso significa que a implantação do controle de origem só será iniciada quando as configurações do aplicativo tiverem sido totalmente atualizadas. Para obter mais configurações de aplicativo, confira Variáveis de ambiente e configurações de aplicativo no Serviço de Aplicativo do Azure.

Solucionar problemas de referências do cofre de chaves

Se uma referência não for resolvida corretamente, a cadeia de caracteres da referência será usada em vez disso (por exemplo, @Microsoft.KeyVault(...)). Isso pode fazer com que o aplicativo gere erros, pois espera um segredo de um valor diferente.

A falha em resolver geralmente se deve a uma configuração incorreta da política de acesso do Key Vault. No entanto, também pode ser devido a um segredo não mais existente ou a um erro de sintaxe na própria referência.

Se a sintaxe estiver correta, você poderá ver outras causas de erro verificando o status atual da resolução no portal. Navegue até configurações do aplicativo e selecione "Editar" para a referência em questão. A caixa de diálogo de edição mostra informações do status, incluindo erros. Se a mensagem status não for exibida, isso significa que a sintaxe é inválida e não é reconhecida como uma referência do cofre de chaves.

Você também pode usar um dos detectores internos para obter informações adicionais.

Como usar o detector para o Serviço de Aplicativo

  1. No portal, navegue até seu aplicativo.
  2. Selecione Diagnosticar e solucionar problemas.
  3. Clique em Disponibilidade e Desempenho e selecione aplicativo Web inoperante.
  4. Na caixa de pesquisa, pesquise e selecione Diagnóstico de Configurações do Aplicativo do Key Vault.

Como usar o detector para Azure Functions

  1. No portal, navegue até seu aplicativo.
  2. Navegue até Recursos da plataforma.
  3. Selecione Diagnosticar e solucionar problemas.
  4. Selecione Disponibilidade e Desempenho e selecione Aplicativo de funções inoperante ou relatando erros.
  5. Clique em Diagnóstico de Configurações de Aplicativo do Key Vault.