Compartir a través de

监视管理租户中的委托更改

作为服务提供商,你可能希望跟踪通过 Azure Lighthouse 委托给租户的客户订阅或资源组的状况,或当之前委派的资源被移除时进行跟踪。

在管理租户中,Azure 活动日志将会跟踪租户级别的委托活动。 记录的此活动包括任何在客户租户中添加或删除的委托。

本文介绍跨所有客户监视租户委派活动所需的权限。 其中还包含一个示例脚本,用于演示一种查询和报告此数据的方法。

重要

请在您的管理租户中,而非任何客户租户中,执行所有这些步骤。

虽然本文指的是服务提供商和客户, 但管理多个租户的企业 可以使用相同的流程。

启用对租户级数据的访问

要访问租户级别的活动日志数据,帐户必须在根范围 (/) 拥有 Azure 内置的 Monitoring Reader 角色。 此分配必须由具有附加提升访问权限的全局管理员执行。

提升全局管理员帐户的访问权限

若要在根范围 (/) 分配角色,你必须具有“全局管理员”角色,并且该角色带有提升的访问权限。 仅在需要进行角色分配时启用此提升的访问权限,并在完成后将其删除。

有关添加和删除提升的访问权限的详细说明,请参阅提升访问权限以管理所有 Azure 订阅和管理组

提升您的访问权限后,您的帐户在 Azure 中拥有根目录范围的用户访问管理员角色。 此角色分配允许查看所有资源,并在目录中的任何订阅或管理组中分配访问权限。 它还允许你在根级别分配角色。

在根范围分配“监视读取者”角色

提升访问权限后,可以向帐户分配适当的权限,以便它可以查询租户级活动日志数据。 在管理租户的根范围内,将 Azure 内置角色监视读取者分配给此帐户。

重要

在根范围授予角色分配意味着相同的权限会应用于租户中的每个资源。 由于此访问权限非常广泛,因此我们建议 将此角色分配给服务主体帐户,并使用该帐户查询数据

还可以将根范围内的“监视读取者”角色分配给单个用户或用户组,以便他们可以 直接在 Azure 门户中查看委派信息。 如果选择此选项,请将这种广泛的访问权限限制为尽可能少的用户数。

使用以下方法之一来进行根范围的分配。

PowerShell

# Log in first with Connect-AzAccount -Environment AzureChinaCloud

New-AzRoleAssignment -SignInName <yourLoginName> -Scope "/" -RoleDefinitionName "Monitoring Reader"  -ObjectId <objectId> 

Azure CLI

# Log in first with az login

az role assignment create --assignee 00000000-0000-0000-0000-000000000000 --role "Monitoring Reader" --scope "/"

删除全局管理员帐户的提升访问权限

将根范围的“监视读者”角色分配给所需的帐户后,请务必将全局管理员帐户的提升访问权限删除,因为不再需要此高访问级别。

在 Azure 门户中查看委托更改

在根范围内被分配了“监控读取者”角色的用户可以直接在 Azure 门户中查看委派更改。

  1. 转到 “我的客户 ”页,然后从左侧导航菜单中选择 “活动日志 ”。
  2. 请确保在屏幕上方附近的筛选器中已选择目录活动
  3. 选择你想要查看委派更改的时间范围。

Azure 门户中的委托更改的屏幕截图。

使用服务主体帐户查询活动日志

由于根范围内的“监控读取者”角色具有广泛的访问权限,因此应将该角色分配给服务主体帐户,并通过脚本使用该帐户查询数据。

重要

目前,查询此数据时,具有大量委派活动的租户可能会遇到错误。

使用服务主体帐户查询活动日志时,请遵循以下最佳做法:

创建在管理租户的根范围内具有监视读取者访问权限的服务主体帐户后,使用它来查询和报告委派活动。

此 Azure PowerShell 脚本 可以查询过去一天的活动,并报告任何添加或删除的委派(或未成功尝试)。 它会查询租户活动日志数据,然后构造以下值来报告已添加或删除的委托:

  • DelegatedResourceId:委托的订阅或资源组的 ID
  • CustomerTenantId:客户租户 ID
  • CustomerSubscriptionId:委托的订阅 ID,或包含委托的资源组的订阅 ID
  • CustomerDelegationStatus:委托的资源的状态更改(成功或失败)
  • EventTimeStamp:记录委托更改的日期和时间

