监视应用程序登录运行状况以提高复原能力

若要提高基础设施的弹性,请为关键应用程序设置应用程序登录运行状况监控。 你可以在发生具有影响力的事件时收到警报。 本文将逐步讲解如何设置应用登录运行状况工作簿,以监视用户登录的中断。

可以根据应用登录运行状况工作簿配置警报。 管理员可以通过此工作簿监视对其租户中应用程序的身份验证请求。 它提供以下关键功能:

  • 将工作簿配置为使用近实时数据监视所有应用或单个应用。
  • 配置针对身份验证模式更改的警报,以便进行调查和响应。
  • 比较一段时间内的趋势。 逐周比较是工作簿的默认设置。

注意

若要查看所有可用工作簿以及使用它们的先决条件,请参阅如何将 Azure Monitor 工作簿用于报表

发生具有影响力的事件时,可能会发生两件事:

  • 当用户无法登录时,应用程序的登录次数可能会急剧下降。
  • 登录失败的次数可能会增加。

先决条件

配置应用登录运行状况工作簿

若要在 Azure 门户中访问工作簿,请打开依次选择“Microsoft Entra ID”和“工作簿”。 以下屏幕截图显示 Azure 门户中的工作簿库。

显示 Azure 门户中的工作簿库的屏幕截图。

使用情况”、“条件访问”和“排除故障”下会显示工作簿。 应用登录运行状况工作簿出现在“健康情况”部分中。 工作簿使用后,可能会出现在“最近修改的工作簿”部分。

可以使用应用登录运行状况工作簿来可视化登录所发生的情况。如以下屏幕截图所示,工作簿显示两个图形。

显示登录运行状况图的屏幕截图。

在前面的屏幕截图中,有两个图表:

  • 每小时使用量(登录成功用户数)。 将当前的成功用户数与典型的使用时间段进行比较就可以发现可能需要调查的使用量下降的情况。 成功使用率下降可以帮助检测失败率检测不到的性能和利用率问题。 例如,当用户无法访问你的应用程序以尝试登录时,使用量会下降,但失败登录次数不会。 请参阅本文下一部分中针对此数据的示例查询。
  • 每小时失败率。 失败率激增可能表明身份验证机制存在问题。 失败率度量值仅在用户可以尝试进行身份验证时才会显示。 如果用户无法获取进行尝试所需的权限,则不会失败。

配置查询和警报

你可以在 Azure Monitor 中创建警报规则,并且定期自动运行保存的查询或自定义日志搜索。 你可以配置警报,以在使用量或失败率超过指定阈值时通知特定组。

按照以下说明,根据图中反映的查询创建电子邮件警报。 示例脚本将在以下情况下发送电子邮件通知:

  • 如前面的每小时使用量图所示,与两天前的同一小时相比,成功使用量下降了 90%。
  • 如前面的每小时失败率图所示,与两天前的同一小时相比,失败率增加了 90%。

若要配置基础查询并设置警报,请使用示例查询作为配置的基础来完成以下步骤。 本部分的末尾对查询结构进行了介绍。 在管理日志警报中了解如何使用 Azure Monitor 的创建、查看和管理日志警报。

  1. 在工作簿中,选择“编辑”,如以下屏幕截图所示。 选择图形右上角的查询图标

    显示编辑工作簿的屏幕截图。

  2. 查看查询日志,如以下屏幕截图所示。

    显示查询日志的屏幕截图。

  3. 为新的 Kusto 查询复制以下示例脚本之一。

  4. 将查询粘贴到窗口中。 选择“运行”。 查找“已完成”消息和查询结果,如以下屏幕截图所示。

    显示运行查询结果的屏幕截图。

  5. 突出显示该查询。 选择“+ 新建警报规则”。

    显示新建警报规则屏幕的屏幕截图。

  6. 配置警报条件。 如以下示例屏幕截图所示,在“条件”部分的“度量”下,为“度量值”选择“表行数”。 为“聚合类型”选择“计数”。 为“聚合粒度”选择“2 天”。

    显示配置警报屏幕的屏幕截图。

    • 表行数。 可以使用返回的行数来处理 Windows 事件日志、Syslog 和应用程序异常等事件。
    • 聚合类型。 应用了“计数”的数据点。
    • 聚合粒度。 此值定义与“计算频率”一起使用的时间段。
  7. 在“警报逻辑”中配置参数,如示例屏幕截图所示。

    显示警报逻辑屏幕的屏幕截图。

    • 阈值:0。 该值将针对任何结果发出警报。
    • 计算频率:1 小时。 该值将前一小时的评估频率设置为每小时一次。
  8. 在“操作”部分中配置设置,如示例屏幕截图所示。

    显示“创建警报规则”屏幕的屏幕截图。

    • 选择“选择操作组”,并添加要为其发送警报通知的组。
    • 在“自定义操作”下,选择“通过电子邮件发送警报”。
    • 添加主题行。
  9. 在“详细信息”部分中配置设置,如示例屏幕截图所示。

    显示“详细信息”部分的屏幕截图。

    • 添加订阅名称和说明。
    • 选择要向其添加警报的资源组
    • 选择默认严重性
    • 如果希望它立即上线,请选择“创建时启用”。 否则,请选择“静音操作”。
  10. 在“查看 + 创建”部分中配置设置,如示例屏幕截图所示。

    显示“查看 + 创建”部分的屏幕截图。

  11. 选择“保存”。 输入查询的名称。 为“另存为”选择“查询”。 为“类别”选择“警报”。 再次选择“保存”。

    显示保存查询按钮的屏幕截图。

