{
  "$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/fad0f8b9-a0a5-430a-9a94-049a1144bf54')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/fad0f8b9-a0a5-430a-9a94-049a1144bf54')]",
      "properties": {
        "alertRuleTemplateName": "fad0f8b9-a0a5-430a-9a94-049a1144bf54",
        "customDetails": null,
        "description": "Detects when a user is assigned a privileged role in Microsoft Entra ID. This may indicate unauthorized privilege escalation and should be validated promptly.\n",
        "displayName": "[Entra ID] Privileged Role Assigned to User",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "Source_Identity_FullName",
                "identifier": "FullName"
              }
            ]
          },
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "Target_Identity_FullName",
                "identifier": "FullName"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "Source_Network_IPAddress",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/eDCRule/Analytic%20Rules/%5BEntra%20ID%5D%20Privileged%20Role%20Assigned%20to%20User.yaml",
        "query": "AuditLogs\n| where Category =~ \"RoleManagement\"\n| where AADOperationType in (\"Assign\", \"AssignEligibleRole\", \"CreateRequestGrantedRole\", \"CreateRequestPermanentEligibleRole\", \"CreateRequestPermanentGrantedRole\")\n| where ActivityDisplayName has_any (\"Add eligible member to role\", \"Add member to role\")\n| mv-apply TargetResourceSubject = TargetResources on\n    (\n    where TargetResourceSubject.type in~ (\"User\", \"ServicePrincipal\")\n    | extend\n        Target = iff(TargetResourceSubject.type =~ \"ServicePrincipal\", tostring(TargetResourceSubject.displayName), tostring(TargetResourceSubject.userPrincipalName)),\n        subjectProps = TargetResourceSubject.modifiedProperties\n    )\n| mv-apply TargetResourceRole = TargetResources on\n    (\n    // mimic modifiedProperties so we can use the same logic to get the role name regardless of where it comes from\n    where TargetResourceRole.type in~ (\"Role\")\n    | extend roleProps = pack_array(bag_pack(\"displayName\", \"Role.DisplayName\", \"newValue\", TargetResourceRole.displayName))\n    )\n| mv-apply Property = iff(array_length(subjectProps) > 0, subjectProps, roleProps) on\n    (\n    where Property.displayName =~ \"Role.DisplayName\"\n    | extend RoleName = trim('\"', tostring(Property.newValue))\n    )\n| where RoleName contains \"Admin\"\n| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)\n| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)\n| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)\n| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)\n| extend InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))\n| extend Initiator = iif(isnotempty(InitiatingAppName), InitiatingAppName, InitiatingUserPrincipalName)\n// Comment below to alert for PIM activations\n| where Initiator != \"MS-PIM\"\n| summarize\n    by\n    bin(TimeGenerated, 1h),\n    OperationName,\n    RoleName,\n    Target,\n    Initiator,\n    InitiatingUserPrincipalName,\n    InitiatingAadUserId,\n    InitiatingAppName,\n    InitiatingAppServicePrincipalId,\n    InitiatingIpAddress,\n    Result\n| extend\n    TargetName = tostring(split(Target, '@', 0)[0]),\n    TargetUPNSuffix = tostring(split(Target, '@', 1)[0]),\n    InitiatorName = tostring(split(InitiatingUserPrincipalName, '@', 0)[0]),\n    InitiatorUPNSuffix = tostring(split(InitiatingUserPrincipalName, '@', 1)[0])\n| extend\n    Source_Network_IPLocation = \"\",\n    ActivityType=OperationName\n| project\n        Alert_Category_en = \"Entra ID\",\n    Alert_SubCategory_en = \"Anomaly Identity Privilege Modification\",\n    Alert_Name_en = \"User Assigned a Privileged Role\",\n    Alert_Description_en = strcat(\n                           \"At Taiwan time: \",\n                           format_datetime(datetime_utc_to_local(TimeGenerated, \"Asia/Taipei\"), \"yyyy-MM-dd HH:mm:ss\"),\n                           \"in the Microsoft Entra ID tenant\",\n                           \", operator: \",\n                           iff(isnotempty(Initiator), Initiator, \"<UnknownInitiator>\"),\n                           \", from IP: \",\n                           InitiatingIpAddress,\n                           \", assigned privileged role  \",\n                           tostring(RoleName),\n                           \"  to user  \",\n                           iff(isnotempty(Target), Target, \"<NoTargetUser>\"),\n                           \". This behavior is a high-risk permission change and must be validated immediately.\"\n                       ),\n    Alert_TriageStep_en = strcat(\n                          \"1. Confirm whether the privileged role assignment was performed through an Entra ID PIM-approved change process.\",\n                          \"2. Confirm with the operator: \",\n                          iff(isnotempty(Initiator), Initiator, \"<UnknownInitiator>\"),\n                          \"  whether this was performed by the account owner.\",\n                          \"3. Check whether the source IP and geolocation are abnormal or not a company public IP.\"\n                      ),\n    Alert_Containment_en = strcat(\n                           \"1. If this is determined to be an unauthorized role assignment, immediately revoke the privileged role from target user  \",\n                           iff(isnotempty(Target), Target, \"<NoTargetUser>\"),\n                           \" 's privileged role (\",\n                           tostring(RoleName),\n                           \"), and restore the state to before the change.\",\n                           \"2. Immediately restrict or suspend the operator that performed the role assignment (user or application), revoke sign-in tokens, and force MFA/password reset as needed.  \",\n                           \"3. If the source is an application (\",\n                           iff(isnotempty(InitiatingAppName), InitiatingAppName, \"<NoServicePrincipal>\"),\n                           \"), immediately disable the Service Principal and revoke high-privilege API consent and credentials/secrets.\"\n                       ),\n    Alert_Remediation_en = strcat(\n                           \"1. Allow privileged role access only through Entra ID PIM.\",\n                           \"2. Enforce Conditional Access and MFA for role management and PIM operations, allowing them only from managed devices and named locations.\",\n                           \"3. Establish real-time alerts and automated response (SOAR) for privileged role changes to detect abnormal role assignments immediately. \"\n                       ),\n            Alert_Time_TW = datetime_utc_to_local(TimeGenerated, \"Asia/Taipei\"),\n    Alert_Time_UTC0 = TimeGenerated,\n    Event_Action = ActivityType,\n    Event_Status = Result,\n    //Event_Description = ActivityDisplayName,\n    Source_Identity_FullName = iff(isnotempty(Initiator), Initiator, InitiatingAppName),\n    //Source_Identity_ID = ActorID,\n    Source_Identity_Type = iff(isnotempty(InitiatingUserPrincipalName), \"User\", \"Service\"),\n    Source_Network_IPAddress = InitiatingIpAddress,\n    Source_Network_IPLocation = Source_Network_IPLocation,\n    //Source_Resource_Name = InitiatingAppName,\n    Target_Identity_FullName = Target,\n    Target_Identity_DomainType = iff(Target contains \"EXT\", 'External', 'Internal'),\n    Target_Identity_Type = \"User\",\n    Target_Resource_ID = \"\",\n    Target_Resource_Type = \"Entra ID\"\n",
        "queryFrequency": "PT2H",
        "queryPeriod": "PT2H",
        "severity": "High",
        "status": "Available",
        "subTechniques": [
          "T1078.004"
        ],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "DefenseEvasion",
          "InitialAccess",
          "Persistence",
          "PrivilegeEscalation"
        ],
        "techniques": [
          "T1078"
        ],
        "templateVersion": "1.0.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}
