无法将 'User-managed identity' 用于 Azure Function App

Unable to use 'User-managed identity' with Azure Function App

我正在尝试将 'User-managed identity' 与我的函数应用程序一起使用。托管 ID 在托管功能的资源组级别具有贡献者访问权限。这是一个 powershell 函数,目前它只有

Write-Host "Hello World"

当我 运行 我的函数时出现以下错误:

2021-10-05T13:34:15Z   [Warning]   WARNING: Unable to acquire token for tenant 'organizations' with error 'ManagedIdentityCredential authentication failed: Service request failed.
Status: 400 (Bad Request)

Headers:
Date: Tue, 05 Oct 2021 13:34:14 GMT
Content-Length: 133
'
2021-10-05T13:34:16Z   [Error]   ERROR: ManagedIdentityCredential authentication failed: Service request failed.
Status: 400 (Bad Request)

Headers:
Date: Tue, 05 Oct 2021 13:34:14 GMT
Content-Length: 133


Exception             : 
    Type           : Azure.Identity.AuthenticationFailedException
    TargetSite     : 
        Name          : FailWrapAndThrow
        DeclaringType : Azure.Identity.CredentialDiagnosticScope, Azure.Identity, Version=1.4.0.0, Culture=neutral, PublicKeyToken=92742159e12e44c8
        MemberType    : Method
        Module        : Azure.Identity.dll
    StackTrace     : 
   at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex)
   at Azure.Identity.ManagedIdentityCredential.GetTokenImplAsync(Boolean async, TokenRequestContext requestContext, CancellationToken cancellationToken)
   at Azure.Identity.ManagedIdentityCredential.GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
   at Microsoft.Azure.PowerShell.Authenticators.MsalAccessTokenAcquirer.GetAccessTokenAsync(String callerClassName, String parametersLog, TokenCredential tokenCredential, TokenRequestContext requestContext, CancellationToken cancellationToken, String tenantId, String userId, String homeAccountId)
   at Microsoft.Azure.Commands.Common.Authentication.Factories.AuthenticationFactory.Authenticate(IAzureAccount account, IAzureEnvironment environment, String tenant, SecureString password, String promptBehavior, Action`1 promptAction, IAzureTokenCache tokenCache, String resourceId)
   at Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient.AcquireAccessToken(IAzureAccount account, IAzureEnvironment environment, String tenantId, SecureString password, String promptBehavior, Action`1 promptAction, String resourceId)
   at Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient.ListAccountTenants(IAzureAccount account, IAzureEnvironment environment, SecureString password, String promptBehavior, Action`1 promptAction)
   at Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient.Login(IAzureAccount account, IAzureEnvironment environment, String tenantId, String subscriptionId, String subscriptionName, SecureString password, Boolean skipValidation, Action`1 promptAction, String name, Boolean shouldPopulateContextList, Int32 maxContextPopulation, String authScope)
   at Microsoft.Azure.Commands.Profile.ConnectAzureRmAccountCommand.<>c__DisplayClass118_2.<ExecuteCmdlet>b__5()
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.Tasks.Task.<>c.<.cctor>b__274_0(Object obj)
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.Azure.Commands.Profile.ConnectAzureRmAccountCommand.<>c__DisplayClass118_0.<ExecuteCmdlet>b__1(AzureRmProfile localProfile, RMProfileClient profileClient, String name)
   at Microsoft.Azure.Commands.Profile.ConnectAzureRmAccountCommand.<>c__DisplayClass126_0.<SetContextWithOverwritePrompt>b__0(AzureRmProfile prof, RMProfileClient client)
   at Microsoft.Azure.Commands.Profile.Common.AzureContextModificationCmdlet.ModifyContext(Action`2 contextAction)
   at Microsoft.Azure.Commands.Profile.ConnectAzureRmAccountCommand.SetContextWithOverwritePrompt(Action`3 setContextAction)
   at Microsoft.Azure.Commands.Profile.ConnectAzureRmAccountCommand.ExecuteCmdlet()
   at Microsoft.WindowsAzure.Commands.Utilities.Common.CmdletExtensions.<>c__3`1.<ExecuteSynchronouslyOrAsJob>b__3_0(T c)
   at Microsoft.WindowsAzure.Commands.Utilities.Common.CmdletExtensions.ExecuteSynchronouslyOrAsJob[T](T cmdlet, Action`1 executor)
   at Microsoft.WindowsAzure.Commands.Utilities.Common.CmdletExtensions.ExecuteSynchronouslyOrAsJob[T](T cmdlet)
   at Microsoft.WindowsAzure.Commands.Utilities.Common.AzurePSCmdlet.ProcessRecord()
    Message        : ManagedIdentityCredential authentication failed: Service request failed.
                     Status: 400 (Bad Request)
                     
                     Headers:
                     Date: Tue, 05 Oct 2021 13:34:14 GMT
                     Content-Length: 133
                     
    InnerException : 
        Type       : Azure.RequestFailedException
        Status     : 400
        TargetSite : 
            Name          : MoveNext
            DeclaringType : Azure.Identity.ManagedIdentitySource+<HandleResponseAsync>d__10, Azure.Identity, Version=1.4.0.0, Culture=neutral, PublicKeyToken=92742159e12e44c8
            MemberType    : Method
            Module        : Azure.Identity.dll
        StackTrace : 
   at Azure.Identity.ManagedIdentitySource.HandleResponseAsync(Boolean async, TokenRequestContext context, Response response, CancellationToken cancellationToken)
   at Azure.Identity.ManagedIdentitySource.AuthenticateAsync(Boolean async, TokenRequestContext context, CancellationToken cancellationToken)
   at Azure.Identity.ManagedIdentityClient.AuthenticateAsync(Boolean async, TokenRequestContext context, CancellationToken cancellationToken)
   at Azure.Identity.ManagedIdentityCredential.GetTokenImplAsync(Boolean async, TokenRequestContext requestContext, CancellationToken cancellationToken)
        Message    : Service request failed.
                     Status: 400 (Bad Request)
                     
                     Headers:
                     Date: Tue, 05 Oct 2021 13:34:14 GMT
                     Content-Length: 133
                     
        Source     : Azure.Identity
        HResult    : -2146233088
    Source         : Azure.Identity
    HResult        : -2146233088
