Master Playbooks IP and Remediation (#2882)
* Master Playbooks IP and Remediation * Modified github links * Updated md files and incident comments * removed commented lines from schema * removed runafter * Updated github link * removed locale file * github links changes * github links update * Update crowdstrike param name * removed locale * removed locale from json files * Exception summary, incident comments and playbook designer files snaps * updated carbon black readme md file * Carbon Black playbook designer screen shots
Двоичные данные
MasterPlaybooks/Remediation-Host/CarbonBlack-Remediation-Host/Images/MainStep1.PNG
Normal file
После Ширина: | Высота: | Размер: 23 KiB |
Двоичные данные
MasterPlaybooks/Remediation-Host/CarbonBlack-Remediation-Host/Images/MainStep2.PNG
Normal file
После Ширина: | Высота: | Размер: 20 KiB |
Двоичные данные
MasterPlaybooks/Remediation-Host/CarbonBlack-Remediation-Host/Images/MainStep3.PNG
Normal file
После Ширина: | Высота: | Размер: 18 KiB |
Двоичные данные
MasterPlaybooks/Remediation-Host/CarbonBlack-Remediation-Host/Images/PlaybookDesignerDark.png
Normal file
После Ширина: | Высота: | Размер: 56 KiB |
Двоичные данные
MasterPlaybooks/Remediation-Host/CarbonBlack-Remediation-Host/Images/PlaybookDesignerLight.png
Normal file
После Ширина: | Высота: | Размер: 60 KiB |
|
@ -0,0 +1,738 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"metadata": {
|
||||
"title": "Block Host Nested Remediation - Carbon Black",
|
||||
"description": "This playbook automatically quarantine the device and enrich sentinel incident with device information.",
|
||||
"mainSteps": [ "1. Fetches a list of potentially malicious Hosts.", "2. Quarantines the malicious Host." ],
|
||||
"prerequisites": [
|
||||
"1. Carbon Black connector needs to be deployed prior to the deployment of this playbook under the same subscription.",
|
||||
"2. Generate an API key to connect with carbon black connector. ",
|
||||
"3. Find Organziation key by refering this link [ Find Organization key by refering this link ](https://defense.conferdeploy.net/settings/connectors) "
|
||||
],
|
||||
"lastUpdateTime": "2021-08-06T00:00:00.000Z",
|
||||
"entities": [ "Host" ],
|
||||
"tags": [ "Remediation" ],
|
||||
"support": {
|
||||
"tier": "community"
|
||||
},
|
||||
"author": {
|
||||
"name": "Accenture"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"PlaybookName": {
|
||||
"defaultValue": "CarbonBlack-QuarantineDevice",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Name of the Logic App/Playbook"
|
||||
}
|
||||
},
|
||||
"ConnectorName": {
|
||||
"defaultValue": "CarbonBlackCloudConnector",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Name of the Azure Firewall"
|
||||
}
|
||||
},
|
||||
"OrganizationKey": {
|
||||
"defaultValue": "OrganizationKey",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "CarbonBlack Org Key"
|
||||
}
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"CarbonBlackConnectionName": "[concat('CarbonBlackCloudConnector-', parameters('PlaybookName'))]"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.Web/connections",
|
||||
"apiVersion": "2016-06-01",
|
||||
"name": "[variables('CarbonBlackConnectionName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"customParameterValues": {},
|
||||
"api": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/customApis/',parameters('ConnectorName'))]"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Logic/workflows",
|
||||
"apiVersion": "2017-07-01",
|
||||
"name": "[parameters('PlaybookName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Web/connections', variables('CarbonBlackConnectionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"state": "Enabled",
|
||||
"definition": {
|
||||
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"defaultValue": {},
|
||||
"type": "Object"
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
"manual": {
|
||||
"type": "Request",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"Hosts": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"Hostname": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"Hostname"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"runtimeConfiguration": {
|
||||
"concurrency": {
|
||||
"runs": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"Carbon_black_information": {
|
||||
"runAfter": {
|
||||
"Organization_Id": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "CarbonblackInformation",
|
||||
"type": "array",
|
||||
"value": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Variable to store the devices information returned from carbon black cloud"
|
||||
},
|
||||
"Condition_to_check_the_scope": {
|
||||
"actions": {
|
||||
"Response": {
|
||||
"runAfter": {},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "@outputs('Compose_HTTP_Response')",
|
||||
"statusCode": 200
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Filter_array": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Compose_HTTP_Failed_Resposne": {
|
||||
"runAfter": {
|
||||
"Create_HTML_table": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Compose",
|
||||
"inputs": "@{outputs('Compose')} CarbonBlack QuarantineDevice Playbook\n\nException occured while Quarantining the Device. Please find the below exception information:\n\n@{body('Create_HTML_table')}"
|
||||
},
|
||||
"Create_HTML_table": {
|
||||
"runAfter": {
|
||||
"Scope_output": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "MethodName",
|
||||
"value": "@item()?['name']"
|
||||
},
|
||||
{
|
||||
"header": "Error",
|
||||
"value": "@item()?['error']?['message']"
|
||||
},
|
||||
{
|
||||
"header": "Status",
|
||||
"value": "@item()?['status']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@outputs('Scope_output')"
|
||||
}
|
||||
},
|
||||
"Response_if_playbook_get(s)_failed": {
|
||||
"runAfter": {
|
||||
"Compose_HTTP_Failed_Resposne": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "@outputs('Compose_HTTP_Failed_Resposne')",
|
||||
"statusCode": 500
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
},
|
||||
"Scope_output": {
|
||||
"runAfter": {},
|
||||
"type": "Compose",
|
||||
"inputs": "@body('Filter_array')"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"lessOrEquals": [
|
||||
"@length(body('Filter_array'))",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
},
|
||||
"Failed_for_Quarantine": {
|
||||
"runAfter": {
|
||||
"Quarantined_devices": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "FailedforQuarantine",
|
||||
"type": "array",
|
||||
"value": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Variable to store the devices information that failed for Quarantine"
|
||||
},
|
||||
"Filter_array": {
|
||||
"runAfter": {
|
||||
"Scope": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@result('Scope')",
|
||||
"where": "@equals(item()?['status'], 'Failed')"
|
||||
}
|
||||
},
|
||||
"Initialize_variable": {
|
||||
"runAfter": {},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "Hosts",
|
||||
"type": "array",
|
||||
"value": "@triggerBody()?['Hosts']"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Organization_Id": {
|
||||
"runAfter": {
|
||||
"Initialize_variable": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "OrganizationKey",
|
||||
"type": "string",
|
||||
"value": "[parameters('OrganizationKey')]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Pre-configured Organization Id"
|
||||
},
|
||||
"Quarantined_devices": {
|
||||
"runAfter": {
|
||||
"Carbon_black_information": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "ActiontakendDevices",
|
||||
"type": "array",
|
||||
"value": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Variable to store the quarantined devices information"
|
||||
},
|
||||
"Scope": {
|
||||
"actions": {
|
||||
"Compose": {
|
||||
"runAfter": {
|
||||
"Create_HTML_table_-_Quarantined_devices": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Compose",
|
||||
"inputs": "<img src=\"https://avatars.githubusercontent.com/u/2071378?s=280&v=4\" alt=\"Lamp\" width=\"32\" height=\"32\">"
|
||||
},
|
||||
"Compose_HTTP_Response": {
|
||||
"runAfter": {
|
||||
"Compose": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Compose",
|
||||
"inputs": "@{outputs('Compose')} CarbonBlack QuarantineDevice Playbook\n\nCarbonBlack QuarantineDevice playbook was triggered and collected the following information from Carbon Black:\n@{body('Create_HTML_table_-_Carbon_Black')}\n\nDevices that were quarantined by this playbook:\n\n@{body('Create_HTML_table_-_Quarantined_devices')}\n"
|
||||
},
|
||||
"Create_HTML_table_-_Carbon_Black": {
|
||||
"runAfter": {
|
||||
"For_each_hosts": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "Devicename",
|
||||
"value": "@item()?['name']"
|
||||
},
|
||||
{
|
||||
"header": "Quarantined",
|
||||
"value": "@item()?['quarantined']"
|
||||
},
|
||||
{
|
||||
"header": "Policyname",
|
||||
"value": "@item()?['policy_name']"
|
||||
},
|
||||
{
|
||||
"header": "PolicyId",
|
||||
"value": "@item()?['policy_id']"
|
||||
},
|
||||
{
|
||||
"header": "DeviceownerId",
|
||||
"value": "@item()?['device_owner_id']"
|
||||
},
|
||||
{
|
||||
"header": "DeviceId",
|
||||
"value": "@item()?['id']"
|
||||
},
|
||||
{
|
||||
"header": "Devicestatus",
|
||||
"value": "@item()?['status']"
|
||||
},
|
||||
{
|
||||
"header": "Operatingsystem",
|
||||
"value": "@item()?['os']"
|
||||
},
|
||||
{
|
||||
"header": "OperatingsystemVersion",
|
||||
"value": "@item()?['os_version']"
|
||||
},
|
||||
{
|
||||
"header": "Organizationname",
|
||||
"value": "@item()?['organization_name']"
|
||||
},
|
||||
{
|
||||
"header": "Email",
|
||||
"value": "@item()?['email']"
|
||||
},
|
||||
{
|
||||
"header": "Sensorstates",
|
||||
"value": "@join(item()?['sensor_states'],',')"
|
||||
},
|
||||
{
|
||||
"header": "LastreportedTime",
|
||||
"value": "@item()?['last_reported_time']"
|
||||
},
|
||||
{
|
||||
"header": "SensorVersion",
|
||||
"value": "@item()?['sensor_version']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@variables('CarbonblackInformation')"
|
||||
}
|
||||
},
|
||||
"Create_HTML_table_-_Quarantined_devices": {
|
||||
"runAfter": {
|
||||
"Create_HTML_table_-_Carbon_Black": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "DeviceId",
|
||||
"value": "@item()?['id']"
|
||||
},
|
||||
{
|
||||
"header": "Devicename",
|
||||
"value": "@item()?['name']"
|
||||
},
|
||||
{
|
||||
"header": "Action",
|
||||
"value": "@item()?['Action']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@variables('ActiontakendDevices')"
|
||||
}
|
||||
},
|
||||
"For_each_hosts": {
|
||||
"foreach": "@variables('Hosts')",
|
||||
"actions": {
|
||||
"Condition": {
|
||||
"actions": {
|
||||
"For_each_results": {
|
||||
"foreach": "@body('Search_devices_in_your_organization')?['results']",
|
||||
"actions": {
|
||||
"Condition_to_check_the_device_is_in_quarantine": {
|
||||
"actions": {
|
||||
"Condition_to_check_the_success_status_codes": {
|
||||
"actions": {
|
||||
"Condition_to_check_the_search_devices_returned_the_results": {
|
||||
"actions": {
|
||||
"For_each_search_results": {
|
||||
"foreach": "@body('Search_devices_in_your_organization_based_on_device_name')?['results']",
|
||||
"actions": {
|
||||
"Append_to_device_information": {
|
||||
"runAfter": {},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "CarbonblackInformation",
|
||||
"value": "@item()"
|
||||
},
|
||||
"description": "Append device information that returned from carbon black"
|
||||
}
|
||||
},
|
||||
"runAfter": {},
|
||||
"type": "Foreach"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Search_devices_in_your_organization_based_on_device_name": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"greater": [
|
||||
"@body('Search_devices_in_your_organization_based_on_device_name')?['num_found']",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
},
|
||||
"Search_devices_in_your_organization_based_on_device_name": {
|
||||
"runAfter": {
|
||||
"Store_devices_information_-_Quarantined": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"query": "name : @{items('For_each_hosts')?['HostName']}"
|
||||
},
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['CarbonBlackCloudConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/appservices/v6/orgs/@{encodeURIComponent(variables('OrganizationKey'))}/devices/_search"
|
||||
}
|
||||
},
|
||||
"Store_devices_information_-_Quarantined": {
|
||||
"runAfter": {},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "ActiontakendDevices",
|
||||
"value": {
|
||||
"Action": "This device was quarantined successfully",
|
||||
"id": "@items('For_each_results')?['id']",
|
||||
"name": "@items('For_each_results')?['name']"
|
||||
}
|
||||
},
|
||||
"description": "Append each devices that quarantined"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"device_actions": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Append_carbon_black_information_-_device_id_in_Quarantine": {
|
||||
"runAfter": {},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "CarbonblackInformation",
|
||||
"value": "@item()"
|
||||
},
|
||||
"description": "Append device information that returned from carbon black"
|
||||
},
|
||||
"Devices_that_Failed_for_quarantined": {
|
||||
"runAfter": {
|
||||
"Append_carbon_black_information_-_device_id_in_Quarantine": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "FailedforQuarantine",
|
||||
"value": "@item()"
|
||||
},
|
||||
"description": "Variable to store the devices that failed to set the devices in quarantine"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"or": [
|
||||
{
|
||||
"equals": [
|
||||
"@outputs('device_actions')?['statusCode']",
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"equals": [
|
||||
"@outputs('device_actions')?['statusCode']",
|
||||
204
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
},
|
||||
"device_actions": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"action_type": "QUARANTINE",
|
||||
"device_id": [
|
||||
"@{items('For_each_results')?['id']}"
|
||||
],
|
||||
"options": {
|
||||
"toggle": "ON"
|
||||
}
|
||||
},
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['CarbonBlackCloudConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/appservices/v6/orgs/@{encodeURIComponent(variables('OrganizationKey'))}/device_actions"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Append_to_array_variable": {
|
||||
"runAfter": {},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "CarbonblackInformation",
|
||||
"value": "@item()"
|
||||
}
|
||||
},
|
||||
"Condition_to_check_the_device_OS": {
|
||||
"actions": {
|
||||
"Store_devices_information_-_Linux": {
|
||||
"runAfter": {},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "ActiontakendDevices",
|
||||
"value": {
|
||||
"Action": "Not supported on devices of OS type Linux",
|
||||
"id": "@items('For_each_results')?['id']",
|
||||
"name": "@items('For_each_results')?['name']"
|
||||
}
|
||||
},
|
||||
"description": "Quarantined is not supported for Linux OS"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Append_to_array_variable": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"equals": [
|
||||
"@toLower(item()?['os'])",
|
||||
"linux"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"equals": [
|
||||
"@items('For_each_results')?['quarantined']",
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"not": {
|
||||
"equals": [
|
||||
"@toLower(item()?['os'])",
|
||||
"linux"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
}
|
||||
},
|
||||
"runAfter": {},
|
||||
"type": "Foreach"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Search_devices_in_your_organization": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Host_not_found": {
|
||||
"runAfter": {},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "ActiontakendDevices",
|
||||
"value": {
|
||||
"Action": "Device not found",
|
||||
"id": "",
|
||||
"name": "@items('For_each_hosts')?['Hostname']"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"greater": [
|
||||
"@body('Search_devices_in_your_organization')?['num_found']",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
},
|
||||
"Search_devices_in_your_organization": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"query": "name : @{items('For_each_hosts')?['HostName']}"
|
||||
},
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['CarbonBlackCloudConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/appservices/v6/orgs/@{encodeURIComponent(variables('OrganizationKey'))}/devices/_search"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {},
|
||||
"type": "Foreach",
|
||||
"runtimeConfiguration": {
|
||||
"concurrency": {
|
||||
"repetitions": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Failed_for_Quarantine": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"value": {
|
||||
"CarbonBlackCloudConnector": {
|
||||
"connectionId": "[resourceId('Microsoft.Web/connections', variables('CarbonBlackConnectionName'))]",
|
||||
"connectionName": "[variables('CarbonBlackConnectionName')]",
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/customApis/',parameters('ConnectorName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
# CarbonBlack Quarantine Host Nested Remediation Playbook
|
||||
## Summary
|
||||
When this playbook gets triggered and it performs below actions
|
||||
1. Gets the list malicious Host information.
|
||||
2. Quarantines the malicious Host.
|
||||
2. Enriches the incident with device information by fetching from CarbonBlack
|
||||
2. Incident information is sent as response to master playbook.
|
||||
|
||||
![CarbonBlack](./Images/PlaybookDesignerLight.png)<br>
|
||||
![CarbonBlack](./Images/PlaybookDesignerDark.png)<br>
|
||||
|
||||
### Prerequisites
|
||||
1. CarbonBlack Custom Connector needs to be deployed prior to the deployment of this playbook under the same subscription and same resource group. Capture the name of connector during deployment.
|
||||
2. Generate an API key ([learn how](https://developer.carbonblack.com/reference/carbon-black-cloud/authentication/#creating-an-api-key)), and grant it to the following access levels:
|
||||
|
||||
| **Product** | **API** | **Service Category** | **API Key Access Level(s) Permitted** |
|
||||
| --------- | -------------- | ----------------- | ------------------------------------ |
|
||||
| **Carbon Black Cloud Platform (PSC)** | Alerts API, Devices API | /appservices/ | Custom (must add an access level with appropriate permissions) |
|
||||
| **Carbon Black Cloud Platform (PSC)** | Platform Search API for Processes | /investigate/ | Custom (must add an access level with appropriate permissions) |
|
||||
|
||||
3. Find Organziation key by refering this link [ Find Organization key by refering this link ](https://defense.conferdeploy.net/settings/connectors)
|
||||
|
||||
### Deploy Custom Connector
|
||||
|
||||
To deploy CarbonBlack Custom connector click on the below button.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FCarbonBlack%2FCarbonBlackConnector%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FCarbonBlack%2FCarbonBlackConnector%2Fazuredeploy.json)
|
||||
|
||||
### Deployment instructions
|
||||
1. Deploy the playbook by clicking on "Deploy to Azure" button. This will take you to deplyoing an ARM Template wizard.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-Host%2FCarbonBlack-Remediation-Host%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-Host%2FCarbonBlack-Remediation-Host%2Fazuredeploy.json)
|
||||
|
||||
|
||||
2. Fill in the required paramteres:
|
||||
|
||||
|Parameter|Description|
|
||||
|--------------|--------------|
|
||||
|**Playbook Name**| Enter the playbook name here (Eg: CarbonBlack-QuarantineDevice-Nested-Remediation)|
|
||||
|**Connector Name**|Enter the name of Carbon Black Connector.|
|
||||
|**Organization Key**| Enter the Organization key|
|
||||
|
||||
### Post-Deployment instructions
|
||||
#### a. Authorize connections
|
||||
Once deployment is complete, you will need to authorize CarbonBlack connection.
|
||||
1. Click the CarbonBlack connection
|
||||
2. Click **Edit API connection**
|
||||
3. Enter API Key
|
||||
4. Click Save
|
||||
|
||||
|
||||
#### b. Configurations in Sentinel
|
||||
1. In Azure sentinel analytical rules should be configured to trigger an incident with risky device.
|
||||
2. Configure the automation rules to trigger this playbook
|
||||
|
||||
|
||||
## Playbook steps explained
|
||||
|
||||
### When Azure Sentinel incident creation rule is triggered
|
||||
Azure Sentinel incident is created. The playbook receives the incident as the input.
|
||||
|
||||
### Entities - Get Hosts
|
||||
Get the list of risky devices as entities from the Incident
|
||||
|
||||
### Initialize variable to assign the Organization Id
|
||||
Initialize an string variable to assign the Organization Id provided by Client while deploying the playbook and used as parameter while calling the search devices with organization API action.
|
||||
|
||||
### Initialize variable to assign the CarbonBlack devices information
|
||||
Initialize an array variable to assign the CarbonBlack devices used as source to format the HTML with the devices information
|
||||
|
||||
### Initialize variable to assign the quarantined devices information
|
||||
Initialize an array variable to assign the quarantined devices information used as source to format the HTML with the action taken on devices
|
||||
|
||||
### For each-Hosts
|
||||
This action will perform the below actions
|
||||
a. Make a call to CarbonBlack API with the parameters such as Organization Key and Quary [ Contains device name ]
|
||||
b. Verify the CarbonBlack returned the results and Check the device is quarantined
|
||||
c. If the device is not quarantined then isolate it.
|
||||
|
||||
### Construct HTML table - CarbonBlack devices information
|
||||
This action will construct the HTML table with devices information
|
||||
|
||||
### Construct HTML table - Quarantined devices through playbook
|
||||
This action will construct the HTML table with Quarantined devices through playbook
|
||||
|
||||
### Send Response with device information
|
||||
This action will send response to master playbook with devices information
|
||||
|
||||
|
Двоичные данные
MasterPlaybooks/Remediation-Host/Crowdstrike-Remediation-Host/Images/MainStep1.PNG
Normal file
После Ширина: | Высота: | Размер: 26 KiB |
Двоичные данные
MasterPlaybooks/Remediation-Host/Crowdstrike-Remediation-Host/Images/MainStep2.PNG
Normal file
После Ширина: | Высота: | Размер: 25 KiB |
Двоичные данные
MasterPlaybooks/Remediation-Host/Crowdstrike-Remediation-Host/Images/PlaybookDesignerDark.png
Normal file
После Ширина: | Высота: | Размер: 113 KiB |
Двоичные данные
MasterPlaybooks/Remediation-Host/Crowdstrike-Remediation-Host/Images/PlaybookDesignerLight.png
Normal file
После Ширина: | Высота: | Размер: 123 KiB |
|
@ -0,0 +1,76 @@
|
|||
# Crowdstrike Remediation Host
|
||||
## Summary
|
||||
When this playbook gets triggered and it performs below actions:
|
||||
1. Gets the list malicious Host information.
|
||||
2. Contain host if it is not already contained.
|
||||
3. Enrich the incident with device information from Crowdstrike
|
||||
4. Incident information is sent as response to master playbook.
|
||||
|
||||
![CrowdStrike](./Images/PlaybookDesignerLight.png)<br>
|
||||
![CrowdStrike](./Images/PlaybookDesignerDark.png)<br>
|
||||
|
||||
### Prerequisites
|
||||
1. Azure Key vault is required for storing the Crowdstrike ClientID and Secrets, create key vault if not exists. [learn how](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2F201-key-vault-secret-create%2Fazuredeploy.json)
|
||||
2. Add Crowdstrike Client ID and Client Secret in Key vault secrets and capture the keys which are required during the template deployment.
|
||||
3. CrowdStrike Base playbook needs to be deployed prior to the deployment of this playbook under the same subscription and under the same resource group. Capture the name of playbook during deployment.
|
||||
4. CrowdStrike Base playbook needs to be added in the access policy of the Key Vault [learn how](https://docs.microsoft.com/azure/key-vault/general/assign-access-policy-portal)
|
||||
|
||||
### Deploy Base Playbook
|
||||
|
||||
To deploy Crowdstrike base playbook click on the below button.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FCrowdStrike%2FPlaybooks%2FCrowdStrike_Base%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FCrowdStrike%2FPlaybooks%2FCrowdStrike_Base%2Fazuredeploy.json)
|
||||
|
||||
### Deployment instructions
|
||||
1. Deploy the playbook by clicking on "Deploy to Azure" button. This will take you to deploying an ARM Template wizard.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-Host%2FCrowdstrike-Remediation-Host%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-Host%2FCrowdstrike-Remediation-Host%2Fazuredeploy.json)
|
||||
|
||||
|
||||
2. Fill in the required parameters:
|
||||
|
||||
|Parameter|Description|
|
||||
|--------------|---------------|
|
||||
|**Playbook Name**| Enter the playbook name here (Eg:Crowdstrike_ContainHost)|
|
||||
|**CrowdStrike Base Playbook Name**| Enter the base playbook name here (Eg:CrowdStrike_Base)|
|
||||
|
||||
### Post-Deployment instructions
|
||||
#### Configurations in Sentinel
|
||||
1. In Azure sentinel analytical rules should be configured to trigger an incident with risky device
|
||||
2. Configure the automation rules to trigger this playbook
|
||||
|
||||
|
||||
## Playbook steps explained
|
||||
|
||||
###When Azure Sentinel incident creation rule is triggered
|
||||
Azure Sentinel incident is created. The playbook receives the incident as the input.
|
||||
|
||||
###Entities - Get Hosts
|
||||
Get the list of risky devices as entities from the Incident
|
||||
|
||||
###Initialize variable comment
|
||||
Initialize a string variable to hold comments to update in the incident
|
||||
|
||||
###Initialize variable success from crowdstrike
|
||||
Initialize a string variable to hold the success or failure information from crowdstrike api actions
|
||||
|
||||
###CrowdStrike Base
|
||||
Call the base logic App to get access token and Falcon Host URL
|
||||
|
||||
###HTTP - Get device id
|
||||
This gets the device id from crowdstrike filtered by hostname
|
||||
|
||||
###Parse JSON Get device id response
|
||||
This prepares Json message for the device id response
|
||||
|
||||
###Condition to check if device is present in crowdstrike
|
||||
1. If device is present, get the device information from crowdstrike API and prepares HTML table with required information
|
||||
2. Checks the device status, if not contained/normal the playbook will contain the device
|
||||
|
||||
###Compose image to add in the incident
|
||||
This action will compose the Crowdstrike image to add to the incident comments
|
||||
|
||||
###Send Response with device information
|
||||
This action will send response to master playbook with devices information
|
||||
|
||||
|
После Ширина: | Высота: | Размер: 32 KiB |
После Ширина: | Высота: | Размер: 114 KiB |
После Ширина: | Высота: | Размер: 54 KiB |
После Ширина: | Высота: | Размер: 52 KiB |
После Ширина: | Высота: | Размер: 53 KiB |
После Ширина: | Высота: | Размер: 111 KiB |
После Ширина: | Высота: | Размер: 875 KiB |
После Ширина: | Высота: | Размер: 39 KiB |
После Ширина: | Высота: | Размер: 40 KiB |
|
@ -0,0 +1,266 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"metadata": {
|
||||
"title": "PlaybookName",
|
||||
"description": "Description",
|
||||
"mainSteps": [
|
||||
"When a new incident is created:",
|
||||
"1. step",
|
||||
"2. step"
|
||||
],
|
||||
"prerequisites": [ "1.preq", "2. preq" ],
|
||||
"lastUpdateTime": "0000-00-00T00:00:00.000Z",
|
||||
"entities": [ "Host" ],
|
||||
"tags": [ "Remediation" ],
|
||||
"support": {
|
||||
"tier": "community"
|
||||
},
|
||||
"author": {
|
||||
"name": "Author"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"PlaybookName": {
|
||||
"defaultValue": "PlaybookName",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Name of the playbook (Logic Apps resource) which will be created"
|
||||
}
|
||||
},
|
||||
"ConnectorName": {
|
||||
"defaultValue": "ConnectorName",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Name of the connector (Logic Apps custom connector resource) which will be created"
|
||||
}
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"LogicAppConnectorConnectionName": "[concat('LogicAppConnector-', parameters('PlaybookName'))]"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.Web/connections",
|
||||
"apiVersion": "2016-06-01",
|
||||
"name": "[variables('LogicAppConnectorConnectionName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"customParameterValues": {},
|
||||
"api": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/customApis/',parameters('ConnectorName'))]"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Logic/workflows",
|
||||
"apiVersion": "2017-07-01",
|
||||
"name": "[parameters('PlaybookName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Web/connections', variables('LogicAppConnectorConnectionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"state": "Enabled",
|
||||
"definition": {
|
||||
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"defaultValue": {},
|
||||
"type": "Object"
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
"manual": {
|
||||
"type": "Request",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"Hosts": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"Hostname": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"Hostname"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"runtimeConfiguration": {
|
||||
"concurrency": {
|
||||
"runs": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"Condition_to_check_the_scope": {
|
||||
"actions": {
|
||||
"Response": {
|
||||
"runAfter": {},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "@outputs('Compose_HTTP_Response')",
|
||||
"statusCode": 200
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Filter_array": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Compose_HTTP_Failed_Resposne": {
|
||||
"runAfter": {
|
||||
"Create_HTML_table": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Compose",
|
||||
"inputs": "Compose Http Response by including a. logo of the product b. playbook name c. Table which contains the host and actions information."
|
||||
},
|
||||
"Create_HTML_table": {
|
||||
"runAfter": {
|
||||
"Scope_output": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "MethodName",
|
||||
"value": "@item()?['name']"
|
||||
},
|
||||
{
|
||||
"header": "Error",
|
||||
"value": "@item()?['error']?['message']"
|
||||
},
|
||||
{
|
||||
"header": "Status",
|
||||
"value": "@item()?['status']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@outputs('Scope_output')"
|
||||
}
|
||||
},
|
||||
"Response_if_playbook_get(s)_failed": {
|
||||
"runAfter": {
|
||||
"Compose_HTTP_Failed_Resposne": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "@outputs('Compose_HTTP_Failed_Resposne')",
|
||||
"statusCode": 500
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
},
|
||||
"Scope_output": {
|
||||
"runAfter": {},
|
||||
"type": "Compose",
|
||||
"inputs": "@body('Filter_array')"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"lessOrEquals": [
|
||||
"@length(body('Filter_array'))",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
},
|
||||
"Filter_array": {
|
||||
"runAfter": {
|
||||
"Scope": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@result('Scope')",
|
||||
"where": "@equals(item()?['status'], 'Failed')"
|
||||
}
|
||||
},
|
||||
"Scope": {
|
||||
"actions": {
|
||||
"Create_HTML_table_-_Quarantined_devices": {
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "Host",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"header": "Action",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": [
|
||||
{
|
||||
"Host": "",
|
||||
"Action": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Compose": {
|
||||
"type": "Compose",
|
||||
"inputs": "<img src=\"https://avatars.githubusercontent.com/u/2071378?s=280&v=4\" alt=\"Lamp\" width=\"32\" height=\"32\">"
|
||||
},
|
||||
"Compose_HTTP_Response": {
|
||||
"type": "Compose",
|
||||
"inputs": "Compose Http Response by including a. logo of the product b. playbook name c. Table which contains the host and actions information."
|
||||
}
|
||||
},
|
||||
"runAfter": {},
|
||||
"type": "Scope"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"value": {
|
||||
"LogicAppConnector": {
|
||||
"connectionId": "[resourceId('Microsoft.Web/connections', variables('LogicAppConnectorConnectionName'))]",
|
||||
"connectionName": "[variables('LogicAppConnectorConnectionName')]",
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/customApis/',parameters('ConnectorName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,404 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"metadata": {
|
||||
"title": "Block Host Nested Remediation - Master Playbook",
|
||||
"description": "This playbook checks if malicious Host is quarantined/contained or not by Security Policy Rule for each of its nested playbooks.",
|
||||
"mainSteps": [
|
||||
"1. Fetches a list of potentially malicious hosts.",
|
||||
"2. Each nested playbook receives the list of hosts and performs respective defined automated actions on it.",
|
||||
"3. Response from individual playbooks are returned to master playbook for incident comment. "
|
||||
],
|
||||
"prerequisites": [
|
||||
"Atlease one of the below mentioned nested playbooks must be deployed prior to deployment of this playbook under same subscription and same resource group. Capture the name of all deployed playbooks during deployment.",
|
||||
"- CarbonBlack-Remediation-Host is a nested playbook that handles remidiation for Azure Firewall.",
|
||||
"- Crowdstrike-Remediation-Host is a nested playbook that handles remidiation for Forcepoint."
|
||||
],
|
||||
"lastUpdateTime": "2021-08-09T00:00:00.000Z",
|
||||
"entities": [ "Host" ],
|
||||
"tags": [ "Remediation" ],
|
||||
"support": {
|
||||
"tier": "community"
|
||||
},
|
||||
"author": {
|
||||
"name": "Accenture"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"MasterPlaybookName": {
|
||||
"defaultValue": "MasterPlaybook_Host_Remidiation",
|
||||
"type": "String",
|
||||
"metadata": {
|
||||
"description": "Enter name for master playbook without spaces"
|
||||
},
|
||||
"minLength": 3
|
||||
},
|
||||
"CarbonBlackPlaybookName": {
|
||||
"defaultValue": "",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter name for CarbonBlack playbook without spaces"
|
||||
}
|
||||
},
|
||||
"CrowdstrikePlaybookName": {
|
||||
"defaultValue": "",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter name for Crowdstrike without spaces"
|
||||
}
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"AzureSentinelConnectionName": "[concat('azuresentienl-',parameters('MasterPlaybookName'))]",
|
||||
"Defaultplaybookname": "MSDefaultNestedPlaybook",
|
||||
"CarbonBlackID": "[ if(not(empty(parameters('CarbonBlackPlaybookName'))),parameters('CarbonBlackPlaybookName'),variables('Defaultplaybookname'))]",
|
||||
"CrowdstrikeID": "[ if(not(empty(parameters('CrowdstrikePlaybookName'))),parameters('CrowdstrikePlaybookName'),variables('Defaultplaybookname'))]"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"apiVersion": "2017-07-01",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[variables('Defaultplaybookname')]",
|
||||
"properties": {
|
||||
"state": "Enabled",
|
||||
"definition": {
|
||||
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
|
||||
"actions": {
|
||||
"Response": {
|
||||
"runAfter": {},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"statusCode": 200
|
||||
}
|
||||
}
|
||||
},
|
||||
"contentVersion": "1.0.0.0",
|
||||
"outputs": {},
|
||||
"parameters": {},
|
||||
"triggers": {
|
||||
"manual": {
|
||||
"type": "Request",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": {}
|
||||
},
|
||||
"type": "Microsoft.Logic/workflows"
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Web/connections",
|
||||
"apiVersion": "2016-06-01",
|
||||
"name": "[variables('AzureSentinelConnectionName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"customParameterValues": {},
|
||||
"api": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Logic/workflows",
|
||||
"apiVersion": "2017-07-01",
|
||||
"name": "[parameters('MasterPlaybookName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]",
|
||||
"[resourceId('Microsoft.Logic/workflows', variables('Defaultplaybookname'))]"
|
||||
],
|
||||
"properties": {
|
||||
"state": "Enabled",
|
||||
"definition": {
|
||||
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"defaultValue": {},
|
||||
"type": "Object"
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
"When_Azure_Sentinel_incident_creation_rule_was_triggered": {
|
||||
"type": "ApiConnectionWebhook",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"callback_url": "@{listCallbackUrl()}"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"path": "/incident-creation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"CarbonBlack": {
|
||||
"actions": {
|
||||
"Append_CarbonBlack_status_code": {
|
||||
"runAfter": {
|
||||
"CarbonBlack-QuarantineDevice": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "StatusCodes",
|
||||
"value": "@outputs('CarbonBlack-QuarantineDevice')['statusCode']"
|
||||
}
|
||||
},
|
||||
"CarbonBlack-QuarantineDevice": {
|
||||
"runAfter": {},
|
||||
"type": "Workflow",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"Hosts": "@body('Entities_-_Get_Hosts')?['Hosts']"
|
||||
},
|
||||
"host": {
|
||||
"triggerName": "manual",
|
||||
"workflow": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name ,'/providers/Microsoft.Logic/workflows/', variables('CarbonBlackID'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Verify_CarbonBlack_response_body": {
|
||||
"actions": {
|
||||
"Add_comment_to_incident_(V3)_CarbonBlack-QuarantineDevice": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"incidentArmId": "@triggerBody()?['object']?['id']",
|
||||
"message": "<p>@{body('CarbonBlack-QuarantineDevice')}</p>"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/Incidents/Comment"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Append_CarbonBlack_status_code": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"not": {
|
||||
"equals": [
|
||||
"@Outputs('CarbonBlack-QuarantineDevice')?['headers']?['x-ms-workflow-name']",
|
||||
"MSDefaultNestedPlaybook"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Initialize_variable_Status_Codes": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
},
|
||||
"Condition_to_check_any_one_of_the_playbook_failed_before_closing_the_incident": {
|
||||
"actions": {
|
||||
"Update_incident": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"classification": {
|
||||
"ClassificationAndReason": "TruePositive - SuspiciousActivity"
|
||||
},
|
||||
"incidentArmId": "@triggerBody()?['object']?['id']",
|
||||
"status": "Closed"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "put",
|
||||
"path": "/Incidents"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Filter_Success_Status_Codes": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"lessOrEquals": [
|
||||
"@length(body('Filter_Success_Status_Codes'))",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
},
|
||||
"Crowdstrike": {
|
||||
"actions": {
|
||||
"Append_Crowdstrike_Host_status_code": {
|
||||
"runAfter": {
|
||||
"Crowdstrike_ContainHost": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "StatusCodes",
|
||||
"value": "@outputs('Crowdstrike_ContainHost')?['statusCode']"
|
||||
}
|
||||
},
|
||||
"Crowdstrike_ContainHost": {
|
||||
"runAfter": {},
|
||||
"type": "Workflow",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"Hosts": "@body('Entities_-_Get_Hosts')?['Hosts']"
|
||||
},
|
||||
"host": {
|
||||
"triggerName": "manual",
|
||||
"workflow": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name ,'/providers/Microsoft.Logic/workflows/', variables('CrowdstrikeID'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Verify_Crowdstrike_response_body": {
|
||||
"actions": {
|
||||
"Add_comment_to_incident_(V3)_Crowdstrike_Host": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"incidentArmId": "@triggerBody()?['object']?['id']",
|
||||
"message": "<p>@{body('Crowdstrike_ContainHost')}</p>"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/Incidents/Comment"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Append_Crowdstrike_Host_status_code": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"greater": [
|
||||
"@Outputs('Crowdstrike_ContainHost')?['headers']?['x-ms-workflow-name']",
|
||||
"MSDefaultNestedPlaybook"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Initialize_variable_Status_Codes": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
},
|
||||
"Entities_-_Get_Hosts": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": "@triggerBody()?['object']?['properties']?['relatedEntities']",
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/entities/host"
|
||||
}
|
||||
},
|
||||
"Filter_Success_Status_Codes": {
|
||||
"runAfter": {
|
||||
"CarbonBlack": [
|
||||
"Succeeded"
|
||||
],
|
||||
"Crowdstrike": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@variables('StatusCodes')",
|
||||
"where": "@not(equals(item(), 200))"
|
||||
}
|
||||
},
|
||||
"Initialize_variable_Status_Codes": {
|
||||
"runAfter": {
|
||||
"Entities_-_Get_Hosts": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "StatusCodes",
|
||||
"type": "array",
|
||||
"value": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"value": {
|
||||
"azuresentinel": {
|
||||
"connectionId": "[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]",
|
||||
"connectionName": "[variables('AzureSentinelConnectionName')]",
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
# Master Playbook Host Remediation
|
||||
|
||||
Master playbook is integrated with multiple firewall Endpoint protection products.
|
||||
- CarbonBlack
|
||||
- Crowdstrike.
|
||||
|
||||
Endpoint protection products are deployed as child/nested playbooks.
|
||||
|
||||
If a malicious host is detected from the Azure sentinel, master playbook calls all the child/nested playbooks and each firewall product will take remidiation steps needed on that host and comments will be passed to the master playbook from the child/nested playbooks involving multiple products.
|
||||
|
||||
## Summary
|
||||
When a new Azure Sentinel incident is created, this playbook gets triggered and performs the below actions:
|
||||
1. Fetches a list of potentially malicious hosts.
|
||||
2. Each nested playbook receives the list of host and performs respective defined automated actions on it.
|
||||
3. Response from individual playbooks are returned to master playbook for incident comment.
|
||||
|
||||
![Master](./Images/PlaybookDesignerLight.png)
|
||||
|
||||
![Master](./Images/PlaybookDesignerDark.png)
|
||||
|
||||
|
||||
## Pre-requisites for deployment
|
||||
Atlease one of the below mentioned nested playbooks must be deployed prior to deployment of this playbook under same subscription and same resource group and the same location/region. Capture the name of all the deployed playbooks during deployment.
|
||||
|
||||
- [CarbonBlack-Remediation-Host](/MasterPlaybook-Host-Remediation/CarbonBlack-Remediation-Host/azuredeploy.json) is a nested playbook that handles remidiation for CarbonBlack.
|
||||
- [Crowdstrike-Remediation-Host](/MasterPlaybook-Host-Remediation/Crowdstrike-Remediation-Host/azuredeploy.json) is a nested playbook that handles remidiation for Crowdstrike.
|
||||
|
||||
If any one of the above mentioned playbooks are not deployed then default playbook will deploy in its place.
|
||||
|
||||
## Nested Playbook Structure
|
||||
|
||||
### Input Schema
|
||||
|
||||
Each of the nested playbooks of Host Remediation accepts following inputs:
|
||||
- Hosts: List of Hosts as entities from azure sentinel incident.
|
||||
- Workflow: Worklfow is identifier for the nested playbook which points to which subscription and which resource group the nested playbook belongs to.
|
||||
- Trigger: Tells how the playbook is invoked/triggered.
|
||||
|
||||
The image below shows example of input schema for Crowdstrike nested playbook.
|
||||
|
||||
![Master](./Images/InputSchema.jpg)
|
||||
|
||||
### Output Schema
|
||||
|
||||
Each of the nested playbooks of Host Remediation gives following outputs:
|
||||
|
||||
- Status code: Status code tells the success or failure status of nested playbook run results. The status code value is displayed in incident comment.
|
||||
- Body: Body provides with all the output values that nested playbook returns. It varies according to the nested playbook. Based on the length of body Incident Comment is created.
|
||||
- Incident Comment: It contains output body from nested playbook in tabular format.
|
||||
|
||||
For example, taking reference of CarbonBlack incident comment image below, CarbonBlack logo is composed for incident comment.
|
||||
Also, table is populated with values such as Device name, Quarantined status, Policy name, Policy id, Device owner id, Device id, Device status, Operating system, Operating system version, Organization name and Email address.
|
||||
|
||||
Another table in image gives brief information of device quarantined.
|
||||
|
||||
![Master](./Images/IncidentComment.png)
|
||||
|
||||
|
||||
## Add new playbook to master playbook
|
||||
|
||||
To add new nested playbook to master playbook:
|
||||
- Hover below action "Initialize variable Status Codes".
|
||||
- Click on symbol '+' for insert a new step and choose add a parallel branch.
|
||||
- First action is to add scope. Within scope add new action and choose the nested playbook to add.
|
||||
- Append the status code from nested playbook to Status Codes variable.
|
||||
- Add condition to verify the body of nested playbook.
|
||||
- Compose Incident Comment.
|
||||
|
||||
![Master](./Images/AddNestedPlaybook.PNG)
|
||||
|
||||
|
||||
## Deployment Instructions
|
||||
1. Deploy the playbook by clicking on the "Deploy to Azure" button. This will take you to deploy an ARM Template wizard.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-Host%2FMasterPlaybook-Host-Remediation%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-Host%2FMasterPlaybook-Host-Remediation%2Fazuredeploy.json)
|
||||
|
||||
2. Fill in the required parameters for deploying the playbook.
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------- | ------------- |
|
||||
| **Playbook Name** | Enter the master playbook name here without spaces. |
|
||||
| **CarbonBlack Playbook Name**|Enter the name of CarbonBlack Nested playbook without spaces. |
|
||||
| **Crowdstrike Playbook Name** | Enter the name of Crowdstrike Nested playbook without spaces. |
|
||||
|
||||
|
||||
# Post-Deployment Instructions
|
||||
|
||||
### Configurations in Sentinel
|
||||
- In Azure sentinel analytical rules should be configured to trigger an incident with host.
|
||||
- Configure the automation rules to trigger the playbook which calls multiple nested playbooks.
|
||||
|
||||
# Playbook steps explained
|
||||
## When Azure Sentinel incident creation rule is triggered
|
||||
Captures potentially malicious host incident information.
|
||||
|
||||
##Entities - Get Hosts
|
||||
Get the list of Hosts as entities from the Incident.
|
||||
|
||||
## For malicious host received from the incident
|
||||
1. The list of hosts is passed as Entity to each of the nested playbook.
|
||||
2. Each nested playbook accepts Host list as entity from master playbook and respectively performs defined automated actions(Contain/Quarantine Host) for each host.
|
||||
3. The response from each of the nested playbook is returned to master playbook.
|
||||
4. Response from each nested playbook is attached to incident comment and consolidated incident comment is created.
|
||||
5. If all the nested playbooks returns success response , the incident will be closed.
|
||||
|
||||
**Incident Comment**
|
||||
|
||||
![Master](./Images/IncidentCommentLight.png)
|
||||
![Master](./Images/IncidentCommentDark.png)
|
||||
|
||||
**Incident Comment: Exception occurred**
|
||||
|
||||
### If any of the nested playbook throws exception then Incident Comment looks like below: (e.g. Crowdstrike)
|
||||
|
||||
![Master](./Images/IncidentComment_Error.PNG)
|
||||
|
||||
**Incident Comment: Ran Successfully**
|
||||
|
||||
### If the nested playbook ran Successfully then Incident Comment looks like below: (e.g. CarbonBlack)
|
||||
|
||||
![Master](./Images/IncidentComment_Success.PNG)
|
||||
|
||||
|
||||
|
||||
|
||||
|
Двоичные данные
MasterPlaybooks/Remediation-IP/AzureFirewall-BlockIP-Nested-Remediation/Images/MainStep1.PNG
Normal file
После Ширина: | Высота: | Размер: 30 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/AzureFirewall-BlockIP-Nested-Remediation/Images/MainStep2.PNG
Normal file
После Ширина: | Высота: | Размер: 35 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/AzureFirewall-BlockIP-Nested-Remediation/Images/PlaybookDesignerDark.png
Normal file
После Ширина: | Высота: | Размер: 50 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/AzureFirewall-BlockIP-Nested-Remediation/Images/PlaybookDesignerLight.png
Normal file
После Ширина: | Высота: | Размер: 54 KiB |
|
@ -0,0 +1,386 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"metadata": {
|
||||
"title": "Block IP Nested Remediation - Azure Firewall",
|
||||
"description": "This playbook allows blocking/allowing IPs in Azure Firewall, using IP Groups. ",
|
||||
"mainSteps": [ "1. Fetches a list of potentially malicious IP addresses", "2. If malicious IP address is not blocked by security policy rule then blocks it.", "3. If malicious IP address is blocked by security policy rule then unblocks it." ],
|
||||
"prerequisites": [
|
||||
"1. Azure Firewall connector needs to be deployed prior to the deployment of this playbook under the same subscription.",
|
||||
"2. Azure Firewall connector need to be authenticated with a Service Principal that has permissions over Azure Firewall. ",
|
||||
"3. IP Group must be created in portal. [Refer here](https://docs.microsoft.com/azure/firewall/ip-groups) on how to create IP Group. User must have access tp IP Group.",
|
||||
"4. Client ID, Tenant ID and Client Secret for your application registered in your AAD."
|
||||
],
|
||||
"lastUpdateTime": "2021-08-06T00:00:00.000Z",
|
||||
"entities": [ "IP" ],
|
||||
"tags": [ "Remediation" ],
|
||||
"support": {
|
||||
"tier": "community"
|
||||
},
|
||||
"author": {
|
||||
"name": "Accenture"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"PlaybookName": {
|
||||
"defaultValue": "Azure-Firewall-Block-IP-Nested-Remediation",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Name of the Logic App/Playbook"
|
||||
}
|
||||
},
|
||||
"ConnectorName": {
|
||||
"defaultValue": "AzureFirewallConnector",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Name of the Azure Firewall"
|
||||
}
|
||||
},
|
||||
"IP Group Name": {
|
||||
"defaultValue": "FirewallIPGroup",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Name of the IP Group"
|
||||
}
|
||||
},
|
||||
"clientId": {
|
||||
"defaultValue": "<enter the ClientId of the application>",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter AAD App ClientID"
|
||||
}
|
||||
},
|
||||
"clientSecret": {
|
||||
"defaultValue": "<enter the Client secret of the application>",
|
||||
"type": "securestring",
|
||||
"metadata": {
|
||||
"description": "Enter AAD App Secret Key"
|
||||
}
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"OAuthConnection": "[concat('OAuthConnection-', parameters('PlaybookName'))]"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.Web/connections",
|
||||
"apiVersion": "2016-06-01",
|
||||
"name": "[variables('OAuthConnection')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"displayName": "OAuthConnection",
|
||||
"parameterValues": {
|
||||
"token:clientId": "[parameters('clientId')]",
|
||||
"token:clientSecret": "[parameters('clientSecret')]",
|
||||
"token:TenantId": "[subscription().tenantId]",
|
||||
"token:grantType": "client_credentials"
|
||||
},
|
||||
"api": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/customApis/',parameters('ConnectorName'))]"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Logic/workflows",
|
||||
"apiVersion": "2017-07-01",
|
||||
"name": "[parameters('PlaybookName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Web/connections', variables('OAuthConnection'))]"
|
||||
],
|
||||
"properties": {
|
||||
"state": "Enabled",
|
||||
"definition": {
|
||||
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"defaultValue": {},
|
||||
"type": "Object"
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
"manual": {
|
||||
"type": "Request",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"method": "POST",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"IPs": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"Address": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"Address"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"runtimeConfiguration": {
|
||||
"concurrency": {
|
||||
"runs": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"Catch_Scope": {
|
||||
"actions": {
|
||||
"Create_HTML_table_for_error": {
|
||||
"runAfter": {
|
||||
"Filter_array": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "IP Address",
|
||||
"value": "@item()['Address']"
|
||||
},
|
||||
{
|
||||
"header": "Action Name",
|
||||
"value": "@body('Filter_array')[0]?['name']"
|
||||
},
|
||||
{
|
||||
"header": "Message",
|
||||
"value": "@body('Filter_array')[0]?['outputs']?['body']?['error']?['message']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@variables('IPs')"
|
||||
}
|
||||
},
|
||||
"Error_Response": {
|
||||
"runAfter": {
|
||||
"Create_HTML_table_for_error": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "Azure Firewall Block IP Address Playbook Error\n@{body('Create_HTML_table_for_error')}",
|
||||
"statusCode": 500
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
},
|
||||
"Filter_array": {
|
||||
"runAfter": {},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@result('Try_Scope')",
|
||||
"where": "@equals(item()?['status'], 'Failed')"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Try_Scope": [
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
},
|
||||
"Initialize_IPGroupName_variable": {
|
||||
"runAfter": {
|
||||
"Initialize_variable_IPs": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "IPGroupName",
|
||||
"type": "string",
|
||||
"value": "[parameters('IP Group Name')]"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Initialize_IP_Address_array_variable": {
|
||||
"runAfter": {
|
||||
"Initialize_IPGroupName_variable": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "IPAddresses",
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Variable to assign IP Groups present with in the IP Group"
|
||||
},
|
||||
"Initialize_variable_IPs": {
|
||||
"runAfter": {},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "IPs",
|
||||
"type": "array",
|
||||
"value": "@triggerBody()?['IPs']"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Try_Scope": {
|
||||
"actions": {
|
||||
"Create_HTML_table": {
|
||||
"runAfter": {
|
||||
"Creates_or_updates_an_ipGroups_in_a_specified_resource_group": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "IPGroupName",
|
||||
"value": "IPGroup"
|
||||
},
|
||||
{
|
||||
"header": "IPAddress",
|
||||
"value": "@item()?['Address']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@variables('IPs')"
|
||||
},
|
||||
"description": "Create HTML table enrichment which contains the list of IP Address were added to the provided IPGroup"
|
||||
},
|
||||
"Creates_or_updates_an_ipGroups_in_a_specified_resource_group": {
|
||||
"runAfter": {
|
||||
"For_each_Malicious_IP_Address_Entity_present_in_the_Incident": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"location": "@body('IP_Groups_-_Get')?['location']",
|
||||
"properties": {
|
||||
"ipAddresses": "@variables('IPAddresses')"
|
||||
},
|
||||
"tags": {
|
||||
"Configuration": "Sentinel"
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['AzureFirewallConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "put",
|
||||
"path": "/subscriptions/@{encodeURIComponent(split(workflow()?['id'],'/')[2])}/resourceGroups/@{encodeURIComponent(split(workflow()?['id'],'/')[4])}/providers/Microsoft.Network/ipGroups/@{encodeURIComponent(variables('IPGroupName'))}",
|
||||
"queries": {
|
||||
"api-version": "2020-07-01"
|
||||
}
|
||||
}
|
||||
},
|
||||
"For_each_Malicious_IP_Address_Entity_present_in_the_Incident": {
|
||||
"foreach": "@variables('IPs')",
|
||||
"actions": {
|
||||
"Append_IP_Address_to_the_existing_List": {
|
||||
"runAfter": {},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "IPAddresses",
|
||||
"value": "@item()?['Address']"
|
||||
},
|
||||
"description": "Append the Malicious IP Address to the variable IPAddresses"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Set_IP_Address_present_in_the_Azure_Firewall_IP_Group": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Foreach"
|
||||
},
|
||||
"IP_Groups_-_Get": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['AzureFirewallConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "get",
|
||||
"path": "/subscriptions/@{encodeURIComponent(split(workflow()?['id'],'/')[2])}/resourceGroups/@{encodeURIComponent(split(workflow()?['id'],'/')[4])}/providers/Microsoft.Network/ipGroups/@{encodeURIComponent(variables('IPGroupName'))}",
|
||||
"queries": {
|
||||
"api-version": "2020-07-01"
|
||||
}
|
||||
},
|
||||
"description": "Get all the IP Addresses present in the provided Azure Firewall IP Group name"
|
||||
},
|
||||
"Response": {
|
||||
"runAfter": {
|
||||
"Create_HTML_table": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "Azure Firewall Block IP Address Playbook\n@{body('Create_HTML_table')}",
|
||||
"statusCode": 200
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
},
|
||||
"Set_IP_Address_present_in_the_Azure_Firewall_IP_Group": {
|
||||
"runAfter": {
|
||||
"IP_Groups_-_Get": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "IPAddresses",
|
||||
"value": "@body('IP_Groups_-_Get')?['properties']?['ipAddresses']"
|
||||
},
|
||||
"description": "Variable to assign IP Groups present with in the IP Group"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Initialize_IP_Address_array_variable": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"value": {
|
||||
"AzureFirewallConnector": {
|
||||
"connectionId": "[resourceId('Microsoft.Web/connections', variables('OAuthConnection'))]",
|
||||
"connectionName": "[variables('OAuthConnection')]",
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/customApis/',parameters('ConnectorName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
# AzureFirewall Block IP Nested Remediation Playbook
|
||||
|
||||
## Summary
|
||||
|
||||
This playbook allows blocking/allowing IPs in Azure Firewall, using **IP Groups**. This allows to make changes on IP groups, which are attached to rules, instead of making direct changes on Azure Firewall. It also allows using the same IP group for multiple firewalls.
|
||||
|
||||
When this playbook gets triggered and it performs below actions:
|
||||
|
||||
1. Gets a list of malicious IP address.
|
||||
2. Fetches list of IP addresses present in IP Group.
|
||||
3. Appends the malicious IP address list to list of IP addresses received from IP Group.
|
||||
4. Updates IP Group with the new list of IP addresses.
|
||||
|
||||
![AzureFirewall](./Images/PlaybookDesignerLight.png)<br>
|
||||
![AzureFirewall](./Images/PlaybookDesignerDark.png)<br>
|
||||
|
||||
### Prerequisites
|
||||
1. Azure Firewall connector needs to be deployed prior to the deployment of this playbook under the same subscription.
|
||||
1. Azure Firewall connector need to be authenticated with a Service Principal that has permissions over Azure Firewall.
|
||||
1. IP Group must be created in portal. [Refer here](https://docs.microsoft.com/azure/firewall/ip-groups) on how to create IP Group. User must have access tp IP Group.
|
||||
1. Client ID, Tenant ID and Client Secret for your application registered in your AAD.
|
||||
|
||||
### Deploy Custom Connector
|
||||
|
||||
To deploy AzureFirewall Custom connector click on the below button.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FAzureFirewall%2FAzureFirewallConnector%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FAzureFirewall%2FAzureFirewallConnector%2Fazuredeploy.json)
|
||||
|
||||
|
||||
|
||||
### Deployment instructions
|
||||
1. Deploy the playbook by clicking on "Deploy to Azure" button. This will take you to deploying an ARM Template wizard.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-IP%2FAzureFirewall-BlockIP-Nested-Remediation%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-IP%2FAzureFirewall-BlockIP-Nested-Remediation%2Fazuredeploy.json)
|
||||
|
||||
2. Fill in the required parameters:
|
||||
|
||||
|Parameter|Description|
|
||||
|----------------|---------------|
|
||||
|**Playbook Name** | Enter the playbook name here (e.g. AzureFirewall-BlockIP-Remediation)|
|
||||
|**Connector name**| Enter name for Azure Firewall Connector.|
|
||||
|**IP Group name** | Enter the IP Group name here.|
|
||||
|**Client ID**| Enter your client ID here.|
|
||||
|**Client Secret** | Enter your client secret here.|
|
||||
|
||||
|
||||
### Post-Deployment instructions
|
||||
#### Authorize connections
|
||||
Authorize the Azure Firewall custom connector by following the below mentioned steps.
|
||||
|
||||
1. Navigate to playbook<br>
|
||||
2. Click Edit<br>
|
||||
3. Find the action with the name "IP Groups - Get" and "Creates or updates an ipGroups in a specified resource group" in the workflow. <br>
|
||||
4. Click Change connection [ Enter Connection name, ClientId, SecretKey and TenantId captured from AAD. ]
|
||||
|
||||
## Playbook steps explained
|
||||
|
||||
### When the playbook is triggered
|
||||
|
||||
The playbook receives list of malicious IP addresses as the input.
|
||||
|
||||
### Initialize variables
|
||||
|
||||
a. IPs - To store IP addresses from IP Group Name.
|
||||
|
||||
b. IP Group Name - To store IP Group Name received as input.
|
||||
|
||||
### Gets all IP address list present in IP Group
|
||||
Fetches all IP addresses present in IP Group.
|
||||
|
||||
### Stores IP Address present in Azure Firewall IP Group
|
||||
Stores the IP address list fetched from IP Group in the IP list.
|
||||
|
||||
### For each-malicious IP
|
||||
Appends each malicious IP Address to the IP address list fetched from IP Group
|
||||
|
||||
#### Create or update IP Group in specified resource group
|
||||
Creates or updates the IP address list in IP Group with all the appended values.
|
||||
|
||||
###Response from playbook is sent to master playbook to generate incident comments.
|
||||
|
||||
|
Двоичные данные
MasterPlaybooks/Remediation-IP/ForcepointNGFW-BlockIP-Nested-Remediation/Images/MainStep1.PNG
Normal file
После Ширина: | Высота: | Размер: 20 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/ForcepointNGFW-BlockIP-Nested-Remediation/Images/MainStep2.PNG
Normal file
После Ширина: | Высота: | Размер: 23 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/ForcepointNGFW-BlockIP-Nested-Remediation/Images/MainStep3.PNG
Normal file
После Ширина: | Высота: | Размер: 25 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/ForcepointNGFW-BlockIP-Nested-Remediation/Images/MainStep4.PNG
Normal file
После Ширина: | Высота: | Размер: 22 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/ForcepointNGFW-BlockIP-Nested-Remediation/Images/PlaybookDesignerDark.png
Normal file
После Ширина: | Высота: | Размер: 184 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/ForcepointNGFW-BlockIP-Nested-Remediation/Images/PlaybookDesignerLight.png
Normal file
После Ширина: | Высота: | Размер: 190 KiB |
|
@ -0,0 +1,790 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"metadata": {
|
||||
"title": "Block IP Nested Remediation - Forcepoint NGFW",
|
||||
"description": "This playbook checks if malicious IP address is blocked or unblocked by SMC firewall.",
|
||||
"mainSteps": [ "1. Fetches a list of potentially malicious IP addresses", "2. If malicious IP address is not blocked by SMC firewall then blocks it." ],
|
||||
"prerequisites": [
|
||||
"1. Forcepoint SMC Custom Connector needs to be deployed prior to the deployment of this playbook under the same resource group.",
|
||||
"2. Forcepoint SMC API Key should be known.[Refer here](http://www.websense.com/content/support/library/ngfw/v610/rfrnce/ngfw_6100_ug_smc-api_a_en-us.pdf )",
|
||||
"3. Forcepoint SMC Version number should be known. [Refer here](https://help.stonesoft.com/onlinehelp/StoneGate/SMC/)",
|
||||
"4. IP address list name for blocking IP address present in SMC should be known."
|
||||
],
|
||||
"lastUpdateTime": "2021-08-06T00:00:00.000Z",
|
||||
"entities": [ "IP" ],
|
||||
"tags": [ "Remediation" ],
|
||||
"support": {
|
||||
"tier": "community"
|
||||
},
|
||||
"author": {
|
||||
"name": "Accenture"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"PlaybookName": {
|
||||
"type": "String",
|
||||
"defaultValue": "Forcepoint-Block-IP-Nested-Remediation",
|
||||
"metadata": {
|
||||
"description": "Enter name for playbook without spaces"
|
||||
}
|
||||
},
|
||||
"ForcepointSMCConnectorName": {
|
||||
"type": "string",
|
||||
"defaultValue": "ForcepointSMC-Connector",
|
||||
"metadata": {
|
||||
"description": "Enter the name for your Forcepoint SMC Connector without spaces"
|
||||
}
|
||||
},
|
||||
"ForcepointSMCApiKey": {
|
||||
"type": "securestring",
|
||||
"metadata": {
|
||||
"description": "Enter the api key for smc login"
|
||||
}
|
||||
},
|
||||
"VersionNumber": {
|
||||
"type": "string",
|
||||
"defaultValue": "6.8",
|
||||
"metadata": {
|
||||
"description": "Enter SMC Api key Version Number"
|
||||
}
|
||||
},
|
||||
"IPListName": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter IP List Name present in SMC"
|
||||
}
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"Forcepoint_Connector": "[concat('ForcepointSMCApiConnector-',parameters('PlaybookName'))]"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.Logic/workflows",
|
||||
"apiVersion": "2017-07-01",
|
||||
"name": "[parameters('PlaybookName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"identity": {
|
||||
"type": "SystemAssigned"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Web/connections', variables('Forcepoint_Connector'))]"
|
||||
],
|
||||
"properties": {
|
||||
"state": "Enabled",
|
||||
"definition": {
|
||||
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"defaultValue": {},
|
||||
"type": "Object"
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
"manual": {
|
||||
"type": "Request",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"method": "POST",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"IPs": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"Address": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"Address"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"runtimeConfiguration": {
|
||||
"concurrency": {
|
||||
"runs": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"Catch_Scope": {
|
||||
"actions": {
|
||||
"Create_HTML_table_for_error": {
|
||||
"runAfter": {
|
||||
"Filter_error_array": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "IP Address",
|
||||
"value": "@item()['Address']"
|
||||
},
|
||||
{
|
||||
"header": "Action Name",
|
||||
"value": "@body('Filter_error_array')[0]?['name']"
|
||||
},
|
||||
{
|
||||
"header": "Message",
|
||||
"value": "@body('Filter_error_array')[0]?['outputs']?['body']?['error']?['message']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@triggerBody()?['IPs']"
|
||||
}
|
||||
},
|
||||
"Error_Response": {
|
||||
"runAfter": {
|
||||
"Create_HTML_table_for_error": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "@{outputs('Forcepoint_Logo')}Forcepoint NGFW-Block IP Address Error\n@{body('Create_HTML_table_for_error')}",
|
||||
"statusCode": 500
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
},
|
||||
"Filter_error_array": {
|
||||
"runAfter": {},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@result('Try_Scope')",
|
||||
"where": "@equals(item()?['status'], 'Failed')"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Try_Scope": [
|
||||
"Failed",
|
||||
"Skipped",
|
||||
"TimedOut"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
},
|
||||
"Forcepoint_Logo": {
|
||||
"runAfter": {
|
||||
"Initialize_variable_to_Error": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Compose",
|
||||
"inputs": "<img src=\"https://upload.wikimedia.org/wikipedia/en/b/b6/Forcepoint.jpg\" alt=\"ForcepointImage\" width=\"32\" height=\"32\">",
|
||||
"description": "Forcepoint logo for comments "
|
||||
},
|
||||
"Initialize_variable_Terminate": {
|
||||
"runAfter": {
|
||||
"Forcepoint_Logo": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "Terminate",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": " This holds the variable terminate to terminate the logic app "
|
||||
},
|
||||
"Initialize_variable_for_IP_Address": {
|
||||
"runAfter": {
|
||||
"SMC_API_Key": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "IP Address",
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Binding Ip address to this IP address variable"
|
||||
},
|
||||
"Initialize_variable_for_IP_list_name": {
|
||||
"runAfter": {
|
||||
"Initialize_variable_Terminate": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "IP list name",
|
||||
"type": "string",
|
||||
"value": "[parameters('IPListName')]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Initialize variable for IP list name"
|
||||
},
|
||||
"Initialize_variable_to_Error": {
|
||||
"runAfter": {
|
||||
"Initialize_variable_to_SMC_Api_Version_Number": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "Error",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "To keep the error into this variable and pass it to wherever required."
|
||||
},
|
||||
"Initialize_variable_to_SMC_Api_Version_Number": {
|
||||
"runAfter": {
|
||||
"Initialize_variable_to_consolidate_variable": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "SMC Api Version Number",
|
||||
"type": "string",
|
||||
"value": "[parameters('VersionNumber')]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "To keep SMC Api version number. Forcepoint will update the SMC version every year"
|
||||
},
|
||||
"Initialize_variable_to_consolidate_variable": {
|
||||
"runAfter": {
|
||||
"Initialize_variable_to_keep_all_actions": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "Consolidatevrbl",
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "To form a JSON object to pass it into Allaction variable"
|
||||
},
|
||||
"Initialize_variable_to_keep_all_actions": {
|
||||
"runAfter": {
|
||||
"Initialize_variable_for_IP_Address": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "Arrayforallactions",
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "To store IP address , severity , action to be taken into one array varriable and we can create a table."
|
||||
},
|
||||
"SMC_API_Key": {
|
||||
"runAfter": {},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "SMC API Key",
|
||||
"type": "string",
|
||||
"value": "[parameters('ForcepointSMCApiKey')]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "SMC API Key is to store Api key for login"
|
||||
},
|
||||
"Try_Scope": {
|
||||
"actions": {
|
||||
"Check_if_body_present_from_output": {
|
||||
"actions": {
|
||||
"Check_Login_Status": {
|
||||
"runAfter": {
|
||||
"Login": [
|
||||
"Succeeded",
|
||||
"Failed",
|
||||
"Skipped",
|
||||
"TimedOut"
|
||||
]
|
||||
},
|
||||
"cases": {
|
||||
"200_Success_OK": {
|
||||
"case": 200,
|
||||
"actions": {
|
||||
"Condition_to_check_if_IP_list_is_present_or_not": {
|
||||
"actions": {
|
||||
"Add_IP_Address_into_IP_List": {
|
||||
"runAfter": {
|
||||
"Looping_IP_Address": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"ip": "@variables('IP Address')"
|
||||
},
|
||||
"headers": {
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['ForcepointSMCApiConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/@{encodeURIComponent(variables('SMC Api Version Number'))}/elements/ip_list/@{encodeURIComponent(last(split(body('Get_IP_List_Element')?['result']?[0]?['href'],'/')))}/ip_address_list"
|
||||
}
|
||||
},
|
||||
"Condition_to_check_if_needs_to_be_terminated": {
|
||||
"actions": {
|
||||
"Terminate_the_playbook_if_API_issue_occurred": {
|
||||
"runAfter": {},
|
||||
"type": "Terminate",
|
||||
"inputs": {
|
||||
"runError": {
|
||||
"message": "Having API issue in playbook"
|
||||
},
|
||||
"runStatus": "Failed"
|
||||
},
|
||||
"description": "Terminate the playbook if API issue occurred"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Create_HTML_table_for_Add_comment_to_incident": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Response": {
|
||||
"runAfter": {},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "@{outputs('Forcepoint_Logo')}Forcepoint NGFW-Block IP Address\n\nThe below IP address(s) are found to be malicious and playbook taken action against to that IPs.\n\n@{body('Create_HTML_table_for_Add_comment_to_incident')}",
|
||||
"statusCode": 200
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"equals": [
|
||||
"@variables('Terminate')",
|
||||
"APIError"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "Condition to check if needs to be terminated"
|
||||
},
|
||||
"Create_HTML_table_for_Add_comment_to_incident": {
|
||||
"runAfter": {
|
||||
"Add_IP_Address_into_IP_List": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "IP-Address",
|
||||
"value": "@item()?['IPAddres']"
|
||||
},
|
||||
{
|
||||
"header": "IP-List-Name",
|
||||
"value": "@variables('IP list name')"
|
||||
},
|
||||
{
|
||||
"header": "IP-Status",
|
||||
"value": "@item()?['IPStatus']"
|
||||
},
|
||||
{
|
||||
"header": "Action-Taken",
|
||||
"value": "@item()?['Action']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@variables('Arrayforallactions')"
|
||||
},
|
||||
"description": "Creating a HTML table from all actions taken by IP address"
|
||||
},
|
||||
"Get_IP_address": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"headers": {
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['ForcepointSMCApiConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "get",
|
||||
"path": "/@{encodeURIComponent(variables('SMC Api Version Number'))}/elements/ip_list/@{encodeURIComponent(last(split(body('Get_IP_List_Element')?['result']?[0]?['href'],'/')))}/ip_address_list"
|
||||
}
|
||||
},
|
||||
"Looping_IP_Address": {
|
||||
"foreach": "@triggerBody()?['IPs']",
|
||||
"actions": {
|
||||
"Check_the_result_length_from_filter_output": {
|
||||
"actions": {
|
||||
"Append_to_array_of_all_actions": {
|
||||
"runAfter": {
|
||||
"Set_variable_to_consolidate_variable_set": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "Arrayforallactions",
|
||||
"value": "@variables('Consolidatevrbl')"
|
||||
}
|
||||
},
|
||||
"Set_variable_to_consolidate_variable_set": {
|
||||
"runAfter": {},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "Consolidatevrbl",
|
||||
"value": {
|
||||
"Action": "Already blocked",
|
||||
"IPAddres": "@{items('Looping_IP_Address')?['Address']}",
|
||||
"IPStatus": "Blocked",
|
||||
"IncidentSeverity": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Append_to_array_variable_to_Not_exit_IP_address": {
|
||||
"runAfter": {},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "IP Address",
|
||||
"value": "@items('Looping_IP_Address')?['Address']"
|
||||
},
|
||||
"description": "Append to array variable to Not exit IP address"
|
||||
},
|
||||
"Append_to_array_variable_to_array_for_actions": {
|
||||
"runAfter": {
|
||||
"Set_variable_for_consolidate_variable": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "Arrayforallactions",
|
||||
"value": "@variables('Consolidatevrbl')"
|
||||
},
|
||||
"description": "Append to array variable to array for actions"
|
||||
},
|
||||
"Set_variable_for_consolidate_variable": {
|
||||
"runAfter": {
|
||||
"Append_to_array_variable_to_Not_exit_IP_address": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "Consolidatevrbl",
|
||||
"value": {
|
||||
"Action": "Blocked by playbook",
|
||||
"IPAddres": "@{items('Looping_IP_Address')?['Address']}",
|
||||
"IPStatus": "Blocked",
|
||||
"IncidentSeverity": ""
|
||||
}
|
||||
},
|
||||
"description": "Set variable for consolidate variable"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"contains": [
|
||||
"@body('Get_IP_address')?['ip']",
|
||||
"@items('Looping_IP_Address')?['Address']"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "We will check for the result output is empty or exist in the policy rule. If result output is empty ,then there is no policy based on IP Address. And If result ouput is having some information related to IP Address then there is a policy with respect to IP"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Set_variable_for_IP_list_array_from_SMC_IP_address": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Failed",
|
||||
"Skipped"
|
||||
]
|
||||
},
|
||||
"type": "Foreach",
|
||||
"description": "Here we are looping each IP Address and check whether it is blocked or not "
|
||||
},
|
||||
"Set_variable_for_IP_list_array_from_SMC_IP_address": {
|
||||
"runAfter": {
|
||||
"Get_IP_address": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "IP Address",
|
||||
"value": "@body('Get_IP_address')?['ip']"
|
||||
},
|
||||
"description": "Set variable for IP list array from SMC IP address"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Get_IP_List_Element": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Set_variable_if_IP_list_is_not_exist": {
|
||||
"runAfter": {},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "Error",
|
||||
"value": "@{variables('IP list name')} is does not exist in the Forcepoint SMC"
|
||||
}
|
||||
},
|
||||
"Terminate": {
|
||||
"runAfter": {
|
||||
"Set_variable_if_IP_list_is_not_exist": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Terminate",
|
||||
"inputs": {
|
||||
"runError": {
|
||||
"message": "@variables('Error')"
|
||||
},
|
||||
"runStatus": "Failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"equals": [
|
||||
"@outputs('Get_IP_List_Element')?['statusCode']",
|
||||
200
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
},
|
||||
"Get_IP_List_Element": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"headers": {
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['ForcepointSMCApiConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "get",
|
||||
"path": "/@{encodeURIComponent(variables('SMC Api Version Number'))}/elements/ip_list",
|
||||
"queries": {
|
||||
"expand": true,
|
||||
"expose_etag": true,
|
||||
"filter": "@variables('IP list name')"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"actions": {
|
||||
"Set_variable_to_login_unsuccessful": {
|
||||
"runAfter": {},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "Error",
|
||||
"value": "Error status code @{outputs('Login')['statusCode']}Unsuccessful login attempt."
|
||||
},
|
||||
"description": "When unsuccessful login atempt has done then we can bind the error to \"Error\" variable."
|
||||
},
|
||||
"Terminate_if_login_is_unsuccessful": {
|
||||
"runAfter": {
|
||||
"Set_variable_to_login_unsuccessful": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Terminate",
|
||||
"inputs": {
|
||||
"runError": {
|
||||
"message": "@variables('Error')"
|
||||
},
|
||||
"runStatus": "Failed"
|
||||
},
|
||||
"description": "Terminate if login is unsuccessful login attempt"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": "@outputs('Login')['statusCode']",
|
||||
"type": "Switch"
|
||||
},
|
||||
"Login": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"authenticationkey": "@variables('SMC API Key')"
|
||||
},
|
||||
"headers": {
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['ForcepointSMCApiConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/@{encodeURIComponent(variables('SMC Api Version Number'))}/login"
|
||||
},
|
||||
"description": "Before take an action against to any other api in Forcepoint SMC we need to do login."
|
||||
}
|
||||
},
|
||||
"runAfter": {},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Set_variable_to_error_variable_if_IP_Address_are_not_available_from_sentinel": {
|
||||
"runAfter": {},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "Error",
|
||||
"value": "IP Address not found from sentinel incident."
|
||||
},
|
||||
"description": "Binding the error to \"Error\" variable and pass it to incident comment."
|
||||
},
|
||||
"Terminate_if_there_are_no_inputs_from_sentinel": {
|
||||
"runAfter": {
|
||||
"Set_variable_to_error_variable_if_IP_Address_are_not_available_from_sentinel": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Terminate",
|
||||
"inputs": {
|
||||
"runError": {
|
||||
"message": "@variables('Error')"
|
||||
},
|
||||
"runStatus": "Failed"
|
||||
},
|
||||
"description": "Terminate the playbook if there are no inputs from sentinel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"greater": [
|
||||
"@length(triggerBody()?['IPs'])",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "Form this condition, we will check like if body present in the sentinel incident or not and we will check the Ip address are available or not."
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Initialize_variable_for_IP_list_name": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"value": {
|
||||
"ForcepointSMCApiConnector": {
|
||||
"connectionId": "[resourceId('Microsoft.Web/connections', variables('Forcepoint_Connector'))]",
|
||||
"connectionName": "[variables('Forcepoint_Connector')]",
|
||||
"id": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name,'/providers/Microsoft.Web/customApis/',parameters('ForcepointSMCConnectorName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "MICROSOFT.WEB/CONNECTIONS",
|
||||
"apiVersion": "2016-06-01",
|
||||
"name": "[variables('Forcepoint_Connector')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"api": {
|
||||
"id": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name,'/providers/Microsoft.Web/customApis/',parameters('ForcepointSMCConnectorName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
# Forcepoint NGFW Block IP Nested Remediation Playbook
|
||||
|
||||
## Summary
|
||||
When this playbook is triggered and it performs the below actions:
|
||||
1. Gets list of potentially malicious IP addresses.
|
||||
2. For each IP address in the list, checks if the IP address is already present in IP List Name or not.
|
||||
3. List of all IP addresses not present in IP List Name is blocked in the firewall by the playbook.
|
||||
|
||||
![Forcepoint](./Images/PlaybookDesignerLight.png)<br>
|
||||
![Forcepoint](./Images/PlaybookDesignerDark.png)<br>
|
||||
|
||||
## Pre-requisites for deployment
|
||||
1. Deploy the Forcepoint SMC Custom Connector before the deployment of this playbook under the same subscription and same resource group as will be used for this playbook. Capture the name of the connector during deployment.
|
||||
2. Forcepoint SMC API Key should be known to establish a connection with Forcepoint SMC. For API Key [Refer here](http://www.websense.com/content/support/library/ngfw/v610/rfrnce/ngfw_6100_ug_smc-api_a_en-us.pdf )
|
||||
3. Forcepoint SMC Version number should be known. [Refer here](https://help.stonesoft.com/onlinehelp/StoneGate/SMC/) to download and install Forcepoint SMC and capture the version number for the same.
|
||||
4. IP address list name for blocking IP address present in SMC should be known.
|
||||
|
||||
### Deploy Custom Connector
|
||||
|
||||
To deploy ForcepointNGFW Custom connector click on the below button.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FForcepointNGFW%2FForcepointSMCApiConnector%2Fazuredeploy.json) [![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FForcepointNGFW%2FForcepointSMCApiConnector%2Fazuredeploy.json)
|
||||
|
||||
|
||||
## Deployment Instructions
|
||||
1. Deploy the playbook by clicking on the "Deploy to Azure" button. This will take you to deploy an ARM Template wizard.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-IP%2FForcepointNGFW-BlockIP-Nested-Remediation%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-IP%2FForcepointNGFW-BlockIP-Nested-Remediation%2Fazuredeploy.json)
|
||||
|
||||
2. Fill in the required parameters for deploying the playbook.
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------- | ------------- |
|
||||
| **Playbook Name** | Enter the Playbook Name here without spaces. (e.g. BlockIP-Forcepoint ) |
|
||||
| **SMC Connector name**|Enter the name of your Forcepoint SMC Connector without spaces.|
|
||||
| **SMC API Key** | Enter the SMC API Key. |
|
||||
| **SMC Version Number** | Enter the version number of SMC. (e.g. 6.9) |
|
||||
| **IP List Name**|Enter IP address list name.|
|
||||
|
||||
|
||||
|
||||
|
||||
# Playbook steps explained
|
||||
## When this playbook is triggered
|
||||
Captures potentially malicious or malware IP addresses incident information.
|
||||
|
||||
##Compose image to add in the incident
|
||||
This action will compose the Forcepoint image to add to the incident comments.
|
||||
|
||||
##Check if security policy exists in SMC
|
||||
* If a security policy exists in the SMC firewall then check for the presence of IP addresses.
|
||||
* If the security policy does not exist then terminate with the error that policy rule not found.
|
||||
|
||||
##For each malicious IP received from the incident
|
||||
|
||||
###Check if IP address is present in IP List Name
|
||||
* If IP address is present in IP List Name then check if IP List is part of security policy rule.
|
||||
* If IP address is not present in IP List Name then add the IP address to IP List Name. Response says IP address blocked by Playbook.
|
||||
|
||||
###Check if IP List is part of security policy in SMC
|
||||
* If a security policy exists in the SMC firewall for IP List Name then IP address is already blocked. Response says IP address already blocked.
|
||||
* If the security policy does not exist for IP List name then security policy is created for IP List Name.
|
||||
|
||||
##Response from playbook is sent to master playbook to generate incident comments.
|
||||
|
||||
|
||||
|
Двоичные данные
MasterPlaybooks/Remediation-IP/Fortinet-BlockIP-Nested-Remediation/Images/MainStep1.PNG
Normal file
После Ширина: | Высота: | Размер: 25 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/Fortinet-BlockIP-Nested-Remediation/Images/MainStep2.PNG
Normal file
После Ширина: | Высота: | Размер: 25 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/Fortinet-BlockIP-Nested-Remediation/Images/PlaybookDesignerDark.png
Normal file
После Ширина: | Высота: | Размер: 99 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/Fortinet-BlockIP-Nested-Remediation/Images/PlaybookDesignerLight.png
Normal file
После Ширина: | Высота: | Размер: 104 KiB |
|
@ -0,0 +1,104 @@
|
|||
# Fortinet BlockIP Nested Remediation Playbook
|
||||
|
||||
## Summary
|
||||
When this playbook gets triggered, it performs below actions:
|
||||
|
||||
1. Gets a list of malicious IP address.
|
||||
2. For each IP address in the list, checks if IP address in blocked in security policy rule or not.
|
||||
3. If IP address is blocked in security policy rule, then it unblocks that IP address.
|
||||
4. If IP address is not blocked in security policy rule, then it blocks that IP address.
|
||||
|
||||
![Fortinet](./Images/PlaybookDesignerLight.png)<br>
|
||||
![Fortinet](./Images/PlaybookDesignerDark.png)<br>
|
||||
|
||||
### Prerequisites
|
||||
1. Sentinel IP block group should be created in the VM.
|
||||
2. FortinetConnector needs to be deployed prior to the deployment of this playbook under the same subscription.
|
||||
3. Function App needs to be deployed prior to the deployment of this playbook under the same subscription.
|
||||
4. FortinetConnector API key should be known. Refer this link [how to generate the API Key](https://www.insoftservices.uk/fortigate-rest-api-token-authentication)
|
||||
5. Managed Identity should be created. [Create user assigned manage identity](/azure/active-directory/managed-identities-azure-resources/how-to-manage-ua-identity-portal)
|
||||
|
||||
### Deploy Custom Connector
|
||||
|
||||
To deploy Fortinet Custom connector click on the below button.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FFortinet-FortiGate%2FCustomConnector%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FFortinet-FortiGate%2FCustomConnector%2Fazuredeploy.json)
|
||||
|
||||
|
||||
|
||||
### Deployment instructions
|
||||
1. Deploy the playbook by clicking on "Deploy to Azure" button. This will take you to deploying an ARM Template wizard.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-IP%2FFortinet-BlockIP-Nested-Remediation%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-IP%2FFortinet-BlockIP-Nested-Remediation%2Fazuredeploy.json)
|
||||
|
||||
|
||||
2. Fill the required parameters:
|
||||
|
||||
|Parameter|Description|
|
||||
|-------------|--------------|
|
||||
|**Playbook Name**| Enter the playbook name here (eg:Fortinet-BlockIP-Remediation)|
|
||||
|**Pre-defined Group Name**| Enter your Group name which is created in firewall|
|
||||
|**Function app Name** |Enter your Function app name |
|
||||
|**Managed Identity Name**| Enter the your managed identity name |
|
||||
|
||||
### Post-Deployment instructions
|
||||
#### a. Authorize connections
|
||||
Once deployment is complete, you will need to authorize Fortinet API connection.
|
||||
1. Click the Fortinet connection resource
|
||||
2. Click edit API connection
|
||||
3. Provide API key
|
||||
4. Click Save
|
||||
|
||||
#### b. Change Managed Identity Connection
|
||||
* Go to logic app designer.
|
||||
* Look for the function call actions. You can find them by the titles:<br>
|
||||
i) Fetch the details of the address object.<br>
|
||||
ii) Get address group details.<br>
|
||||
* For each one of the above function call actions and perform the below mentioned steps:<br>
|
||||
i) Go to "Managed identity" dropdown and select user identity.<br>
|
||||
ii) Save playbook.
|
||||
|
||||
##Playbook steps explained
|
||||
|
||||
### When the playbook is triggered
|
||||
|
||||
The playbook receives list of malicious IP addresses as the input.
|
||||
|
||||
### Initialize variables
|
||||
|
||||
- Action Name (type-String) - To store action name as block IP or unblock IP
|
||||
|
||||
- Address group Members(type-Array) - To store list of address group members
|
||||
|
||||
- IP Action (type-Object) - To store action taken against each IP
|
||||
|
||||
- IP Address Action(type-Array) - To store consolidated action taken against each IP
|
||||
|
||||
- Predefined Group name(type-String)- To store pre-defined address group name
|
||||
|
||||
### For each-malicious IP
|
||||
Iterates on the IPs found in this incident and performs the following:
|
||||
|
||||
### Condition to check if IP address already present in list of address objects
|
||||
|
||||
a)If IP is present in list of address objects
|
||||
|
||||
* Condition to check if IP present in predefined address group
|
||||
|
||||
i) If IP present in predefined address group then unreference that IP from the address group. Set action name as UnblockIP.
|
||||
|
||||
ii) If IP not present in predefined address group then append that IP into address group members. Set action name as BlockIP.
|
||||
|
||||
b)If IP address is not present in list of address objects then append that IP address to address group member and set action name as BlockIP.
|
||||
|
||||
## Update the address group
|
||||
|
||||
a) If IP needs to be blocked then create new address object for that malicious IP and update the address object group.
|
||||
|
||||
b) If IP need not be blocked, then simply update the address object group.
|
||||
|
||||
##Update the IP address action variable.
|
||||
|
||||
|
||||
##Response from playbook is sent to master playbook to generate incident comments.
|
||||
|
После Ширина: | Высота: | Размер: 37 KiB |
После Ширина: | Высота: | Размер: 95 KiB |
После Ширина: | Высота: | Размер: 71 KiB |
После Ширина: | Высота: | Размер: 20 KiB |
После Ширина: | Высота: | Размер: 71 KiB |
После Ширина: | Высота: | Размер: 20 KiB |
После Ширина: | Высота: | Размер: 18 KiB |
После Ширина: | Высота: | Размер: 44 KiB |
После Ширина: | Высота: | Размер: 44 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/Meraki-BlockIP-Nested-Remediation/Images/MainStep1.PNG
Normal file
После Ширина: | Высота: | Размер: 25 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/Meraki-BlockIP-Nested-Remediation/Images/MainStep2.PNG
Normal file
После Ширина: | Высота: | Размер: 22 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/Meraki-BlockIP-Nested-Remediation/Images/MainStep3.PNG
Normal file
После Ширина: | Высота: | Размер: 36 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/Meraki-BlockIP-Nested-Remediation/Images/PlaybookDesignerDark.png
Normal file
После Ширина: | Высота: | Размер: 183 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/Meraki-BlockIP-Nested-Remediation/Images/PlaybookDesignerLight.png
Normal file
После Ширина: | Высота: | Размер: 190 KiB |
|
@ -0,0 +1,939 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"metadata": {
|
||||
"title": "Block IP Nested Remediation - Cisco Meraki",
|
||||
"description": "This playbook checks if malicious IP address is blocked or unblocked by Cisco Meraki MX network.",
|
||||
"mainSteps": [ "1. Fetches a list of potentially malicious IP addresses", "2. If malicious IP address is not blocked by Cisco meraki network then blocks it." ],
|
||||
"prerequisites": [
|
||||
"1. Deploy the Cisco Meraki Custom Connector before the deployment of this playbook under the same subscription and same resource group. Capture the name of the connector during deployment.",
|
||||
"2. Cisco Meraki API Key should be known to establish a connection with Cisco Meraki Custom Connector.",
|
||||
"3. Organization name should be known.",
|
||||
"4. Network name should be known."
|
||||
],
|
||||
"lastUpdateTime": "2021-08-06T00:00:00.000Z",
|
||||
"entities": [ "IP" ],
|
||||
"tags": [ "Remediation" ],
|
||||
"support": {
|
||||
"tier": "community"
|
||||
},
|
||||
"author": {
|
||||
"name": "Accenture"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"PlaybookName": {
|
||||
"type": "string",
|
||||
"defaultValue": "Meraki-Block-IP-Nested-Remediation",
|
||||
"metadata": {
|
||||
"description": "Enter name for Block IP Address playbook without spaces"
|
||||
},
|
||||
"minLength": 3
|
||||
},
|
||||
"CiscoMerakiConnectorName": {
|
||||
"type": "string",
|
||||
"defaultValue": "MerakiConnector",
|
||||
"metadata": {
|
||||
"description": "Enter name of Cisco Meraki custom connector without spaces"
|
||||
},
|
||||
"minLength": 3
|
||||
},
|
||||
"OrganizationName": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter organization name"
|
||||
},
|
||||
"minLength": 3
|
||||
},
|
||||
"NetworkName": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter network name"
|
||||
},
|
||||
"minLength": 3
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"Meraki_Connection": "[concat('Meraki-', parameters('PlaybookName'))]"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.Logic/workflows",
|
||||
"apiVersion": "2017-07-01",
|
||||
"name": "[parameters('PlaybookName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Web/connections', variables('Meraki_Connection'))]"
|
||||
],
|
||||
"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",
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"defaultValue": {},
|
||||
"type": "Object"
|
||||
},
|
||||
"NetworkName": {
|
||||
"defaultValue": "[parameters('NetworkName')]",
|
||||
"type": "String"
|
||||
},
|
||||
"OrganizationName": {
|
||||
"defaultValue": "[parameters('OrganizationName')]",
|
||||
"type": "String"
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
"manual": {
|
||||
"type": "Request",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"method": "POST",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"IPs": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"Address": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"Address"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"runtimeConfiguration": {
|
||||
"concurrency": {
|
||||
"runs": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"Catch_Scope": {
|
||||
"actions": {
|
||||
"Create_HTML_table_for_error": {
|
||||
"runAfter": {
|
||||
"Filter_error_array": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "IP Address",
|
||||
"value": "@item()['Address']"
|
||||
},
|
||||
{
|
||||
"header": "Action Name",
|
||||
"value": "@body('Filter_error_array')[0]?['name']"
|
||||
},
|
||||
{
|
||||
"header": "Message",
|
||||
"value": "@body('Filter_error_array')[0]?['outputs']?['body']?['error']?['message']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@triggerBody()?['IPs']"
|
||||
}
|
||||
},
|
||||
"Error_Response": {
|
||||
"runAfter": {
|
||||
"Create_HTML_table_for_error": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "@{outputs('Cisco_Meraki_Logo')} Cisco Meraki Block IP Address Playbook Error\n@{body('Create_HTML_table_for_error')}",
|
||||
"statusCode": 500
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
},
|
||||
"Filter_error_array": {
|
||||
"runAfter": {},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@result('Try_Scope')",
|
||||
"where": "@equals(item()?['status'], 'Failed')"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Try_Scope": [
|
||||
"Failed",
|
||||
"Skipped",
|
||||
"TimedOut"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
},
|
||||
"Cisco_Meraki_Logo": {
|
||||
"runAfter": {
|
||||
"Initialize_consolidated_action_array_variable": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Compose",
|
||||
"inputs": "<img src=\"https://www.kellerschroeder.com/wp-content/uploads/2017/05/Cisco-Meraki.jpg\" alt=\"CiscoMerakiLogo\" width=\"32\" height=\"32\">",
|
||||
"description": "To add logo for incident "
|
||||
},
|
||||
"Initialize_L3_firewall_rules_variable": {
|
||||
"runAfter": {},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "L3FirewallRules",
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "To store L3 firewall rule object"
|
||||
},
|
||||
"Initialize_action_object_variable": {
|
||||
"runAfter": {
|
||||
"Initialize_L3_firewall_rules_variable": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "Action",
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "To create JSON action object"
|
||||
},
|
||||
"Initialize_consolidated_action_array_variable": {
|
||||
"runAfter": {
|
||||
"Initialize_action_object_variable": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "ConsolidatedAction",
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "To create consolidated array variable for HTML incident table"
|
||||
},
|
||||
"Try_Scope": {
|
||||
"actions": {
|
||||
"Check_if_body_present_in_Azure_Sentinel_incident": {
|
||||
"actions": {
|
||||
"Check_if_Organization_exists": {
|
||||
"actions": {
|
||||
"Check_if_Network_exists": {
|
||||
"actions": {
|
||||
"Compose_Network_Id": {
|
||||
"runAfter": {},
|
||||
"type": "Compose",
|
||||
"inputs": "@body('Filter_Network')?[0]?['id']",
|
||||
"description": "To store network id from filter network result"
|
||||
},
|
||||
"Create_incident_HTML_table": {
|
||||
"runAfter": {
|
||||
"Update_Network_Appliance_L3_Firewall_Rules": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "Incident IP Address",
|
||||
"value": "@item()?['IP']"
|
||||
},
|
||||
{
|
||||
"header": "Source",
|
||||
"value": "@item()?['SourceCidr']"
|
||||
},
|
||||
{
|
||||
"header": "Source Port",
|
||||
"value": "@item()?['SourcePort']"
|
||||
},
|
||||
{
|
||||
"header": "Destination",
|
||||
"value": "@item()?['DestinationCidr']"
|
||||
},
|
||||
{
|
||||
"header": "Destination Port",
|
||||
"value": "@item()?['DestinationPort']"
|
||||
},
|
||||
{
|
||||
"header": "Policy",
|
||||
"value": "@toUpper(item()?['Policy'])"
|
||||
},
|
||||
{
|
||||
"header": "Protocol",
|
||||
"value": "@toUpper(item()?['Protocol'])"
|
||||
},
|
||||
{
|
||||
"header": "Previous Status",
|
||||
"value": "@item()?['PreviousStatus']"
|
||||
},
|
||||
{
|
||||
"header": "Current Status",
|
||||
"value": "@item()?['CurrentStatus']"
|
||||
},
|
||||
{
|
||||
"header": "Action",
|
||||
"value": "@item()?['Action']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@variables('ConsolidatedAction')"
|
||||
},
|
||||
"description": "To create incident HTML table from consolidated action array"
|
||||
},
|
||||
"Filter_L3_firewall_default_rule": {
|
||||
"runAfter": {
|
||||
"Get_Network_Appliance_Firewall_L3_Firewall_Rules": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@body('Get_Network_Appliance_Firewall_L3_Firewall_Rules')?['rules']",
|
||||
"where": "@not(equals(item()?['comment'], string('Default rule')))"
|
||||
},
|
||||
"description": "To filter out L3 firewall default rule"
|
||||
},
|
||||
"For_each_IP_Address": {
|
||||
"foreach": "@triggerBody()?['IPs']",
|
||||
"actions": {
|
||||
"Check_if_IP_Address_exists_in_L3_Firewall_Rules": {
|
||||
"actions": {
|
||||
"Check_if_IP_address_is_blocked_by_L3_firewall_rule": {
|
||||
"actions": {
|
||||
"Append_to_consolidated_action_variable_for_blocked_IP_address_in_L3_firewall": {
|
||||
"runAfter": {
|
||||
"Set_action_variable_for_blocked_IP_address_in_L3_firewall": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "ConsolidatedAction",
|
||||
"value": "@variables('Action')"
|
||||
},
|
||||
"description": "To append action JSON object"
|
||||
},
|
||||
"Set_action_variable_for_blocked_IP_address_in_L3_firewall": {
|
||||
"runAfter": {},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "Action",
|
||||
"value": {
|
||||
"Action": "Blocked using L3 firewall rule",
|
||||
"CurrentStatus": "Blocked",
|
||||
"DestinationCidr": "@{outputs('Compose_L3_firewall_rule')?['destCidr']}",
|
||||
"DestinationPort": "@{outputs('Compose_L3_firewall_rule')?['destPort']}",
|
||||
"IP": "@{items('For_each_IP_Address')?['Address']}",
|
||||
"Policy": "@{outputs('Compose_L3_firewall_rule')?['policy']}",
|
||||
"PreviousStatus": "Blocked",
|
||||
"Protocol": "@{outputs('Compose_L3_firewall_rule')?['protocol']}",
|
||||
"SourceCidr": "@{outputs('Compose_L3_firewall_rule')?['srcCidr']}",
|
||||
"SourcePort": "@{outputs('Compose_L3_firewall_rule')?['srcPort']}"
|
||||
}
|
||||
},
|
||||
"description": "To create action JSON object"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Compose_L3_firewall_rule": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Condition_if_IP_address_exists_in_L7_firewall_rules": {
|
||||
"actions": {
|
||||
"Append_to_consolidated_action_variable_for_IP_address_blocked_in_L7_firewall": {
|
||||
"runAfter": {
|
||||
"Set_action_variable_for_IP_address_blocked_in_L7_firewall": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "ConsolidatedAction",
|
||||
"value": "@variables('Action')"
|
||||
},
|
||||
"description": "To append action JSON object"
|
||||
},
|
||||
"Compose_L7_firewall_rule": {
|
||||
"runAfter": {},
|
||||
"type": "Compose",
|
||||
"inputs": "@body('Filter_L7_firewall_rule')?[0]",
|
||||
"description": "To create firewall rule item"
|
||||
},
|
||||
"Set_action_variable_for_IP_address_blocked_in_L7_firewall": {
|
||||
"runAfter": {
|
||||
"Compose_L7_firewall_rule": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "Action",
|
||||
"value": {
|
||||
"Action": "Blocked using L7 firewall rule",
|
||||
"CurrentStatus": "Blocked",
|
||||
"DestinationCidr": "@{outputs('Compose_L7_firewall_rule')?['value']}",
|
||||
"DestinationPort": "NA",
|
||||
"IP": "@{items('For_each_IP_Address')?['Address']}",
|
||||
"Policy": "@{outputs('Compose_L7_firewall_rule')?['policy']}",
|
||||
"PreviousStatus": "Blocked",
|
||||
"Protocol": "NA",
|
||||
"SourceCidr": "NA",
|
||||
"SourcePort": "NA"
|
||||
}
|
||||
},
|
||||
"description": "To create action JSON object"
|
||||
}
|
||||
},
|
||||
"runAfter": {},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Append_to_consolidated_action_variable_for_IP_address_allowed_in_firewall": {
|
||||
"runAfter": {
|
||||
"Set_action_variable_for_IP_address_allowed_in_firewall": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "ConsolidatedAction",
|
||||
"value": "@variables('Action')"
|
||||
},
|
||||
"description": "To append action JSON object"
|
||||
},
|
||||
"Set_action_variable_for_IP_address_allowed_in_firewall": {
|
||||
"runAfter": {},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "Action",
|
||||
"value": {
|
||||
"Action": "Allowed using L3 & L7 firewall rules",
|
||||
"CurrentStatus": "Allowed",
|
||||
"DestinationCidr": "@{outputs('Compose_L3_firewall_rule')?['destCidr']}",
|
||||
"DestinationPort": "@{outputs('Compose_L3_firewall_rule')?['destPort']}",
|
||||
"IP": "@{items('For_each_IP_Address')?['Address']}",
|
||||
"Policy": "@{outputs('Compose_L3_firewall_rule')?['policy']}",
|
||||
"PreviousStatus": "Allowed",
|
||||
"Protocol": "@{outputs('Compose_L3_firewall_rule')?['protocol']}",
|
||||
"SourceCidr": "@{outputs('Compose_L3_firewall_rule')?['srcCidr']}",
|
||||
"SourcePort": "@{outputs('Compose_L3_firewall_rule')?['srcPort']}"
|
||||
}
|
||||
},
|
||||
"description": "To create action json object"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"greater": [
|
||||
"@length(body('Filter_L7_firewall_rule'))",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "Condition to check if filter L7 firewall rule"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"equals": [
|
||||
"@outputs('Compose_L3_firewall_rule')?['Policy']",
|
||||
"deny"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": " Condition to check if IP address is blocked by L3 firewall"
|
||||
},
|
||||
"Compose_L3_firewall_rule": {
|
||||
"runAfter": {},
|
||||
"type": "Compose",
|
||||
"inputs": "@body('Filter_L3_firewall_rule')?[0]",
|
||||
"description": "To store L3 firewall rule"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Filter_L7_firewall_rule": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Check_if_IP_address_exists_in_L7_firewall_rule": {
|
||||
"actions": {
|
||||
"Append_to_consolidated_action_variable_for_blocked_IP_address_in_L7_firewall": {
|
||||
"runAfter": {
|
||||
"Set_action_variable_for_blocked_IP_address_in_L7_firewall": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "ConsolidatedAction",
|
||||
"value": "@variables('Action')"
|
||||
},
|
||||
"description": "To append action JSON object"
|
||||
},
|
||||
"Compose_L7_firewall_rule_item": {
|
||||
"runAfter": {},
|
||||
"type": "Compose",
|
||||
"inputs": "@body('Filter_L7_firewall_rule')?[0]",
|
||||
"description": "To create firewall rule item"
|
||||
},
|
||||
"Set_action_variable_for_blocked_IP_address_in_L7_firewall": {
|
||||
"runAfter": {
|
||||
"Compose_L7_firewall_rule_item": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "Action",
|
||||
"value": {
|
||||
"Action": "Blocked using L7 firewall rule",
|
||||
"CurrentStatus": "Blocked",
|
||||
"DestinationCidr": "@{outputs('Compose_L7_firewall_rule_item')?['value']}",
|
||||
"DestinationPort": "NA",
|
||||
"IP": "@{items('For_each_IP_Address')?['Address']}",
|
||||
"Policy": "@{outputs('Compose_L7_firewall_rule_item')?['policy']}",
|
||||
"PreviousStatus": "Blocked",
|
||||
"Protocol": "NA",
|
||||
"SourceCidr": "NA",
|
||||
"SourcePort": "NA"
|
||||
}
|
||||
},
|
||||
"description": "To create action JSON object"
|
||||
}
|
||||
},
|
||||
"runAfter": {},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Append_to_L3_firewall_rules_variable": {
|
||||
"runAfter": {},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "L3FirewallRules",
|
||||
"value": {
|
||||
"comment": "Blocked by playbook",
|
||||
"destCidr": "@items('For_each_IP_Address')?['Address']",
|
||||
"destPort": "any",
|
||||
"policy": "deny",
|
||||
"protocol": "any",
|
||||
"srcCidr": "any",
|
||||
"srcPort": "any",
|
||||
"syslogEnabled": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"Append_to_consolidated_action_variable_for_new_IP_address": {
|
||||
"runAfter": {
|
||||
"Set_action_variable_for_new_IP_address": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "ConsolidatedAction",
|
||||
"value": "@variables('Action')"
|
||||
},
|
||||
"description": " To append action JSON object"
|
||||
},
|
||||
"Set_action_variable_for_new_IP_address": {
|
||||
"runAfter": {
|
||||
"Append_to_L3_firewall_rules_variable": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "Action",
|
||||
"value": {
|
||||
"Action": "Blocked using L3 firewall rule by playbook",
|
||||
"CurrentStatus": "Blocked",
|
||||
"DestinationCidr": "@{items('For_each_IP_Address')?['Address']}",
|
||||
"DestinationPort": "Any",
|
||||
"IP": "@{items('For_each_IP_Address')?['Address']}",
|
||||
"Policy": "deny",
|
||||
"PreviousStatus": "Not Found",
|
||||
"Protocol": "any",
|
||||
"SourceCidr": "Any",
|
||||
"SourcePort": "Any"
|
||||
}
|
||||
},
|
||||
"description": "To create action JSON object for IP address"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"greater": [
|
||||
"@length(body('Filter_L7_firewall_rule'))",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "Condition to check if IP address exists in L7 firewall rule"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"greater": [
|
||||
"@length(body('Filter_L3_firewall_rule'))",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "Condition to check if filter IP address returns network object"
|
||||
},
|
||||
"Filter_L3_firewall_rule": {
|
||||
"runAfter": {},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@body('Get_Network_Appliance_Firewall_L3_Firewall_Rules')?['rules']",
|
||||
"where": "@contains(item()?['destCidr'], items('For_each_IP_Address')?['Address'])"
|
||||
},
|
||||
"description": "To filter rule detail from get network appliance L3 firewall rule action based on IP address"
|
||||
},
|
||||
"Filter_L7_firewall_rule": {
|
||||
"runAfter": {
|
||||
"Filter_L3_firewall_rule": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@body('Get_Network_Appliance_Firewall_L7_Firewall_Rules')?['rules']",
|
||||
"where": "@contains(item()?['value'], items('For_each_IP_Address')?['Address'])"
|
||||
},
|
||||
"description": "To filter rule detail from get network appliance L7 firewall rule action based on IP address"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Get_Network_Appliance_Firewall_L7_Firewall_Rules": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Foreach",
|
||||
"description": "For each loop for IP addresses from azure sentinel",
|
||||
"runtimeConfiguration": {
|
||||
"concurrency": {
|
||||
"repetitions": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"Get_Network_Appliance_Firewall_L3_Firewall_Rules": {
|
||||
"runAfter": {
|
||||
"Compose_Network_Id": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['MerakiConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "get",
|
||||
"path": "/networks/@{encodeURIComponent(outputs('Compose_Network_Id'))}/appliance/firewall/l3FirewallRules"
|
||||
}
|
||||
},
|
||||
"Get_Network_Appliance_Firewall_L7_Firewall_Rules": {
|
||||
"runAfter": {
|
||||
"Set_L3_firewall_rules_variable": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['MerakiConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "get",
|
||||
"path": "/networks/@{encodeURIComponent(outputs('Compose_Network_Id'))}/appliance/firewall/l7FirewallRules"
|
||||
}
|
||||
},
|
||||
"Set_L3_firewall_rules_variable": {
|
||||
"runAfter": {
|
||||
"Filter_L3_firewall_default_rule": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "L3FirewallRules",
|
||||
"value": "@body('Filter_L3_firewall_default_rule')"
|
||||
},
|
||||
"description": " To create L3 firewall rules array"
|
||||
},
|
||||
"Update_Network_Appliance_L3_Firewall_Rules": {
|
||||
"runAfter": {
|
||||
"For_each_IP_Address": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"rules": "@variables('L3FirewallRules')"
|
||||
},
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['MerakiConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "put",
|
||||
"path": "/networks/@{encodeURIComponent(outputs('Compose_Network_Id'))}/appliance/firewall/l3FirewallRules"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Filter_Network": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Terminate_if_network_not_found": {
|
||||
"runAfter": {},
|
||||
"type": "Terminate",
|
||||
"inputs": {
|
||||
"runError": {
|
||||
"code": "404",
|
||||
"message": "Network Not Found"
|
||||
},
|
||||
"runStatus": "Failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"greater": [
|
||||
"@length(body('Filter_Network'))",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "Condition to check if filter network returns network object"
|
||||
},
|
||||
"Filter_Network": {
|
||||
"runAfter": {
|
||||
"Get_Networks": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@body('Get_Networks')",
|
||||
"where": "@equals(item()?['name'], parameters('NetworkName'))"
|
||||
},
|
||||
"description": "To filter network detail from get networks action based on network name"
|
||||
},
|
||||
"Get_Networks": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['MerakiConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "get",
|
||||
"path": "/organizations/@{encodeURIComponent(body('Filter_Organization')?[0]?['id'])}/networks",
|
||||
"queries": {
|
||||
"perPage": 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Filter_Organization": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Terminate_if_organization_not_found": {
|
||||
"runAfter": {},
|
||||
"type": "Terminate",
|
||||
"inputs": {
|
||||
"runError": {
|
||||
"code": "404",
|
||||
"message": "Organization Not Found"
|
||||
},
|
||||
"runStatus": "Failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"greater": [
|
||||
"@length(body('Filter_Organization'))",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "Condition to check if filter organization returns organization object"
|
||||
},
|
||||
"Filter_Organization": {
|
||||
"runAfter": {
|
||||
"Get_Organizations": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@body('Get_Organizations')",
|
||||
"where": "@equals(item()?['name'], parameters('OrganizationName'))"
|
||||
},
|
||||
"description": "To filter organization detail from get organizations action based on organization name"
|
||||
},
|
||||
"Get_Organizations": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['MerakiConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "get",
|
||||
"path": "/organizations"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Terminate_if_IP_address_not_found": {
|
||||
"runAfter": {},
|
||||
"type": "Terminate",
|
||||
"inputs": {
|
||||
"runError": {
|
||||
"code": "404",
|
||||
"message": "IP Address Not Found in Azure Sentinel Incident"
|
||||
},
|
||||
"runStatus": "Failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"greater": [
|
||||
"@length(triggerBody()?['IPs'])",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "Condition to check if body present in the sentinel incident"
|
||||
},
|
||||
"Response": {
|
||||
"runAfter": {
|
||||
"Check_if_body_present_in_Azure_Sentinel_incident": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "@{outputs('Cisco_Meraki_Logo')} Cisco Meraki Block IP Address Playbook\n\nBelow incident IP address(s) are found in azure sentinel have the following status in network - @{parameters('NetworkName')} for organization - @{parameters('OrganizationName')}\n@{body('Create_incident_HTML_table')}",
|
||||
"statusCode": 200
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Cisco_Meraki_Logo": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"value": {
|
||||
"MerakiConnector": {
|
||||
"connectionId": "[resourceId('Microsoft.Web/connections', variables('Meraki_Connection'))]",
|
||||
"connectionName": "[variables('Meraki_Connection')]",
|
||||
"id": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name,'/providers/Microsoft.Web/customApis/',parameters('CiscoMerakiConnectorName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "MICROSOFT.WEB/CONNECTIONS",
|
||||
"apiVersion": "2016-06-01",
|
||||
"name": "[variables('Meraki_Connection')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"api": {
|
||||
"id": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name,'/providers/Microsoft.Web/customApis/',parameters('CiscoMerakiConnectorName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
# Cisco Meraki Block IP Nested Remediation Playbook
|
||||
|
||||
## Summary
|
||||
When this playbook gets triggered and it performs the below actions:
|
||||
1. Gets a list of potentially malicious IP addresses.
|
||||
2. For each IP address in the list, checks if the IP address is blocked by L3 firewall rule or L7 firewall rule of MX network.<br>
|
||||
a) If IP address is blocked by either L3 firewall rule or L7 firewall rule, then response says IP address is blocked.<br>
|
||||
b) If IP address is not blocked by either L3 firewall rule or L7 firewall rule, then that IP address is blocked by playbook.
|
||||
|
||||
![Meraki](./Images/PlaybookDesignerLight.png)
|
||||
|
||||
![Meraki](./Images/PlaybookDesignerDark.png)
|
||||
|
||||
|
||||
## Pre-requisites for deployment
|
||||
1. Deploy the Cisco Meraki Custom Connector before the deployment of this playbook under the same subscription and same resource group. Capture the name of the connector during deployment.
|
||||
2. Cisco Meraki API Key should be known to establish a connection with Cisco Meraki Custom Connector. [Refer here](https://developer.cisco.com/meraki/api-v1/#!getting-started/authorization)
|
||||
3. Organization name should be known. [Refer here](https://developer.cisco.com/meraki/api-v1/#!getting-started/find-your-organization-id)
|
||||
4. Network name should be known.[Refer here](https://developer.cisco.com/meraki/api-v1/#!getting-started/find-your-network-id)
|
||||
|
||||
### Deploy Custom Connector
|
||||
|
||||
To deploy Cisco Meraki Custom connector click on the below button.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FCiscoMeraki%2FConnector%2FMerakiConnector%2Fazuredeploy.json) [![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FCiscoMeraki%2FConnector%2FMerakiConnector%2Fazuredeploy.json)
|
||||
|
||||
## Deployment Instructions
|
||||
1. Deploy the playbook by clicking on the "Deploy to Azure" button. This will take you to deploy an ARM Template wizard.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-IP%2FMeraki-BlockIP-Nested-Remediation%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-IP%2FMeraki-BlockIP-Nested-Remediation%2Fazuredeploy.json)
|
||||
|
||||
|
||||
2. Fill in the required parameters for deploying the playbook.
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------- | ------------- |
|
||||
| **Playbook Name** | Enter the playbook name here without spaces (e.g. Block-IP-Address-Nested) |
|
||||
| **Cisco Meraki Connector Name**|Enter the name of Cisco Meraki custom connector without spaces |
|
||||
| **Organization Name** | Enter organization name |
|
||||
| **Network Name**| Enter network name |
|
||||
|
||||
|
||||
# Post-Deployment Instructions
|
||||
## Authorize API connection
|
||||
Once deployment is complete, go under deployment details and authorize Cisco Meraki connection.
|
||||
1. Click the Cisco Meraki connection
|
||||
2. Click **Edit API connection**
|
||||
3. Enter API Key
|
||||
4. Click Save
|
||||
|
||||
# Playbook steps explained
|
||||
## When the playbook is triggered
|
||||
The playbook receives list of malicious IP addresses as the input.
|
||||
|
||||
## Compose image to add in the incident
|
||||
This action will compose the Cisco Meraki image to add to the incident comments.
|
||||
|
||||
## Check if Organization exists
|
||||
* If organization name exists in list of organizations associated with the account, then get list of networks associated with the organization.
|
||||
* If organization name does not exist, then terminate with the error that organization not found.
|
||||
|
||||
## Check if network exists
|
||||
* If network name exists in list of networks associated with the account, then return network associated with the organization.
|
||||
* If network name does not exist, then terminate with the error that network not found.
|
||||
|
||||
## For each malicious IP received from the incident
|
||||
- Checks if the IP address is part of L3 firewall rule or L7 firewall rule of MX network.
|
||||
- If IP address is part of both L3 firewall rule and L7 firewall rule but not blocked by either of the rules, then response says IP address allowed by firewall.
|
||||
- If IP address is part of either L3 firewall rule or L7 firewall rule and blocked by the rule, then response says IP address is blocked.
|
||||
- If IP address is not part of either L3 firewall rule or L7 firewall rule, then that IP address is blocked by playbook. Response IP address blocked by playbook.
|
||||
- Responses from all the cases are combined.
|
||||
|
||||
## Response from playbook is sent to master playbook to generate incident comments.
|
||||
|
Двоичные данные
MasterPlaybooks/Remediation-IP/PaloAlto-PAN-OS-BlockIP-Remediation/Images/MainStep1.PNG
Normal file
После Ширина: | Высота: | Размер: 25 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/PaloAlto-PAN-OS-BlockIP-Remediation/Images/MainStep2.PNG
Normal file
После Ширина: | Высота: | Размер: 20 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/PaloAlto-PAN-OS-BlockIP-Remediation/Images/MainStep3.PNG
Normal file
После Ширина: | Высота: | Размер: 21 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/PaloAlto-PAN-OS-BlockIP-Remediation/Images/MainStep4.PNG
Normal file
После Ширина: | Высота: | Размер: 18 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/PaloAlto-PAN-OS-BlockIP-Remediation/Images/PlaybookDesignerDark.png
Normal file
После Ширина: | Высота: | Размер: 92 KiB |
Двоичные данные
MasterPlaybooks/Remediation-IP/PaloAlto-PAN-OS-BlockIP-Remediation/Images/PlaybookDesignerLight.png
Normal file
После Ширина: | Высота: | Размер: 96 KiB |
|
@ -0,0 +1,734 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"metadata": {
|
||||
"title": "Block IP Nested Remediation - Palo Alto PAN-OS",
|
||||
"description": "This playbook checks if malicious IP address is blocked or unblocked by Security Policy Rule.",
|
||||
"mainSteps": [ "1. Fetches a list of potentially malicious IP addresses", "2. If malicious IP address is not blocked by security policy rule then blocks it.", "3. If malicious IP address is blocked by security policy rule then unblocks it." ],
|
||||
"prerequisites": [
|
||||
"1. PaloAlto connector needs to be deployed prior to the deployment of this playbook under the same subscription and same resource group. Capture the name of Connector during deployment. Relevant instructions can be found in the connector doc page.",
|
||||
"2. Generate an API key.[Refer this link on how to generate the API Key](https://paloaltolactest.trafficmanager.net/restapi-doc/#tag/key-generation)",
|
||||
"3. Address group should be created for PAN-OS and this should be used while creating playbooks."
|
||||
],
|
||||
"lastUpdateTime": "2021-08-06T00:00:00.000Z",
|
||||
"entities": [ "IP" ],
|
||||
"tags": [ "Remediation" ],
|
||||
"support": {
|
||||
"tier": "community"
|
||||
},
|
||||
"author": {
|
||||
"name": "Accenture"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"PlaybookName": {
|
||||
"type": "string",
|
||||
"defaultValue": "PaloAlto-PAN-OS-Block-IP-Nested-Remediation",
|
||||
"metadata": {
|
||||
"description": "Enter name for Block IP Address playbook without spaces"
|
||||
},
|
||||
"minLength": 3
|
||||
},
|
||||
"PAN-OSConnectorName": {
|
||||
"type": "string",
|
||||
"defaultValue": "PaloAltoConnector",
|
||||
"metadata": {
|
||||
"description": "Enter name of PAN OS custom connector without spaces"
|
||||
},
|
||||
"minLength": 3
|
||||
},
|
||||
"AddressGroup": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter the predefined address group name here to Block IP / Unblock IP"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"variables": {
|
||||
"PaloaltoConnectionName": "[concat('PaloaltoConnector-', parameters('PlaybookName'))]"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.Logic/workflows",
|
||||
"apiVersion": "2017-07-01",
|
||||
"name": "[parameters('PlaybookName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"identity": {
|
||||
"type": "SystemAssigned"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Web/connections', variables('PaloaltoConnectionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"state": "Enabled",
|
||||
"definition": {
|
||||
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"defaultValue": {},
|
||||
"type": "Object"
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
"manual": {
|
||||
"type": "Request",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"method": "POST",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"IPs": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"Type": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"friendlyName": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"address",
|
||||
"friendlyName",
|
||||
"Type"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"runtimeConfiguration": {
|
||||
"concurrency": {
|
||||
"runs": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"Catch_Scope": {
|
||||
"actions": {
|
||||
"Create_HTML_table_for_error": {
|
||||
"runAfter": {
|
||||
"Filter_error_array": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "IP Address",
|
||||
"value": "@item()['address']"
|
||||
},
|
||||
{
|
||||
"header": "Action Name",
|
||||
"value": "@body('Filter_error_array')[0]?['name']"
|
||||
},
|
||||
{
|
||||
"header": "Message",
|
||||
"value": "@body('Filter_error_array')[0]?['outputs']?['body']?['error']?['message']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@triggerBody()?['IPs']"
|
||||
},
|
||||
"description": " This composes the incident comment in a HTML table"
|
||||
},
|
||||
"Error_Response": {
|
||||
"runAfter": {
|
||||
"Create_HTML_table_for_error": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "@{outputs('Compose_Image_to_add_to_the_Incident')} PAN-OS -Remidiation Playbook Error\n@{body('Create_HTML_table_for_error')}",
|
||||
"statusCode": 500
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
},
|
||||
"Filter_error_array": {
|
||||
"runAfter": {},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@result('Try_Scope')",
|
||||
"where": "@equals(item()?['status'], 'Failed')"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Try_Scope": [
|
||||
"Failed",
|
||||
"Skipped",
|
||||
"TimedOut"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
},
|
||||
"Initialize_variable_Address_action": {
|
||||
"runAfter": {
|
||||
"Initialize_variable_address_group_members": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "AddressAction",
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "This holds the address action"
|
||||
},
|
||||
"Initialize_variable_IP_address_action": {
|
||||
"runAfter": {
|
||||
"Initialize_variable_Address_action": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "IPAddressAction",
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "This holds the action taken on each IP "
|
||||
},
|
||||
"Initialize_variable_action_name": {
|
||||
"runAfter": {},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "ActionName",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "variable to store action name "
|
||||
},
|
||||
"Initialize_variable_address_group_members": {
|
||||
"runAfter": {
|
||||
"Initialize_variable_action_name": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "AddressGroupMembers",
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "variable to store the list of address group members"
|
||||
},
|
||||
"Try_Scope": {
|
||||
"actions": {
|
||||
"Compose_Image_to_add_to_the_Incident": {
|
||||
"runAfter": {
|
||||
"Create_HTML_table_to_comment_in_the_Incident": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Compose",
|
||||
"inputs": "<img src=\"https://avatars.githubusercontent.com/u/4855743?s=200&v=4\" ,alt=\"Lamp\" width=\"32\" height=\"32\" />",
|
||||
"description": "This composes the PAN-OS Image to be added in the incident"
|
||||
},
|
||||
"Create_HTML_table_to_comment_in_the_Incident": {
|
||||
"runAfter": {
|
||||
"For_each_malicious_IP": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "IP Address",
|
||||
"value": "@item()?['IPAddress']"
|
||||
},
|
||||
{
|
||||
"header": "Action Taken",
|
||||
"value": "@item()?['ActionTaken']"
|
||||
},
|
||||
{
|
||||
"header": "Status",
|
||||
"value": "@item()?['Status']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@variables('IPAddressAction')"
|
||||
},
|
||||
"description": "This composes the incident comment in a HTML table"
|
||||
},
|
||||
"For_each_malicious_IP": {
|
||||
"foreach": "@triggerBody()?['IPs']",
|
||||
"actions": {
|
||||
"Condition__to_check_if_IP_needs_to_be_blocked": {
|
||||
"actions": {
|
||||
"Create_an_address_object": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"entry": {
|
||||
"@@name": "@items('For_each_malicious_IP')?['Address']",
|
||||
"description": "@items('For_each_malicious_IP')?['Address']",
|
||||
"ip-netmask": "@items('For_each_malicious_IP')?['Address']"
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['PaloAltoConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/restapi/v10.0/Objects/Addresses",
|
||||
"queries": {
|
||||
"address type": "ip-netmask",
|
||||
"location": "vsys",
|
||||
"name": "@items('For_each_malicious_IP')?['Address']",
|
||||
"vsys": "vsys1"
|
||||
}
|
||||
},
|
||||
"description": "This creates a new address object for the malicious IP"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Condition_to_check_if_IP_address_already_present_in_list_of_address_objects": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"equals": [
|
||||
"@length(body('Filter_array_of_IP_address_from_list_of_address_objects'))",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "This check if IP needs to be blocked"
|
||||
},
|
||||
"Condition_to_check_if_IP_address_already_present_in_list_of_address_objects": {
|
||||
"actions": {
|
||||
"Condition_to_check_if_IP_already_present_in_predefined_address_group": {
|
||||
"actions": {
|
||||
"Filter_array_IP_address_from_the_list_of_address_objects_to_unreference": {
|
||||
"runAfter": {
|
||||
"Set_dynamic_action_name": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@variables('AddressGroupMembers')",
|
||||
"where": "@not(equals(item(), items('For_each_malicious_IP')?['Address']))"
|
||||
},
|
||||
"description": "This filters the IP address from predefined address group to unreference/unblock IP"
|
||||
},
|
||||
"Set_dynamic_action_name": {
|
||||
"runAfter": {},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "ActionName",
|
||||
"value": "UnBlock IP"
|
||||
},
|
||||
"description": "variable to set action name dynamically"
|
||||
},
|
||||
"unreference_IP_address_from_the_existing_group_members": {
|
||||
"runAfter": {
|
||||
"Filter_array_IP_address_from_the_list_of_address_objects_to_unreference": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "AddressGroupMembers",
|
||||
"value": "@body('Filter_array_IP_address_from_the_list_of_address_objects_to_unreference')"
|
||||
},
|
||||
"description": "unreference IP address from the group members and update"
|
||||
}
|
||||
},
|
||||
"runAfter": {},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Append_IP_address_to_the_address_group_members": {
|
||||
"runAfter": {},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "AddressGroupMembers",
|
||||
"value": "@items('For_each_malicious_IP')?['Address']"
|
||||
},
|
||||
"description": "append IP address to the address group members"
|
||||
},
|
||||
"Set_dynamic_action_name_to_variable_Action_name": {
|
||||
"runAfter": {
|
||||
"Append_IP_address_to_the_address_group_members": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "ActionName",
|
||||
"value": "Block IP"
|
||||
},
|
||||
"description": "set action name dynamically"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"contains": [
|
||||
"@variables('AddressGroupMembers')",
|
||||
"@items('For_each_malicious_IP')?['Address']"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "condition to check the malicious IP address is present in the predefined address group and the IP is part of static member"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Filter_array_IP_from_list_of_security_rules": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Append_IP_to_array_of_address_group_members": {
|
||||
"runAfter": {},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "AddressGroupMembers",
|
||||
"value": "@items('For_each_malicious_IP')?['Address']"
|
||||
},
|
||||
"description": "append the Malicious IP address to the existing group members to block / unblock from the predefined address group"
|
||||
},
|
||||
"Set_variable_to_Block_IP": {
|
||||
"runAfter": {
|
||||
"Append_IP_to_array_of_address_group_members": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "ActionName",
|
||||
"value": "Block IP"
|
||||
},
|
||||
"description": "This sets the variable block IP"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"greater": [
|
||||
"@length(body('Filter_array_of_IP_address_from_list_of_address_objects'))",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "This checks if IP is a member of any of the list of address objects"
|
||||
},
|
||||
"Condition_to_check_the_edit_an_address_object_group_status": {
|
||||
"actions": {
|
||||
"Append_success_status_Blocked_IP_to_IP_address_action": {
|
||||
"runAfter": {
|
||||
"Set_variable_Address_action_in_case_of_success": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "IPAddressAction",
|
||||
"value": "@variables('AddressAction')"
|
||||
},
|
||||
"description": "append action taken to IP address action array"
|
||||
},
|
||||
"Set_variable_Address_action_in_case_of_success": {
|
||||
"runAfter": {},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "AddressAction",
|
||||
"value": {
|
||||
"ActionTaken": " @{variables('ActionName')} ",
|
||||
"IPAddress": " @{items('For_each_malicious_IP')?['Address']}",
|
||||
"Status": "Success"
|
||||
}
|
||||
},
|
||||
"description": "This sets address action variable in case of success"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Update_an_address_object_group": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Append_failure_status_to_IP_address_action": {
|
||||
"runAfter": {
|
||||
"Set_variable_Address_action_in_case_of_failure": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "IPAddressAction",
|
||||
"value": "@variables('AddressAction')"
|
||||
},
|
||||
"description": "append action taken to IP address action array"
|
||||
},
|
||||
"Set_variable_Address_action_in_case_of_failure": {
|
||||
"runAfter": {},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "AddressAction",
|
||||
"value": {
|
||||
"ActionTaken": " @{variables('ActionName')} ",
|
||||
"IPAddress": " @{items('For_each_malicious_IP')?['Address']}",
|
||||
"Status": "Failure"
|
||||
}
|
||||
},
|
||||
"description": "This sets address action variable in case of failure"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"equals": [
|
||||
"@body('Update_an_address_object_group')?['@status']",
|
||||
"success"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
},
|
||||
"Configured_address_group": {
|
||||
"runAfter": {
|
||||
"Set_variable_address_group_members": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Compose",
|
||||
"inputs": "@body('List_address_groups')?['result']?['entry']?[0]?['@name']",
|
||||
"description": "compose predefined address group"
|
||||
},
|
||||
"Filter_array_IP_from_list_of_security_rules": {
|
||||
"runAfter": {
|
||||
"Configured_address_group": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@body('List_security_rules')?['result']?['entry']",
|
||||
"where": "@contains(item()?['source']?['member'], items('For_each_malicious_IP')?['Address'])"
|
||||
},
|
||||
"description": "This filters all the security rules in which this IP is a member"
|
||||
},
|
||||
"Filter_array_of_IP_address_from_list_of_address_objects": {
|
||||
"runAfter": {},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@body('List_address_objects')?['result']?['entry']",
|
||||
"where": "@equals(item()?['ip-netmask'], items('For_each_malicious_IP')?['Address'])"
|
||||
},
|
||||
"description": "This filters the list of address objects in which this IP is a member "
|
||||
},
|
||||
"List_address_groups": {
|
||||
"runAfter": {
|
||||
"Filter_array_of_IP_address_from_list_of_address_objects": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['PaloAltoConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "get",
|
||||
"path": "/restapi/v10.0/Objects/AddressGroups",
|
||||
"queries": {
|
||||
"location": "vsys",
|
||||
"name": "[parameters('AddressGroup')]",
|
||||
"vsys": "vsys1"
|
||||
}
|
||||
},
|
||||
"description": "This gets complete list of address object groups present in the PAN-OS"
|
||||
},
|
||||
"Set_variable_address_group_members": {
|
||||
"runAfter": {
|
||||
"List_address_groups": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "SetVariable",
|
||||
"inputs": {
|
||||
"name": "AddressGroupMembers",
|
||||
"value": "@body('List_address_groups')?['result']?['entry']?[0]?['static']?['member']"
|
||||
},
|
||||
"description": "assign list of address group members"
|
||||
},
|
||||
"Update_an_address_object_group": {
|
||||
"runAfter": {
|
||||
"Condition__to_check_if_IP_needs_to_be_blocked": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"entry": {
|
||||
"@@name": "[parameters('AddressGroup')]",
|
||||
"static": {
|
||||
"member": "@variables('AddressGroupMembers')"
|
||||
}
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['PaloAltoConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "put",
|
||||
"path": "/restapi/v10.0/Objects/AddressGroups",
|
||||
"queries": {
|
||||
"location": "vsys",
|
||||
"name": "[parameters('AddressGroup')]",
|
||||
"vsys": "vsys1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"List_security_rules": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Foreach",
|
||||
"runtimeConfiguration": {
|
||||
"concurrency": {
|
||||
"repetitions": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"List_address_objects": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['PaloAltoConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "get",
|
||||
"path": "/restapi/v10.0/Objects/Addresses",
|
||||
"queries": {
|
||||
"location": "vsys",
|
||||
"vsys": "vsys1"
|
||||
}
|
||||
},
|
||||
"description": "This gets complete list of address object present in the PAN-OS"
|
||||
},
|
||||
"List_security_rules": {
|
||||
"runAfter": {
|
||||
"List_address_objects": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['PaloAltoConnector']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "get",
|
||||
"path": "/restapi/v10.0/Policies/SecurityRules",
|
||||
"queries": {
|
||||
"location": "vsys",
|
||||
"vsys": "vsys1"
|
||||
}
|
||||
},
|
||||
"description": "This gets complete list of security policy rules present in the PAN-OS"
|
||||
},
|
||||
"Response": {
|
||||
"runAfter": {
|
||||
"Compose_Image_to_add_to_the_Incident": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "@{outputs('Compose_Image_to_add_to_the_Incident')} PAN-OS -Remidiation Playbook ran and performed the following actions:@{body('Create_HTML_table_to_comment_in_the_Incident')}",
|
||||
"statusCode": 200
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Initialize_variable_IP_address_action": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"value": {
|
||||
"PaloAltoConnector": {
|
||||
"connectionId": "[resourceId('Microsoft.Web/connections', variables('PaloaltoConnectionName'))]",
|
||||
"connectionName": "[variables('PaloAltoConnectionName')]",
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/customApis/', parameters('PAN-OSConnectorName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Web/connections",
|
||||
"apiVersion": "2016-06-01",
|
||||
"name": "[variables('PaloaltoConnectionName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"customParameterValues": {},
|
||||
"api": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/customApis/', parameters('PAN-OSConnectorName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
# PaloAlto-PAN-OS Block IP Nested Remediation Playbook
|
||||
|
||||
## Summary
|
||||
|
||||
This playbook allows blocking/unblocking IP addresses in PaloAlto, using **IP Groups**. This allows to make changes on predefined address group, which is attached to predefined security policy rule.
|
||||
|
||||
When this playbook gets triggered and it performs below actions:
|
||||
|
||||
1. Gets a list of malicious IP address.
|
||||
2. For each IP address in the list, checks if IP address in blocked in security policy rule or not.
|
||||
3. If IP address is blocked in security policy rule, then it unblocks that IP address.
|
||||
4. If IP address is not blocked in security policy rule, then it blocks that IP address.
|
||||
|
||||
![PAN-OS](./Images/PlaybookdesignerLight.png)<br>
|
||||
![PAN-OS](./Images/PlaybookdesignerDark.png)<br>
|
||||
|
||||
### Prerequisites
|
||||
1. PaloAlto connector needs to be deployed prior to the deployment of this playbook under the same subscription and same resource group. Capture the name of Connector during deployment. Relevant instructions can be found in the connector doc page.
|
||||
2. Generate an API key.[Refer this link on how to generate the API Key](https://paloaltolactest.trafficmanager.net/restapi-doc/#tag/key-generation)
|
||||
3. Address group should be created for PAN-OS and this should be used while creating playbooks.
|
||||
4. Security policy rule should be created in PAN-OS.
|
||||
|
||||
### Deploy Custom Connector
|
||||
|
||||
To deploy Palo Alto PAN-OS Custom connector click on the below button.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FPaloAlto-PAN-OS%2FPaloAltoCustomConnector%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FPaloAlto-PAN-OS%2FPaloAltoCustomConnector%2Fazuredeploy.json)
|
||||
|
||||
|
||||
### Deployment instructions
|
||||
1. Deploy the playbook by clicking on "Deploy to Azure" button. This will take you to deploying an ARM Template wizard.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-IP%2FPaloAlto-PAN-OS-BlockIP-Nested-Remediation%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-IP%2FPaloAlto-PAN-OS-BlockIP-Nested-Remediation%2Fazuredeploy.json)
|
||||
|
||||
|
||||
2. Fill in the required parameters:
|
||||
|
||||
|Parameter|Description|
|
||||
|------------|---------------|
|
||||
|**Playbook Name**|Enter the playbook name here (e.g. PaloAlto-PAN-OS-Remediation)|
|
||||
|**PAN-OS Connector name**|Enter the name of PAN-OS Connector captured during deployment.|
|
||||
|**Address group name**|Enter the predefined address group name here to Block IP / Unblock IP.|
|
||||
|
||||
|
||||
### Post-Deployment instructions
|
||||
#### Authorize connections
|
||||
Once deployment is complete, you will need to authorize PAN-OS API connection.
|
||||
1. Click the PAN-OS connection resource
|
||||
2. Click edit API connection
|
||||
3. Provide API key
|
||||
4. Click Save
|
||||
|
||||
|
||||
|
||||
## Playbook steps explained
|
||||
|
||||
### When the playbook is triggered
|
||||
|
||||
The playbook receives list of malicious IP addresses as the input.
|
||||
|
||||
### Initialize variables
|
||||
|
||||
a. Action Name (type-String) - To store action name as block IP or unblock IP
|
||||
|
||||
b. Address group Members(type-Array) - To store list of address group members
|
||||
|
||||
c. Address action (type-object) - To store address action in case of success or failure
|
||||
|
||||
d. IP Address Action(type-Array) - To store action taken against each IP
|
||||
|
||||
### Lists all address objects
|
||||
Lists all the address objects present in the firewall
|
||||
|
||||
### Lists all security rules
|
||||
Lists all the security policy rules present in the firewall
|
||||
|
||||
### For each-malicious IP
|
||||
Iterates on the IPs found in this incident (probably one) and performs the following:
|
||||
|
||||
#### Filter array of IP address from list of address objects
|
||||
This filters the list of address objects in which IP is a member
|
||||
|
||||
#### Lists all address object groups
|
||||
Lists all the address object groups present in the firewall
|
||||
|
||||
#### Sets variable address group members
|
||||
This assign list of address group members
|
||||
|
||||
#### Compose configured address group
|
||||
This composes predefined address group
|
||||
|
||||
###Filter array IP from list of security rules
|
||||
Filter array list of security rules in which IP is a member
|
||||
|
||||
###Condition to check if the IP present in list of address objects
|
||||
|
||||
a) If IP is present in list of address objects
|
||||
|
||||
* Condition to check if IP present in predefined address group
|
||||
|
||||
i) If IP present in predefined address group then unreference that IP from the address group. Set action name as UnblockIP.
|
||||
|
||||
ii) If IP not present in predefined address group then append that IP into address group members. Set action name as BlockIP.
|
||||
|
||||
b) If IP address is not present in list of address objects then append that IP address to address group member and set action name as BlockIP.
|
||||
|
||||
###Condition to check if IP needs to be blocked
|
||||
|
||||
a) If IP needs to be blocked then create new address object for that malicious IP and update the address object group.
|
||||
|
||||
b) If IP need not be blocked, then simply update the address object group.
|
||||
|
||||
###Update the address action variable according to success or failure.
|
||||
|
||||
###Response from playbook is sent to master playbook to generate incident comments.
|
||||
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"metadata": {
|
||||
"title": "PlaybookName",
|
||||
"description": "Description",
|
||||
"mainSteps": [
|
||||
"When a new incident is created:",
|
||||
"1. step",
|
||||
"2. step"
|
||||
],
|
||||
"prerequisites": [ "1.preq", "2. preq" ],
|
||||
"lastUpdateTime": "0000-00-00T00:00:00.000Z",
|
||||
"entities": [ "IP" ],
|
||||
"tags": [ "Remediation" ],
|
||||
"support": {
|
||||
"tier": "community"
|
||||
},
|
||||
"author": {
|
||||
"name": "Author"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"PlaybookName": {
|
||||
"defaultValue": "PlaybookName",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Name of the playbook (Logic Apps resource) which will be created"
|
||||
}
|
||||
},
|
||||
"ConnectorName": {
|
||||
"defaultValue": "ConnectorName",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Name of the connector (Logic Apps custom connector resource) which will be created"
|
||||
}
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"LogicAppConnectorConnectionName": "[concat('LogicAppConnector-', parameters('PlaybookName'))]"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.Web/connections",
|
||||
"apiVersion": "2016-06-01",
|
||||
"name": "[variables('LogicAppConnectorConnectionName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"customParameterValues": {},
|
||||
"api": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/customApis/',parameters('ConnectorName'))]"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Logic/workflows",
|
||||
"apiVersion": "2017-07-01",
|
||||
"name": "[parameters('PlaybookName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Web/connections', variables('LogicAppConnectorConnectionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"state": "Enabled",
|
||||
"definition": {
|
||||
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"defaultValue": {},
|
||||
"type": "Object"
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
"manual": {
|
||||
"type": "Request",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"Hosts": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"Hostname": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"Hostname"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"runtimeConfiguration": {
|
||||
"concurrency": {
|
||||
"runs": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"Condition_to_check_the_scope": {
|
||||
"actions": {
|
||||
"Response": {
|
||||
"runAfter": {},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "@outputs('Compose_HTTP_Response')",
|
||||
"statusCode": 200
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Filter_array": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"actions": {
|
||||
"Compose_HTTP_Failed_Resposne": {
|
||||
"runAfter": {
|
||||
"Create_HTML_table": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Compose",
|
||||
"inputs": "Compose Http Response by including a. logo of the product b. playbook name c. Table which contains the host and actions information."
|
||||
},
|
||||
"Create_HTML_table": {
|
||||
"runAfter": {
|
||||
"Scope_output": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "MethodName",
|
||||
"value": "@item()?['name']"
|
||||
},
|
||||
{
|
||||
"header": "Error",
|
||||
"value": "@item()?['error']?['message']"
|
||||
},
|
||||
{
|
||||
"header": "Status",
|
||||
"value": "@item()?['status']"
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": "@outputs('Scope_output')"
|
||||
}
|
||||
},
|
||||
"Response_if_playbook_get(s)_failed": {
|
||||
"runAfter": {
|
||||
"Compose_HTTP_Failed_Resposne": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"body": "@outputs('Compose_HTTP_Failed_Resposne')",
|
||||
"statusCode": 500
|
||||
},
|
||||
"operationOptions": "Asynchronous"
|
||||
},
|
||||
"Scope_output": {
|
||||
"runAfter": {},
|
||||
"type": "Compose",
|
||||
"inputs": "@body('Filter_array')"
|
||||
}
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"and": [
|
||||
{
|
||||
"lessOrEquals": [
|
||||
"@length(body('Filter_array'))",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If"
|
||||
},
|
||||
"Filter_array": {
|
||||
"runAfter": {
|
||||
"Scope": [
|
||||
"Succeeded",
|
||||
"TimedOut",
|
||||
"Skipped",
|
||||
"Failed"
|
||||
]
|
||||
},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@result('Scope')",
|
||||
"where": "@equals(item()?['status'], 'Failed')"
|
||||
}
|
||||
},
|
||||
"Scope": {
|
||||
"actions": {
|
||||
"Create_HTML_table_-_IP_devices": {
|
||||
"type": "Table",
|
||||
"inputs": {
|
||||
"columns": [
|
||||
{
|
||||
"header": "Host",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"header": "Action",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"format": "HTML",
|
||||
"from": [
|
||||
{
|
||||
"Host": "",
|
||||
"Action": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Compose": {
|
||||
"type": "Compose",
|
||||
"inputs": "<img src=\"https://avatars.githubusercontent.com/u/2071378?s=280&v=4\" alt=\"Lamp\" width=\"32\" height=\"32\">"
|
||||
},
|
||||
"Compose_HTTP_Response": {
|
||||
"type": "Compose",
|
||||
"inputs": "Compose Http Response by including a. logo of the product b. playbook name c. Table which contains the host and actions information."
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
},
|
||||
"type": "Scope"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"value": {
|
||||
"LogicAppConnector": {
|
||||
"connectionId": "[resourceId('Microsoft.Web/connections', variables('LogicAppConnectorConnectionName'))]",
|
||||
"connectionName": "[variables('LogicAppConnectorConnectionName')]",
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/customApis/',parameters('ConnectorName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,622 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"metadata": {
|
||||
"title": "Block IP Nested Remediation - Master Playbook",
|
||||
"description": "This playbook checks if malicious IP address is blocked or unblocked by Security Policy Rule for each of its nested playbooks.",
|
||||
"mainSteps": [
|
||||
"1. Fetches a list of potentially malicious IP addresses.",
|
||||
"2. Each nested playbook receives the list of IP addresses and performs respective defined automated actions on it.",
|
||||
"3. Response from individual playbooks are returned to master playbook for incident comment. "
|
||||
],
|
||||
"prerequisites": [
|
||||
"Atlease one of the below mentioned nested playbooks must be deployed prior to deployment of this playbook under same subscription and same resource group. Capture the name of all deployed playbooks during deployment.",
|
||||
"- AzureFirewall-BlockIP-Nested-Remediation is a nested playbook that handles remidiation for Azure Firewall.",
|
||||
"- Forcepoint-BlockIP-Nested-Remediation is a nested playbook that handles remidiation for Forcepoint.",
|
||||
"- Fortinet-BlockIP-Nested-Remediation is a nested playbook that handles remidiation for Fortinet.",
|
||||
"- Meraki-BlockIP-Nested-Remediation is a nested playbook that handles remidiation for Meraki.",
|
||||
"- PaloAlto-PAN-OS-BlockIP-Nested-Remediation is a nested playbook that handles remidiation for Palo Alto PAN-OS."
|
||||
],
|
||||
"lastUpdateTime": "2021-08-09T00:00:00.000Z",
|
||||
"entities": [ "IP" ],
|
||||
"tags": [ "Remediation" ],
|
||||
"support": {
|
||||
"tier": "community"
|
||||
},
|
||||
"author": {
|
||||
"name": "Accenture"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"MasterPlaybookName": {
|
||||
"defaultValue": "MasterPlaybook_IP_Remidiation",
|
||||
"type": "String",
|
||||
"metadata": {
|
||||
"description": "Enter name for master playbook without spaces"
|
||||
},
|
||||
"minLength": 3
|
||||
},
|
||||
"AzureFirewallPlaybookName": {
|
||||
"defaultValue": "",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter name for Azure Firewall playbook without spaces"
|
||||
}
|
||||
},
|
||||
"FortinetPlaybookName": {
|
||||
"defaultValue": "",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter name for Fortinet playbook without spaces"
|
||||
}
|
||||
},
|
||||
"ForcepointPlaybookName": {
|
||||
"defaultValue": "",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter name for Forcepoint playbook without spaces"
|
||||
}
|
||||
},
|
||||
"CiscoMerakiPlaybookName": {
|
||||
"defaultValue": "",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter name for Cisco Meraki playbook without spaces"
|
||||
}
|
||||
},
|
||||
"PaloAltoPAN-OSPlaybookName": {
|
||||
"defaultValue": "",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Enter name for PaloAlto PAN-OS playbook without spaces"
|
||||
}
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"AzureSentinelConnectionName": "[concat('azuresentienl-',parameters('MasterPlaybookName'))]",
|
||||
"Defaultplaybookname": "MSDefaultNestedPlaybook",
|
||||
"ForcepointID": "[if(not(empty(parameters('ForcepointPlaybookName'))),parameters('ForcepointPlaybookName'),variables('Defaultplaybookname'))]",
|
||||
"FortinetID": "[if(not(empty(parameters('FortinetPlaybookName'))),parameters('FortinetPlaybookName'),variables('Defaultplaybookname'))]",
|
||||
"AzureFirewallID": "[if(not(empty(parameters('AzureFirewallPlaybookName'))),parameters('AzureFirewallPlaybookName'),variables('Defaultplaybookname'))]",
|
||||
"MerakiID": "[if(not(empty(parameters('CiscoMerakiPlaybookName'))),parameters('CiscoMerakiPlaybookName'),variables('Defaultplaybookname'))]",
|
||||
"PANOSID": "[if(not(empty(parameters('PaloAltoPAN-OSPlaybookName'))),parameters('PaloAltoPAN-OSPlaybookName'),variables('Defaultplaybookname'))]"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"apiVersion": "2017-07-01",
|
||||
"condition": "[or(empty(parameters('ForcepointPlaybookName')),empty(parameters('AzureFirewallPlaybookName')),empty(parameters('CiscoMerakiPlaybookName')),empty(parameters('FortinetPlaybookName')),empty(parameters('PaloAltoPAN-OSPlaybookName')))]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[variables('Defaultplaybookname')]",
|
||||
"properties": {
|
||||
"state": "Enabled",
|
||||
"definition": {
|
||||
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"defaultValue": {},
|
||||
"type": "Object"
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
"manual": {
|
||||
"type": "Request",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"Response": {
|
||||
"runAfter": {},
|
||||
"type": "Response",
|
||||
"kind": "Http",
|
||||
"inputs": {
|
||||
"statusCode": 200
|
||||
}
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"parameters": {}
|
||||
},
|
||||
"type": "Microsoft.Logic/workflows"
|
||||
},
|
||||
{
|
||||
"type": "MICROSOFT.WEB/CONNECTIONS",
|
||||
"apiVersion": "2016-06-01",
|
||||
"name": "[variables('AzureSentinelConnectionName')]",
|
||||
"kind": "V1",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"displayName": "[variables('AzureSentinelConnectionName')]",
|
||||
"customParameterValues": {},
|
||||
"parameterValueType": "Alternative",
|
||||
"api": {
|
||||
"id": "[concat('/subscriptions/',subscription().subscriptionId,'/providers/Microsoft.Web/locations/',resourceGroup().location,'/managedApis/azuresentinel')]"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Logic/workflows",
|
||||
"apiVersion": "2017-07-01",
|
||||
"name": "[parameters('MasterPlaybookName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]",
|
||||
"[resourceId('Microsoft.Logic/workflows', variables('Defaultplaybookname'))]"
|
||||
],
|
||||
"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",
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"defaultValue": {},
|
||||
"type": "Object"
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
"When_Azure_Sentinel_incident_creation_rule_was_triggered": {
|
||||
"type": "ApiConnectionWebhook",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"callback_url": "@{listCallbackUrl()}"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"path": "/incident-creation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"Azure_Firewall_Scope": {
|
||||
"actions": {
|
||||
"Add_comment_to_incident_for_Azure_Firewall": {
|
||||
"runAfter": {
|
||||
"Azure-Firewall-Block-IP-to-IP-Group": [
|
||||
"Succeeded",
|
||||
"Failed",
|
||||
"Skipped",
|
||||
"TimedOut"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"incidentArmId": "@triggerBody()?['object']?['id']",
|
||||
"message": "<p>@{body('Azure-Firewall-Block-IP-to-IP-Group')}</p>"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/Incidents/Comment"
|
||||
}
|
||||
},
|
||||
"Append_Azure_Firewall_status_code": {
|
||||
"runAfter": {
|
||||
"Add_comment_to_incident_for_Azure_Firewall": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "StatusCodes",
|
||||
"value": "@outputs('Azure-Firewall-Block-IP-to-IP-Group')['statusCode']"
|
||||
}
|
||||
},
|
||||
"Azure-Firewall-Block-IP-to-IP-Group": {
|
||||
"runAfter": {},
|
||||
"type": "Workflow",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"IPs": "@body('Entities_-_Get_IPs')?['IPs']"
|
||||
},
|
||||
"host": {
|
||||
"triggerName": "manual",
|
||||
"workflow": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name ,'/providers/Microsoft.Logic/workflows/', variables('AzureFirewallID'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Initialize_variable_for_playbook_status_code": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
},
|
||||
"Condition_to_check_any_one_of_the_playbook_failed_before_closing_the_incident": {
|
||||
"actions": {
|
||||
"Update_incident": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"classification": {
|
||||
"ClassificationAndReason": "TruePositive - SuspiciousActivity"
|
||||
},
|
||||
"incidentArmId": "@triggerBody()?['object']?['id']",
|
||||
"status": "Closed"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "put",
|
||||
"path": "/Incidents"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Filter_success_status_code": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"expression": {
|
||||
"or": [
|
||||
{
|
||||
"lessOrEquals": [
|
||||
"@length(body('Filter_success_status_code'))",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "If",
|
||||
"description": "Condition to check playbook status variable has value"
|
||||
},
|
||||
"Entities_-_Get_IPs": {
|
||||
"runAfter": {},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": "@triggerBody()?['object']?['properties']?['relatedEntities']",
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/entities/ip"
|
||||
},
|
||||
"runtimeConfiguration": {
|
||||
"staticResult": {
|
||||
"staticResultOptions": "Disabled",
|
||||
"name": "Entities_-_Get_IPs0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Filter_success_status_code": {
|
||||
"runAfter": {
|
||||
"Azure_Firewall_Scope": [
|
||||
"Succeeded"
|
||||
],
|
||||
"Forcepoint_Scope": [
|
||||
"Succeeded"
|
||||
],
|
||||
"Fortinet_FortiGate_Scope": [
|
||||
"Succeeded"
|
||||
],
|
||||
"Meraki_Scope": [
|
||||
"Succeeded"
|
||||
],
|
||||
"PAN-OS_Scope": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Query",
|
||||
"inputs": {
|
||||
"from": "@variables('StatusCodes')",
|
||||
"where": "@not(equals(item(), 200))"
|
||||
}
|
||||
},
|
||||
"Forcepoint_Scope": {
|
||||
"actions": {
|
||||
"Add_comment_to_incident_for_Forcepoint": {
|
||||
"runAfter": {
|
||||
"Forcepoint-Block-IP-Address": [
|
||||
"Succeeded",
|
||||
"Failed",
|
||||
"Skipped",
|
||||
"TimedOut"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"incidentArmId": "@triggerBody()?['object']?['id']",
|
||||
"message": "<p>@{body('Forcepoint-Block-IP-Address')}</p>"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/Incidents/Comment"
|
||||
}
|
||||
},
|
||||
"Append_Forcepoint_status_code": {
|
||||
"runAfter": {
|
||||
"Add_comment_to_incident_for_Forcepoint": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "StatusCodes",
|
||||
"value": "@outputs('Forcepoint-Block-IP-Address')['statusCode']"
|
||||
}
|
||||
},
|
||||
"Forcepoint-Block-IP-Address": {
|
||||
"runAfter": {},
|
||||
"type": "Workflow",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"IPs": "@body('Entities_-_Get_IPs')?['IPs']"
|
||||
},
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"host": {
|
||||
"triggerName": "manual",
|
||||
"workflow": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name ,'/providers/Microsoft.Logic/workflows/', variables('ForcepointID'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Initialize_variable_for_playbook_status_code": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
},
|
||||
"Fortinet_FortiGate_Scope": {
|
||||
"actions": {
|
||||
"Add_comment_to_incident_for_Fortinet": {
|
||||
"runAfter": {
|
||||
"Fortinet-FortiGate-Block-IP-Address": [
|
||||
"Succeeded",
|
||||
"Failed",
|
||||
"Skipped",
|
||||
"TimedOut"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"incidentArmId": "@triggerBody()?['object']?['id']",
|
||||
"message": "<p>@{body('Fortinet-FortiGate-Block-IP-Address')}</p>"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/Incidents/Comment"
|
||||
}
|
||||
},
|
||||
"Append_Fortinet_status_code": {
|
||||
"runAfter": {
|
||||
"Add_comment_to_incident_for_Fortinet": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "StatusCodes",
|
||||
"value": "@outputs('Fortinet-FortiGate-Block-IP-Address')['statusCode']"
|
||||
}
|
||||
},
|
||||
"Fortinet-FortiGate-Block-IP-Address": {
|
||||
"runAfter": {},
|
||||
"type": "Workflow",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"IPs": "@body('Entities_-_Get_IPs')?['IPs']"
|
||||
},
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"host": {
|
||||
"triggerName": "manual",
|
||||
"workflow": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name ,'/providers/Microsoft.Logic/workflows/', variables('FortinetID'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Initialize_variable_for_playbook_status_code": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
},
|
||||
"Initialize_variable_for_playbook_status_code": {
|
||||
"runAfter": {
|
||||
"Entities_-_Get_IPs": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "InitializeVariable",
|
||||
"inputs": {
|
||||
"variables": [
|
||||
{
|
||||
"name": "StatusCodes",
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "To store playbook status"
|
||||
},
|
||||
"Meraki_Scope": {
|
||||
"actions": {
|
||||
"Add_comment_to_incident_for_Meraki": {
|
||||
"runAfter": {
|
||||
"Meraki-Block-IP-Address": [
|
||||
"Succeeded",
|
||||
"Failed",
|
||||
"Skipped",
|
||||
"TimedOut"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"incidentArmId": "@triggerBody()?['object']?['id']",
|
||||
"message": "<p>@{body('Meraki-Block-IP-Address')}</p>"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/Incidents/Comment"
|
||||
}
|
||||
},
|
||||
"Append_Meraki_status_code": {
|
||||
"runAfter": {
|
||||
"Add_comment_to_incident_for_Meraki": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "StatusCodes",
|
||||
"value": "@outputs('Meraki-Block-IP-Address')['statusCode']"
|
||||
}
|
||||
},
|
||||
"Meraki-Block-IP-Address": {
|
||||
"runAfter": {},
|
||||
"type": "Workflow",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"IPs": "@body('Entities_-_Get_IPs')?['IPs']"
|
||||
},
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"host": {
|
||||
"triggerName": "manual",
|
||||
"workflow": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name ,'/providers/Microsoft.Logic/workflows/', variables('MerakiID'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Initialize_variable_for_playbook_status_code": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
},
|
||||
"PAN-OS_Scope": {
|
||||
"actions": {
|
||||
"Add_comment_to_incident_for_PaloAlto_PAN-OS": {
|
||||
"runAfter": {
|
||||
"PaloAlto-PAN-OS-Block-IP-Address": [
|
||||
"Succeeded",
|
||||
"Failed",
|
||||
"Skipped",
|
||||
"TimedOut"
|
||||
]
|
||||
},
|
||||
"type": "ApiConnection",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"incidentArmId": "@triggerBody()?['object']?['id']",
|
||||
"message": "<p>@{body('PaloAlto-PAN-OS-Block-IP-Address')}</p>"
|
||||
},
|
||||
"host": {
|
||||
"connection": {
|
||||
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
|
||||
}
|
||||
},
|
||||
"method": "post",
|
||||
"path": "/Incidents/Comment"
|
||||
}
|
||||
},
|
||||
"Append_PAN-OS_status_code": {
|
||||
"runAfter": {
|
||||
"Add_comment_to_incident_for_PaloAlto_PAN-OS": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "AppendToArrayVariable",
|
||||
"inputs": {
|
||||
"name": "StatusCodes",
|
||||
"value": "@outputs('PaloAlto-PAN-OS-Block-IP-Address')['statusCode']"
|
||||
}
|
||||
},
|
||||
"PaloAlto-PAN-OS-Block-IP-Address": {
|
||||
"runAfter": {},
|
||||
"type": "Workflow",
|
||||
"inputs": {
|
||||
"body": {
|
||||
"IPs": "@body('Entities_-_Get_IPs')?['IPs']"
|
||||
},
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"host": {
|
||||
"triggerName": "manual",
|
||||
"workflow": {
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name ,'/providers/Microsoft.Logic/workflows/', variables('PANOSID'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"runAfter": {
|
||||
"Initialize_variable_for_playbook_status_code": [
|
||||
"Succeeded"
|
||||
]
|
||||
},
|
||||
"type": "Scope"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
"parameters": {
|
||||
"$connections": {
|
||||
"value": {
|
||||
"azuresentinel": {
|
||||
"connectionId": "[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]",
|
||||
"connectionName": "[variables('AzureSentinelConnectionName')]",
|
||||
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]",
|
||||
"connectionProperties": {
|
||||
"authentication": {
|
||||
"type": "ManagedServiceIdentity"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
# Master Playbook Block IP Remediation
|
||||
|
||||
Master playbook is integrated with multiple firewall end products like AzureFirewall ,Forcepoint ,Fortinet-Fortigate, Cisco Meraki and PaloAlto-PAN-OS.
|
||||
|
||||
Firewall end products are deployed as child/nested playbooks.
|
||||
|
||||
If a malicious IP is detected from the Azure sentinel, master playbook calls all the child/nested playbooks and each firewall product will take remidiation steps needed on that Ip Address and comments will be passed on the master playbook from the child/nested playbooks involving multiple products.
|
||||
|
||||
## Summary
|
||||
When a new Azure Sentinel incident is created, this playbook gets triggered and performs the below actions:
|
||||
1. Fetches a list of potentially malicious IP addresses.
|
||||
2. Each nested playbook receives the list of IP addresses and performs respective defined automated actions on it.
|
||||
3. Response from individual playbooks are returned to master playbook for incident comment.
|
||||
|
||||
![Master](./Images/PlaybookDesignerLight.png)
|
||||
|
||||
![Master](./Images/PlaybookDesignerDark.png)
|
||||
|
||||
|
||||
## Pre-requisites for deployment
|
||||
Atlease one of the below mentioned nested playbooks must be deployed prior to deployment of this playbook under same subscription and same resource group and the same location/region. Capture the name of all the deployed playbooks during deployment.
|
||||
|
||||
- [AzureFirewall-BlockIP-Nested-Remediation](/MasterPlaybook-IP-Remediation/AzureFirewall-BlockIP-Nested-Remediation/azuredeploy.json) is a nested playbook that handles remidiation for AzureFirewall.
|
||||
- [Forcepoint-BlockIP-Nested-Remediation](/MasterPlaybook-IP-Remediation/ForcepointNGFW-BlockIP-Nested-Remediation/azuredeploy.json) is a nested playbook that handles remidiation for Forcepoint.
|
||||
- [Fortinet-BlockIP-Nested-Remediation](/MasterPlaybook-IP-Remediation/Fortinet-BlockIP-Nested-Remediation/azuredeploy.json) is a nested playbook that handles remidiation for Fortinet.
|
||||
- [Meraki-BlockIP-Nested-Remediation](/MasterPlaybook-IP-Remediation/Meraki-BlockIP-Nested-Remediation/azuredeploy.json) is a nested playbook that handles remidiation for Meraki.
|
||||
- [PaloAlto-PAN-OS-BlockIP-Nested-Remediation](/MasterPlaybook-IP-Remediation/PaloAlto-PAN-OS-BlockIP-Nested-Remediation/azuredeploy.json) is a nested playbook that handles remidiation for PaloAlto.
|
||||
|
||||
If any one of the above mentioned playbooks are not deployed then default playbook will deploy in its place.
|
||||
|
||||
## Nested Playbook Structure
|
||||
|
||||
### Input Schema
|
||||
|
||||
Each of the nested playbooks of IP Remediation accepts following inputs:
|
||||
- IPs: List of IPs as entities from azure sentinel incident.
|
||||
- Workflow: Worklfow is identifier for the nested playbook which points to which subscription and which resource group the nested playbook belongs to.
|
||||
- Trigger: Tells how the playbook is invoked/triggered.
|
||||
- Headers: Tells the content type of entity accepting by nested playbook.
|
||||
|
||||
The image below shows example of input schema for CiscoMeraki nested playbook.
|
||||
|
||||
![Master](./Images/InputSchema.PNG)
|
||||
|
||||
### Output Schema
|
||||
|
||||
Each of the nested playbooks of IP Remediation gives following outputs:
|
||||
|
||||
- Status code: Status code tells the success or failure status of nested playbook run results. The status code value is displayed in incident comment.
|
||||
- Body: Body provides with all the output values that nested playbook returns. It varies according to the nested playbook.
|
||||
- Incident Comment: It contains output body from nested playbook in tabular format.
|
||||
|
||||
For example, taking reference of CiscoMeraki incident comment image below, CiscoMeraki logo is composed for incident comment.
|
||||
Also, table is populated with values such as Incident IP address, Source, Source Port, Destination, Destination Port, Policy, Protocol, Previous status, Current status and Action.
|
||||
|
||||
![Master](./Images/IncidentComment.png)
|
||||
|
||||
|
||||
## Add new playbook to master playbook
|
||||
|
||||
To add new nested playbook to master playbook:
|
||||
- Hover below action "Initialize variable playbook status Codes".
|
||||
- Click on symbol '+' for insert a new step and choose add a parallel branch.
|
||||
- First action is to add scope. Within scope add new action and choose the nested playbook to add.
|
||||
- Compose Incident Comment.
|
||||
- Append the status code from nested playbook to Status Codes variable .
|
||||
|
||||
![Master](./Images/AddNestedPlaybook.PNG)
|
||||
|
||||
|
||||
## Deployment Instructions
|
||||
1. Deploy the playbook by clicking on the "Deploy to Azure" button. This will take you to deploy an ARM Template wizard.
|
||||
|
||||
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-IP%2FMasterPlaybook-IP-Remediation%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Ftree%2Fmaster%2FMasterPlaybooks%2FRemediation-IP%2FMasterPlaybook-IP-Remediation%2Fazuredeploy.json)
|
||||
|
||||
|
||||
2. Fill in the required parameters for deploying the playbook.
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------- | ------------- |
|
||||
| **Playbook Name** | Enter the master playbook name here without spaces. |
|
||||
| **Azure Firewall Playbook Name**|Enter the name of Azure Firewall Nested playbook without spaces. |
|
||||
| **Forcepoint Playbook Name** | Enter the name of Forcepoint Nested playbook without spaces. |
|
||||
| **Fortinet Playbook Name**| Enter the name of Fortinet Nested playbook without spaces. |
|
||||
| **Cisco Meraki Playbook Name**|Enter the name of Meraki Nested playbook without spaces.|
|
||||
| **Palo Alto PAN-OS Playbook Name**|Enter the name of PaloAlto PAN OS Nested playbook without spaces.|
|
||||
|
||||
|
||||
# Post-Deployment Instructions
|
||||
|
||||
### Configurations in Sentinel
|
||||
- In Azure sentinel analytical rules should be configured to trigger an incident with IP addresses.
|
||||
- Configure the automation rules to trigger the playbook which calls multiple nested playbooks.
|
||||
|
||||
# Playbook steps explained
|
||||
## When Azure Sentinel incident creation rule is triggered
|
||||
Captures potentially malicious or malware IP addresses incident information.
|
||||
|
||||
##Entities - Get IPs
|
||||
Get the list of IPs as entities from the Incident.
|
||||
|
||||
## For malicious IP addresses received from the incident
|
||||
1. The list of IP address is passed as Entity to each of the nested playbook.
|
||||
2. Each nested playbook accepts IP list as entity from master playbook and respectively performs defined automated actions(Block/Unblock IP) for each IP address.
|
||||
3. The response from each of the nested playbook is returned to master playbook.
|
||||
4. Response from each nested playbook is attached to incident comment and consolidated incident comment is created.
|
||||
5. If all the nested playbooks returns success response , the incident will be closed.
|
||||
|
||||
**Incident Comment**
|
||||
|
||||
![Master](./Images/IncidentCommentLight.png)
|
||||
![Master](./Images/IncidentCommentDark.png)
|
||||
|
||||
**Incident Comment for error handling**
|
||||
|
||||
![Master](./Images/IncidentCommentLight1.png)
|
||||
![Master](./Images/IncidentCommentDark1.png)
|