Usare riferimenti Key Vault come impostazioni dell'app in Servizio app di Azure e Funzioni di Azure

Questo articolo illustra come usare segreti da Azure Key Vault come valori delle impostazioni dell'app o stringhe di connessione nelle app servizio app o Funzioni di Azure.

Azure Key Vault è un servizio che supporta la gestione centralizzata dei segreti con controllo completo sui criteri di accesso e sulla cronologia di controllo. Quando un'impostazione dell'app o una stringa di connessione è un riferimento all'insieme di credenziali delle chiavi, il codice dell'applicazione può usarlo come qualsiasi altra impostazione o stringa di connessione. In questo modo, è possibile gestire i segreti a parte la configurazione dell'app. Le impostazioni dell'app vengono crittografate in modo sicuro inattive, ma se sono necessarie funzionalità di gestione dei segreti, devono entrare in un insieme di credenziali delle chiavi.

Concedere all'app l'accesso a un insieme di credenziali delle chiavi

Per leggere i segreti da un insieme di credenziali delle chiavi, è necessario creare un insieme di credenziali e concedere all'app l'autorizzazione per accedervi.

  1. Creare un insieme di credenziali seguendo l'avvio rapido per Key Vault.

  2. Creare un'identità gestita per l'applicazione.

    I riferimenti all'insieme di credenziali delle chiavi usano l'identità assegnata dal sistema dell'app per impostazione predefinita, ma è possibile specificare un'identità assegnata dall'utente.

  3. Autorizzare l'accesso in lettura ai segreti dell'insieme di credenziali delle chiavi per l'identità gestita creata in precedenza. In che modo dipende dal modello di autorizzazioni dell'insieme di credenziali delle chiavi:

Accedere agli insiemi di credenziali con restrizioni di rete

Se l'insieme di credenziali è configurato con restrizioni di rete, assicurarsi che l'applicazione disponga dell'accesso alla rete. Gli insiemi di credenziali non devono dipendere dagli INDIRIZZI IP pubblici in uscita dell'app perché l'INDIRIZZO IP di origine della richiesta privata potrebbe essere diverso. L'insieme di credenziali deve invece essere configurato per accettare il traffico da una rete virtuale usata dall'app.

  1. Assicurarsi che l'applicazione disponga di funzionalità di rete in uscita configurate, come descritto in servizio app funzionalità di rete e Funzioni di Azure opzioni di rete.

    Le applicazioni Linux che si connettono agli endpoint privati devono essere configurate in modo esplicito per instradare tutto il traffico attraverso la rete virtuale. Questo requisito verrà rimosso in un prossimo aggiornamento. Per configurare questa impostazione, eseguire il comando seguente:

    az webapp config set --subscription <sub> -g <group-name> -n <app-name> --generic-configurations '{"vnetRouteAllEnabled": true}'
    
  2. Assicurarsi che la configurazione dell'insieme di credenziali consenta la rete o la subnet usata dall'app per accedervi.

Accedere agli insiemi di credenziali con un'identità assegnata dall'utente

Alcune app devono fare riferimento ai segreti in fase di creazione, quando un'identità assegnata dal sistema non è ancora disponibile. In questi casi, è possibile creare un'identità assegnata dall'utente e assegnare l'accesso all'insieme di credenziali in anticipo.

Dopo aver concesso le autorizzazioni all'identità assegnata dall'utente, seguire questa procedura:

  1. Assegnare l'identità all'applicazione se non è già stata eseguita.

  2. Configurare l'app per usare questa identità per le operazioni di riferimento dell'insieme di credenziali delle chiavi impostando la keyVaultReferenceIdentity proprietà sull'ID risorsa dell'identità assegnata dall'utente.

    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}
    

Questa impostazione si applica a tutti i riferimenti all'insieme di credenziali delle chiavi per l'app.

Rotazione

