Utiliser des références Key Vault comme paramètres d’application dans Azure App Service et Azure Functions

Cet article vous montre comment utiliser des secrets d’Azure Key Vault comme valeurs de paramètres d’application ou de chaînes de connexion dans vos applications App Service ou Azure Functions.

Azure Key Vault est un service qui fournit une gestion centralisée des secrets, avec un contrôle total sur les stratégies d’accès et l’historique d’audit. Quand un paramètre d’application ou une chaîne de connexion est une référence de coffre de clés, votre code d’application peut l’utiliser comme n’importe quel autre paramètre d’application ou chaîne de connexion. De cette façon, vous pouvez conserver les secrets en dehors de la configuration de votre application. Les paramètres d’application sont chiffrés au repos de manière sécurisée, mais si vous avez besoin de fonctionnalités de gestion des secrets, ils doivent être gardés dans un coffre de clés.

Autoriser votre application à accéder à un coffre de clés

Pour pouvoir lire les secrets dans un coffre de clés, vous devez créer un coffre et donner à votre application l’autorisation d’y accéder.

  1. Créez un coffre de clés en suivant le Guide de démarrage rapide de Key Vault.

  2. Créez une identité managée pour votre application.

    Les références Key Vault utilisent l’identité attribuée par le système de l’application par défaut, mais vous pouvez spécifier une identité attribuée par l’utilisateur.

  3. Autorisez l’accès en lecture aux secrets de votre coffre de clés pour l’identité managée que vous avez créée précédemment. La façon dont vous procédez dépend du modèle d’autorisations de votre coffre de clés :

Accéder aux coffres restreints du réseau

Si votre coffre est configuré avec des restrictions réseau, assurez-vous que l’application dispose d’un accès réseau. Les coffres ne doivent pas dépendre des adresses IP publiques de sortie de l’application, car l’adresse IP d’origine de la requête secrète peut être différente. Au lieu de cela, le coffre doit être configuré pour accepter le trafic provenant d’un réseau virtuel utilisé par l’application.

  1. Vérifiez que les fonctionnalités de mise en réseau sortantes de l’application sont configurées, comme décrit dans les fonctionnalités de mise en réseau App Service et les options de mise en réseau Azure Functions.

    Les applications Linux qui se connectent à des points de terminaison privés doivent être configurée de manière explicite pour acheminer tout le trafic par le biais du réseau virtuel. Cette exigence sera supprimée dans une prochaine mise à jour. Pour configurer ce paramètre, exécutez la commande suivante :

    az webapp config set --subscription <sub> -g <group-name> -n <app-name> --generic-configurations '{"vnetRouteAllEnabled": true}'
    
  2. Assurez-vous que la configuration du coffre autorise le réseau ou le sous-réseau utilisé par votre application pour y accéder.

Accédez aux coffres avec une identité attribuée par l’utilisateur

Certaines applications doivent référencer des secrets au moment de la création, quand une identité attribuée par le système n’est pas encore disponible. Dans ce cas, une identité attribuée par l’utilisateur peut être créée et l’accès au coffre doit être accordé à l’avance.

Une fois que vous avez accordé des autorisations à l’identité attribuée par l’utilisateur, procédez comme suit :

  1. Attribuez l’identité à votre application si vous ne l’avez pas déjà fait.

  2. Configurez l’application pour utiliser cette identité pour les opérations de référence de coffre de clés en définissant la propriété keyVaultReferenceIdentity sur l’ID de ressource de l’identité attribuée par l’utilisateur.

    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}
    

Ce paramètre s’applique à toutes les références de coffre de clés pour l’application.

Rotation

Si la version du secret n’est pas spécifiée dans la référence, l’application utilise la dernière version qui existe dans le coffre de clés. Quand des versions plus récentes sont disponibles, par exemple avec un événement de renouvellement, l’application est automatiquement mise à jour de façon à utiliser la dernière version dans un délai de 24 heures. Le délai est dû au fait que App Service met en cache les valeurs des références du coffre de clés et les récupère toutes les 24 heures. Toute modification de la configuration de l’application entraîne un redémarrage de l’application et une récupération immédiate de tous les secrets référencés.

Paramètres de l’application source du coffre de clés

Pour utiliser une référence de coffre de clés, définissez la référence comme valeur du paramètre. Votre application peut référencer le secret par le biais de sa clé comme d’habitude. Le code n’a pas besoin d’être modifié.

Conseil

La plupart des paramètres d’application qui utilisent des références de coffre de clés doivent être marqués comme des paramètres d’emplacement, car vous devez avoir des coffres distincts pour chaque environnement.

Une référence de coffre de clés se présente sous la forme @Microsoft.KeyVault({referenceString}), où {referenceString} utilise l’un des formats suivants :

Chaîne de référence Description
SecretUri=URI_secret La chaîne SecretUri doit correspondre à l’URI complet du plan de données d’un secret dans le coffre, y compris éventuellement une version, par exemple https://myvault.vault.azure.net/secrets/mysecret/ ou https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931.
VaultName=Nom_coffre;SecretName=Nom_secret;SecretVersion=Version_secret La chaîne VaultName est obligatoire et correspond au nom du coffre. La chaîne SecretName est obligatoire et correspond au nom du secret. Version_secret est facultatif, mais indique, s’il est mentionné, la version du secret à utiliser.

Par exemple, une référence complète ressemble à la chaîne suivante :

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

Sinon :

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

Considérations relatives au montage Azure Files

