你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

获取资源更改

在日常使用、重新配置甚至是重新部署的过程中,资源都会发生更改。 大部分更改是依设计做出的,但有时并非如此。 可以:

  • 查找在 Azure 资源管理器属性上检测到更改的时间。
  • 查看属性更改详细信息。
  • 大规模查询订阅、管理组或租户中的变更。

本文内容:

  • 有效负载 JSON 的样子。
  • 如何使用 CLI、PowerShell 或 Azure 门户通过 Resource Graph 查询资源更改。
  • 查询资源更改的查询示例和最佳做法。
  • 更改分析使用“更改行动者”功能:
    • changedBy:发起了资源更改的人员,例如应用 ID 或授权人员的电子邮件地址。
    • clientType:进行了更改的客户端,例如 Azure 门户
    • operation:调用的操作,例如 Microsoft.Compute/virtualmachines/write

先决条件

  • 要使 Azure PowerShell 能够查询 Azure Resource Graph,则添加模块
  • 若要使 Azure CLI 能够查询 Azure Resource Graph,则添加扩展

了解更改事件属性

创建、更新或删除资源时,会创建一个新的变更资源 (Microsoft.Resources/changes) 来扩展已修改的资源并表示已更改的属性。 更改记录应在五分钟内提供。 以下 JSON 有效负载示例演示了更改资源属性:

{
  "targetResourceId": "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/myResourceGroup/providers/microsoft.compute/virtualmachines/myVM",
  "targetResourceType": "microsoft.compute/virtualmachines",
  "changeType": "Update",
  "changeAttributes": {
    "previousResourceSnapshotId": "11111111111111111111_22222222-3333-aaaa-bbbb-444444444444_5555555555_6666666666",
    "newResourceSnapshotId": "33333333333333333333_44444444-5555-ffff-gggg-666666666666_7777777777_8888888888",
    "correlationId": "11111111-1111-1111-1111-111111111111",
    "changedByType": "User",
    "changesCount": 2,
    "clientType": "Azure Portal",
    "changedBy": "john@contoso.com",
    "operation": "microsoft.compute/virtualmachines/write",
    "timestamp": "2024-06-12T13:26:17.347+00:00"
  },
  "changes": {
    "properties.provisioningState": {
      "newValue": "Succeeded",
      "previousValue": "Updating",
      "isTruncated": "true"
    },
    "tags.key1": {
      "newValue": "NewTagValue",
      "previousValue": "null",
    }
  }
}

请参阅更改资源属性的完整参考指南。

运行查询

尝试对 resourcechanges 表进行基于租户的 Resource Graph 查询。 该查询返回前五个最近的 Azure 资源更改,以及每个更改记录的更改时间、更改类型、目标资源 ID、目标资源类型和更改详细信息。

# Login first with az login if not using Cloud Shell

# Run Azure Resource Graph query
az graph query -q 'resourcechanges | project properties.changeAttributes.timestamp, properties.changeType, properties.targetResourceId, properties.targetResourceType, properties.changes | limit 5'

可以更新查询,为 timestamp 属性指定一个更加用户友好的列名

# Run Azure Resource Graph query with 'extend'
az graph query -q 'resourcechanges | extend changeTime=todatetime(properties.changeAttributes.timestamp) | project changeTime, properties.changeType, properties.targetResourceId, properties.targetResourceType, properties.changes | limit 5'

若要将查询结果限制为最近的更改,请将查询更新为 order by 用户定义的 changeTime 属性。

# Run Azure Resource Graph query with 'order by'
az graph query -q 'resourcechanges | extend changeTime=todatetime(properties.changeAttributes.timestamp) | project changeTime, properties.changeType, properties.targetResourceId, properties.targetResourceType, properties.changes | order by changeTime desc | limit 5'

你还可以分别使用 -ManagementGroup 参数按管理组-Subscription或订阅进行查询。

注意

如果查询未从你已有权访问的订阅返回结果,则 Search-AzGraph PowerShell cmdlet 默认为默认上下文中的订阅。

Resource Graph Explorer 还提供一个整洁的界面用于将某些查询的结果转换为可固定到 Azure 仪表板的图表。

查询资源更改

使用 Resource Graph,可以查询 resourcechangesresourcecontainerchangeshealthresourcechanges 表,以按任何更改资源属性进行筛选或排序。 以下示例查询 resourcechanges 表,但也可以应用于 resourcecontainerchangeshealthresourcechanges 表。

注意

详细了解 Project Flash 文档中 healthresourcechanges 数据。

示例

