Back
Id4c1c9aee-8e44-4bb9-bd53-f3e7d6761282
RulenameDataverse - New sign-in from an unauthorized domain
DescriptionIdentifies Dataverse sign-in activity originating from users with UPN suffixes that have not been seen previously in the last 14 days and are not present on a predefined list of authorized domains. Common internal Power Platform system users are excluded by default.
SeverityMedium
TacticsInitialAccess
TechniquesT1078
T1190
T1133
Required data connectorsDataverse
KindScheduled
Query frequency1h
Query period14d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft%20Business%20Applications/Analytic%20Rules/Dataverse%20-%20New%20sign-in%20from%20an%20unauthorized%20domain.yaml
Version3.2.0
Arm template4c1c9aee-8e44-4bb9-bd53-f3e7d6761282.json
Deploy To Azure
// Allow list of UPN suffixes allowed by the organization.
let allowed_domains = dynamic([
    'onmicrosoft.com',
    'microsoft.com'
    ]);
// All list of users allowed by the organization
let allowed_users = dynamic([
    'user1@mydomain.com',
    'user2@mydomain.com'
    ]);
let query_frequency = 1h;
let query_lookback = 14d;
let historical_users = DataverseActivity
    | where TimeGenerated between(ago(query_lookback) .. ago(query_frequency))
    | where Message == 'UserSignIn'
    | summarize by UserId;
DataverseActivity
| where TimeGenerated >= ago (query_frequency)
| where Message == 'UserSignIn'
| join kind=leftanti (historical_users) on UserId
| summarize FirstEvent = min(TimeGenerated), LastEvent = max(TimeGenerated) by UserId, ClientIp, InstanceUrl
| where isnotempty(ClientIp)
| extend CloudAppId = int(32780)
| extend AccountName = tostring(split(UserId, '@')[0])
| extend UPNSuffix = tostring(split(UserId, '@')[1])
| where UPNSuffix !in (allowed_domains) and UserId !in (allowed_users)
| project
    FirstEvent,
    LastEvent,
    UserId,
    ClientIp,
    InstanceUrl,
    AccountName,
    UPNSuffix,
    CloudAppId
entityMappings:
- entityType: Account
  fieldMappings:
  - identifier: Name
    columnName: AccountName
  - identifier: UPNSuffix
    columnName: UPNSuffix
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: ClientIp
- entityType: CloudApplication
  fieldMappings:
  - identifier: AppId
    columnName: CloudAppId
  - identifier: InstanceName
    columnName: InstanceUrl
name: Dataverse - New sign-in from an unauthorized domain
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft%20Business%20Applications/Analytic%20Rules/Dataverse%20-%20New%20sign-in%20from%20an%20unauthorized%20domain.yaml
queryFrequency: 1h
triggerOperator: gt
status: Available
queryPeriod: 14d
requiredDataConnectors:
- connectorId: Dataverse
  dataTypes:
  - DataverseActivity
tactics:
- InitialAccess
query: |
  // Allow list of UPN suffixes allowed by the organization.
  let allowed_domains = dynamic([
      'onmicrosoft.com',
      'microsoft.com'
      ]);
  // All list of users allowed by the organization
  let allowed_users = dynamic([
      'user1@mydomain.com',
      'user2@mydomain.com'
      ]);
  let query_frequency = 1h;
  let query_lookback = 14d;
  let historical_users = DataverseActivity
      | where TimeGenerated between(ago(query_lookback) .. ago(query_frequency))
      | where Message == 'UserSignIn'
      | summarize by UserId;
  DataverseActivity
  | where TimeGenerated >= ago (query_frequency)
  | where Message == 'UserSignIn'
  | join kind=leftanti (historical_users) on UserId
  | summarize FirstEvent = min(TimeGenerated), LastEvent = max(TimeGenerated) by UserId, ClientIp, InstanceUrl
  | where isnotempty(ClientIp)
  | extend CloudAppId = int(32780)
  | extend AccountName = tostring(split(UserId, '@')[0])
  | extend UPNSuffix = tostring(split(UserId, '@')[1])
  | where UPNSuffix !in (allowed_domains) and UserId !in (allowed_users)
  | project
      FirstEvent,
      LastEvent,
      UserId,
      ClientIp,
      InstanceUrl,
      AccountName,
      UPNSuffix,
      CloudAppId