Les applications peuvent utiliser le paramètre d’application WEBSITE_CONTENTAZUREFILECONNECTIONSTRING pour monter Azure Files en tant que système de fichiers. Ce paramètre a des contrôles de validation pour garantir que l’application peut être démarrée correctement. La plateforme s’appuie sur un partage de contenu dans Azure Files et suppose un nom par défaut, sauf si un nom est spécifié via le paramètre WEBSITE_CONTENTSHARE. Pour les demandes qui modifient ces paramètres, la plateforme vérifie si ce partage de contenu existe, et si ce n’est pas le cas, elle tente de le créer. Si elle ne peut pas localiser ou créer le partage de contenu, elle bloque la demande.

Quand vous utilisez des références de coffre de clés dans ce paramètre, le contrôle de validation échoue par défaut, car le secret lui-même ne peut pas être résolu lors du traitement de la demande entrante. Pour éviter ce problème, vous pouvez ignorer la validation en affectant « 1 » à WEBSITE_SKIP_CONTENTSHARE_VALIDATION. Ce paramètre indique à App Service de contourner tous les contrôles et ne crée pas le partage de contenu pour vous. Vous devez vérifier qu’il est créé à l’avance.

Attention

Si vous ignorez la validation et que la chaîne de connexion ou le partage de contenu ne sont pas valides, l’application ne pourra pas démarrer correctement et renverra uniquement des erreurs HTTP 500.

Dans le cadre de la création de l’application, la tentative de montage du partage de contenu peut échouer en raison d’autorisations d’identité managée qui ne sont pas propagées ou d’une intégration de réseau virtuel qui n’est pas configurée. Vous pouvez différer la configuration d’Azure Files jusqu’à une date ultérieure dans le modèle de déploiement pour traiter ce cas. Pour en savoir plus, consultez Modes de déploiement d’Azure Resource Manager. Dans ce cas, App Service utilise un système de fichiers par défaut jusqu’à ce qu’Azure Files soit configuré, et les fichiers ne sont pas copiés. Vous devez vous assurer qu’aucune tentative de déploiement ne se produit pendant la période intermédiaire avant le montage d’Azure Files.

Considérations relatives à l’instrumentation Application Insights

Les applications peuvent utiliser les paramètres d’application APPINSIGHTS_INSTRUMENTATIONKEY ou APPLICATIONINSIGHTS_CONNECTION_STRING pour s’intégrer à Application Insights. Les expériences du portail pour App Service et Azure Functions également utiliser ces paramètres pour exposer les données de télémétrie de la ressource. Si ces valeurs sont référencées à partir de Key Vault, ces expériences ne sont pas disponibles et vous devez travailler directement avec la ressource Application Insights pour afficher les données de télémétrie. Toutefois, ces valeurs ne sont pas considérées comme des secrets. Vous pouvez également envisager de les configurer directement au lieu d’utiliser des références de coffre de clés.

Déploiement Azure Resource Manager

Quand vous automatisez des déploiements de ressources par le biais de modèles Azure Resource Manager, vous pouvez avoir besoin de séquencer vos dépendances dans un ordre particulier pour que cette fonctionnalité fonctionne. Veillez à définir vos paramètres d’application comme étant leur propre ressource, au lieu d’utiliser une propriété siteConfig dans la définition de l’application. En effet, l’application doit être définie en premier pour que le système puisse attribuer l’identité et que cette identité puisse être utilisée dans la stratégie d’accès.

Le pseudo-modèle suivant est un exemple d’application de fonction :

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

Notes

Dans cet exemple, le déploiement du contrôle de code source varie selon les paramètres d’application. Il s’agit normalement d’un comportement non sécurisé, car la mise à jour du paramètre d’application se comporte de façon asynchrone. Toutefois, comme nous avons inclus le paramètre d'application WEBSITE_ENABLE_SYNC_UPDATE_SITE, la mise à jour est synchrone. Cela signifie que le déploiement de contrôle source commence uniquement une fois que les paramètres d’application ont été entièrement mis à jour. Pour plus d’informations sur les paramètres d’application, consultez Variables d’environnement et paramètres d’application dans Azure App Service.

Résolution des problèmes liés aux références de coffre de clés

Si une référence n’est pas résolue correctement, la chaîne de référence est utilisée à la place (par exemple, @Microsoft.KeyVault(...)). Cela peut entraîner la génération d’erreurs par l’application, car elle attend un secret d’une valeur différente.

Un échec de résolution est généralement dû à une configuration incorrecte de la stratégie d’accès à Key Vault. Mais cela peut également être dû à un secret qui n'existe plus ou à une erreur de syntaxe dans la référence elle-même.

Si la syntaxe est correcte, vous pouvez afficher d’autres causes d’erreur en vérifiant l’état de résolution actuel dans le portail. Accédez à Paramètres d’application et sélectionnez « Modifier » pour la référence en question. La boîte de dialogue de modification affiche les informations d’état, y compris les erreurs éventuelles. Si vous ne voyez pas le message d’état, la syntaxe n’est pas valide et n’est pas reconnue comme référence de coffre de clés.

Vous pouvez également utiliser l’un des détecteurs intégrés pour obtenir des informations supplémentaires.

Utilisation du détecteur pour App Service

  1. Dans le portail, accédez à votre application.
  2. Sélectionnez Diagnostiquer et résoudre les problèmes.
  3. Sélectionnez Disponibilité et performances, puis Application web inactive.
  4. Dans la zone de recherche, recherchez et sélectionnez Diagnostics des paramètres d’application Key Vault.

Utilisation du détecteur pour Azure Functions

  1. Dans le portail, accédez à votre application.
  2. Accédez à Fonctionnalités de la plateforme.
  3. Sélectionnez Diagnostiquer et résoudre les problèmes.
  4. Sélectionnez Disponibilité et performances, puis L’application de fonction cesse de fonctionner ou signale des erreurs.
  5. Sélectionnez Diagnostics des paramètres d’application Key Vault.