Azure App Service 및 Azure Functions에서 앱 설정으로 Key Vault 참조 사용

이 문서에서는 Azure Key Vault의 비밀을 App Service 또는 Azure Functions 앱에서 앱 설정 또는 연결 문자열 값으로 사용하는 방법을 보여 줍니다.

Azure Key Vault는 액세스 정책 및 감사 기록에 대한 전체 제어와 함께 중앙 집중식 비밀 관리를 제공하는 서비스입니다. 앱 설정 또는 연결 문자열이 키 자격 증명 모음 참조인 경우 애플리케이션 코드는 다른 앱 설정 또는 연결 문자열처럼 사용할 수 있습니다. 이렇게 하면 앱의 구성과 별도로 비밀을 유지할 수 있습니다. 앱 설정은 안전하게 암호화되어 있지만 비밀 관리 기능이 필요한 경우 키 자격 증명 모음으로 이동해야 합니다.

키 자격 증명 모음에 앱 액세스 권한 부여

키 자격 증명 모음에서 비밀을 읽으려면 자격 증명 모음을 만들고 해당 자격 증명에 앱 권한을 부여해야 합니다.

  1. Key Vault 빠른 시작에 따라 키 자격 증명 모음을 만듭니다.

  2. 애플리케이션에 대한 관리 ID를 만듭니다.

    키 자격 증명 모음 참조는 기본적으로 앱의 시스템 할당 ID를 사용하지만 사용자가 할당한 ID를 지정할 수 있습니다.

  3. 이전에 만든 관리 ID에 대한 키 자격 증명 모음 비밀에 대한 읽기 액세스 권한을 부여합니다. 이 작업을 수행하는 방법은 키 자격 증명 모음의 권한 모델에 따라 달라집니다.

네트워크 제한 자격 증명 모음 액세스

자격 증명 모음이 네트워크 제한으로 구성된 경우 애플리케이션에 네트워크 액세스 권한이 있는지 확인합니다. 비밀 요청의 원본 IP가 다를 수 있으므로 자격 증명 모음은 앱의 퍼블릭 아웃바운드 IP에 의존해서는 안 됩니다. 대신 앱에서 사용하는 가상 네트워크의 트래픽을 허용하도록 자격 증명 모음을 구성해야 합니다.

  1. App Service 네트워킹 기능Azure Functions 네트워킹 옵션에 설명된 대로 애플리케이션에 아웃바운드 네트워킹 기능이 구성되어 있는지 확인합니다.

    프라이빗 엔드포인트에 연결하는 Linux 애플리케이션은 가상 네트워크를 통해 모든 트래픽을 라우팅하도록 명시적으로 구성해야 합니다. 이 요구 사항은 향후 업데이트에서 제거됩니다. 이 설정을 구성하려면 다음 명령을 실행합니다.

    az webapp config set --subscription <sub> -g <group-name> -n <app-name> --generic-configurations '{"vnetRouteAllEnabled": true}'
    
  2. 자격 증명 모음의 구성이 앱에서 액세스하는 데 사용하는 네트워크 또는 서브넷을 허용하는지 확인합니다.

사용자가 할당한 ID를 사용하여 자격 증명 모음에 액세스

일부 앱은 시스템 할당 ID를 아직 사용할 수 없는 경우 생성 시 비밀을 참조해야 합니다. 이러한 경우 사용자가 할당한 ID를 만들고 자격 증명 모음에 대한 액세스 권한을 미리 부여할 수 있습니다.

사용자가 할당한 ID에 대한 사용 권한을 부여한 후에는 다음 단계를 수행합니다.

  1. 아직 없는 경우 애플리케이션에 ID를 할당합니다.

  2. keyVaultReferenceIdentity 속성을 사용자가 할당한 ID의 리소스 ID로 설정하여 키 자격 증명 모음 참조 작업에 이 ID를 사용하도록 앱을 구성합니다.

    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}
    

이 설정은 앱의 모든 키 자격 증명 모음 참조에 적용됩니다.

회전

