Skip to main content

Penfield and Microsoft Sentinel integration (Logic App)

Overview

This document outlines the process of integrating Microsoft Sentinel with the Penfield Platform. The integration involves two main steps:

  1. Building Azure Logic App Playbooks to push relevant Incident Data to Penfield Platform via Penfield's API.
  2. Creating Automation Rules in Sentinel to trigger specific playbooks when certain incident conditions are met.

Prerequisites

  • Access to Microsoft Azure portal
  • Permissions to create and manage Logic Apps and Microsoft Sentinel
  • Penfield API endpoint and API key (provided by Penfield)

Step 1: Building Azure Logic App Playbooks

1.1 Create a Logic App

  1. In the Azure portal, search for "Logic Apps”
  2. If you already have a Logic App built for Sentinel, you may choose to utilize that instead and jump to 1.2.
  3. Click "Create" to create a new Logic App
  4. Fill in the required details:
    • Resource Group: Select or create a new one
    • Logic App name: e.g., "Penfield-Sentinel-Integration"
    • Region: Choose appropriate region
    • Plan type: Consumption
  5. Click "Review + Create" and then "Create"

1.2 Create Workflows

Create three workflows within the Logic App:



Create 3 Workflows: Next we need to create 3 workflows.



Workflow 1: create-incident

Select Add and fill in Workflow Name:

Select Designer

Select Add Trigger

Search for “sentinel Incident” and select “Microsoft Sentinel incident” fom the list.

Select (+) under Microsoft Sentinel incident and then search for “HTTP” and select

  1. Configure the HTTP action:
    • Method: POST
    • URI: [Provided by Penfield]
    • Headers:
      • Content-Type: application/json
      • x-api-key: [Provided by Penfield]
    • Body: see below
  • Body:
{
"type": "create",
"incident": {
"severity": "@{coalesce(triggerBody()?['object']?['properties']?['severity'], 'Unknown')}",
"description": "@{coalesce(replace(coalesce(triggerBody()?['object']?['properties']?['description'], ''), '\\\"', '\\\\\\\"'), 'No description provided')}",
"incident_number": "@{coalesce(triggerBody()?['object']?['properties']?['incidentNumber'], 'Unknown')}",
"incident_title": "@{coalesce(triggerBody()?['object']?['properties']?['title'], 'Untitled Incident')}",
"incident_id": "@{coalesce(last(split(triggerBody()?['object']?['id'], '/')), 'Unknown')}",
"incident_status": "@{coalesce(triggerBody()?['object']?['properties']?['status'], 'Unknown')}",
"assignee": "@{coalesce(triggerBody()?['object']?['properties']?['owner']?['userPrincipalName'], 'Unassigned')}",
"updated_at": "@{coalesce(triggerBody()?['object']?['properties']?['lastModifiedTimeUtc'], utcNow())}",
"tactics": "@{if(empty(triggerBody()?['object']?['properties']?['tactics']), '[]', string(triggerBody()?['object']?['properties']?['tactics']))}",
"classification": "@{coalesce(triggerBody()?['object']?['properties']?['classification'], 'Unclassified')}",
"classification_reason": "@{coalesce(triggerBody()?['object']?['properties']?['classificationReason'], 'Not specified')}",
"classification_comment": "@{coalesce(triggerBody()?['object']?['properties']?['classificationComment'], '')}",
"event_time": "@{utcNow()}"
}
}

Note: Please contact Penfield team should you have privacy concerns. The Penfield platform can be configured to anonymize/pseudonymize specific fields before they are saved. Alternatively, you may choose not to push specific fields to Penfield - the control is yours but please consult Penfield.

End state should look something like this:

Select save.

Workflow 2: assign-incident

Follow the same steps as Workflow 1, but use the following JSON structure in the HTTP action body.

{
"type": "assign",
"incident": {
"severity": "@{coalesce(triggerBody()?['object']?['properties']?['severity'], 'Unknown')}",
"description": "@{coalesce(replace(coalesce(triggerBody()?['object']?['properties']?['description'], ''), '\\\"', '\\\\\\\"'), 'No description provided')}",
"incident_number": "@{coalesce(triggerBody()?['object']?['properties']?['incidentNumber'], 'Unknown')}",
"incident_title": "@{coalesce(triggerBody()?['object']?['properties']?['title'], 'Untitled Incident')}",
"incident_id": "@{coalesce(last(split(triggerBody()?['object']?['id'], '/')), 'Unknown')}",
"incident_status": "@{coalesce(triggerBody()?['object']?['properties']?['status'], 'Unknown')}",
"assignee": "@{coalesce(triggerBody()?['object']?['properties']?['owner']?['userPrincipalName'], 'Unassigned')}",
"updated_at": "@{coalesce(triggerBody()?['object']?['properties']?['lastModifiedTimeUtc'], utcNow())}",
"tactics": "@{if(empty(triggerBody()?['object']?['properties']?['tactics']), '[]', string(triggerBody()?['object']?['properties']?['tactics']))}",
"classification": "@{coalesce(triggerBody()?['object']?['properties']?['classification'], 'Unclassified')}",
"classification_reason": "@{coalesce(triggerBody()?['object']?['properties']?['classificationReason'], 'Not specified')}",
"classification_comment": "@{coalesce(triggerBody()?['object']?['properties']?['classificationComment'], '')}",
"event_time": "@{utcNow()}"
}
}

