Skip to main content
COSMICBYTEZLABS
NewsSecurityHOWTOsToolsStudyTraining
ProjectsChecklistsAI RankingsNewsletterStatusTagsAbout
Subscribe

Press Enter to search or Esc to close

News
Security
HOWTOs
Tools
Study
Training
Projects
Checklists
AI Rankings
Newsletter
Status
Tags
About
RSS Feed
Reading List
Subscribe

Stay in the Loop

Get the latest security alerts, tutorials, and tech insights delivered to your inbox.

Subscribe NowFree forever. No spam.
COSMICBYTEZLABS

Your trusted source for IT intelligence, cybersecurity insights, and hands-on technical guides.

429+ Articles
114+ Guides

CONTENT

  • Latest News
  • Security Alerts
  • HOWTOs
  • Projects
  • Exam Prep

RESOURCES

  • Search
  • Browse Tags
  • Newsletter Archive
  • Reading List
  • RSS Feed

COMPANY

  • About Us
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CosmicBytez Labs. All rights reserved.

System Status: Operational
  1. Home
  2. Projects
  3. Azure Sentinel SIEM Implementation
Azure Sentinel SIEM Implementation
PROJECTAdvanced

Azure Sentinel SIEM Implementation

Deploy Microsoft Sentinel as your cloud-native SIEM with data connectors, analytics rules, workbooks, and SOAR automation for comprehensive security operations.

Dylan H.

Security Engineering

February 3, 2026
19 min read
8-10 hours

Tools & Technologies

Azure PortalLog AnalyticsAzure Logic AppsKQLPowerShell

Introduction

Microsoft Sentinel is a cloud-native Security Information and Event Management (SIEM) and Security Orchestration, Automation and Response (SOAR) solution that provides intelligent security analytics across your enterprise. This project implements a production-grade Sentinel deployment with comprehensive data collection, threat detection, investigation workbooks, and automated response playbooks.

What You'll Build

  • Centralized SIEM: Single pane of glass for security monitoring
  • Data Connectors: Integration with Microsoft 365, Azure, and third-party sources
  • Analytics Rules: Detection of threats aligned with MITRE ATT&CK framework
  • Custom Workbooks: Security dashboards for visibility and reporting
  • SOAR Playbooks: Automated incident response with Logic Apps
  • Threat Intelligence: TI platform integration for enrichment

Who This Is For

  • Security engineers implementing enterprise SIEM
  • SOC analysts building detection and response capabilities
  • Cloud architects designing security monitoring
  • MSPs providing managed security services

Prerequisites

Knowledge Requirements

  • Azure administration fundamentals
  • Security operations concepts
  • KQL (Kusto Query Language) basics
  • Understanding of MITRE ATT&CK framework

Azure Requirements

  • Azure subscription with Owner or Contributor access
  • Log Analytics workspace permissions
  • Microsoft Defender for Cloud (recommended)
  • Microsoft 365 E5 or Security add-on (for M365 integration)

Planning Requirements

  • Data retention requirements defined
  • Compliance requirements identified
  • Alert routing and escalation procedures
  • Integration requirements documented

Architecture Overview

