Back
Idfecd4ab1-b24e-8413-9164-e3621c8d7caa
RulenameUniFi Site Manager: ISP SLA Breach
DescriptionIdentifies when ISP uptime falls below the SLA threshold. Useful for tracking SLA compliance and supporting ISP accountability conversations.
SeverityMedium
TacticsImpact
TechniquesT1499
Required data connectorsUniFiSiteManagerConnectorDefinition
KindScheduled
Query frequency1h
Query period1h
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/UniFi%20Site%20Manager%20%28CCF%29/Analytic%20Rules/UniFiCloudISPSLABreach.yaml
Version1.0.1
Arm templatefecd4ab1-b24e-8413-9164-e3621c8d7caa.json
Deploy To Azure
// UniFi ISP SLA Breach Detection
let SLAThreshold = 99.9;
Unifi_SiteManager_ISPMetrics_CL
| where TimeGenerated > ago(1h)
| mv-expand period = Periods
| extend
    metricTime = todatetime(period.metricTime),
    uptime = todouble(period.data.wan.uptime),
    downtime = toint(period.data.wan.downtime),
    ispName = tostring(period.data.wan.ispName),
    ispAsn = tostring(period.data.wan.ispAsn),
    siteIdStr = tostring(SiteId)
// De-duplicate Periods: each poll returns the same hour buckets, so collapse to latest value per metricTime
| summarize arg_max(TimeGenerated, uptime, downtime, ispAsn) by siteIdStr, ispName, metricTime
| where metricTime > ago(1h)
| summarize
    AvgUptime = round(avg(uptime), 3),
    MinUptime = round(min(uptime), 3),
    TotalDowntimeSeconds = sum(downtime),
    MeasurementCount = count()
    by SiteId = siteIdStr, ispName, ispAsn
| where AvgUptime < SLAThreshold
| extend 
    TimeGenerated = now(),
    SLATarget = SLAThreshold,
    UptimeGap = round(SLAThreshold - AvgUptime, 3)
| project
    TimeGenerated,
    SiteId = SiteId,
    ISPName = ispName,
    ISPAsn = ispAsn,
    AvgUptimePct = AvgUptime,
    MinUptimePct = MinUptime,
    SLATargetPct = SLATarget,
    UptimeGapPct = UptimeGap,
    TotalDowntimeSeconds,
    MeasurementCount
entityMappings:
- fieldMappings:
  - identifier: HostName
    columnName: SiteId
  entityType: Host
- fieldMappings:
  - identifier: Name
    columnName: ISPName
  entityType: CloudApplication
id: fecd4ab1-b24e-8413-9164-e3621c8d7caa
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/UniFi%20Site%20Manager%20%28CCF%29/Analytic%20Rules/UniFiCloudISPSLABreach.yaml
triggerOperator: gt
tactics:
- Impact
kind: Scheduled
requiredDataConnectors:
- dataTypes:
  - Unifi_SiteManager_ISPMetrics_CL
  connectorId: UniFiSiteManagerConnectorDefinition
queryPeriod: 1h
severity: Medium
relevantTechniques:
- T1499
triggerThreshold: 0
version: 1.0.1
name: 'UniFi Site Manager: ISP SLA Breach'
status: Available
subTechniques:
- T1499.002
description: |
  Identifies when ISP uptime falls below the SLA threshold. Useful for tracking SLA compliance and supporting ISP accountability conversations.