查询此数据时,请记住:

  • 如果在单个部署中委派了多个资源组,则会为每个资源组返回单独的条目。
  • 对前一委派所做的更改(例如更新权限结构)会记录为一个已添加的委派。
  • 如前所述,帐户必须在根范围(/)具有“监视读取者”(Monitoring Reader)Azure 内置角色才能访问此租户级数据。
  • 你可以在自己的工作流和报告中使用此数据。 例如,可以使用日志引入 API将数据从 REST API 客户端记录到 Azure Monitor,然后使用操作组创建通知或警报。
# Log in first with Connect-AzAccount -Environment AzureChinaCloud

# Azure Lighthouse: Query Tenant Activity Log for registered/unregistered delegations for the last 1 day

$GetDate = (Get-Date).AddDays((-1))

$dateFormatForQuery = $GetDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")

# Getting Azure context for the API call
$currentContext = Get-AzContext

# Fetching new token
$azureRmProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
$profileClient = [Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient]::new($azureRmProfile)
$token = $profileClient.AcquireAccessToken($currentContext.Tenant.Id)

$listOperations = @{
    Uri = "https://management.chinacloudapi.cn/providers/microsoft.insights/eventtypes/management/values?api-version=2015-04-01&`$filter=eventTimestamp ge '$($dateFormatForQuery)'"
    Headers = @{
        Authorization  = "Bearer $($token.AccessToken)"
        'Content-Type' = 'application/json'
    }
    Method  = 'GET'
}
$list = Invoke-RestMethod @listOperations

# First link can be empty - and point to a next link (or potentially multiple pages)
# While you get more data - continue fetching and add result
while($list.nextLink){
    $list2 = Invoke-RestMethod $list.nextLink -Headers $listOperations.Headers -Method Get
    $data+=$list2.value;
    $list.nextLink = $list2.nextlink;
}

$showOperations = $data;

if ($showOperations.operationName.value -eq "Microsoft.Resources/tenants/register/action") {
    $registerOutputs = $showOperations | Where-Object -FilterScript { $_.eventName.value -eq "EndRequest" -and $_.resourceType.value -and $_.operationName.value -eq "Microsoft.Resources/tenants/register/action" }
    foreach ($registerOutput in $registerOutputs) {
        $eventDescription = $registerOutput.description | ConvertFrom-Json;
    $registerOutputdata = [pscustomobject]@{
        Event                    = "An Azure customer has registered delegated resources to your Azure tenant";
        DelegatedResourceId      = $eventDescription.delegationResourceId; 
        CustomerTenantId         = $eventDescription.subscriptionTenantId;
        CustomerSubscriptionId   = $eventDescription.subscriptionId;
        CustomerDelegationStatus = $registerOutput.status.value;
        EventTimeStamp           = $registerOutput.eventTimestamp;
        }
        $registerOutputdata | Format-List
    }
}
if ($showOperations.operationName.value -eq "Microsoft.Resources/tenants/unregister/action") {
    $unregisterOutputs = $showOperations | Where-Object -FilterScript { $_.eventName.value -eq "EndRequest" -and $_.resourceType.value -and $_.operationName.value -eq "Microsoft.Resources/tenants/unregister/action" }
    foreach ($unregisterOutput in $unregisterOutputs) {
        $eventDescription = $unregisterOutput.description | ConvertFrom-Json;
    $unregisterOutputdata = [pscustomobject]@{
        Event                    = "An Azure customer has unregistered delegated resources from your Azure tenant";
        DelegatedResourceId      = $eventDescription.delegationResourceId;
        CustomerTenantId         = $eventDescription.subscriptionTenantId;
        CustomerSubscriptionId   = $eventDescription.subscriptionId;
        CustomerDelegationStatus = $unregisterOutput.status.value;
        EventTimeStamp           = $unregisterOutput.eventTimestamp;
        }
        $unregisterOutputdata | Format-List
    }
}
else {
    Write-Output "No new delegation events for tenant: $($currentContext.Tenant.TenantId)"
}

后续步骤