┌─────────────────────────────────────────────────────────────────────────────┐
│                    MICROSOFT SENTINEL ARCHITECTURE                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                      DATA SOURCES                                    │   │
│   │                                                                      │   │
│   │   ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────────┐   │   │
│   │   │Microsoft │  │  Azure   │  │  On-Prem │  │   Third-Party    │   │   │
│   │   │   365    │  │ Services │  │  Systems │  │     Sources      │   │   │
│   │   │          │  │          │  │          │  │                  │   │   │
│   │   │ • Entra  │  │ • Azure  │  │ • AD DS  │  │ • Palo Alto      │   │   │
│   │   │ • Defender│  │   AD     │  │ • DNS    │  │ • Fortinet       │   │   │
│   │   │ • Office │  │ • Key    │  │ • DHCP   │  │ • CrowdStrike    │   │   │
│   │   │ • Teams  │  │   Vault  │  │ • Syslog │  │ • AWS/GCP        │   │   │
│   │   │          │  │ • NSG    │  │ • CEF    │  │ • Custom APIs    │   │   │
│   │   └────┬─────┘  └────┬─────┘  └────┬─────┘  └────────┬─────────┘   │   │
│   └────────┼─────────────┼─────────────┼─────────────────┼─────────────┘   │
│            │             │             │                 │                  │
│            ▼             ▼             ▼                 ▼                  │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                    DATA CONNECTORS                                   │   │
│   │   • Native Connectors (API-based)                                   │   │
│   │   • Azure Monitor Agent (AMA)                                       │   │
│   │   • Syslog/CEF Collectors                                          │   │
│   │   • REST API Ingestion                                             │   │
│   └────────────────────────────┬────────────────────────────────────────┘   │
│                                │                                            │
│                                ▼                                            │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                   LOG ANALYTICS WORKSPACE                            │   │
│   │   ┌────────────────────────────────────────────────────────────┐    │   │
│   │   │                    DATA TABLES                              │    │   │
│   │   │  SecurityEvent │ SigninLogs │ AuditLogs │ CommonSecurityLog │    │   │
│   │   │  AzureActivity │ OfficeActivity │ ThreatIntelligence │ ...  │    │   │
│   │   └────────────────────────────────────────────────────────────┘    │   │
│   │                                                                      │   │
│   │   Data Retention: 90 days (hot) → Archive → Purge                   │   │
│   └────────────────────────────┬────────────────────────────────────────┘   │
│                                │                                            │
│                                ▼                                            │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                    MICROSOFT SENTINEL                                │   │
│   │   ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐   │   │
│   │   │  Analytics  │ │  Workbooks  │ │  Hunting    │ │  Notebooks  │   │   │
│   │   │   Rules     │ │ (Dashboards)│ │  Queries    │ │  (Jupyter)  │   │   │
│   │   └──────┬──────┘ └─────────────┘ └─────────────┘ └─────────────┘   │   │
│   │          │                                                           │   │
│   │          ▼                                                           │   │
│   │   ┌─────────────────────────────────────────────────────────────┐   │   │
│   │   │                    INCIDENTS                                 │   │   │
│   │   │   Alert Correlation → Incident Creation → Investigation     │   │   │
│   │   │                          │                                   │   │   │
│   │   └──────────────────────────┼───────────────────────────────────┘   │   │
│   └──────────────────────────────┼───────────────────────────────────────┘   │
│                                  │                                          │
│                                  ▼                                          │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                    SOAR / AUTOMATION                                 │   │
│   │   ┌──────────────┐  ┌──────────────┐  ┌──────────────────────────┐  │   │
│   │   │  Automation  │  │   Logic      │  │     Integrations         │  │   │
│   │   │   Rules      │  │   Apps       │  │     • ServiceNow         │  │   │
│   │   │              │  │  (Playbooks) │  │     • Teams/Slack        │  │   │
│   │   │ Auto-assign  │  │              │  │     • Email              │  │   │
│   │   │ Auto-enrich  │  │ Block IP     │  │     • Defender Actions   │  │   │
│   │   │ Auto-close   │  │ Isolate Host │  │     • Custom Webhooks    │  │   │
│   │   └──────────────┘  └──────────────┘  └──────────────────────────┘  │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────┘

Part 1: Log Analytics Workspace Setup

1.1 Create Log Analytics Workspace

Deploy the workspace using Azure CLI:

# Set variables
RESOURCE_GROUP="rg-sentinel-prod"
LOCATION="eastus"
WORKSPACE_NAME="law-sentinel-prod"
 
# Create resource group
az group create \
  --name $RESOURCE_GROUP \
  --location $LOCATION
 
# Create Log Analytics workspace
az monitor log-analytics workspace create \
  --resource-group $RESOURCE_GROUP \
  --workspace-name $WORKSPACE_NAME \
  --location $LOCATION \
  --retention-time 90 \
  --sku PerGB2018
 
# Get workspace ID
WORKSPACE_ID=$(az monitor log-analytics workspace show \
  --resource-group $RESOURCE_GROUP \
  --workspace-name $WORKSPACE_NAME \
  --query id -o tsv)

1.2 Configure Workspace Settings

# Enable workspace features
az monitor log-analytics workspace update \
  --resource-group $RESOURCE_GROUP \
  --workspace-name $WORKSPACE_NAME \
  --retention-time 90 \
  --daily-quota-gb 10
 
# Configure data collection endpoints
az monitor data-collection endpoint create \
  --name "dce-sentinel-prod" \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --public-network-access Enabled

1.3 Terraform Deployment (Alternative)

# providers.tf
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
  }
}
 
provider "azurerm" {
  features {}
}
 
# main.tf
resource "azurerm_resource_group" "sentinel" {
  name     = "rg-sentinel-prod"
  location = "eastus"
}
 
resource "azurerm_log_analytics_workspace" "sentinel" {
  name                = "law-sentinel-prod"
  location            = azurerm_resource_group.sentinel.location
  resource_group_name = azurerm_resource_group.sentinel.name
  sku                 = "PerGB2018"
  retention_in_days   = 90
  daily_quota_gb      = 10
 
  tags = {
    environment = "production"
    purpose     = "sentinel-siem"
  }
}
 