queryFrequency: 1h
query: |
  // UniFi ISP SLA Breach Detection
  let SLAThreshold = 99.9;
  Unifi_SiteManager_ISPMetrics_CL
  | where TimeGenerated > ago(1h)
  | mv-expand period = Periods
  | extend
      metricTime = todatetime(period.metricTime),
      uptime = todouble(period.data.wan.uptime),
      downtime = toint(period.data.wan.downtime),
      ispName = tostring(period.data.wan.ispName),
      ispAsn = tostring(period.data.wan.ispAsn),
      siteIdStr = tostring(SiteId)
  // De-duplicate Periods: each poll returns the same hour buckets, so collapse to latest value per metricTime
  | summarize arg_max(TimeGenerated, uptime, downtime, ispAsn) by siteIdStr, ispName, metricTime
  | where metricTime > ago(1h)
  | summarize
      AvgUptime = round(avg(uptime), 3),
      MinUptime = round(min(uptime), 3),
      TotalDowntimeSeconds = sum(downtime),
      MeasurementCount = count()
      by SiteId = siteIdStr, ispName, ispAsn
  | where AvgUptime < SLAThreshold
  | extend 
      TimeGenerated = now(),
      SLATarget = SLAThreshold,
      UptimeGap = round(SLAThreshold - AvgUptime, 3)
  | project
      TimeGenerated,
      SiteId = SiteId,
      ISPName = ispName,
      ISPAsn = ispAsn,
      AvgUptimePct = AvgUptime,
      MinUptimePct = MinUptime,
      SLATargetPct = SLATarget,
      UptimeGapPct = UptimeGap,
      TotalDowntimeSeconds,
      MeasurementCount
incidentConfiguration:
  groupingConfiguration:
    enabled: true
    lookbackDuration: P1D
    reopenClosedIncident: false
    matchingMethod: AllEntities
  createIncident: true
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/fecd4ab1-b24e-8413-9164-e3621c8d7caa')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/fecd4ab1-b24e-8413-9164-e3621c8d7caa')]",
      "properties": {
        "alertRuleTemplateName": "fecd4ab1-b24e-8413-9164-e3621c8d7caa",
        "customDetails": null,
        "description": "Identifies when ISP uptime falls below the SLA threshold. Useful for tracking SLA compliance and supporting ISP accountability conversations.\n",
        "displayName": "UniFi Site Manager: ISP SLA Breach",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Host",
            "fieldMappings": [
              {
                "columnName": "SiteId",
                "identifier": "HostName"
              }
            ]
          },
          {
            "entityType": "CloudApplication",
            "fieldMappings": [
              {
                "columnName": "ISPName",
                "identifier": "Name"
              }
            ]
          }
        ],
        "incidentConfiguration": {
          "createIncident": true,
          "groupingConfiguration": {
            "enabled": true,
            "lookbackDuration": "P1D",
            "matchingMethod": "AllEntities",
            "reopenClosedIncident": false
          }
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/UniFi%20Site%20Manager%20%28CCF%29/Analytic%20Rules/UniFiCloudISPSLABreach.yaml",
        "query": "// UniFi ISP SLA Breach Detection\nlet SLAThreshold = 99.9;\nUnifi_SiteManager_ISPMetrics_CL\n| where TimeGenerated > ago(1h)\n| mv-expand period = Periods\n| extend\n    metricTime = todatetime(period.metricTime),\n    uptime = todouble(period.data.wan.uptime),\n    downtime = toint(period.data.wan.downtime),\n    ispName = tostring(period.data.wan.ispName),\n    ispAsn = tostring(period.data.wan.ispAsn),\n    siteIdStr = tostring(SiteId)\n// De-duplicate Periods: each poll returns the same hour buckets, so collapse to latest value per metricTime\n| summarize arg_max(TimeGenerated, uptime, downtime, ispAsn) by siteIdStr, ispName, metricTime\n| where metricTime > ago(1h)\n| summarize\n    AvgUptime = round(avg(uptime), 3),\n    MinUptime = round(min(uptime), 3),\n    TotalDowntimeSeconds = sum(downtime),\n    MeasurementCount = count()\n    by SiteId = siteIdStr, ispName, ispAsn\n| where AvgUptime < SLAThreshold\n| extend \n    TimeGenerated = now(),\n    SLATarget = SLAThreshold,\n    UptimeGap = round(SLAThreshold - AvgUptime, 3)\n| project\n    TimeGenerated,\n    SiteId = SiteId,\n    ISPName = ispName,\n    ISPAsn = ispAsn,\n    AvgUptimePct = AvgUptime,\n    MinUptimePct = MinUptime,\n    SLATargetPct = SLATarget,\n    UptimeGapPct = UptimeGap,\n    TotalDowntimeSeconds,\n    MeasurementCount\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "PT1H",
        "severity": "Medium",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "Impact"
        ],
        "techniques": [
          "T1499"
        ],
        "templateVersion": "1.0.1",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}