CategoryInfo          : CloseError: (:) [Connect-AzAccount], AuthenticationFailedException
FullyQualifiedErrorId : Microsoft.Azure.Commands.Profile.ConnectAzureRmAccountCommand
InvocationInfo        : 
    MyCommand        : Connect-AzAccount
    ScriptLineNumber : 16
    OffsetInLine     : 5
    HistoryId        : 1
    ScriptName       : C:\home\site\wwwroot\profile.ps1
    Line             : Connect-AzAccount -Identity
                       
    PositionMessage  : At C:\home\site\wwwroot\profile.ps1:16 char:5
                       +     Connect-AzAccount -Identity
                       +     ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    PSScriptRoot     : C:\home\site\wwwroot
    PSCommandPath    : C:\home\site\wwwroot\profile.ps1
    InvocationName   : Connect-AzAccount
    CommandOrigin    : Internal
ScriptStackTrace      : at <ScriptBlock>, C:\home\site\wwwroot\profile.ps1: line 16
PipelineIterationInfo : 





2021-10-05T13:34:17Z   [Error]   Errors reported while executing profile.ps1. See logs for detailed errors. Profile location: C:\home\site\wwwroot\profile.ps1.
2021-10-05T13:34:17Z   [Information]   INFORMATION: Hello World

我已按照 doc here 中列出的步骤进行操作,并且还仔细检查了功能应用程序是否设置了 IDENTITY_ENDPOINT 和 IDENTITY_HEADER 值。

我这辈子都无法让它工作。但是它确实适用于 'System-assigned managed identity'.

我也尝试了 Connect-AzAccount 和 Set-AzContext 命令的组合,但我最终遇到了同样的错误。

有谁能指出我在这里遗漏了什么,将不胜感激。

谢谢Owns支持您的回答添加有关如何在功能应用程序设置中添加用户身份的屏幕截图。

此外, 需要启用系统分配,默认情况下它会处于关闭状态需要将其打开并保存如下图

下面是有关如何在 Azure 函数中使用托管标识的示例代码

# Replace the built-in code for Azure function
# Input bindings are passed in via param block.
param($Timer)

# Get the current universal time in the default string format
$currentUTCtime = (Get-Date).ToUniversalTime()
# The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled.
if ($Timer.IsPastDue) {
    Write-Host "PowerShell timer is running late!"
}

# This function app is using 'Managed Service Identity' to connect to the Azure SQL Database.
# Used help from following resources in setting up 'Managed Service Identity'
# [https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi](https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi)
# [https://www.azurecorner.com/using-managed-service-identity-in-azure-functions-to-access-azure-sql-database/](https://www.azurecorner.com/using-managed-service-identity-in-azure-functions-to-access-azure-sql-database/)
# [https://docs.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=powershell](https://docs.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=powershell)
$resourceURI = "[https://database.windows.net/](https://database.windows.net/)"
$tokenAuthURI = $env:MSI_ENDPOINT + "?resource=$resourceURI&api-version=2017-09-01"
$tokenResponse = Invoke-RestMethod -Method Get -Headers @{"Secret"="$env:MSI_SECRET"} -Uri $tokenAuthURI
$accessToken = $tokenResponse.access_token
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Data Source =azuresqlservername.database.windows.net ; Initial Catalog = azuresqldatabasename"
$SqlConnection.AccessToken = $AccessToken
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "ALTER INDEX ALL ON testRebuild REBUILD;"
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)

有关更多信息,请查看 Managed Identity link.

成功了,下面需要 运行。ps1

Connect-AzAccount -Identity -AccountId <Managed-User Identity> -ErrorAction SilentlyContinue