resource "azurerm_sentinel_log_analytics_workspace_onboarding" "sentinel" {
  workspace_id                 = azurerm_log_analytics_workspace.sentinel.id
  customer_managed_key_enabled = false
}

Part 2: Enable Microsoft Sentinel

2.1 Onboard Sentinel

# Enable Sentinel on the workspace
az sentinel onboard create \
  --resource-group $RESOURCE_GROUP \
  --workspace-name $WORKSPACE_NAME
 
# Verify Sentinel is enabled
az sentinel show \
  --resource-group $RESOURCE_GROUP \
  --workspace-name $WORKSPACE_NAME

2.2 Configure Sentinel Settings

Navigate to Microsoft Sentinel → Settings → Settings:

{
  "entityAnalytics": {
    "enabled": true,
    "ueba": {
      "enabled": true,
      "dataSources": ["AuditLogs", "SigninLogs", "SecurityEvents"]
    }
  },
  "anomalies": {
    "enabled": true
  },
  "playbooks": {
    "tenantId": "<your-tenant-id>",
    "subscriptionId": "<your-subscription-id>"
  }
}

Part 3: Data Connectors

3.1 Microsoft 365 Defender Connector

# Enable Microsoft 365 Defender connector
az sentinel data-connector create \
  --resource-group $RESOURCE_GROUP \
  --workspace-name $WORKSPACE_NAME \
  --data-connector-id "MicrosoftThreatProtection" \
  --kind "MicrosoftThreatProtection" \
  --tenant-id "<tenant-id>" \
  --data-types-to-connect "[Alerts, Incidents, DeviceEvents]"

3.2 Azure Active Directory / Entra ID

# Enable Azure AD connector
az sentinel data-connector create \
  --resource-group $RESOURCE_GROUP \
  --workspace-name $WORKSPACE_NAME \
  --data-connector-id "AzureActiveDirectory" \
  --kind "AzureActiveDirectory" \
  --tenant-id "<tenant-id>" \
  --data-types "[SigninLogs, AuditLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs, AADManagedIdentitySignInLogs, AADProvisioningLogs]"

3.3 Azure Activity Logs

# Enable Azure Activity connector at subscription level
az monitor diagnostic-settings create \
  --name "sentinel-activity-logs" \
  --subscription "<subscription-id>" \
  --logs '[{"category": "Administrative", "enabled": true}, {"category": "Security", "enabled": true}, {"category": "Alert", "enabled": true}, {"category": "Policy", "enabled": true}]' \
  --workspace $WORKSPACE_ID

3.4 Windows Security Events

Deploy Azure Monitor Agent and Data Collection Rule:

# Create Data Collection Rule for Windows Security Events
az monitor data-collection rule create \
  --name "dcr-windows-security" \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --data-flows '[{
    "streams": ["Microsoft-SecurityEvent"],
    "destinations": ["law-sentinel-prod"]
  }]' \
  --data-sources '{
    "windowsEventLogs": [{
      "name": "SecurityEvents",
      "streams": ["Microsoft-SecurityEvent"],
      "xPathQueries": ["Security!*[System[(EventID=4624 or EventID=4625 or EventID=4648 or EventID=4672 or EventID=4688 or EventID=4698 or EventID=4720 or EventID=4728 or EventID=4732)]]"]
    }]
  }' \
  --destinations '{
    "logAnalytics": [{
      "workspaceResourceId": "'$WORKSPACE_ID'",
      "name": "law-sentinel-prod"
    }]
  }'

3.5 Syslog/CEF Connector

Configure Linux syslog collector:

# Install Azure Monitor Agent on Linux
wget https://github.com/microsoft/OMS-Agent-for-Linux/releases/download/OMSAgent_v1.14.23-0/omsagent-1.14.23-0.universal.x64.sh
sudo sh omsagent-1.14.23-0.universal.x64.sh --upgrade -w <workspace-id> -s <workspace-key>
 
# Configure CEF collection
sudo wget -O cef_installer.py https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/DataConnectors/CEF/cef_installer.py
sudo python3 cef_installer.py <workspace-id> <workspace-key>

3.6 Third-Party Connectors

FortiGate Syslog Configuration:

config log syslogd setting
    set status enable
    set server "10.1.0.50"
    set port 514
    set format cef
    set facility local7
end

config log syslogd filter
    set severity information
    set forward-traffic enable
    set local-traffic enable
    set multicast-traffic enable
    set sniffer-traffic enable
    set anomaly enable
    set voip enable
end

Part 4: Analytics Rules

4.1 Scheduled Analytics Rule - Brute Force Detection