Se la versione privata non è specificata nel riferimento, l'app usa la versione più recente presente nell'insieme di credenziali delle chiavi. Quando le versioni più recenti diventano disponibili, ad esempio con un evento di rotazione, l'app aggiorna automaticamente e inizia a usare la versione più recente entro 24 ore. Il ritardo è dovuto al fatto che il Servizio app memorizza nella cache i valori dei riferimenti all'insieme di credenziali delle chiavi e li recupera ogni 24 ore. Qualsiasi modifica di configurazione all'app causa il riavvio di un'app e un refetch immediato di tutti i segreti a cui si fa riferimento.

Impostazioni dell'app di origine dall'insieme di credenziali delle chiavi

Per usare un riferimento all'insieme di credenziali delle chiavi, impostare il riferimento come valore dell'impostazione. L'app può fare riferimento al segreto tramite la relativa chiave come di consueto. Non sono necessarie modifiche al codice.

Suggerimento

La maggior parte delle impostazioni dell'app che usano i riferimenti all'insieme di credenziali delle chiavi deve essere contrassegnata come impostazioni dello slot, come è consigliabile disporre di insiemi di credenziali separati per ogni ambiente.

Un riferimento all'insieme di credenziali delle chiavi è del modulo @Microsoft.KeyVault({referenceString}), dove {referenceString} si trova in uno dei formati seguenti:

Stringa di riferimento Descrizione
SecretUri=secretUri SecretUri deve essere l'URI completo del piano dati di un segreto nell'insieme di credenziali, facoltativamente inclusa una versione, ad esempio https://myvault.vault.azure.net/secrets/mysecret/ ohttps://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931
VaultName=vaultName;SecretName=secretName;SecretVersion=secretVersion VaultName è obbligatorio ed è il nome dell'insieme di credenziali. SecretName è obbligatorio ed è il nome segreto. SecretVersion è facoltativo, ma se presente indica la versione del segreto da usare.

Ad esempio, un riferimento completo sarà simile alla stringa seguente:

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

In alternativa:

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

Considerazioni sul montaggio di File di Azure

Le app possono usare l'impostazione WEBSITE_CONTENTAZUREFILECONNECTIONSTRING dell'applicazione per montare File di Azure come file system. Questa impostazione dispone di controlli di convalida per assicurarsi che l'app possa essere avviata correttamente. La piattaforma si basa sulla presenza di una condivisione di contenuto all'interno di File di Azure e presuppone un nome predefinito a meno che non sia specificato tramite l'impostazioneWEBSITE_CONTENTSHARE. Per eventuali richieste che modificano queste impostazioni, la piattaforma convalida se questa condivisione di contenuto esiste e tenta di crearla in caso contrario. Se non è in grado di individuare o creare la condivisione contenuto, blocca la richiesta.

Quando si usano riferimenti all'insieme di credenziali delle chiavi in questa impostazione, il controllo di convalida ha esito negativo per impostazione predefinita, perché il segreto stesso non può essere risolto durante l'elaborazione della richiesta in ingresso. Per evitare questo problema, è possibile ignorare la convalida impostando WEBSITE_SKIP_CONTENTSHARE_VALIDATION su "1". Questa impostazione indica servizio app di ignorare tutti i controlli e non crea la condivisione contenuto per l'utente. È necessario assicurarsi che venga creato in anticipo.

Attenzione

Se si ignora la convalida e la stringa di connessione o la condivisione contenuto non sono valide, l'app non sarà in grado di avviare correttamente e gestirà solo errori HTTP 500.

Nell'ambito della creazione dell'app, il tentativo di montaggio della condivisione contenuto potrebbe non riuscire a causa delle autorizzazioni di identità gestite non propagate o dell'integrazione della rete virtuale non configurata. È possibile rinviare la configurazione File di Azure fino a un secondo momento nel modello di distribuzione per soddisfare questo problema. Per altre informazioni, vedere Distribuzione di Azure Resource Manager. In questo caso, servizio app usa un file system predefinito fino a quando non viene configurato File di Azure e i file non vengono copiati. È necessario assicurarsi che non si verifichino tentativi di distribuzione durante il periodo provvisorio prima che venga montato File di Azure.