Workflow 3: resolve-incident

Follow the same steps as Workflow 1, but use the following JSON structure in the HTTP action body.

{
"type": "resolve",
"incident": {
"severity": "@{coalesce(triggerBody()?['object']?['properties']?['severity'], 'Unknown')}",
"description": "@{coalesce(replace(coalesce(triggerBody()?['object']?['properties']?['description'], ''), '\\\"', '\\\\\\\"'), 'No description provided')}",
"incident_number": "@{coalesce(triggerBody()?['object']?['properties']?['incidentNumber'], 'Unknown')}",
"incident_title": "@{coalesce(triggerBody()?['object']?['properties']?['title'], 'Untitled Incident')}",
"incident_id": "@{coalesce(last(split(triggerBody()?['object']?['id'], '/')), 'Unknown')}",
"incident_status": "@{coalesce(triggerBody()?['object']?['properties']?['status'], 'Unknown')}",
"assignee": "@{coalesce(triggerBody()?['object']?['properties']?['owner']?['userPrincipalName'], 'Unassigned')}",
"updated_at": "@{coalesce(triggerBody()?['object']?['properties']?['lastModifiedTimeUtc'], utcNow())}",
"tactics": "@{if(empty(triggerBody()?['object']?['properties']?['tactics']), '[]', string(triggerBody()?['object']?['properties']?['tactics']))}",
"classification": "@{coalesce(triggerBody()?['object']?['properties']?['classification'], 'Unclassified')}",
"classification_reason": "@{coalesce(triggerBody()?['object']?['properties']?['classificationReason'], 'Not specified')}",
"classification_comment": "@{coalesce(triggerBody()?['object']?['properties']?['classificationComment'], '')}",
"event_time": "@{utcNow()}"
}
}

Step 2: Creating Automation Rules in Sentinel

Next, we will create 3 Automation rules on Sentinel to fire when certain conditions are met to trigger our playbooks

2.1 Navigate to Automation Rules

  1. In the Microsoft Sentinel portal, go to the "Automation" section
  2. Click "Create" and select "Automation rule"

2.2 Create Automation Rules

Create three automation rules:

Rule 1: On Create Incident

  1. Name: "On Create Incident"
  2. Trigger: "When incident is created"
  3. Actions: Run playbook "create-incident"

Rule 2: On Assign Incident

  1. Name: "On Assign Incident"
  2. Trigger: "When incident is updated"
  3. Condition: Status changes to "Active" Or Owner “Changed”
  4. Actions: Run playbook "assign-incident"

Rule 3: On Resolve Incident

  1. Name: "On Resolve Incident"
  2. Trigger: "When incident is updated"
  3. Condition: Status changes to "Closed"
  4. Actions: Run playbook "resolve-incident"

Step 3: Whitelists Azure Logic App IP Addresses into Kubernetes cluster Load Balancer

You should whitelist the Azure Logic App IP addresses in the Kubernetes cluster Load Balancer to allow the Logic App to communicate with the Penfield Platform.

  1. You can find the Azure Logic App IP addresses by going to your Logic App -> Settings -> Networking -> Outbound addresses.

    Note: The IP addresses may change over time, so it is recommended to monitor and update the whitelist as needed.

  2. Whitelist the above IP addresses in the Kubernetes cluster Load Balancer security group.

Permissions and Testing

  1. Ensure the Logic App has the following permissions:
    • "Logic App Contributor" role
    • "Microsoft Sentinel Contributor" role
  2. Test the integration by:
    • Creating a new incident in Sentinel
    • Assigning the incident to a user
    • Closing the incident
  3. Verify that the corresponding events are received in the Penfield Platform

Troubleshooting

  • Check Logic App run history for any errors
  • Verify API key and endpoint are correct
  • Ensure proper permissions are set for the Logic App