참조에 비밀 버전이 지정되지 않은 경우 앱은 키 자격 증명 모음에 있는 최신 버전을 사용합니다. 순환 이벤트와 같이 최신 버전을 사용할 수 있게 되면 앱이 자동으로 업데이트되고 24시간 이내에 최신 버전을 사용하기 시작합니다. 지연은 App Service가 키 자격 증명 모음 참조의 값을 캐시하고 24시간마다 다시 가져오기 때문입니다. 앱에 대한 구성 변경으로 인해 앱이 다시 시작되고 참조된 모든 비밀이 즉시 다시 생성됩니다.

키 자격 증명 모음의 원본 앱 설정

자격 증명 모음 참조를 사용하려면 설정 값으로 참조를 설정합니다. 앱은 키를 사용하여 비밀을 정상적으로 참조할 수 있습니다. 코드 변경은 필요하지 않습니다.

키 자격 증명 모음 참조를 사용하는 대부분의 앱 설정은 각 환경에 대해 별도의 자격 증명 모음이 있어야 하므로 슬롯 설정으로 표시되어야 합니다.

키 자격 증명 모음 참조는 @Microsoft.KeyVault({referenceString}) 형식이며, 여기서 {referenceString}은 다음 형식 중 하나입니다.

참조 문자열 설명
SecretUri=secretUri SecretUri는 자격 증명 모음에 있는 비밀의 전체 데이터 평면 URI이어야 하며, 선택적으로 버전(예: https://myvault.vault.azure.net/secrets/mysecret/ 또는 https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931)을 포함해야 합니다.
VaultName=vaultName;SecretName=secretName;SecretVersion=secretVersion VaultName은 필수이며 자격 증명 모음 이름입니다. SecretName은 필수이며 비밀 이름입니다. SecretVersion은 선택 사항이지만, 있으면 사용할 비밀의 버전을 나타냅니다.

예를 들어 전체 참조는 다음 문자열과 같습니다.

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

또는 다음과 같습니다.

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

Azure Files 탑재 시 고려 사항

앱은 WEBSITE_CONTENTAZUREFILECONNECTIONSTRING 애플리케이션 설정을 사용하여 Azure Files를 파일 시스템으로 탑재할 수 있습니다. 이 설정에는 앱이 제대로 시작될 수 있는지 확인하기 위한 유효성 검사가 포함되어 있습니다. 플랫폼은 Azure Files 내에서 콘텐츠 공유에 따라 달라지며 WEBSITE_CONTENTSHARE 설정을 통해 지정되지 않는 한 기본 이름을 사용합니다. 이러한 설정을 수정하는 모든 요청에 대해 플랫폼은 이 콘텐츠 공유가 있는지 확인하고, 없으면 만들려고 시도합니다. 콘텐츠 공유를 찾거나 만들 수 없으면 요청을 차단합니다.

이 설정에서 키 자격 증명 모음 참조를 사용하는 경우 들어오는 요청을 처리하는 동안 비밀 자체를 확인할 수 없으므로 기본적으로 유효성 검사가 실패합니다. 이 문제를 방지하려면 WEBSITE_SKIP_CONTENTSHARE_VALIDATION를 "1"로 설정하여 유효성 검사를 건너뛸 수 있습니다. 이 설정은 App Service에 모든 검사를 무시하도록 지시하고 콘텐츠 공유를 만들지 않습니다. 미리 만들어져 있는지 확인해야 합니다.

주의

유효성 검사를 건너뛰고 연결 문자열 또는 콘텐츠 공유가 유효하지 않으면 앱이 제대로 시작되지 않고 HTTP 500 오류만 제공됩니다.

앱을 만드는 과정에서 관리 ID 권한이 전파되지 않거나 가상 네트워크 통합이 설정되지 않아 콘텐츠 공유 탑재 시도가 실패할 수도 있습니다. 배포 템플릿에서 나중에 이를 수용할 때까지 Azure Files 설정을 연기할 수 있습니다. 자세한 내용은 Azure Resource Manager 배포를 참조하세요. 이 경우 App Service는 Azure Files가 설정될 때까지 기본 파일 시스템을 사용하고 파일은 복사되지 않습니다. Azure Files가 탑재되기 전에 중간 기간 동안 배포 시도가 발생하지 않도록 해야 합니다.

Application Insights 계측에 대한 고려 사항

앱은 APPINSIGHTS_INSTRUMENTATIONKEY 또는 APPLICATIONINSIGHTS_CONNECTION_STRING 애플리케이션 설정을 사용하여 Application Insights와 통합할 수 있습니다. App Service 및 Azure Functions에 대한 포털 환경에서도 이러한 설정을 사용하여 리소스의 원격 분석 데이터를 표시합니다. 이러한 값이 Key Vault에서 참조되는 경우 이러한 환경을 사용할 수 없으며 대신 Application Insights 리소스와 직접 작업하여 원격 분석을 확인해야 합니다. 그러나 이러한 값은 비밀로 간주되지 않으므로 키 자격 증명 모음 참조를 사용하는 대신 직접 구성하는 것이 좋습니다.

Azure Resource Manager 배포

Azure Resource Manager 템플릿을 통해 리소스 배포를 자동화할 때 이 기능이 작동하려면 종속성을 특정 순서로 시퀀스해야 할 수 있습니다. 앱 정의에서 siteConfig 속성을 사용하는 대신 앱 설정을 자체 리소스로 정의해야 합니다. 이는 앱을 먼저 정의해야 앱을 사용하여 시스템 할당 ID를 만들고 액세스 정책에서 사용할 수 있기 때문입니다.

다음 의사 템플릿은 함수 앱의 모양을 보여 주는 예입니다.

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

참고 항목

이 예제에서 원본 제어 배포는 애플리케이션 설정에 따라 다릅니다. 일반적으로 앱 설정 업데이트는 비동기적으로 동작하므로 안전하지 않은 동작입니다. 그러나 WEBSITE_ENABLE_SYNC_UPDATE_SITE 애플리케이션 설정을 포함했으므로 업데이트가 동기적입니다. 이는 애플리케이션 설정이 완전히 업데이트된 후에만 원본 제어 배포가 시작됨을 의미합니다. 더 많은 앱 설정은 Azure App Service에서 환경 변수 및 앱 설정을 참조하세요.

키 자격 증명 모음 참조 문제 해결

참조가 제대로 확인되지 않으면 참조 문자열이 대신 사용됩니다(예: @Microsoft.KeyVault(...)). 다른 값의 비밀을 예상하고 있기 때문에 애플리케이션에서 오류를 throw할 수 있습니다.

해결 오류는 일반적으로 Key Vault 액세스 정책의 잘못된 구성으로 인해 발생합니다. 그러나 비밀이 더 이상 존재하지 않거나 참조 자체의 구문 오류가 원인일 수도 있습니다.

구문이 올바르면 포털에서 현재 해결 상태를 확인하여 오류의 다른 원인을 확인할 수 있습니다. 애플리케이션 설정으로 이동하여 해당 참조에 관해 "편집"을 선택합니다. 편집 대화 상자에는 오류를 포함한 상태 정보가 표시됩니다. 상태 메시지가 표시되지 않으면 구문이 유효하지 않고 키 자격 증명 모음 참조로 인식되지 않음을 의미합니다.

기본 제공 탐지기 중 하나를 사용하여 추가 정보를 얻을 수도 있습니다.

App Service를 위한 탐지기 사용

  1. 포털에서 앱으로 이동합니다.
  2. 문제 진단 및 해결을 선택합니다.
  3. 가용성 및 성능을 선택하고 웹앱 중단을 선택합니다.
  4. 검색 상자에서 Key Vault 애플리케이션 설정 진단을 검색하고 선택합니다.

Azure Functions을 위한 탐지기 사용

  1. 포털에서 앱으로 이동합니다.
  2. 플랫폼 기능으로 이동합니다.
  3. 문제 진단 및 해결을 선택합니다.
  4. 가용성 및 성능을 선택하고 함수 앱 중단 또는 오류 보고를 선택합니다.
  5. Key Vault 애플리케이션 설정 진단을 선택합니다.