Použití odkazů Key Vault pro App Service a Azure Functions

V tomto tématu se dozvíte, jak pracovat s tajnými kódy z Azure Key Vault ve vaší App Service nebo Azure Functions aplikaci bez nutnosti změn kódu. Azure Key Vault je služba, která poskytuje centralizovanou správu tajných kódů s plnou kontrolou nad zásadami přístupu a historií auditu.

Udělení přístupu aplikace k Key Vault

Abyste mohli číst tajné kódy z Key Vault, musíte mít vytvořený trezor a udělit aplikaci oprávnění pro přístup k němu.

  1. Vytvořte trezor klíčů pomocí rychlého startu Key Vault.

  2. Vytvořte spravovanou identitu pro vaši aplikaci.

    Key Vault odkazy budou ve výchozím nastavení používat identitu přiřazenou systémem aplikace, ale můžete zadat identitu přiřazenou uživatelem.

  3. Vytvořte zásadu přístupu v Key Vault pro identitu aplikace, kterou jste vytvořili dříve. U této zásady povolte oprávnění získat tajný kód. Nenakonfigurujte "autorizovanou aplikaci" nebo applicationId nastavení, protože to není kompatibilní se spravovanou identitou.

Přístup k trezorům s omezeným přístupem k síti

Pokud je váš trezor nakonfigurovaný s omezeními sítě, budete také muset zajistit, aby aplikace získala síťový přístup.

  1. Ujistěte se, že aplikace má nakonfigurované možnosti odchozích sítí, jak je popsáno v App Service síťových funkcích a možnostech sítě Azure Functions.

    Aplikace pro Linux, které se pokoušejí používat privátní koncové body, navíc vyžadují, aby aplikace byla explicitně nakonfigurovaná tak, aby měla veškerou trasu provozu přes virtuální síť. Tento požadavek bude odebrán v nadcházející aktualizaci. K nastavení použijte následující příkaz Azure CLI nebo Azure PowerShell:

    az webapp config set --subscription <sub> -g MyResourceGroupName -n MyAppName --generic-configurations '{"vnetRouteAllEnabled": true}'
    
  2. Ujistěte se, že účty konfigurace trezoru pro síť nebo podsíť, přes kterou bude vaše aplikace přistupovat.

Poznámka

Windows kontejner v současné době nepodporuje Key Vault odkazy na integraci virtuální sítě.

Přístup k trezorům s identitou přiřazenou uživatelem

Některé aplikace potřebují při vytváření odkazovat na tajné kódy, pokud by identita přiřazená systémem ještě nebyla k dispozici. V těchto případech je možné předem vytvořit identitu přiřazenou uživatelem a získat přístup k trezoru.

Jakmile udělíte oprávnění k identitě přiřazené uživatelem, postupujte takto:

  1. Pokud jste to ještě neudělali, přiřaďte identitu k aplikaci.

  2. Nakonfigurujte aplikaci tak, aby používala tuto identitu pro Key Vault referenční operace nastavením keyVaultReferenceIdentity vlastnosti na ID prostředku identity přiřazené uživatelem.

    userAssignedIdentityResourceId=$(az identity show -g MyResourceGroupName -n MyUserAssignedIdentityName --query id -o tsv)
    appResourceId=$(az webapp show -g MyResourceGroupName -n MyAppName --query id -o tsv)
    az rest --method PATCH --uri "${appResourceId}?api-version=2021-01-01" --body "{'properties':{'keyVaultReferenceIdentity':'${userAssignedIdentityResourceId}'}}"
    

Tato konfigurace se použije pro všechny odkazy na aplikaci.

Syntaxe odkazů

Odkaz na Key Vault je ve formuláři @Microsoft.KeyVault({referenceString}), kde {referenceString} se nahrazuje jednou z následujících možností:

Referenční řetězec Popis
SecretUri=secretUri Identifikátor SecretUri by měl být úplný identifikátor URI roviny dat tajného kódu v Key Vault, volitelně včetně verze, například https://myvault.vault.azure.net/secrets/mysecret/ nebohttps://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931
VaultName=vaultName; SecretName=secretName; SecretVersion=secretVersion Název trezoru je povinný a měl by obsahovat název vašeho prostředku Key Vault. Název tajného klíče je povinný a měl by být názvem cílového tajného kódu. SecretVersion je nepovinný, ale pokud je k dispozici, označuje verzi tajného kódu, která se má použít.

Například úplný odkaz by vypadal takto:

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

Máte k dispozici i další možnosti:

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

Obměna

Pokud není v odkazu zadána verze, bude aplikace používat nejnovější verzi, která existuje v trezoru klíčů. Jakmile budou k dispozici novější verze, například s událostí obměně, aplikace se automaticky aktualizuje a začne používat nejnovější verzi do 24 hodin. Zpoždění spočívá v tom, že App Service ukládá hodnoty odkazů na trezor klíčů a načítá je každých 24 hodin. Všechny změny konfigurace aplikace, která vede k restartování webu, způsobí okamžité opětovné načtení všech odkazovaných tajných kódů.

Nastavení zdrojové aplikace z Key Vault

Key Vault odkazy lze použít jako hodnoty pro Nastavení aplikace, což vám umožní uchovávat tajné kódy v Key Vault místo konfigurace webu. Nastavení aplikace jsou bezpečně zašifrované v klidovém stavu, ale pokud potřebujete funkce správy tajných kódů, měly by přejít do Key Vault.

Pokud chcete použít odkaz Key Vault pro nastavení aplikace, nastavte odkaz jako hodnotu nastavení. Vaše aplikace může odkazovat na tajný kód prostřednictvím jeho klíče jako normální. Nejsou vyžadovány žádné změny kódu.

