Technical Tip: Updating a FortiManager local external resource feed from a FortiAnalyzer playbook
Description
This article describes how to use a FortiAnalyzer playbook, triggered by an event handler, to update a FortiManager local external resource feed.
Scope
FortiAnalyzer v7.6, v8.0, FortiManager, FortiGate.
Solution
This example uses an administrator who fails to log in to a FortiGate. The login generates a system event log with the following Log ID: 0100032002.
The workflow is:
An administrator logs in to the FortiGate.
The FortiGate sends the log to FortiAnalyzer.
A FortiAnalyzer Alert/Event Handler detects the event.
The Alert/Event Handler triggers a playbook.
The playbook creates an incident.
The playbook retrieves the current external resource feed from FortiManager.
The playbook checks whether the source IP is already present.
If the source IP is not present, the playbook appends it and updates the feed.
If the source IP is already present, the feed is not modified, and the incident is updated accordingly.
Note: A FortiManager API set request replaces the complete content of the external resource file. It does not automatically append a new entry. Therefore, the playbook must first retrieve the current content and include it in the subsequent set request.
Download pre-built Playbooks from the GitHub repository Update IP Feed on FortiManager.
Topology:

Create a FortiManager API Administrator.
Create an API Admin user in FortiManager, refer to Creating administrators for the FortiManager API, set JSON API Access to 'Read-Write', and set the FortiAnalyzer IP address as a trusted host. Keep the API safe, as it will be used later.
Create the External Resource Feed.
In FortiManager, navigate to FortiGuard -> External Resources -> Files -> Create/Import an external resource file named: test_feed.txt.
The external resource feed can be referenced by a FortiGate firewall policy or security profile as required.

Create the FortiManager API Connector in FortiAnalyzer.
Under FortiAnalyzer -> Incidents & Alerts (old versions: Incidents & Events) -> Automation -> Active Connectors -> Create new -> Select 'Generic Connector':
Name | FortiManager_API |
Protocol | HTTPS |
Port | 443, or the configured FortiManager administrative HTTPS port |
Method | POST |
URL | https://<FortiManager_IP_OR_FQDN>/jsonrpc |
Custom HTTP Header | Enable |
Status | Enable |
Configure these HTTP headers:
Content-Type | application/json |
Authorization | Bearer <FortiManager API KEY FROM STEP_1> |

Create the FortiAnalyzer Alert (Event) Handler.
Under FortiAnalyzer -> Incidents & Alerts -> Alert Handler (Event Handler) -> Create New:
Status | Enable |
Name | FortiGate_Login |
Handler Type | Basic |
Under Rules, select Add New Rule and configure:
Status | Enable |
Name | Login |
Severity | Select as required |
Log Device Type | FortiGate |
Log Type | Event Log |
Log Subtype | System |
Log Field / Group By |
|
Under Log Filters, configure:
Log Field | Log ID |
Match Criteria | Equal To |
Value | 0100032002 |
Set the alert to trigger when a group contains one or more log occurrences within one minute. Save the rule and the handler.

Create a FortiAnalyzer playbook.
Under FortiAnalyzer -> Incidents & Alerts -> Automation -> Playbook -> Create New -> Select New Playbook created from scratch. Name the playbook: Update_IP_Feed_on_FMG. Enable the playbook after all tasks have been configured.
Playbook workflow:

Playbook Step 1: Alert Trigger.
Choose Trigger: Alert Trigger.
Add condition -> 'Basic Handler Name' Equal To 'FortiGate_Login'. Select Save.

Playbook Step 2: Retrieve the current feed content.
Select the '+' icon to the right of the ALERT_TRIGGER step to add a new step.
Select Webhook -> FortiManager_API -> POST Request.
Name: Get_Current_Feed_Content
HTTP Body -> Select the 'A' icon to switch to text mode and set the following API call (the 'test_feed.txt' is the name of the External Resource list created in FortiManager), then select SAVE.
{
 "id": 1,
 "method": "get",
 "params": [
   {
     "url": "pm/config/global/_external/resource/test_feed.txt"
   }
 ],
 "verbose": 1
}
Playbook Step 3: Update feed on FortiManager.
Select the '+' icon to the right of the POST Request (Get_Current_Feed_Content) step to add a new step.
Select Webhook -> FortiManager_API -> POST Request.
Name: Update_IP_Feed_on_FMG.
HTTP Body: Select the 'A' icon to switch to text mode and set the following API call:
{
"id": 2,
"method": "set",
"params": [
{
"data": {
"content": "${get_current_feed_content.response.result[0].data.content}
${trigger.groupby1}"
},
"url": "pm/config/global/_external/resource/test_feed.txt"
}
]
}
Here, get_current_feed_content.response is the Task ID of the Get_Current_Feed_Content step and ${get_current_feed_content.response.result[0].data.content} refers to the 'content' field - in the API response of 'Get_Current_Feed_Content', which fetches the current list of IP addresses present in the Feed.
The trigger is the Task ID of the first Trigger step of the playbook and {trigger.group1} refers to the Log Field option of the Alert Rule, which was set to 'Source IP'.

