Używanie odwołań Key Vault jako ustawień aplikacji w Azure App Service i Azure Functions

W tym artykule pokazano, jak używać wpisów tajnych z usługi Azure Key Vault jako wartości ustawień aplikacji lub parametrów połączenia w aplikacjach App Service lub Azure Functions.

Azure Key Vault to usługa, która zapewnia scentralizowane zarządzanie wpisami tajnymi z pełną kontrolą nad zasadami dostępu i historią inspekcji. Jeśli ustawienie aplikacji lub parametry połączenia są odwołaniem do magazynu kluczy, kod aplikacji może używać go jak każde inne ustawienie aplikacji lub parametry połączenia. Dzięki temu można przechowywać wpisy tajne poza konfiguracją aplikacji. Ustawienia aplikacji są bezpiecznie szyfrowane w spoczynku, ale jeśli potrzebujesz funkcji zarządzania wpisami tajnymi, powinny one przejść do magazynu kluczy.

Udzielanie aplikacji dostępu do magazynu kluczy

Aby odczytywać wpisy tajne z magazynu kluczy, musisz mieć utworzony magazyn i przyznać aplikacji uprawnienia dostępu do niego.

  1. Utwórz magazyn kluczy, wykonując czynności opisane w przewodniku Szybki start Key Vault.

  2. Utwórz tożsamość zarządzaną dla aplikacji.

    Odwołania do magazynu kluczy domyślnie używają tożsamości przypisanej przez system aplikacji, ale można określić tożsamość przypisaną przez użytkownika.

  3. Autoryzuj dostęp do odczytu do wpisów tajnych magazynu kluczy dla utworzonej wcześniej tożsamości zarządzanej. Jak to zrobić, zależy od modelu uprawnień magazynu kluczy:

Uzyskiwanie dostępu do magazynów z ograniczeniami sieci

Jeśli magazyn został skonfigurowany z ograniczeniami sieciowymi, upewnij się, że aplikacja ma dostęp do sieci. Magazyny nie powinny zależeć od publicznych adresów IP wychodzących aplikacji, ponieważ początkowy adres IP żądania wpisu tajnego może być inny. Zamiast tego magazyn należy skonfigurować tak, aby akceptował ruch z sieci wirtualnej używanej przez aplikację.

  1. Upewnij się, że aplikacja ma skonfigurowane możliwości sieci wychodzącej zgodnie z opisem w temacie App Service funkcje sieciowe i opcje sieci Azure Functions.

    Aplikacje systemu Linux łączące się z prywatnymi punktami końcowymi muszą być jawnie skonfigurowane do kierowania całego ruchu przez sieć wirtualną. To wymaganie zostanie usunięte w nadchodzącej aktualizacji. Aby skonfigurować to ustawienie, uruchom następujące polecenie:

    az webapp config set --subscription <sub> -g <group-name> -n <app-name> --generic-configurations '{"vnetRouteAllEnabled": true}'
    
  2. Upewnij się, że konfiguracja magazynu zezwala na dostęp do niej sieci lub podsieci używanej przez aplikację.

Uzyskiwanie dostępu do magazynów przy użyciu tożsamości przypisanej przez użytkownika

Niektóre aplikacje muszą odwoływać się do wpisów tajnych w czasie tworzenia, gdy tożsamość przypisana przez system nie jest jeszcze dostępna. W takich przypadkach można utworzyć tożsamość przypisaną przez użytkownika i uzyskać dostęp do magazynu z wyprzedzeniem.

Po udzieleniu uprawnień do tożsamości przypisanej przez użytkownika wykonaj następujące kroki:

  1. Przypisz tożsamość do aplikacji, jeśli jeszcze tego nie zrobiono.

  2. Skonfiguruj aplikację do używania tej tożsamości dla operacji referencyjnych magazynu kluczy, ustawiając keyVaultReferenceIdentity właściwość na identyfikator zasobu tożsamości przypisanej przez użytkownika.

    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}
    

To ustawienie dotyczy wszystkich odwołań magazynu kluczy dla aplikacji.

Wymiana