Tip

Většina nastavení aplikace používající odkazy na Key Vault by měla být označena jako nastavení slotu, protože byste měli mít samostatné trezory pro každé prostředí.

Důležité informace o montáži Azure Files

Aplikace můžou pomocí WEBSITE_CONTENTAZUREFILECONNECTIONSTRING nastavení aplikace připojit Azure Files jako systém souborů. Toto nastavení obsahuje další kontroly ověření, aby se zajistilo, že aplikace může být správně spuštěná. Platforma spoléhá na sdílení obsahu v rámci Azure Files a předpokládá výchozí název, pokud není zadán prostřednictvím WEBSITE_CONTENTSHARE nastavení. U všech požadavků, které tato nastavení upravují, se platforma pokusí ověřit, jestli tato sdílená složka obsahu existuje, a pokusí se ji vytvořit, pokud ne. Pokud nemůže najít nebo vytvořit sdílenou složku obsahu, požadavek se zablokuje.

Při použití Key Vault odkazů na toto nastavení se tato kontrola ověření ve výchozím nastavení nezdaří, protože při zpracování příchozího požadavku se samotný tajný klíč nedá vyřešit. Pokud se chcete tomuto problému vyhnout, můžete ověření přeskočit nastavením WEBSITE_SKIP_CONTENTSHARE_VALIDATION na 1. Tím se všechny kontroly obejití a sdílená složka obsahu se pro vás nevytvořila. Měli byste se ujistit, že je vytvořený předem.

Upozornění

Pokud přeskočíte ověření a připojovací řetězec nebo sdílená složka obsahu jsou neplatné, aplikace nebude moct správně spustit a bude obsluhovat pouze chyby HTTP 500.

V rámci vytváření lokality je také možné, že pokus o připojení sdílené složky obsahu může selhat kvůli tomu, že se nešířila oprávnění spravované identity nebo se nenastavila integrace virtuální sítě. Nastavení Azure Files můžete odložit až později v šabloně nasazení tak, aby to vyhovovalo. Další informace najdete v tématu nasazení Azure Resource Manager. App Service použije výchozí systém souborů, dokud se nenastaví Azure Files a soubory se nekopírují, takže před připojením Azure Files budete muset zajistit, aby nedošlo k žádným pokusům o nasazení.

Nasazení podle modelu Azure Resource Manager

Při automatizaci nasazení prostředků prostřednictvím šablon Azure Resource Manager budete možná muset sekvencovat závislosti v určitém pořadí, aby tato funkce fungovala. Nezapomeňte, že místo použití siteConfig vlastnosti v definici webu budete muset definovat nastavení aplikace jako vlastní prostředek. Důvodem je to, že lokalita musí být definována jako první, aby se s ní vytvořila identita přiřazená systémem a dá se použít v zásadách přístupu.

Příklad pseudo šablony pro aplikaci funkcí může vypadat takto:

{
    //...
    "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('storageConnectionStringResourceId')).secretUriWithVersion, ')')]",
                        "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('storageConnectionStringResourceId')).secretUriWithVersion, ')')]",
                        "APPINSIGHTS_INSTRUMENTATIONKEY": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('appInsightsKeyResourceId')).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]"
                    }
                }
            ]
        }
    ]
}

Poznámka

V tomto příkladu nasazení správy zdrojového kódu závisí na nastavení aplikace. Toto chování je obvykle nebezpečné, protože aktualizace nastavení aplikace se chová asynchronně. Vzhledem k tomu, že jsme zahrnuli WEBSITE_ENABLE_SYNC_UPDATE_SITE nastavení aplikace, je aktualizace synchronní. To znamená, že nasazení správy zdrojového kódu začne jenom po úplné aktualizaci nastavení aplikace. Další nastavení aplikace najdete v tématu Proměnné prostředí a nastavení aplikace v Azure App Service.

Řešení potíží s odkazy na Key Vault

Pokud odkaz není správně vyřešen, použije se místo toho referenční hodnota. To znamená, že pro nastavení aplikace by se vytvořila proměnná prostředí, jejíž hodnota má @Microsoft.KeyVault(...) syntaxi. To může způsobit, že aplikace vyvolá chyby, protože očekávala tajný kód určité struktury.

Nejčastěji je to způsobeno chybnou konfigurací zásad přístupu Key Vault. Důvodem může být také chyba tajného kódu, která už neexistuje, nebo kvůli chybě syntaxe samotného odkazu.

Pokud je syntaxe správná, můžete zobrazit další příčiny chyby kontrolou aktuálního stavu řešení na portálu. Přejděte do aplikace Nastavení a vyberte Upravit pro daný odkaz. Pod konfigurací nastavení byste měli vidět informace o stavu, včetně chyb. Absence těchto skutečností znamená, že syntaxe odkazu je neplatná.

K získání dalších informací můžete použít také jeden z integrovaných detektorů.

Použití detektoru pro App Service

  1. Na portálu přejděte do aplikace.
  2. Vyberte Diagnostikovat a řešit problémy.
  3. Zvolte dostupnost a výkon a vyberte webovou aplikaci dolů.
  4. Vyhledejte Key Vault Diagnostiku Nastavení aplikace a klikněte na Další informace.

Použití detektoru pro Azure Functions

  1. Na portálu přejděte do aplikace.
  2. Přejděte na funkce platformy.
  3. Vyberte Diagnostikovat a řešit problémy.
  4. Zvolte Dostupnost a výkon a vyberte Aplikaci funkcí, která se vypne nebo nahlásí chyby.
  5. Klikněte na Key Vault Diagnostika Nastavení aplikace.