{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "metadata": {
        "title": "RecordedFuture-TIforDefenderEndpoint",
        "description": "This playbook leverages Recorded Future API and automatically imports the Command and Control IPs and Weaponized Domains Security Control Feeds, as Threat Intelligence Indicators, for prevention purposes in Microsoft Defender for Endpoint",
        "prerequisites": [
            "To use the Recorded Future for Azure connector, you will need a valid API token from Recorded Future as described in the documentation https://learn.microsoft.com/en-us/connectors/recordedfuturev2/#how-to-get-credentials",
            "Register an App in Microsoft Entra with API permissions for Microsoft Defender for Endpoint (WindowsDefenderATP - Ti.ReadWrite)"
        ],
        "postDeployment": [
            "After deployment you have to open the playbook to configure all connections and press save.",
            "Configure the MS Defender Client ID and Client Secret parameters with your Entra App credentials."
        ],
        "prerequisitesDeployTemplateFile": "./RecordedFuture-ImportToDefenderEndpoint.json",
        "lastUpdateTime": "2026-03-02T12:00:00.000Z",
        "entities": [],
        "tags": [ "Threat Intelligence" ],
        "support": {
            "tier": "Partner",
            "armtemplate": "Generated from https://github.com/Azure/Azure-Sentinel/tree/master/Tools/Playbook-ARM-Template-Generator"
        },
        "author": {
            "name": "Recorded Future"
        },
        "releaseNotes": [
            {
                "version": "1.0",
                "title": "RecordedFuture-TIforDefenderEndpoint",
                "notes": [ "Initial version" ]
            },
            {
                "version": "1.1",
                "title": "Changed Risk list",
                "notes": [ "Changed to risk list that are suitible for Azure. Updated documentaiton and unified connector naming." ]
            },
            {
                "version": "2.0",
                "title": "Direct MS Defender Integration",
                "notes": [ "Replaced batching workflow with direct HTTP calls to MS Defender for Endpoint API. Added OAuth authentication and indicator transformation." ]
            }
        ]
    },
    "parameters": {
        "PlaybookName": {
            "defaultValue": "RecordedFuture-TIforDefenderEndpoint",
            "type": "string"
        },
        "TenantId": {
            "type": "string",
            "defaultValue": "[subscription().tenantId]",
            "metadata": {
                "description": "Microsoft Entra Tenant ID for authentication"
            }
        },
        "MsDefenderClientId": {
            "type": "string",
            "metadata": {
                "description": "Microsoft Entra App Client ID for MS Defender for Endpoint API access"
            }
        },
        "MsDefenderClientSecret": {
            "type": "securestring",
            "metadata": {
                "description": "Microsoft Entra App Client Secret for MS Defender for Endpoint API access"
            }
        },
        "IndicatorAction": {
            "type": "string",
            "defaultValue": "Allowed",
            "allowedValues": [ "Allowed", "Audit", "Block", "BlockAndRemediate", "Warn" ],
            "metadata": {
                "description": "Action to take when indicator is matched"
            }
        },
        "GenerateAlert": {
            "type": "bool",
            "defaultValue": false,
            "metadata": {
                "description": "Whether to generate an alert when indicator is matched"
            }
        },
        "ExpirationDays": {
            "type": "int",
            "defaultValue": 30,
            "metadata": {
                "description": "Number of days until indicators expire"
            }
        }
    },
    "variables": {
        "Recordedfuturev2ConnectionName": "RecordedFuture-ConnectorV2"
    },
    "resources": [
        {
            "properties": {
                "provisioningState": "Succeeded",
                "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"
                        },
                        "TenantId": {
                            "defaultValue": "[parameters('TenantId')]",
                            "type": "String"
                        },
                        "MsDefenderClientId": {
                            "defaultValue": "[parameters('MsDefenderClientId')]",
                            "type": "String"
                        },
                        "MsDefenderClientSecret": {
                            "defaultValue": "[parameters('MsDefenderClientSecret')]",
                            "type": "SecureString"
                        },
                        "IndicatorAction": {
                            "defaultValue": "[parameters('IndicatorAction')]",
                            "type": "String"
                        },
                        "GenerateAlert": {
                            "defaultValue": "[parameters('GenerateAlert')]",
                            "type": "Bool"
                        },
                        "ExpirationDays": {
                            "defaultValue": "[parameters('ExpirationDays')]",
                            "type": "Int"
                        }
                    },
                    "triggers": {
                        "Recurrence": {
                            "recurrence": {
                                "frequency": "Hour",
                                "interval": 24
                            },
                            "evaluatedRecurrence": {
                                "frequency": "Hour",
                                "interval": 24
                            },
                            "type": "Recurrence"
                        }
                    },
                    "actions": {
                        "Authenticate_with_MS_Defender": {
                            "runAfter": {},
                            "type": "Http",
                            "inputs": {
                                "method": "POST",
                                "uri": "@{concat('https://login.microsoftonline.com/', parameters('TenantId'), '/oauth2/v2.0/token')}",
                                "headers": {
                                    "Content-Type": "application/x-www-form-urlencoded"
                                },
                                "body": "@{concat('client_id=', parameters('MsDefenderClientId'), '&client_secret=', encodeUriComponent(parameters('MsDefenderClientSecret')), '&scope=https://api.securitycenter.microsoft.com/.default&grant_type=client_credentials')}"
                            }
                        },
                        "Parse_Auth_Response": {
                            "runAfter": {
                                "Authenticate_with_MS_Defender": [
                                    "Succeeded"
                                ]
                            },
                            "type": "ParseJson",
                            "inputs": {
                                "content": "@body('Authenticate_with_MS_Defender')",
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "access_token": {
                                            "type": "string"
                                        },
                                        "token_type": {
                                            "type": "string"
                                        },
                                        "expires_in": {
                                            "type": "integer"
                                        }
                                    }
                                }
                            }
                        },
                        "Recorded_Future_-_C2_IP_download": {
                            "runAfter": {
                                "Parse_Auth_Response": [
                                    "Succeeded"
                                ]
                            },
                            "type": "ApiConnection",
                            "inputs": {
                                "host": {
                                    "connection": {
                                        "name": "@parameters('$connections')['recordedfuturev2']['connectionId']"
                                    }
                                },
                                "method": "get",
                                "path": "/fusion/files",
                                "queries": {
                                    "path": "/public/MicrosoftAzure/ip_active_c2.json"
                                }
                            }
                        },
                        "Recorded_Future_-_Weaponized_Domains_download": {
                            "runAfter": {
                                "Parse_Auth_Response": [
                                    "Succeeded"
                                ]
                            },
                            "type": "ApiConnection",
                            "inputs": {
                                "host": {
                                    "connection": {
                                        "name": "@parameters('$connections')['recordedfuturev2']['connectionId']"
                                    }
                                },
                                "method": "get",
                                "path": "/fusion/files",
                                "queries": {
                                    "path": "/public/MicrosoftAzure/domain_c2_dns.json"
                                }
                            }
                        },
                        "Transform_IP_Indicators": {
                            "runAfter": {
                                "Recorded_Future_-_C2_IP_download": [
                                    "Succeeded"
                                ]
                            },
                            "type": "Select",
                            "inputs": {
                                "from": "@body('Recorded_Future_-_C2_IP_download')",
                                "select": {
                                    "indicatorValue": "@item()?['Name']",
                                    "indicatorType": "IpAddress",
                                    "title": "@concat('Recorded Future: ', substring(coalesce(item()?['Name'], ''), 0, min(length(coalesce(item()?['Name'], '')), 50)))",
                                    "description": "@concat('Recorded Future C&C IPs - Risk Score: ', coalesce(string(item()?['Risk']), 'N/A'))",
                                    "action": "@parameters('IndicatorAction')",
                                    "severity": "@if(lessOrEquals(coalesce(item()?['Risk'], 50), 25), 'Informational', if(lessOrEquals(coalesce(item()?['Risk'], 50), 75), 'Medium', 'High'))",
                                    "expirationTime": "@addDays(utcNow(), parameters('ExpirationDays'))",
                                    "generateAlert": "@parameters('GenerateAlert')"
                                }
                            }
                        },
                        "Transform_Domain_Indicators": {
                            "runAfter": {
                                "Recorded_Future_-_Weaponized_Domains_download": [
                                    "Succeeded"
                                ]
                            },
                            "type": "Select",
                            "inputs": {
                                "from": "@body('Recorded_Future_-_Weaponized_Domains_download')",
                                "select": {
                                    "indicatorValue": "@item()?['Name']",
                                    "indicatorType": "DomainName",
                                    "title": "@concat('Recorded Future: ', substring(coalesce(item()?['Name'], ''), 0, min(length(coalesce(item()?['Name'], '')), 50)))",
                                    "description": "@concat('Recorded Future Weaponised Domains - Risk Score: ', coalesce(string(item()?['Risk']), 'N/A'))",
                                    "action": "@parameters('IndicatorAction')",
                                    "severity": "@if(lessOrEquals(coalesce(item()?['Risk'], 50), 25), 'Informational', if(lessOrEquals(coalesce(item()?['Risk'], 50), 75), 'Medium', 'High'))",
                                    "expirationTime": "@addDays(utcNow(), parameters('ExpirationDays'))",
                                    "generateAlert": "@parameters('GenerateAlert')"
                                }
                            }
                        },
                        "Combine_All_Indicators": {
                            "runAfter": {
                                "Transform_IP_Indicators": [
                                    "Succeeded"
                                ],
                                "Transform_Domain_Indicators": [
                                    "Succeeded"
                                ]
                            },
                            "type": "Compose",
                            "inputs": "@union(body('Transform_IP_Indicators'), body('Transform_Domain_Indicators'))"
                        },
                        "Initialize_Batch_Index": {
                            "runAfter": {
                                "Combine_All_Indicators": [
                                    "Succeeded"
                                ]
                            },
                            "type": "InitializeVariable",
                            "inputs": {
                                "variables": [
                                    {
                                        "name": "BatchIndex",
                                        "type": "integer",
                                        "value": 0
                                    }
                                ]
                            }
                        },
                        "Initialize_Batch_Size": {
                            "runAfter": {
                                "Initialize_Batch_Index": [
                                    "Succeeded"
                                ]
                            },
                            "type": "InitializeVariable",
                            "inputs": {
                                "variables": [
                                    {
                                        "name": "BatchSize",
                                        "type": "integer",
                                        "value": 500
                                    }
                                ]
                            }
                        },
                        "Initialize_Success_Count": {
                            "runAfter": {
                                "Initialize_Batch_Size": [
                                    "Succeeded"
                                ]
                            },
                            "type": "InitializeVariable",
                            "inputs": {
                                "variables": [
                                    {
                                        "name": "SuccessCount",
                                        "type": "integer",
                                        "value": 0
                                    }
                                ]
                            }
                        },
                        "Push_Indicators_In_Batches": {
                            "runAfter": {
                                "Initialize_Success_Count": [
                                    "Succeeded"
                                ]
                            },
                            "type": "Until",
                            "expression": "@greaterOrEquals(variables('BatchIndex'), length(outputs('Combine_All_Indicators')))",
                            "limit": {
                                "count": 100,
                                "timeout": "PT1H"
                            },
                            "actions": {
                                "Get_Current_Batch": {
                                    "runAfter": {},
                                    "type": "Compose",
                                    "inputs": "@take(skip(outputs('Combine_All_Indicators'), variables('BatchIndex')), variables('BatchSize'))"
                                },
                                "Push_Batch_to_Defender": {
                                    "runAfter": {
                                        "Get_Current_Batch": [
                                            "Succeeded"
                                        ]
                                    },
                                    "type": "Http",
                                    "inputs": {
                                        "method": "POST",
                                        "uri": "https://api.securitycenter.microsoft.com/api/indicators/import",
                                        "headers": {
                                            "Authorization": "@concat('Bearer ', body('Parse_Auth_Response')?['access_token'])",
                                            "Content-Type": "application/json"
                                        },
                                        "body": {
                                            "Indicators": "@outputs('Get_Current_Batch')"
                                        }
                                    }
                                },
                                "Increment_Success_Count": {
                                    "runAfter": {
                                        "Push_Batch_to_Defender": [
                                            "Succeeded"
                                        ]
                                    },
                                    "type": "IncrementVariable",
                                    "inputs": {
                                        "name": "SuccessCount",
                                        "value": "@length(outputs('Get_Current_Batch'))"
                                    }
                                },
                                "Increment_Batch_Index": {
                                    "runAfter": {
                                        "Increment_Success_Count": [
                                            "Succeeded"
                                        ]
                                    },
                                    "type": "IncrementVariable",
                                    "inputs": {
                                        "name": "BatchIndex",
                                        "value": "@variables('BatchSize')"
                                    }
                                }
                            }
                        },
                        "Summary": {
                            "runAfter": {
                                "Push_Indicators_In_Batches": [
                                    "Succeeded"
                                ]
                            },
                            "type": "Compose",
                            "inputs": {
                                "totalIndicators": "@length(outputs('Combine_All_Indicators'))",
                                "ipIndicators": "@length(body('Transform_IP_Indicators'))",
                                "domainIndicators": "@length(body('Transform_Domain_Indicators'))",
                                "successfullyPushed": "@variables('SuccessCount')",
                                "message": "Recorded Future indicators imported to Microsoft Defender for Endpoint"
                            }
                        }
                    },
                    "outputs": {}
                },
                "parameters": {
                    "$connections": {
                        "value": {
                            "recordedfuturev2": {
                                "connectionId": "[resourceId('Microsoft.Web/connections', variables('Recordedfuturev2ConnectionName'))]",
                                "connectionName": "[variables('Recordedfuturev2ConnectionName')]",
                                "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/Recordedfuturev2')]"
                            }
                        }
                    }
                }
            },
            "name": "[parameters('PlaybookName')]",
            "type": "Microsoft.Logic/workflows",
            "location": "[resourceGroup().location]",
            "tags": {
                "hidden-SentinelTemplateName": "RecordedFuture-TIforDefenderEndpoint",
                "hidden-SentinelTemplateVersion": "2.0"
            },
            "identity": {
                "type": "SystemAssigned"
            },
            "apiVersion": "2017-07-01",
            "dependsOn": [
                "[resourceId('Microsoft.Web/connections', variables('Recordedfuturev2ConnectionName'))]"
            ]
        },
        {
            "type": "Microsoft.Web/connections",
            "apiVersion": "2016-06-01",
            "name": "[variables('Recordedfuturev2ConnectionName')]",
            "location": "[resourceGroup().location]",
            "kind": "V1",
            "properties": {
                "displayName": "[variables('Recordedfuturev2ConnectionName')]",
                "customParameterValues": {},
                "api": {
                    "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/Recordedfuturev2')]"
                }
            }
        }
    ]
}