Considerazioni sulla strumentazione di Application Insights

Le app possono usare le APPINSIGHTS_INSTRUMENTATIONKEY impostazioni dell'applicazione o APPLICATIONINSIGHTS_CONNECTION_STRING per integrare Application Insights. Le esperienze del portale per servizio app e Funzioni di Azure usano anche queste impostazioni per visualizzare i dati di telemetria dalla risorsa. Se questi valori vengono a cui si fa riferimento da Key Vault, queste esperienze non sono disponibili e è invece necessario usare direttamente la risorsa di Application Insights per visualizzare i dati di telemetria. Tuttavia, questi valori non vengono considerati segreti, pertanto è possibile configurarli direttamente anziché usare riferimenti all'insieme di credenziali delle chiavi.

Distribuzione Azure Resource Manager

Durante l'automazione delle distribuzioni di risorse tramite modelli di Azure Resource Manager, potrebbe essere necessario disporre in sequenza le dipendenze in un determinato ordine per usufruire di questa funzionalità. Assicurarsi di definire le impostazioni dell'app come propria risorsa, anziché usare una siteConfig proprietà nella definizione dell'app. Questo è dovuto al fatto che l'app deve essere definita prima in modo che l'identità assegnata dal sistema venga creata con essa e possa essere usata nei criteri di accesso.

Il modello pseudo-modello seguente è un esempio di cosa potrebbe essere simile a un'app per le funzioni:

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

In questo esempio, la distribuzione del controllo del codice sorgente dipende dalle impostazioni dell'applicazione. Si tratta in genere di un comportamento non sicuro, dato che l'aggiornamento delle impostazioni dell'applicazione ha un comportamento asincrono. Tuttavia, dato che è stata inclusa l'impostazione dell'applicazione WEBSITE_ENABLE_SYNC_UPDATE_SITE, l'aggiornamento è sincrono. Questo significa che la distribuzione del controllo del codice sorgente inizierà solo dopo l'aggiornamento completo delle impostazioni dell'applicazione. Per altre impostazioni dell'app, vedere Variabili di ambiente e impostazioni dell'app in Servizio app di Azure.

Risoluzione dei problemi relativi ai riferimenti all'insieme di credenziali delle chiavi

Se un riferimento non viene risolto correttamente, viene usata invece la stringa di riferimento , ad esempio @Microsoft.KeyVault(...). Può causare l'errore generato dall'applicazione perché prevede un segreto di un valore diverso.

L'errore di risoluzione è comunemente dovuto a una configurazione errata dei criteri di accesso Key Vault. Tuttavia, potrebbe anche essere dovuto a un segreto non esistente o a un errore di sintassi nel riferimento stesso.

Se la sintassi è corretta, è possibile visualizzare altre cause di errore controllando lo stato di risoluzione corrente nel portale. Passare a Impostazioni applicazione e selezionare "Modifica" per il riferimento in questione. La finestra di dialogo di modifica mostra le informazioni sullo stato, incluse eventuali errori. Se non viene visualizzato il messaggio di stato, significa che la sintassi non è valida e non viene riconosciuta come riferimento all'insieme di credenziali delle chiavi.

È anche possibile usare uno dei rilevatori predefiniti per ottenere informazioni aggiuntive.

Uso del rilevatore per servizio app

  1. Nel portale passare all'app.
  2. Selezionare Diagnostica e risoluzione dei problemi.
  3. Scegliere Disponibilità e prestazioni e selezionare App Web in basso.
  4. Nella casella di ricerca cercare e selezionare Key Vault Diagnostica impostazioni applicazione.

Uso del rilevatore per Funzioni di Azure

  1. Nel portale passare all'app.
  2. Passare a Funzionalità della piattaforma.
  3. Selezionare Diagnostica e risoluzione dei problemi.
  4. Scegliere Disponibilità e prestazioni e selezionare App per le funzioni inattiva o segnala errori.
  5. Selezionare Key Vault Diagnostica impostazioni applicazione.