監視管理租用戶中的委派變更

身為服務提供者,您可能會想要注意何時透過 Azure Lighthouse 將客戶訂用帳戶或資源群組委派給租用戶,或何時移除先前委派的資源。

在管理租用戶中,Azure 活動記錄會追蹤租用戶層級的委派活動。 這個記錄的活動包括客戶租用戶的任何新增或移除的委派。

本主題說明監視所有客戶租用戶委派活動所需的權限。 這也包括範例指令碼,而此指令碼顯示一種對此資料進行查詢和報告的方法。

重要

所有這些步驟都必須在管理租用戶中執行,而不是在任何客戶租用戶中執行。

雖然我們在這個主題中所述的是服務提供者和客戶,但管理多個租用戶的企業可以使用相同的程序。

啟用租用戶層級資料的存取

若要存取租用戶層級活動記錄資料,必須在根範圍 (/) 將監視讀取者 Azure 內建角色指派給帳戶。 此指派必須由其全域管理員角色具有額外提高存取權的使用者執行。

提高全域管理員帳戶的存取權

若要在根範圍 (/) 指派角色,您需要擁有具有提高存取權的全域管理員角色。 只有在您需要進行角色指派時,才應該新增此提高存取權,然後在完成時予以移除。

如需新增和移除提高存取權的詳細指示,請參閱提高存取權以管理所有 Azure 訂用帳戶和管理群組

在您提高存取權之後,您的帳戶將會在根範圍獲指派 Azure 中的使用者存取管理員角色。 此角色指派可讓您檢視所有資源,並指派目錄中任何訂用帳戶或管理群組中的存取權,以及在根範圍進行角色指派。

在根範圍指派監視讀取者角色

提高存取權之後,您可以將適當的權限指派給帳戶,以查詢租用戶層級活動記錄資料。 此帳戶需要在管理租用戶的根範圍指派監視讀取者 Azure 內建角色。

重要

在根範圍授與角色指派,表示相同的權限將會套用至租用戶中的每個資源。 因為這是廣泛的存取層級,所以建議將此角色指派給服務主體帳戶,並使用該帳戶來查詢資料

您也可以將根範圍中的監視讀取者角色指派給個別使用者或使用者群組,讓他們可以直接在 Azure 入口網站中檢視委派資訊。 如果您這樣做,則請注意,這是廣泛的存取層級,應該盡可能限制為最少的使用者數目。

使用下列其中一種方法來進行根範圍指派。

PowerShell

# Log in first with Connect-AzAccount if you're not using Cloud Shell

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

Azure CLI

# Log in first with az login if you're not using Cloud Shell

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

移除全域管理員帳戶的提高權限存取權

將根範圍的監視讀取者角色指派給所需的帳戶之後,請務必針對全域管理員帳戶移除提升存取權,因為將不再需要此存取層級。

檢視 Azure 入口網站中的委派變更

已獲指派根範圍監視讀取者角色的使用者可以直接在 Azure 入口網站中檢視委派變更。

  1. 導覽至 [我的客戶] 頁面,然後從左側導覽功能表中選取 [活動記錄]
  2. 確定在接近畫面頂端的篩選中選取 [目錄活動]

委派變更清單隨即出現。 您可以選取 [編輯資料行] 以顯示或隱藏 [狀態]、[事件類別]、[時間]、[時間戳記]、[訂用帳戶]、[事件起始者]、[資源群組]、[資源類型] 和 [資源] 值。

Screenshot of delegation changes in the Azure portal.

使用服務主體帳戶來查詢活動記錄

因為根範圍的監視讀取者角色是這類廣泛的存取層級,所以您可能想要將該角色指派給服務主體帳戶,並使用該帳戶以使用下面的指令碼來查詢資料。

重要

目前,查詢此資料時,具有大量委派活動的租用戶可能會發生錯誤。

使用服務主體帳戶來查詢活動記錄時,建議下列最佳做法:

建立具有管理租用戶根範圍監視讀取者存取權的新服務主體帳戶之後,您就可以將其用來查詢和報告租用戶中的委派活動。

此 Azure PowerShell 指令碼 (英文) 可以用來查詢前一天任何已新增或移除的委派 (或未成功的嘗試) 的活動和報表。 其會查詢租用戶活動記錄資料,然後建構下列值,以報告已新增或移除的委派:

  • DelegatedResourceId:已委派訂用帳戶或資源群組的識別碼
  • CustomerTenantId:客戶租用戶識別碼
  • CustomerSubscriptionId:已委派或包含已委派資源群組的訂用帳戶識別碼
  • CustomerDelegationStatus:已委派資源的狀態變更 (成功或失敗)
  • EventTimeStamp:記錄委派變更的日期和時間

查詢此資料時,請記住:

  • 如果在單一部署中委派多個資源群組,則會針對每個資源群組傳回個別的項目。
  • 對先前委派所做的變更 (例如更新權限結構) 將會記錄為已新增的委派。
  • 如上所述,帳戶必須具有根範圍 (/) 的監視讀取者 Azure 內建角色,才能存取此租用戶層級資料。
  • 您可以在自己的工作流程和報告中使用此資料。 例如,您可以使用 HTTP 資料收集器 API (預覽) 從 REST API 用戶端將資料記錄至 Azure 監視器,然後使用動作群組 (部分機器翻譯) 來建立通知或警示。
# Log in first with Connect-AzAccount if you're not using Cloud Shell

# 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.azure.com/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 = $registerOutput.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)"
}

下一步