首页 > 解决方案 > 在 Azure 函数中使用托管标识访问 Graph API

问题描述

简短版本
我想避免使用用户名/密码/秘密/key valults/等。通过在 Azure Functions 上运行的 PowerShell 脚本中使用托管标识。
它似乎失败了:

Import-Module Microsoft.Graph.Authentication
Connect-MgGraph -Scopes 'Reports.Read.All', 'Group.ReadWrite.All' 

背景
我已经从一个安全的应用程序作为应用程序访问 Microsoft Graph,并且设置似乎很好。
我在 Azure 函数上启用了系统标识并授予 Microsoft Graph 权限,当我检查企业应用程序时,权限似乎很好。我在 GraphAggregatorService (00000003-0000-0000-c000-000000000000) 中找到了托管标识。

当我以我的身份从 VScode 调试时,脚本运行良好。

当 Azure Functions 运行代码时,会发生以下情况:

WARNING: Interactive authentication is not supported in this session,
falling back to DeviceCode. Future versions will not automatically fallback to DeviceCode.

然后

ERROR: Could not find file 'C:\home\site\wwwroot\.graph'. 
Exception : Type : System.IO.FileNotFoundException 
Message : Could not find file 'C:\home\site\wwwroot\.graph'. 
FileName : C:\home\site\wwwroot\.graph TargetSite : 
Name : MoveNext DeclaringType : Microsoft.Graph.PowerShell.Authentication.Cmdlets.ConnectMgGraph+<ProcessRecordAsync>d__52, Microsoft.Graph.Authentication, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 
...<cut>
Line : Connect-MgGraph -Scopes 'Reports.Read.All', 'Group.ReadWrite.All' PositionMessage : At C:\home\site\wwwroot\TestPowerShellTimer\run.ps1:15 char:1 + Connect-MgGraph -Scopes 'Reports.Read.All', 'Group.ReadWrite.All' 
...<cut>

代码

# Input bindings are passed in via param block.
param($Timer)

Import-Module Microsoft.Graph.Authentication
Connect-MgGraph -Scopes 'Reports.Read.All', 'Group.ReadWrite.All' 

$reportJson = Invoke-GraphRequest -Uri 'https://graph.microsoft.com/beta/reports/credentialUserRegistrationDetails?$top=5000' -Method GET

为什么
我可以使用 Connect-MsOnline(对 msonline 做同样的事情),但代码使用的完成时间要长得多。

正在遍历我们的用户以查看他们是否设置了 MFA,并将它们添加到安全组中。不,没有办法使用 azure 广告动态组 afaik 做到这一点。但是,如果有人对实现此目标的其他方法有建议,请随时提及...

我的想法
显然,我遗漏了一些东西或完全误解了一些东西。
错误消息“C:\home\site\wwwroot.graph”的部分,我无法弄清楚。在这一点上,谷歌不是我的朋友。

我想我必须以某种方式指示 AzF 使用托管标识:

Import-Module Microsoft.Graph.Authentication
Connect-MgGraph -Scopes -TenantId -ClientId 

但我不知道怎么做。我意识到我已经猜到了,然后是时候寻求帮助了。

如何通过 Microsoft.Graph.Authentication 模块在 Azure Functions 中使用托管标识?

标签: powershellazure-functionsazure-managed-identity

解决方案


由于您使用的是已连接到 Azure 的系统标识,因此您可以生成访问令牌并将其传递给Connect-MGGraph -AccessToken

这是我大约一两年前制作的一个功能,正是为了达到这个目的。(我需要任何经过身份验证的用户能够根据他们当前连接的身份获得任何 Azure 端点的令牌,而无需任何其他形式的凭据验证)

function Get-AzToken {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [String]
        $ResourceUri,
        [Switch]$AsHeader
    ) 
    $Context = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile.DefaultContext
    $Token = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $ResourceUri).AccessToken
    if ($AsHeader) {
        return @{Headers = @{Authorization = "Bearer $Token" } }
    }
    return $Token
    
}

$Token = Get-AzToken -ResourceUri 'https://graph.microsoft.com/'
Connect-MgGraph -AccessToken $Token

请注意,要使其正常工作,在您的 Azure 函数profile.ps1中,您应该Connect-AzAccount -Identity取消注释该行。

Profile.ps1片段


if ($env:MSI_SECRET) {
    Disable-AzContextAutosave -Scope Process | Out-Null
    Connect-AzAccount -Identity 
}

如果启用 Azure AD 身份验证,此方法将用于获取任何 Azure 终结点(包括您自己的函数)的令牌。

奖金

如果 Azure 函数受 Azure AD 身份验证保护,那么您将如何使用它来调用 Azure 函数。

# This work assuming you connecteded through Connect-AzAccount at some point.
# ResourceUri is the ClientID of your application.
$Headers = Get-AzToken -ResourceUri '3953d051-c61f-43c5-8848-487a921aae31' -AsHeader
$base = 'https://YourFunctionUrl.azurewebsites.net/api'
Invoke-RestMethod -Method Get -Uri "$base/MyApiEndpoint" @Headers 

推荐阅读