{
  "displayName": "Brute Force Attack Against Azure AD",
  "description": "Identifies multiple failed sign-in attempts followed by a successful sign-in from the same IP address.",
  "severity": "Medium",
  "enabled": true,
  "query": "let failureThreshold = 10;\nlet timeRange = 1h;\nlet successThreshold = 1;\nSigninLogs\n| where TimeGenerated >= ago(timeRange)\n| where ResultType != 0\n| summarize FailureCount = count(), FailedAccounts = make_set(UserPrincipalName) by IPAddress, bin(TimeGenerated, 5m)\n| where FailureCount >= failureThreshold\n| join kind=inner (\n    SigninLogs\n    | where TimeGenerated >= ago(timeRange)\n    | where ResultType == 0\n    | project SuccessTime = TimeGenerated, IPAddress, UserPrincipalName, AppDisplayName\n) on IPAddress\n| where SuccessTime > TimeGenerated\n| project IPAddress, FailureCount, FailedAccounts, SuccessfulUser = UserPrincipalName, SuccessTime, AppDisplayName",
  "queryFrequency": "PT5M",
  "queryPeriod": "PT1H",
  "triggerOperator": "GreaterThan",
  "triggerThreshold": 0,
  "suppressionDuration": "PT1H",
  "suppressionEnabled": true,
  "tactics": ["CredentialAccess", "InitialAccess"],
  "techniques": ["T1110"],
  "entityMappings": [
    {
      "entityType": "Account",
      "fieldMappings": [
        {"identifier": "FullName", "columnName": "SuccessfulUser"}
      ]
    },
    {
      "entityType": "IP",
      "fieldMappings": [
        {"identifier": "Address", "columnName": "IPAddress"}
      ]
    }
  ]
}

4.2 PowerShell Script for Rule Deployment

# Connect to Azure
Connect-AzAccount
 
# Variables
$resourceGroup = "rg-sentinel-prod"
$workspaceName = "law-sentinel-prod"
 
# Create Analytics Rule - Suspicious PowerShell Commands
$ruleName = "Suspicious-PowerShell-Commands"
$ruleQuery = @"
SecurityEvent
| where EventID == 4688
| where Process has_any ("powershell.exe", "pwsh.exe")
| where CommandLine has_any (
    "-enc", "-encodedcommand", "-e ",
    "bypass", "-ep bypass",
    "downloadstring", "downloadfile",
    "invoke-webrequest", "iwr",
    "invoke-expression", "iex",
    "frombase64string",
    "hidden", "-w hidden"
)
| extend AccountName = tostring(split(SubjectUserName, '@')[0])
| project TimeGenerated, Computer, AccountName, CommandLine, ParentProcessName
"@
 
New-AzSentinelAlertRule `
    -ResourceGroupName $resourceGroup `
    -WorkspaceName $workspaceName `
    -Kind Scheduled `
    -DisplayName "Suspicious PowerShell Command Execution" `
    -Description "Detects suspicious PowerShell command patterns often used in attacks" `
    -Severity High `
    -Query $ruleQuery `
    -QueryFrequency (New-TimeSpan -Minutes 5) `
    -QueryPeriod (New-TimeSpan -Hours 1) `
    -TriggerOperator GreaterThan `
    -TriggerThreshold 0 `
    -Enabled
 
# Create Analytics Rule - Privilege Escalation
$privEscQuery = @"
SecurityEvent
| where EventID == 4672
| where SubjectUserName !endswith "$"
| where SubjectUserName !in ("SYSTEM", "LOCAL SERVICE", "NETWORK SERVICE")
| summarize PrivilegeCount = count(), Privileges = make_set(PrivilegeList) by SubjectUserName, Computer, bin(TimeGenerated, 1h)
| where PrivilegeCount > 5
"@
 
New-AzSentinelAlertRule `
    -ResourceGroupName $resourceGroup `
    -WorkspaceName $workspaceName `
    -Kind Scheduled `
    -DisplayName "Unusual Privilege Elevation Activity" `
    -Description "Detects accounts receiving special privileges at an unusual rate" `
    -Severity Medium `
    -Query $privEscQuery `
    -QueryFrequency (New-TimeSpan -Minutes 15) `
    -QueryPeriod (New-TimeSpan -Hours 2) `
    -TriggerOperator GreaterThan `
    -TriggerThreshold 0 `
    -Enabled

4.3 MITRE ATT&CK Aligned Rules

TacticTechniqueRule NameDetection Logic
Initial AccessT1078Impossible TravelSign-ins from geographically distant locations
ExecutionT1059Suspicious ScriptsPowerShell/CMD with encoded commands
PersistenceT1098Account ModificationService principal credential added
Privilege EscalationT1078.004Cloud Account AbuseRole assignment to sensitive groups
Defense EvasionT1562Security Tool DisabledDefender/AV disabled events
Credential AccessT1110Brute ForceMultiple failed authentications
DiscoveryT1087Account EnumerationGraph API bulk queries
Lateral MovementT1021RDP/SSH from InternetRemote access from external IPs
CollectionT1530Storage AccessBlob storage enumeration
ExfiltrationT1567Cloud Storage UploadLarge data uploads to external clouds