在查询和分析资源中的更改之前,请查看以下最佳做法。

  • 查询特定时段内的更改事件,并评估更改详细信息。
    • 此查询在事件管理期间用于了解可能相关的更改时效果最佳。
  • 保持最新的配置管理数据库 (CMDB)。
    • 不会按计划的频率刷新所有资源及其完整属性集,而只会收到其更改。
  • 了解当某个资源更改“符合性状态”时可能更改的其他属性。
    • 评估这些额外属性可以洞察可能需要通过 Azure Policy 定义进行管理的其他属性。
  • 查询命令的顺序非常重要。 在以下示例中,order by 必须位于 limit 命令之前。
    • order by 命令按更改时间对查询结果进行排序。
    • 然后,limit 命令会限制有序结果,以确保获得五个最新的结果。
  • “未知”的含义是什么? 
    • 当更改发生在未识别的客户端上时,将显示“未知”。 根据与原始更改请求关联的用户代理和客户端应用程序 ID 来识别客户端。
  • “系统”的含义是什么?
    • 当发生与任何直接用户操作无关的后台更改时,系统将显示为 changedBy 值。

过去 24 小时内的所有更改

resourcechanges
| extend changeTime = todatetime(properties.changeAttributes.timestamp), targetResourceId = tostring(properties.targetResourceId),
changeType = tostring(properties.changeType), correlationId = properties.changeAttributes.correlationId, 
changedProperties = properties.changes, changeCount = properties.changeAttributes.changesCount
| where changeTime > ago(1d)
| order by changeTime desc
| project changeTime, targetResourceId, changeType, correlationId, changeCount, changedProperties

特定资源组中已删除的资源

resourcechanges
| where resourceGroup == "myResourceGroup"
| extend changeTime = todatetime(properties.changeAttributes.timestamp), targetResourceId = tostring(properties.targetResourceId),
  changeType = tostring(properties.changeType), correlationId = properties.changeAttributes.correlationId
| where changeType == "Delete"
| order by changeTime desc
| project changeTime, resourceGroup, targetResourceId, changeType, correlationId

对特定属性值的变更

resourcechanges
| extend provisioningStateChange = properties.changes["properties.provisioningState"], changeTime = todatetime(properties.changeAttributes.timestamp), targetResourceId = tostring(properties.targetResourceId), changeType = tostring(properties.changeType)
| where isnotempty(provisioningStateChange)and provisioningStateChange.newValue == "Succeeded"
| order by changeTime desc
| project changeTime, targetResourceId, changeType, provisioningStateChange.previousValue, provisioningStateChange.newValue

过去七天的更改,按更改人员和客户端分列,并按计数排序

resourcechanges 
| extend changeTime = todatetime(properties.changeAttributes.timestamp), 
  targetResourceId = tostring(properties.targetResourceId), 
  changeType = tostring(properties.changeType), changedBy = tostring(properties.changeAttributes.changedBy), 
  changedByType = properties.changeAttributes.changedByType, 
  clientType = tostring(properties.changeAttributes.clientType) 
| where changeTime > ago(7d) 
| project changeType, changedBy, changedByType, clientType 
| summarize count() by changedBy, changeType, clientType 
| order by count_ desc 

虚拟机大小的更改

resourcechanges
| extend vmSize = properties.changes["properties.hardwareProfile.vmSize"], changeTime = todatetime(properties.changeAttributes.timestamp), targetResourceId = tostring(properties.targetResourceId), changeType = tostring(properties.changeType) 
| where isnotempty(vmSize) 
| order by changeTime desc 
| project changeTime, targetResourceId, changeType, properties.changes, previousSize = vmSize.previousValue, newSize = vmSize.newValue

按更改类型和订阅名称进行的更改计数

resourcechanges  
| extend changeType = tostring(properties.changeType), changeTime = todatetime(properties.changeAttributes.timestamp), targetResourceType=tostring(properties.targetResourceType)  
| summarize count() by changeType, subscriptionId 
| join (resourcecontainers | where type=='microsoft.resources/subscriptions' | project SubscriptionName=name, subscriptionId) on subscriptionId 
| project-away subscriptionId, subscriptionId1
| order by count_ desc  

使用某种标记创建的资源的最新资源更改

resourcechanges 
|extend targetResourceId = tostring(properties.targetResourceId), changeType = tostring(properties.changeType), createTime = todatetime(properties.changeAttributes.timestamp) 
| where createTime > ago(7d) and changeType == "Create" or changeType == "Update" or changeType == "Delete"
| project  targetResourceId, changeType, createTime 
| join ( resources | extend targetResourceId=id) on targetResourceId
| where tags ['Environment'] =~ 'prod' 
| order by createTime desc 
| project createTime, id, resourceGroup, type

后续步骤