description: Identifies Dataverse sign-in activity originating from users with UPN suffixes that have not been seen previously in the last 14 days and are not present on a predefined list of authorized domains. Common internal Power Platform system users are excluded by default.
severity: Medium
kind: Scheduled
eventGroupingSettings:
  aggregationKind: SingleAlert
triggerThreshold: 0
id: 4c1c9aee-8e44-4bb9-bd53-f3e7d6761282
alertDetailsOverride:
  alertDescriptionFormat: New user sign-in activity was detected in {{InstanceUrl}} originating from user {{UserId}}. This user's UPN suffix is not on the authorized list of domains.
  alertDisplayNameFormat: Dataverse - Unauthorized sign-in activity
version: 3.2.0
relevantTechniques:
- T1078
- T1190
- T1133
{
  "$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/4c1c9aee-8e44-4bb9-bd53-f3e7d6761282')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/4c1c9aee-8e44-4bb9-bd53-f3e7d6761282')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "New user sign-in activity was detected in {{InstanceUrl}} originating from user {{UserId}}. This user's UPN suffix is not on the authorized list of domains.",
          "alertDisplayNameFormat": "Dataverse - Unauthorized sign-in activity"
        },
        "alertRuleTemplateName": "4c1c9aee-8e44-4bb9-bd53-f3e7d6761282",
        "customDetails": null,
        "description": "Identifies Dataverse sign-in activity originating from users with UPN suffixes that have not been seen previously in the last 14 days and are not present on a predefined list of authorized domains. Common internal Power Platform system users are excluded by default.",
        "displayName": "Dataverse - New sign-in from an unauthorized domain",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "AccountName",
                "identifier": "Name"
              },
              {
                "columnName": "UPNSuffix",
                "identifier": "UPNSuffix"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "ClientIp",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "CloudApplication",
            "fieldMappings": [
              {
                "columnName": "CloudAppId",
                "identifier": "AppId"
              },
              {
                "columnName": "InstanceUrl",
                "identifier": "InstanceName"
              }
            ]
          }
        ],
        "eventGroupingSettings": {
          "aggregationKind": "SingleAlert"
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft%20Business%20Applications/Analytic%20Rules/Dataverse%20-%20New%20sign-in%20from%20an%20unauthorized%20domain.yaml",
        "query": "// Allow list of UPN suffixes allowed by the organization.\nlet allowed_domains = dynamic([\n    'onmicrosoft.com',\n    'microsoft.com'\n    ]);\n// All list of users allowed by the organization\nlet allowed_users = dynamic([\n    'user1@mydomain.com',\n    'user2@mydomain.com'\n    ]);\nlet query_frequency = 1h;\nlet query_lookback = 14d;\nlet historical_users = DataverseActivity\n    | where TimeGenerated between(ago(query_lookback) .. ago(query_frequency))\n    | where Message == 'UserSignIn'\n    | summarize by UserId;\nDataverseActivity\n| where TimeGenerated >= ago (query_frequency)\n| where Message == 'UserSignIn'\n| join kind=leftanti (historical_users) on UserId\n| summarize FirstEvent = min(TimeGenerated), LastEvent = max(TimeGenerated) by UserId, ClientIp, InstanceUrl\n| where isnotempty(ClientIp)\n| extend CloudAppId = int(32780)\n| extend AccountName = tostring(split(UserId, '@')[0])\n| extend UPNSuffix = tostring(split(UserId, '@')[1])\n| where UPNSuffix !in (allowed_domains) and UserId !in (allowed_users)\n| project\n    FirstEvent,\n    LastEvent,\n    UserId,\n    ClientIp,\n    InstanceUrl,\n    AccountName,\n    UPNSuffix,\n    CloudAppId\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P14D",
        "severity": "Medium",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "InitialAccess"
        ],
        "techniques": [
          "T1078",
          "T1133",
          "T1190"
        ],
        "templateVersion": "3.2.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}