Part 5: Custom Workbooks

5.1 Security Overview Workbook

{
  "version": "Notebook/1.0",
  "items": [
    {
      "type": 1,
      "content": {
        "json": "# Security Operations Overview\n---\nReal-time security metrics and incident tracking"
      }
    },
    {
      "type": 3,
      "content": {
        "version": "KqlItem/1.0",
        "query": "SecurityIncident\n| where TimeGenerated >= ago(7d)\n| summarize Incidents = count() by Severity\n| order by Severity asc",
        "size": 1,
        "title": "Incidents by Severity (Last 7 Days)",
        "queryType": 0,
        "visualization": "piechart"
      }
    },
    {
      "type": 3,
      "content": {
        "version": "KqlItem/1.0",
        "query": "SecurityIncident\n| where TimeGenerated >= ago(30d)\n| summarize Incidents = count() by bin(TimeGenerated, 1d), Severity\n| render timechart",
        "size": 0,
        "title": "Incident Trend (Last 30 Days)",
        "queryType": 0,
        "visualization": "timechart"
      }
    },
    {
      "type": 3,
      "content": {
        "version": "KqlItem/1.0",
        "query": "SecurityIncident\n| where TimeGenerated >= ago(24h)\n| where Status == 'New'\n| project Title, Severity, CreatedTime = TimeGenerated, Owner = OwnerName\n| order by Severity asc, CreatedTime desc\n| take 20",
        "size": 0,
        "title": "Open Incidents (Last 24 Hours)",
        "queryType": 0,
        "visualization": "table"
      }
    }
  ],
  "fallbackResourceIds": [],
  "fromTemplateId": "sentinel-SecurityOverview"
}

5.2 Sign-in Analysis Workbook

// Failed Sign-ins by Location
SigninLogs
| where TimeGenerated >= ago(7d)
| where ResultType != 0
| summarize FailedAttempts = count() by Location
| top 10 by FailedAttempts desc
| render barchart
 
// Sign-in Risk Analysis
SigninLogs
| where TimeGenerated >= ago(24h)
| summarize
    TotalSignIns = count(),
    RiskySignIns = countif(RiskLevelDuringSignIn in ("medium", "high")),
    MFARequired = countif(AuthenticationRequirement == "multiFactorAuthentication"),
    LegacyAuth = countif(ClientAppUsed !in ("Browser", "Mobile Apps and Desktop clients"))
| extend RiskPercentage = round(100.0 * RiskySignIns / TotalSignIns, 2)
 
// Conditional Access Policy Impact
SigninLogs
| where TimeGenerated >= ago(7d)
| mv-expand ConditionalAccessPolicies
| extend PolicyName = tostring(ConditionalAccessPolicies.displayName)
| extend PolicyResult = tostring(ConditionalAccessPolicies.result)
| summarize count() by PolicyName, PolicyResult
| render columnchart

Part 6: Threat Hunting

6.1 Hunting Queries

// Hunt: Suspicious Service Principal Activity
let timeRange = 7d;
AuditLogs
| where TimeGenerated >= ago(timeRange)
| where OperationName has_any ("Add service principal", "Add application", "Update application")
| where Result == "success"
| extend InitiatedBy = tostring(InitiatedBy.user.userPrincipalName)
| extend AppName = tostring(TargetResources[0].displayName)
| extend AppId = tostring(TargetResources[0].id)
| project TimeGenerated, InitiatedBy, OperationName, AppName, AppId
| order by TimeGenerated desc
 
// Hunt: Lateral Movement via RDP
let timeRange = 24h;
SecurityEvent
| where TimeGenerated >= ago(timeRange)
| where EventID == 4624
| where LogonType == 10
| where IpAddress !startswith "10." and IpAddress !startswith "192.168." and IpAddress !startswith "172."
| summarize RDPSessions = count(), Computers = make_set(Computer) by IpAddress, Account
| where RDPSessions > 3
| order by RDPSessions desc
 
// Hunt: Data Exfiltration Indicators
let timeRange = 7d;
let threshold = 1000000000; // 1 GB
AzureDiagnostics
| where TimeGenerated >= ago(timeRange)
| where ResourceType == "STORAGEACCOUNTS"
| where OperationName == "GetBlob"
| summarize TotalBytes = sum(requestBodySize_d) by CallerIpAddress, AccountName = Resource
| where TotalBytes > threshold
| extend TotalGB = round(TotalBytes / 1000000000.0, 2)
| order by TotalGB desc
 
// Hunt: Persistence via Scheduled Tasks
SecurityEvent
| where TimeGenerated >= ago(7d)
| where EventID == 4698
| parse EventData with * '<Data Name="TaskName">' TaskName '</Data>' *
| parse EventData with * '<Data Name="SubjectUserName">' SubjectUserName '</Data>' *
| where SubjectUserName !endswith "$"
| project TimeGenerated, Computer, SubjectUserName, TaskName
| order by TimeGenerated desc

6.2 Bookmarked Evidence

// Create bookmark from hunting results
// In Sentinel UI: Hunting → Queries → Run Query → Add Bookmark
 
// Example: Bookmark suspicious sign-in
SigninLogs
| where TimeGenerated >= ago(1h)
| where RiskLevelDuringSignIn == "high"
| where ResultType == 0
| project
    TimeGenerated,
    UserPrincipalName,
    IPAddress,
    Location,
    AppDisplayName,
    RiskDetail,
    ConditionalAccessStatus

Part 7: SOAR Playbooks

7.1 Playbook: Block IP in Azure Firewall

{
  "definition": {
    "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
    "actions": {
      "Get_Incident": {
        "inputs": {
          "body": {
            "incidentArmId": "@triggerBody()?['object']?['id']"
          },
          "host": {
            "connection": {
              "name": "@parameters('$connections')['azuresentinel']['connectionId']"
            }
          },
          "method": "post",
          "path": "/Incidents"
        },
        "type": "ApiConnection"
      },
      "For_Each_Entity": {
        "actions": {
          "Condition_Is_IP": {
            "actions": {
              "Add_IP_to_Blocklist": {
                "inputs": {
                  "body": {
                    "properties": {
                      "action": {
                        "type": "Deny"
                      },
                      "destinationAddresses": ["*"],
                      "destinationPorts": ["*"],
                      "protocols": ["Any"],
                      "sourceAddresses": ["@{items('For_Each_Entity')?['properties']?['address']}"]
                    }
                  },
                  "method": "PUT",
                  "uri": "https://management.azure.com/subscriptions/@{variables('SubscriptionId')}/resourceGroups/@{variables('ResourceGroup')}/providers/Microsoft.Network/azureFirewalls/@{variables('FirewallName')}/networkRuleCollections/BlockedIPs/rules/@{guid()}?api-version=2021-05-01"
                },
                "type": "Http"
              }
            },
            "expression": {
              "and": [
                {
                  "equals": ["@items('For_Each_Entity')?['kind']", "Ip"]
                }
              ]
            },
            "type": "If"
          }
        },
        "foreach": "@body('Get_Incident')?['properties']?['relatedEntities']",
        "type": "Foreach"
      },
      "Add_Comment_to_Incident": {
        "inputs": {
          "body": {
            "incidentArmId": "@triggerBody()?['object']?['id']",
            "message": "Automated Response: Malicious IP addresses have been blocked in Azure Firewall."
          },
          "host": {
            "connection": {
              "name": "@parameters('$connections')['azuresentinel']['connectionId']"
            }
          },
          "method": "post",
          "path": "/Incidents/Comment"
        },
        "type": "ApiConnection"
      }
    },
    "triggers": {
      "Microsoft_Sentinel_incident": {
        "inputs": {
          "body": {
            "callback_url": "@{listCallbackUrl()}"
          },
          "host": {
            "connection": {
              "name": "@parameters('$connections')['azuresentinel']['connectionId']"
            }
          },
          "path": "/incident-creation"
        },
        "type": "ApiConnectionWebhook"
      }
    }
  }
}

7.2 Playbook: Isolate Compromised Device

# PowerShell function for Logic App
# Isolates device using Microsoft Defender for Endpoint API
 
param(
    [string]$DeviceId,
    [string]$IncidentId,
    [string]$Comment
)
 
# Get access token
$tenantId = $env:TENANT_ID
$clientId = $env:CLIENT_ID
$clientSecret = $env:CLIENT_SECRET
 
$body = @{
    grant_type    = "client_credentials"
    client_id     = $clientId
    client_secret = $clientSecret
    scope         = "https://api.securitycenter.microsoft.com/.default"
}
 
$tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -Method Post -Body $body
$accessToken = $tokenResponse.access_token
 
# Isolate the device
$isolateBody = @{
    Comment = "Automated isolation due to incident $IncidentId. $Comment"
    IsolationType = "Full"
} | ConvertTo-Json
 
$headers = @{
    "Authorization" = "Bearer $accessToken"
    "Content-Type" = "application/json"
}
 
$response = Invoke-RestMethod `
    -Uri "https://api.securitycenter.microsoft.com/api/machines/$DeviceId/isolate" `
    -Method Post `
    -Headers $headers `
    -Body $isolateBody
 
return $response

7.3 Playbook: Enrich IOCs with Threat Intelligence

{
  "definition": {
    "actions": {
      "For_Each_IP": {
        "actions": {
          "Query_VirusTotal": {
            "inputs": {
              "headers": {
                "x-apikey": "@parameters('VirusTotalApiKey')"
              },
              "method": "GET",
              "uri": "https://www.virustotal.com/api/v3/ip_addresses/@{items('For_Each_IP')}"
            },
            "type": "Http"
          },
          "Query_AbuseIPDB": {
            "inputs": {
              "headers": {
                "Key": "@parameters('AbuseIPDBApiKey')"
              },
              "method": "GET",
              "uri": "https://api.abuseipdb.com/api/v2/check?ipAddress=@{items('For_Each_IP')}&maxAgeInDays=90"
            },
            "type": "Http"
          },
          "Update_Incident_with_TI": {
            "inputs": {
              "body": {
                "incidentArmId": "@triggerBody()?['object']?['id']",
                "message": "Threat Intelligence Enrichment:\n\nVirusTotal: @{body('Query_VirusTotal')?['data']?['attributes']?['reputation']}\nAbuseIPDB Score: @{body('Query_AbuseIPDB')?['data']?['abuseConfidenceScore']}"
              }
            },
            "type": "ApiConnection"
          }
        },
        "foreach": "@variables('IPAddresses')",
        "type": "Foreach"
      }
    }
  }
}

Part 8: Automation Rules

8.1 Auto-Assignment Rules

{
  "displayName": "Auto-Assign High Severity Incidents",
  "order": 1,
  "triggeringLogic": {
    "isEnabled": true,
    "triggersOn": "Incidents",
    "triggersWhen": "Created",
    "conditions": [
      {
        "conditionType": "Property",
        "conditionProperties": {
          "propertyName": "IncidentSeverity",
          "operator": "Equals",
          "propertyValues": ["High"]
        }
      }
    ]
  },
  "actions": [
    {
      "actionType": "ModifyProperties",
      "actionConfiguration": {
        "owner": {
          "objectId": "<senior-analyst-guid>",
          "email": "senior.analyst@yourdomain.com",
          "userPrincipalName": "senior.analyst@yourdomain.com"
        },
        "status": "Active"
      }
    },
    {
      "actionType": "RunPlaybook",
      "actionConfiguration": {
        "playbookResourceId": "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Logic/workflows/Send-Teams-Notification"
      }
    }
  ]
}

8.2 Auto-Close Rules

{
  "displayName": "Auto-Close Known False Positives",
  "order": 10,
  "triggeringLogic": {
    "isEnabled": true,
    "triggersOn": "Incidents",
    "triggersWhen": "Created",
    "conditions": [
      {
        "conditionType": "Property",
        "conditionProperties": {
          "propertyName": "IncidentTitle",
          "operator": "Contains",
          "propertyValues": ["Test-", "Scheduled-Scan-", "Maintenance-"]
        }
      }
    ]
  },
  "actions": [
    {
      "actionType": "ModifyProperties",
      "actionConfiguration": {
        "status": "Closed",
        "classification": "BenignPositive",
        "classificationReason": "ConfirmedActivity"
      }
    },
    {
      "actionType": "AddIncidentTask",
      "actionConfiguration": {
        "title": "Auto-closed - Review if unexpected",
        "description": "This incident was auto-closed based on known patterns. Review if this closure was unexpected."
      }
    }
  ]
}

Part 9: Cost Optimization

9.1 Data Collection Optimization

// Analyze data ingestion by table
Usage
| where TimeGenerated >= ago(30d)
| where IsBillable == true
| summarize TotalGB = sum(Quantity) / 1000 by DataType
| order by TotalGB desc
| take 20
 
// Find noisy events
SecurityEvent
| where TimeGenerated >= ago(7d)
| summarize EventCount = count() by EventID
| order by EventCount desc
| take 20

9.2 Basic Logs Configuration

Configure lower-cost basic logs for high-volume tables:

# Set table to Basic tier
az monitor log-analytics workspace table update \
  --resource-group $RESOURCE_GROUP \
  --workspace-name $WORKSPACE_NAME \
  --name "ContainerLog" \
  --plan Basic
 
# Set retention separately
az monitor log-analytics workspace table update \
  --resource-group $RESOURCE_GROUP \
  --workspace-name $WORKSPACE_NAME \
  --name "ContainerLog" \
  --retention-time 30 \
  --total-retention-time 90

9.3 Commitment Tiers

Daily IngestionRecommended TierCost Savings
< 100 GBPay-as-you-goN/A
100-500 GB100 GB/day commitment~20%
500-1000 GB500 GB/day commitment~30%
> 1000 GB1000 GB/day commitment~35%

Part 10: Verification and Testing

10.1 Validate Data Connectors

// Check data connector health
SentinelHealth
| where TimeGenerated >= ago(1d)
| where OperationName == "Data collection"
| summarize LastHeartbeat = max(TimeGenerated), Status = arg_max(TimeGenerated, *) by SentinelResourceId
| project SentinelResourceId, LastHeartbeat, Status
 
// Verify data flow per connector
union withsource=TableName *
| where TimeGenerated >= ago(1h)
| summarize RecordCount = count() by TableName
| order by RecordCount desc

10.2 Test Analytics Rules

// Simulate brute force for testing
// Run this query manually - should trigger alert
SigninLogs
| take 1
| extend TestIP = "192.0.2.1"
| extend TestUser = "testuser@domain.com"
| project IPAddress = TestIP, UserPrincipalName = TestUser, ResultType = "50126"

10.3 Test Playbooks

# Trigger test incident for playbook validation
$incidentBody = @{
    properties = @{
        title = "Test Incident for Playbook Validation"
        severity = "Medium"
        status = "New"
        description = "This is a test incident to validate SOAR playbook execution."
    }
}
 
New-AzSentinelIncident `
    -ResourceGroupName $resourceGroup `
    -WorkspaceName $workspaceName `
    -IncidentId (New-Guid).Guid `
    @incidentBody

Troubleshooting

Common Issues and Solutions

IssueSymptomsResolution
Data not appearingEmpty tables after connector setupCheck connector permissions, verify agent health
High latencyDelayed alertsCheck query complexity, optimize KQL
Playbook failuresActions not executingVerify Logic App permissions, check API limits
Missing entitiesEntities not extractedReview entity mappings in analytics rules
Cost overrunsUnexpected chargesImplement data filtering, use Basic logs tier

Diagnostic Queries

// Check for data gaps
let interval = 5m;
SigninLogs
| where TimeGenerated >= ago(24h)
| summarize Count = count() by bin(TimeGenerated, interval)
| where Count < 10
| order by TimeGenerated desc
 
// Analyze query performance
AzureDiagnostics
| where ResourceType == "MICROSOFT.OPERATIONALINSIGHTS/WORKSPACES"
| where OperationName == "Query"
| extend QueryHash = tostring(parse_json(tostring(parse_json(Properties).QueryHash)))
| summarize AvgDuration = avg(DurationMs), Count = count() by QueryHash
| order by AvgDuration desc
| take 10

Security Considerations

Best Practices

  1. Least Privilege: Grant minimum required permissions for data connectors
  2. Encryption: Enable customer-managed keys for sensitive data
  3. Network Security: Use Private Link for workspace access
  4. Audit Logging: Enable diagnostic settings on Sentinel itself
  5. Playbook Security: Use managed identities, store secrets in Key Vault

Compliance Mapping

FrameworkSentinel Capability
PCI-DSSLog retention, access controls, monitoring
HIPAAAudit trails, incident response
SOC 2Continuous monitoring, alerting
NIST CSFDetect, Respond, Recover functions

Next Steps

After completing this Sentinel implementation:

  1. Advanced Hunting: Develop custom hunting queries for your environment
  2. Machine Learning: Enable ML-based anomaly detection
  3. UEBA: Implement User and Entity Behavior Analytics
  4. Threat Intelligence: Integrate additional TI feeds

Related Resources

  • Incident Response: Ransomware Playbook
  • CIS Controls Implementation
  • Conditional Access Zero Trust
  • Azure Landing Zone with Terraform
#Azure Sentinel#SIEM#Microsoft Defender#Security Operations#KQL#SOAR#Threat Detection

Related Articles

Build Your Own SIEM with Open-Source Tools

Step-by-step project guide for building a functional SIEM using Wazuh, Elastic, and Grafana. Perfect for homelabs and small businesses.

4 min read

Build a Collaborative IPS with CrowdSec

Deploy CrowdSec on a Linux server to get community-powered intrusion prevention — block brute-force attacks, credential stuffing, and vulnerability scanners using crowd-sourced threat intelligence and automatic firewall enforcement.

10 min read

Keycloak SSO: Self-Hosted Identity Provider for Your Homelab

Deploy Keycloak with Docker Compose and PostgreSQL to build a centralised single sign-on platform for your homelab services, with OIDC integration for...

11 min read
Back to all Projects