Jeśli wersja wpisu tajnego nie jest określona w odwołaniu, aplikacja używa najnowszej wersji, która istnieje w magazynie kluczy. Gdy nowsze wersje staną się dostępne, na przykład ze zdarzeniem rotacji, aplikacja zostanie automatycznie zaktualizowana i rozpocznie korzystanie z najnowszej wersji w ciągu 24 godzin. Opóźnienie jest spowodowane tym, że usługa App Service buforuje wartości odwołań do magazynu kluczy i pobiera je ponownie co 24 godziny. Każda zmiana konfiguracji w aplikacji powoduje ponowne uruchomienie aplikacji i natychmiastowe ponowne pobranie wszystkich odwołanych wpisów tajnych.

Ustawienia aplikacji źródłowej z magazynu kluczy

Aby użyć odwołania do magazynu kluczy, ustaw odwołanie jako wartość ustawienia. Aplikacja może odwoływać się do wpisu tajnego za pomocą klucza w zwykły sposób. Nie są wymagane żadne zmiany w kodzie.

Porada

Większość ustawień aplikacji korzystających z odwołań magazynu kluczy powinna być oznaczona jako ustawienia miejsca, ponieważ dla każdego środowiska powinny istnieć oddzielne magazyny.

Odwołanie do magazynu kluczy ma postać @Microsoft.KeyVault({referenceString}), gdzie {referenceString} znajduje się w jednym z następujących formatów:

Ciąg odwołania Opis
SecretUri=secretUri Identyfikator SecretUri powinien być pełnym identyfikatorem URI płaszczyzny danych wpisu tajnego w magazynie, opcjonalnie zawierającym wersję, np. https://myvault.vault.azure.net/secrets/mysecret/ lub https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931
VaultName=vaultName; SecretName=secretName; SecretVersion=secretVersion Nazwa magazynu jest wymagana i jest nazwą magazynu. Nazwa _wpisu tajnego jest wymagana i jest nazwą wpisu tajnego. Element SecretVersion jest opcjonalny, ale jeśli istnieje wskazuje wersję wpisu tajnego do użycia.

Na przykład pełne odwołanie będzie wyglądać podobnie do następującego ciągu:

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

Inna możliwość:

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

Zagadnienia dotyczące instalowania Azure Files

Aplikacje mogą używać WEBSITE_CONTENTAZUREFILECONNECTIONSTRING ustawienia aplikacji do instalowania Azure Files jako systemu plików. To ustawienie ma sprawdzanie poprawności, aby upewnić się, że aplikacja może być prawidłowo uruchomiona. Platforma opiera się na udostępnianiu zawartości w Azure Files i zakłada domyślną nazwę, chyba że zostanie określona za pośrednictwem WEBSITE_CONTENTSHARE ustawienia. W przypadku żądań modyfikujących te ustawienia platforma sprawdza, czy ten udział zawartości istnieje, i próbuje go utworzyć, jeśli nie. Jeśli nie można zlokalizować ani utworzyć udziału zawartości, blokuje żądanie.

Jeśli używasz odwołań do magazynu kluczy w tym ustawieniu, sprawdzanie poprawności domyślnie kończy się niepowodzeniem, ponieważ nie można rozpoznać samego wpisu tajnego podczas przetwarzania żądania przychodzącego. Aby uniknąć tego problemu, możesz pominąć walidację, ustawiając wartość WEBSITE_SKIP_CONTENTSHARE_VALIDATION "1". To ustawienie informuje App Service o obejściu wszystkich testów i nie tworzy udziału zawartości. Upewnij się, że została utworzona z wyprzedzeniem.

Przestroga

Jeśli pominiesz walidację i parametry połączenia lub udział zawartości są nieprawidłowe, aplikacja nie będzie mogła uruchomić poprawnie i będzie obsługiwać tylko błędy HTTP 500.

W ramach tworzenia aplikacji próba instalowania udziału zawartości może zakończyć się niepowodzeniem z powodu braku propagacji uprawnień tożsamości zarządzanej lub nie skonfigurowano integracji z siecią wirtualną. Możesz odroczyć konfigurowanie Azure Files do późniejszego użycia w szablonie wdrożenia, aby go uwzględnić. Aby dowiedzieć się więcej, zobacz Wdrażanie usługi Azure Resource Manager. W takim przypadku App Service używa domyślnego systemu plików do momentu skonfigurowania Azure Files, a pliki nie są kopiowane. Przed zainstalowaniem Azure Files należy się upewnić, że w okresie przejściowym nie są podejmowane żadne próby wdrożenia.