Note:
FortiAnalyzer v7.6 may not allow the visible task name to be used directly as the task ID, except for the initial trigger task. Refer to the Configuring tasks using variables section 'Obtaining task IDs'.
For example, to obtain the task ID of the 'Get_Current_Content' step:
In the 'Update_IP_Feed_on_FMG' step in the 'body' field drop down select 'Get_Current_Content', and the next drop down will automatically populate with 'response'.
Select the 'A' icon to switch to text mode. It will show the task ID like: placeholder_15f3b0d8_b6fb_4e99_9a4a_0928141f1f5d.response.
Use that in the API call above.
Playbook Step 4: Check whether the IP already exists.
Check if the IP address is already present in the IP Feed in FortiManager. Use the Switch Operator for comparison.
Between the two Post Requests, Get_Current_Feed_Content and Update_IP_Feed_on_FMG select the '+' icon -> LocalHost -> Select Switch Operator:
Name: Check_if_IP_already_exist.
Under 'Condition', set the following Jinja script, which returns TRUE if the source IP from the alert is not already present:
{%- set feed = get_current_feed_content.response.result[0].data.content | default('') -%}
{%- set ip = trigger.groupby1 | string | trim -%}
{{- ip not in feed.splitlines() -}}Next Task: Update_Feed_on_FMG.
Label: IP Check.
Select Save.

Note:
The FortiAnalyzer v7.6 does not have the 'Switch Operator' action; instead, use the 'Branch Operator' action:
lvalue | ${<step_id of Get_Current_Feed_Content Step>.response.result[0].data.content} |
rvalue | ${trigger.groupby1} |
type | string |
comparison | contains |
task_for_check_pass | <step_id of Update_Incident Step> |
task_for_check_fail | <step_id of Update_IP_Feed_on_FMG Step> |

To obtain the task IDs, refer to the document Configuring tasks using variables.
Playbook Step 5: Create Incident.
Under the ALERT_TRIGGER step, add a new step by dragging the arrow.
Select LocalHost -> Create Incident:
Name | src_ip. |
Incident Name | Select the 'A' icon to switch to text mode and enter Feed_Update_{{trigger.groupby1}}. For v7.6 just set ${trigger.groupby1}. Here, 'trigger.groupby1' refers to the first Log Field option of the Alert Rule, which was set to 'Source IP'. |
Endpoint | Playbook Starter -> groupby2. Here, 'groupby2' refers to the second Log Field option of the Alert Rule, which was set to 'Device ID and VDOM'. |
Category | Select any or create a new. |
Severity | High. |
Status | New. |
Description | Alert/Event Triggered. |
Connect the Create_Incident step with the Switch_Operator step.

Playbook Step 6: Update incident - IP already exists.
Below the Switch_Operator (Branch Operator) step, add a new step by dragging the arrow -> Select LocalHost -> Update Incident:
Name | IP_Already_Exist. |
Incident ID | src_ip -> incident_id. |
Category | Select as required. |
Endpoint | Playbook Starter -> groupby2 |
Severity | High |
Status | Closed: Remediated |
Description | IP is already present in the Feed. |

Edit the Switch_Operator step again and set Fallback: IP_Already_Exist.
Playbook Step 7: Update Incident - IP added to list.
Under the Update_IP_Feed_on_FMG step, add a new step by dragging the arrow -> Select LocalHost -> Update Incident:
Name | IP_Added_to_List. |
Incident ID | src_ip -> incident_id. |
Category | Select as required. |
Endpoint | ${trigger.groupby2} |
Severity | High |
Status | Closed: Remediated |
Description | IP added to FortiManager Feed. |

Name the Playbook: Update_IP_Feed_on_FortiManager, toggle the Enabled button, and select OK to save the playbook.
Verification:
To trigger the playbook, attempt a failed login to the FortiGate.
Check the Playbook status: Incidents & Alerts -> Automation -> Playbook Monitor.
Check the incident: Incidents & Alerts -> Incidents.
Check the External Resource list on FortiManager -> FortiGuard -> External Resource -> Files to verify the list has been updated with the new IP address.

Related documents:
