Stop Reacting Manually: Automating Security Alert Response with Bicep

Advertisement

Stop Reacting Manually: Automating Security Alert Response with Bicep

Automating the Response to a Security Alert with Bicep (Microsoft Sentinel)

When a security analyst is asleep and a brute-force sign-in attempt fires at 3 a.m., the difference between a contained incident and a breach is often just a few minutes. Instead of relying on someone to notice an alert and react manually, you can wire the reaction directly into your infrastructure-as-code: the moment a specific alert fires, Azure runs a playbook that takes action automatically — no human in the loop required for the first response.

This article walks through building that pipeline entirely in Bicep, using Microsoft Sentinel (Azure's SIEM) as the alerting engine and a Logic Apps playbook as the automated responder.

The architecture

Three pieces work together:

  1. Analytics rule — the detection logic that scans logs and raises an incident when a specific pattern is found (for example, repeated failed sign-ins from the same account).
  2. Automation rule — a Sentinel resource that watches for incidents matching a condition (e.g. "created by this specific analytics rule") and triggers an action.
  3. Logic App playbook — the actual responder. It receives the incident and performs the remediation, such as disabling the user account, blocking an IP address, or isolating a device.

Analytics Rule ──► Incident created ──► Automation Rule (condition match) ──► Logic App Playbook ──► Remediation action

All three can be defined and deployed as code with Bicep, so the entire response pipeline lives in source control alongside the rest of your infrastructure.

Prerequisites

  • A Log Analytics workspace with Microsoft Sentinel enabled
  • Bicep CLI / Azure CLI (az bicep or the bicep binary) installed
  • Contributor access on the resource group, and permission to create role assignments if the playbook needs to call other Azure APIs (e.g. Microsoft Graph, Azure AD)
  • The playbook's connectors (e.g. Azure Sentinel connector, Office 365, Microsoft Graph) authorized after first deployment — API connections in Logic Apps typically require a one-time manual consent step

Step 1 — The Logic App playbook

The playbook must start with the Microsoft Sentinel trigger (Microsoft Sentinel alert / incident trigger). Below is a minimal playbook that receives an incident and, as an example action, posts a Teams/email notification — you would replace the final action with your actual remediation step (disable account, block IP, isolate machine, etc.).

param location string = resourceGroup().location
param playbookName string = 'pb-respond-bruteforce'
param sentinelConnectionName string = 'azuresentinel-connection'

resource sentinelConnection 'Microsoft.Web/connections@2016-06-01' = {
  name: sentinelConnectionName
  location: location
  properties: {
    displayName: sentinelConnectionName
    api: {
      id: subscriptionResourceId('Microsoft.Web/locations/managedApis', location, 'azuresentinel')
    }
  }
}

resource playbook 'Microsoft.Logic/workflows@2019-05-01' = {
  name: playbookName
  location: location
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    state: 'Enabled'
    definition: {
      '$schema': 'https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#'
      contentVersion: '1.0.0.0'
      triggers: {
        Microsoft_Sentinel_incident: {
          type: 'ApiConnectionWebhook'
          inputs: {
            host: {
              connection: {
                name: '@parameters(\'$connections\')[\'azuresentinel\'][\'connectionId\']'
              }
            }
            body: {
              callback_url: '@{listCallbackUrl()}'
            }
            path: '/incident-creation'
          }
        }
      }
      actions: {
        // Replace this with the real remediation step, e.g.:
        // - HTTP call to Microsoft Graph to disable the user
        // - Azure Firewall / NSG rule update to block the source IP
        // - Defender for Endpoint "isolate machine" action
        Notify_Team: {
          type: 'Http'
          inputs: {
            method: 'POST'
            uri: 'https://YOUR-NOTIFICATION-WEBHOOK'
            body: {
              text: 'Security alert triggered automated response: @{triggerBody()?[\'object\']?[\'properties\']?[\'title\']}'
            }
          }
          runAfter: {}
        }
      }
    }
    parameters: {
      '$connections': {
        value: {
          azuresentinel: {
            connectionId: sentinelConnection.id
            connectionName: sentinelConnectionName
            id: subscriptionResourceId('Microsoft.Web/locations/managedApis', location, 'azuresentinel')
          }
        }
      }
    }
  }
}

output playbookId string = playbook.id

 

Note: After deployment, the Sentinel API connection needs a one-time interactive authorization in the portal (Resource → API connections → Authorize), since Logic Apps connectors can't complete OAuth consent unattended during a Bicep deployme

Step 2 — The automation rule

The automation rule is what actually ties a specific alert to the playbook. The key piece is the triggeringLogic.conditions block, where you filter on the analytics rule that produced the incident (using IncidentRelatedAnalyticRuleIds), and the actions block, where actionType: 'RunPlaybook' points at the Logic App's resource ID.

param workspaceName string
param analyticRuleId string // resourceId of the specific alert/analytics rule to react to
param automationRuleName string = guid('auto-rule-bruteforce')

resource workspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = {
  name: workspaceName
}

resource automationRule 'Microsoft.SecurityInsights/automationRules@2023-02-01-preview' = {
  name: automationRuleName
  scope: workspace
  properties: {
    displayName: 'Auto-respond to brute-force alert'
    order: 1
    triggeringLogic: {
      isEnabled: true
      triggersOn: 'Incidents'
      triggersWhen: 'Created'
      conditions: [
        {
          conditionType: 'Property'
          conditionProperties: {
            propertyName: 'IncidentRelatedAnalyticRuleIds'
            operator: 'Contains'
            propertyValues: [
              analyticRuleId
            ]
          }
        }
      ]
    }
    actions: [
      {
        order: 1
        actionType: 'RunPlaybook'
        actionConfiguration: {
          logicAppResourceId: playbook.id
          tenantId: tenant().tenantId
        }
      }
    ]
  }
}

 

analyticRuleId is the resource ID of the analytics rule you want to react to for example, one that flags brute-force sign-ins. You get this from an existing rule (Microsoft.SecurityInsights/alertRules) or deploy one alongside this template.

Step 3 — Granting the playbook permission to act

If the remediation step calls Azure Resource Manager or Microsoft Graph (e.g. to disable a user, or update a network security group), the playbook's system-assigned managed identity needs a role assignment. For example, granting it rights to modify NSG rules.

 

resource nsgRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(playbook.id, 'Network Contributor')
  scope: resourceGroup()
  properties: {
    principalId: playbook.identity.principalId
    roleDefinitionId: subscriptionResourceId(
      'Microsoft.Authorization/roleDefinitions',
      '4d97b98b-1d4f-4787-a291-c67834d212e7' // Network Contributor
    )
    principalType: 'ServicePrincipal'
  }
}

 

Also, Sentinel itself needs permission to run the playbook that's handled by an existing built-in role, Microsoft Sentinel Automation Contributor, assigned to the Sentinel automation identity on the playbook's resource group. This is normally granted the first time you link a playbook to an automation rule through the portal or API, for a fully code-driven pipeline, add it explicitly as a roleAssignments resource scoped to the playbook.

Step 4 — Deploying

az deployment group create \
  --resource-group rg-security \
  --template-file main.bicep \
  --parameters workspaceName=my-sentinel-workspace analyticRuleId=/subscriptions/.../alertRules/xxxx
 
 

Step 5 — Testing safely

Before trusting this in production:

  • Trigger the analytics rule in a test environment (e.g. simulate the failed sign-in pattern) and confirm the incident is created.
  • Confirm the automation rule fires and the playbook run appears in the Logic App's Run history.
  • Start the remediation action in "dry run" mode (log the intended action instead of executing it) until you're confident the condition logic only matches the alert you intend.
  • Add a second condition on severity or entity type if the analytics rule is broad, to avoid over-triggering.

Key takeaways

  • Microsoft.SecurityInsights/automationRules is the glue resource: it's what makes the response automatic rather than requiring an analyst to manually run a playbook from the incident.
  • The RunPlaybook action type just needs the Logic App's resource ID and tenant ID — the matching logic is entirely in triggeringLogic.conditions.
  • Keep the remediation logic in the Logic App itself, and keep the decision to respond in the automation rule's conditions — this makes it easy to reuse one playbook across several different alerts by attaching multiple automation rules to it.
  • Because everything is Bicep, the whole detection-to-response pipeline can be versioned, reviewed, and deployed the same way as any other infrastructure change.

 

Induranga Lokuliyanage

Induranga Lokuliyanage

Senior Cloud Engineer | Cloud Enthusiast | Solutions Architect | Azure ☁| DevOps | IAC | FinOps Certified | Microsoft | MCT | Making Technology Work for Humans

Comments (0)

Success!
Your comment has been submitted successfully. It will appear once approved by an admin.
Men Avatar Woman Avatar

No comments yet. Be the first to share your thoughts!