优化查询和警报

若要修改查询和警报,使其发挥最大效率,请执行以下操作:

  • 始终测试警报。
  • 修改警报敏感度和频率,以便接收重要通知。 如果管理员收到过多警报,可能会变得对警报不敏感,从而错过重要警报。
  • 在管理员的电子邮件客户端中,将发送警报的电子邮件地址添加到“允许的发件人”列表。 此方法可防止由于电子邮件客户端上的垃圾邮件筛选器而错过通知。
  • 根据设计,Azure Monitor 中的警报查询只能包含过去 48 小时内的结果。

示例脚本

针对失败率上升的 Kusto 查询

在以下查询中,我们检测到失败率增加。 可以根据需要调整底部的比率。 它表示过去一小时的流量与昨天同一时间相比的变化百分比。 0.5 结果表示流量存在 50% 的差异。

let today = SigninLogs
| where TimeGenerated > ago(1h) // Query failure rate in the last hour
| project TimeGenerated, UserPrincipalName, AppDisplayName, status = case(Status.errorCode == "0", "success", "failure")
// Optionally filter by a specific application
//| where AppDisplayName == **APP NAME**
| summarize success = countif(status == "success"), failure = countif(status == "failure") by bin(TimeGenerated, 1h) // hourly failure rate
| project TimeGenerated, failureRate = (failure * 1.0) / ((failure + success) * 1.0)
| sort by TimeGenerated desc
| serialize rowNumber = row_number();
let yesterday = SigninLogs
| where TimeGenerated between((ago(1h) – totimespan(1d))..(now() – totimespan(1d))) // Query failure rate at the same time yesterday
| project TimeGenerated, UserPrincipalName, AppDisplayName, status = case(Status.errorCode == "0", "success", "failure")
// Optionally filter by a specific application
//| where AppDisplayName == **APP NAME**
| summarize success = countif(status == "success"), failure = countif(status == "failure") by bin(TimeGenerated, 1h) // hourly failure rate at same time yesterday
| project TimeGenerated, failureRateYesterday = (failure * 1.0) / ((failure + success) * 1.0)
| sort by TimeGenerated desc
| serialize rowNumber = row_number();
today
| join (yesterday) on rowNumber // join data from same time today and yesterday
| project TimeGenerated, failureRate, failureRateYesterday
// Set threshold to be the percent difference in failure rate in the last hour as compared to the same time yesterday
// Day variable is the number of days since the previous Sunday. Optionally ignore results on Sat, Sun, and Mon because large variability in traffic is expected.
| extend day = dayofweek(now())
| where day != time(6.00:00:00) // exclude Sat
| where day != time(0.00:00:00) // exclude Sun
| where day != time(1.00:00:00) // exclude Mon
| where abs(failureRate – failureRateYesterday) > 0.5

针对使用量下降的 Kusto 查询

在以下查询中,我们将过去一小时的流量与昨天同一时间进行比较。 我们排除了星期六、星期日和星期一,因为我们预计它们前一天同一时间的流量会发生较大变化。

可以根据需要调整底部的比率。 它表示过去一小时的流量与昨天同一时间相比的变化百分比。 0.5 结果表示流量存在 50% 的差异。 根据你的业务操作模型调整这些值。

Let today = SigninLogs // Query traffic in the last hour
| where TimeGenerated > ago(1h)
| project TimeGenerated, AppDisplayName, UserPrincipalName
// Optionally filter by AppDisplayName to scope query to a single application
//| where AppDisplayName contains "Office 365 Exchange Online"
| summarize users = dcount(UserPrincipalName) by bin(TimeGenerated, 1hr) // Count distinct users in the last hour
| sort by TimeGenerated desc
| serialize rn = row_number();
let yesterday = SigninLogs // Query traffic at the same hour yesterday
| where TimeGenerated between((ago(1h) – totimespan(1d))..(now() – totimespan(1d))) // Count distinct users in the same hour yesterday
| project TimeGenerated, AppDisplayName, UserPrincipalName
// Optionally filter by AppDisplayName to scope query to a single application
//| where AppDisplayName contains "Office 365 Exchange Online"
| summarize usersYesterday = dcount(UserPrincipalName) by bin(TimeGenerated, 1hr)
| sort by TimeGenerated desc
| serialize rn = row_number();
today
| join // Join data from today and yesterday together
(
yesterday
)
on rn
// Calculate the difference in number of users in the last hour compared to the same time yesterday
| project TimeGenerated, users, usersYesterday, difference = abs(users – usersYesterday), max = max_of(users, usersYesterday)
| extend ratio = (difference * 1.0) / max // Ratio is the percent difference in traffic in the last hour as compared to the same time yesterday
// Day variable is the number of days since the previous Sunday. Optionally ignore results on Sat, Sun, and Mon because large variability in traffic is expected.
| extend day = dayofweek(now())
| where day != time(6.00:00:00) // exclude Sat
| where day != time(0.00:00:00) // exclude Sun
| where day != time(1.00:00:00) // exclude Mon
| where ratio > 0.7 // Threshold percent difference in sign-in traffic as compared to same hour yesterday

创建警报管理流程

设置查询和警报后,创建业务流程来管理警报。

  • 谁来监视工作簿?何时监视?
  • 警报发生时,谁来进行调查?
  • 通信需求是什么? 谁创建通信,谁接收通信?
  • 发生中断时,哪些业务流程适用?

后续步骤

详细了解工作簿