Zagadnienia dotyczące instrumentacji usługi Application Insights

Aplikacje mogą używać APPINSIGHTS_INSTRUMENTATIONKEY ustawień aplikacji lub APPLICATIONINSIGHTS_CONNECTION_STRING do integracji z usługą Application Insights. Środowiska portalu dla App Service i Azure Functions również używają tych ustawień do przedstawiania danych telemetrycznych z zasobu. Jeśli te wartości pochodzą z Key Vault, te środowiska nie są dostępne i zamiast tego należy pracować bezpośrednio z zasobem usługi Application Insights, aby wyświetlić dane telemetryczne. Jednak te wartości nie są uznawane za wpisy tajne, więc możesz też rozważyć ich bezpośrednie skonfigurowanie zamiast używania odwołań do magazynu kluczy.

Wdrożenie usługi Azure Resource Manager

Podczas automatyzowania wdrożeń zasobów za pośrednictwem szablonów usługi Azure Resource Manager może być konieczne sekwencjonowanie zależności w określonej kolejności, aby ta funkcja działała. Pamiętaj, aby zdefiniować ustawienia aplikacji jako własny zasób, zamiast używać siteConfig właściwości w definicji aplikacji. Jest to spowodowane tym, że aplikacja musi być najpierw zdefiniowana, aby tożsamość przypisana przez system została utworzona za jej pomocą i może być używana w zasadach dostępu.

Poniższy przykładowy szablon jest przykładem tego, jak może wyglądać aplikacja funkcji:

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

Uwaga

W tym przykładzie wdrożenie kontroli źródła zależy od ustawień aplikacji. Jest to zwykle niebezpieczne zachowanie, ponieważ aktualizacja ustawień aplikacji zachowuje się asynchronicznie. Jednak ponieważ dołączyliśmy WEBSITE_ENABLE_SYNC_UPDATE_SITE ustawienie aplikacji, aktualizacja jest synchroniczna. Oznacza to, że wdrożenie kontroli źródła rozpocznie się dopiero po pełnej aktualizacji ustawień aplikacji. Aby uzyskać więcej ustawień aplikacji, zobacz Zmienne środowiskowe i ustawienia aplikacji w Azure App Service.

Rozwiązywanie problemów z odwołaniami do magazynu kluczy

Jeśli odwołanie nie zostało poprawnie rozpoznane, zamiast tego zostanie użyty ciąg odwołania (na przykład @Microsoft.KeyVault(...)). Może to spowodować, że aplikacja zgłasza błędy, ponieważ oczekuje wpisu tajnego innej wartości.

Niepowodzenie rozwiązania jest często spowodowane błędną konfiguracją zasad dostępu Key Vault. Może to być jednak spowodowane tym, że wpis tajny już nie istnieje lub błąd składniowy w samym odwołaniu.

Jeśli składnia jest poprawna, możesz wyświetlić inne przyczyny błędu, sprawdzając bieżący stan rozwiązania w portalu. Przejdź do obszaru Ustawienia aplikacji i wybierz pozycję "Edytuj", aby uzyskać odwołanie. W oknie dialogowym edycji są wyświetlane informacje o stanie, w tym wszelkie błędy. Jeśli nie widzisz komunikatu o stanie, oznacza to, że składnia jest nieprawidłowa i nie jest rozpoznawana jako odwołanie do magazynu kluczy.

Możesz również użyć jednego z wbudowanych detektorów, aby uzyskać dodatkowe informacje.

Używanie detektora do App Service

  1. W portalu przejdź do aplikacji.
  2. Kliknij pozycję Diagnozowanie i rozwiązywanie problemów.
  3. Wybierz pozycję Dostępność i wydajność, a następnie wybierz pozycję Aplikacja internetowa w dół.
  4. W polu wyszukiwania wyszukaj i wybierz pozycję Key Vault Diagnostyka ustawień aplikacji.

Używanie detektora do Azure Functions

  1. W portalu przejdź do aplikacji.
  2. Przejdź do pozycji Funkcje platformy.
  3. Kliknij pozycję Diagnozowanie i rozwiązywanie problemów.
  4. Wybierz pozycję Dostępność i wydajność, a następnie wybierz pozycję Aplikacja funkcji nie działa lub zgłasza błędy.
  5. Wybierz pozycję Key Vault Diagnostyka ustawień aplikacji.