Collect Fortinet Firewall logs
This document explains how to collect and ingest Fortinet logs to Google Security Operations by using Bindplane. The parser extracts fields from logs, handling both JSON and SYSLOG (with key-value pair) formats. It normalizes the extracted fields into the Unified Data Model (UDM), including network connections, user activity, DNS events, and security findings, while also handling various log formats and edge cases.
Before you begin
- Ensure that you have a Google Security Operations instance.
- Ensure that you are using Windows 2016 or later, or a Linux host with
systemd
. - If running behind a proxy, ensure firewall ports are open.
- Ensure that you have privileged access to a Fortinet Firewall appliance.
Get Google SecOps ingestion authentication file
- Sign in to the Google SecOps console.
- Go to SIEM Settings > Collection Agents.
- Download the Ingestion Authentication File. Save the file securely on the system where Bindplane will be installed.
Get Google SecOps customer ID
- Sign in to the Google SecOps console.
- Go to SIEM Settings > Profile.
- Copy and save the Customer ID from the Organization Details section.
Install the Bindplane agent
Windows installation
- Open the Command Prompt or PowerShell as an administrator.
Run the following command:
msiexec /i "https://github.com/observIQ/bindplane-agent/releases/latest/download/observiq-otel-collector.msi" /quiet
Linux installation
- Open a terminal with root or sudo privileges.
Run the following command:
sudo sh -c "$(curl -fsSlL https://github.com/observiq/bindplane-agent/releases/latest/download/install_unix.sh)" install_unix.sh
Additional installation resources
- For additional installation options, consult this installation guide.
Configure the Bindplane agent to ingest Syslog and send to Google SecOps
Access the configuration file:
- Locate the
config.yaml
file. Typically, it's in the/etc/bindplane-agent/
directory on Linux or in the installation directory on Windows. - Open the file using a text editor (for example,
nano
,vi
, or Notepad).
- Locate the
Edit the
config.yaml
file as follows:```yaml receivers: udplog: # Replace the port and IP address as required listen_address: "0.0.0.0:514" exporters: chronicle/chronicle_w_labels: compression: gzip # Adjust the path to the credentials file you downloaded in Step 1 creds: '/path/to/ingestion-authentication-file.json' # Replace with your actual customer ID from Step 2 customer_id: <customer_id> endpoint: malachiteingestion-pa.googleapis.com # Add optional ingestion labels for better organization ingestion_labels: log_type: FORTINET_FIREWALL raw_log_field: body service: pipelines: logs/source0__chronicle_w_labels-0: receivers: - udplog exporters: - chronicle/chronicle_w_labels ```
Replace the port and IP address as required in your infrastructure.
Replace
<customer_id>
with the actual customer ID.Update
/path/to/ingestion-authentication-file.json
to the path where the authentication file was saved in the Get Google SecOps ingestion authentication file section.
Restart the Bindplane agent to apply the changes
To restart the Bindplane agent in Linux, run the following command:
sudo systemctl restart bindplane-agent
To restart the Bindplane agent in Windows, you can either use the Services console or enter the following command:
net stop BindPlaneAgent && net start BindPlaneAgent
Configure Syslog on FortiGate using CLI
- Sign in to the command line interface on your Fortinet FortiGate appliance.
Type the following commands in the same order (replace the variables with values that align with your environment).
sh full-configuration | grep -f syslogd config log syslogd setting set status enable set server IP_ADDRESS set mode udp set port PORT set facility LOCAL set reliable enable or disable set source-ip FIEWALL_IP end
Update the following values:
IP_ADDRESS
: enter the IPv4 address of the Bindplane agent.PORT
: enter the port number for the Bindplane agent; for example,514
.LOCAL
: set facility level as local6 (you can also select other aslocal0
,local1
,local2
,local3
,local4
,local5
, orlocal7
for informational logs).enable or disable
: enterdisable
to send data as UDP (If you set the value of reliable asenable
, it sends data as TCP).FIEWALL_IP
: enter the IPv4 address of the Firewall.
Configure Syslog on FortiGate using GUI
- Sign in to the Fortinet Fortigate web UI.
- Go to Log & Report > Log Settings.
- Edit the following configurations:
- Send logs to Syslog: select to Enable.
- IP Address / FQDN: enter the IPv4 address of the Bindplane agent.
- Event Logging: select All.
- Local Traffic Log: select All.
Go to Policy & Objects > Firewall Policy
- Enable log level to All (do not set to Disable & UTM) for every firewall policy.
- Ensure Implicit Deny policy should also be in log level All.
Open CLI and enter the following commands.
Get your firewall applicance IP:
Show full-configuration | grep -f syslogd
Set source IP & Facility:
LOCAL
: Set facility level as local6 (you can also select other aslocal0
,local1
,local2
,local3
,local4
,local5
, orlocal7
for informational logs).FIEWALL_IP
: Enter the IPv4 address of the Firewall.config log syslogd setting set source-ip FIEWALL_IP set facility LOCAL end
Enable resolve-ip for each fortigate device:
config log setting set resolve-ip enable
Repeat the process for each device which needs to be onboarded to Google SecOps.
Optional: Additional Fortigate Syslog configuration options
For FortiGate v5.X, to enable extended logs, run the following commands:
config antivirus profile edit default set extended-utm-log enable end config application edit default set extended-utm-log enable end config webfilter edit default set extended-utm-log enable end config spamfilter edit default set extended-utm-log enable end config dlp edit default set extended-utm-log enable end config ips edit default set extended-utm-log enable end
UDM Mapping Table
Log Field | UDM Mapping | Logic |
---|---|---|
action |
security_result.action_details |
The value is taken directly from the action field in the raw log. |
act |
security_result.action_details |
If the action field is empty, the value is taken from the act field in the raw log. |
agent |
network.http.user_agent , network.http.parsed_user_agent |
The value is taken from the agent field. The parsed_user_agent field is a parsed version of the user_agent field. |
appid |
security_result1.rule_id |
The value is taken from the appid field. |
app |
target.application , network.application_protocol , additional.fields |
If service field is empty, the value is taken from the app field. If service is one of HTTPS, HTTP, DNS, DHCP, or SMB, the value is used to populate network.application_protocol . Otherwise, it's used for target.application . An additional field with key app and string value of the app field is added to additional.fields . |
appact |
additional.fields |
An additional field with key appact and string value of the appact field is added to additional.fields . |
appcat |
additional.fields |
An additional field with key appcat and string value of the appcat field is added to additional.fields . |
applist |
additional.fields |
An additional field with key applist and string value of the applist field is added to additional.fields . |
apprisk |
additional.fields |
An additional field with key apprisk and string value of the apprisk field is added to additional.fields . |
attack |
security_result.category_details , security_result.threat_name , security_result.summary , security_result.detection_fields |
The value is added to security_result.category_details . For IPS/Anomaly events, it's also used for security_result.summary and security_result.threat_name . A detection field with key attack and value of the attack field is added to security_result.detection_fields . |
attackid |
security_result.threat_id , security_result1.rule_id , security_result.detection_fields |
For IPS events, the value is used for security_result.threat_id . For other events, it's used for security_result1.rule_id . A detection field with key attackId and value of the attackid field is added to security_result.detection_fields . |
cat |
security_result1.rule_id |
For webfilter events, the value is used for security_result1.rule_id . |
catdesc |
security_result.description , security_result1.rule_name , security_result.category_details |
If present, it's appended to the msg field to create the security_result.description . It's also used for security_result1.rule_name . The value is added to security_result.category_details . |
changes |
security_result.summary |
The changes field is parsed as key-value pairs. The mode value from the parsed changes is used for security_result.summary . |
connection_type |
metadata.product_event_type |
The value is appended to the metadata.product_event_type if present. |
craction |
security_result.about.labels |
A label with key craction and value of the craction field is added to security_result.about.labels . |
crlevel |
security_result.severity , event.idm.is_alert , event.idm.is_significant |
If crlevel is CRITICAL or level is alert, is_alert and is_significant are set to TRUE. The value is mapped to security_result.severity based on the following mapping: HIGH for HIGH , MEDIUM for MEDIUM , LOW for LOW , CRITICAL for CRITICAL . |
crscore |
security_result.severity_details |
For IPS events, the value is used for security_result.severity_details . |
cs6 |
principal.user.group_identifiers |
The value is added to principal.user.group_identifiers . |
date , time |
timestamp |
The date and time fields are combined and parsed to create the timestamp . |
devid |
security_result.detection_fields |
A detection field with key devid and value of the devid field is added to security_result.detection_fields . |
devname |
intermediary.hostname , target.hostname , target.asset.hostname , principal.hostname , principal.asset.hostname |
If dvchost is present, dvchost is used for intermediary.hostname . Otherwise, devname is used. For VPN events with type as event , it's used for target.hostname . For user creation events, it's used for principal.hostname . |
deviceSeverity |
level |
The value is used to populate the level field. |
device_product |
metadata.product_name |
The value is used for metadata.product_name . If not present, Fortigate is used as the default. |
device_vendor |
metadata.vendor_name |
The value is used for metadata.vendor_name . If not present, Fortinet is used as the default. |
device_version |
metadata.product_version |
The value is used for metadata.product_version . |
dhcp_msg |
network.dhcp.type , metadata.event_type , network.application_protocol |
If the value is Ack , network.dhcp.type is set to ACK , metadata.event_type is set to NETWORK_DHCP , and network.application_protocol is set to DHCP . |
dir |
direction |
If direction is empty, the value is taken from the dir field. |
direction |
network.direction |
The value is mapped to network.direction based on the following mapping: INBOUND for incoming , inbound , and response ; OUTBOUND for outgoing , outbound , and request . |
dst |
target.ip , target.asset.ip |
The value is parsed as an IP address and used for target.ip . |
dstauthserver |
target.hostname , target.asset.hostname |
The value is used for target.hostname . |
dstcountry |
target.location.country_or_region |
If the value is not Reserved or empty, it's used for target.location.country_or_region . |
dstip |
target.ip , target.asset.ip |
The value is parsed as an IP address and used for target.ip . |
dstinetsvc |
security_result.detection_fields |
A detection field with key dstinetsvc and value of the dstinetsvc field is added to security_result.detection_fields . |
dstintf |
security_result.detection_fields |
A detection field with key dstintf and value of the dstintf field is added to security_result.detection_fields . |
dstintfrole |
security_result.detection_fields |
A detection field with key dstintfrole and value of the dstintfrole field is added to security_result.detection_fields . |
dstmac |
target.mac |
The value is parsed as a MAC address and used for target.mac . |
dstosname |
target.platform |
If the value is WINDOWS , target.platform is set to WINDOWS . |
dstport |
target.port |
The value is converted to an integer and used for target.port . |
dstswversion |
target.platform_version |
The value is used for target.platform_version . |
dstuuid |
target.resource.product_object_id |
The value is used for target.resource.product_object_id . |
dstuser |
target.user.userid |
The value is used for target.user.userid . |
dtype |
security_result.category_details |
The value is added to security_result.category_details . |
duration |
network.session_duration.seconds |
If the value is not empty or 0 , it's converted to an integer and used for network.session_duration.seconds . |
duser |
principal.user.userid , target.user.userid , target.user.user_display_name |
For endpoint/system events, it's used for principal.user.userid . For user login events, it's used for target.user.userid . For CEF formatted logs, it's used for target.user.user_display_name . |
dvchost |
devname |
The value is used to replace the devname field. |
d_uid |
target.user.userid |
The value extracted from the request field is used for target.user.userid . |
error |
security_result.severity_details |
If level is error , and error is present, the value is used for security_result.severity_details . |
eventtime |
timestamp , metadata.event_timestamp |
The value is parsed to create the timestamp and metadata.event_timestamp . |
eventtype |
security_result1.rule_type , security_result.detection_fields |
The value is used for security_result1.rule_type . For IPS events, it's also used for security_result.detection_fields . |
filename |
target.file.full_path |
The value is used for target.file.full_path . |
group |
principal.user.group_identifiers |
If the value is not N/A or empty, it's added to principal.user.group_identifiers . |
hostname |
target.hostname , target.asset.hostname , principal.hostname , principal.asset.hostname |
The value is used for target.hostname . For DHCP Ack events, it's used for principal.hostname . |
httpmethod |
network.http.method |
The value is used for network.http.method . |
in |
network.received_bytes |
The value is converted to an unsigned integer and used for network.received_bytes . |
incidentserialno |
security_result.about.labels |
A label with key incidentserialno and value of the incidentserialno field is added to security_result.about.labels . |
ip |
principal.ip , principal.asset.ip , network.dhcp.yiaddr |
For endpoint/system events, the value is added to principal.ip . For DHCP Ack events, it's used for network.dhcp.yiaddr . |
ipaddr |
intermediary.ip |
The value is parsed as a comma-separated list of IP addresses and added to intermediary.ip . |
level |
security_result.severity , security_result.severity_details , event.idm.is_alert , event.idm.is_significant |
If crlevel is CRITICAL or level is alert, is_alert and is_significant are set to TRUE. The value is mapped to security_result.severity based on the following mapping: HIGH for warning , MEDIUM for notice , LOW for information and info , ERROR for error . security_result.severity_details is set to level: <value> . |
locip |
principal.ip , principal.asset.ip |
For VPN events, the value is added to principal.ip . |
locport |
dstport |
The value is used to replace the dstport field. |
logdesc |
metadata.description |
The value is used for metadata.description . |
logid |
metadata.product_log_id , additional.fields |
The value is used for metadata.product_log_id . An additional field with key logid and string value of the logid field is added to additional.fields . |
log_id |
metadata.product_log_id |
The value is used for metadata.product_log_id . |
metadata.event_type |
metadata.event_type |
The value is set based on the event type and other fields. Defaults to GENERIC_EVENT. Can be set to NETWORK_CONNECTION, USER_UNCATEGORIZED, NETWORK_HTTP, USER_LOGIN, USER_LOGOUT, NETWORK_DNS, NETWORK_DHCP, STATUS_UNCATEGORIZED, NETWORK_UNCATEGORIZED, USER_CREATION, USER_DELETION. |
metadata.log_type |
metadata.log_type |
The value is set to FORTINET_FIREWALL . |
metadata.product_event_type |
metadata.product_event_type |
The value is set to <type> - <subtype> . If connection_type is present, it's appended to the value. For CEF formatted logs, it's set to [<device_event_class_id>] - <event_name> <severity> . |
metadata.product_name |
metadata.product_name |
The value is set to Fortigate by default. If device_product is present, that value is used instead. |
metadata.product_version |
metadata.product_version |
The value is taken from the device_version field if present. |
metadata.vendor_name |
metadata.vendor_name |
The value is set to Fortinet by default. If device_vendor is present, that value is used instead. |
mode |
security_result.summary |
The value extracted from the changes field is used for security_result.summary . |
msg |
metadata.description , security_result.summary , security_result.description , security_result1.rule_name |
If logdesc is not present, the value is used for metadata.description . For system events, it's used for security_result.summary . For webfilter events, it's prepended to the security_result.description . For virus events where msg is File is infected. , it's used in conjunction with virus to populate security_result.summary . For app-ctrl events, it's used for security_result1.rule_name . |
name |
principal.hostname , principal.asset.hostname |
The value is used for principal.hostname . |
nas |
principal.nat_ip |
The value is parsed as an IP address and used for principal.nat_ip . |
operation |
security_result.action_details , security_result.action |
The value is used for security_result.action_details . It's also mapped to security_result.action based on the following mapping: ALLOW for accept , passthrough , pass , permit , detected , close , and edit ; BLOCK for deny , dropped , and blocked ; FAIL for timeout ; UNKNOWN_ACTION for other values. |
os |
principal.platform , principal.platform_version |
If the value contains Windows , principal.platform is set to WINDOWS and the version is extracted and used for principal.platform_version . |
osname |
principal.platform |
If the value is WINDOWS , principal.platform is set to WINDOWS . |
osversion |
principal.platform_version |
The value is used for principal.platform_version . |
out |
network.sent_bytes |
The value is converted to an unsigned integer and used for network.sent_bytes . |
path |
security_result.description |
The value is used for security_result.description . |
performed_on |
security_result.about.application |
The value is used for security_result.about.application . |
policyid |
security_result.rule_id |
The value is used for security_result.rule_id . |
policyname |
security_result.rule_name |
The value is used for security_result.rule_name . |
policytype |
security_result.rule_type |
The value is used for security_result.rule_type . |
poluuid |
additional.fields |
An additional field with key poluuid and string value of the poluuid field is added to additional.fields . |
pri |
security_result.severity_details |
The value is used for security_result.severity_details . |
profile |
target.resource.name , target.resource.resource_type |
The value is used for target.resource.name and target.resource.resource_type is set to ACCESS_POLICY . |
proto |
network.ip_protocol |
The value is mapped to network.ip_protocol based on the following mapping: UDP for 17 , TCP for 6 , IP6IN4 for 41 , ICMP for 1 and when service is PING or contains ICMP . |
protocol |
network.application_protocol |
If the value is udp , network.ip_protocol is set to UDP . If the value is tcp , network.ip_protocol is set to TCP . Otherwise, if not empty, it's parsed and used for network.application_protocol . |
qclass |
network.dns.questions.class |
If the value is IN , network.dns.questions.class is set to 1 . |
qname |
network.dns.questions.name |
The value is used for network.dns.questions.name . |
qtypeval |
network.dns.questions.type |
The value is converted to an unsigned integer and renamed to network.dns.questions.type . |
rcvdbyte |
network.received_bytes |
The value is converted to an unsigned integer and used for network.received_bytes . |
rcvdpkt |
additional.fields |
An additional field with key receivedPackets and string value of the rcvdpkt field is added to additional.fields . |
reason |
security_result.description |
If the value is not N/A or empty, it's used for security_result.description . |
referralurl |
network.http.referral_url |
The value is used for network.http.referral_url . |
ref |
metadata.url_back_to_product |
The value is used for metadata.url_back_to_product . |
remip |
principal.ip , principal.asset.ip |
For VPN events, the value is added to principal.ip . |
remport |
srcport |
The value is used to replace the srcport field. |
request |
target.user.userid |
If the value contains duid , the duid is extracted and used for target.user.userid . |
sentbyte |
network.sent_bytes |
The value is converted to an unsigned integer and used for network.sent_bytes . |
sentpkt |
additional.fields |
An additional field with key sentPackets and string value of the sentpkt field is added to additional.fields . |
server |
target.hostname , target.asset.hostname |
For user events, the value is used for target.hostname . |
service |
network.application_protocol , target.application |
If the value is one of HTTPS, HTTP, DNS, DHCP, or SMB, it's used for network.application_protocol . Otherwise, it's used for target.application . |
sessionid |
network.session_id |
The value is used for network.session_id . |
session_id |
network.session_id |
The value is used for network.session_id . |
severity |
security_result.severity , security_result.detection_fields |
For CEF formatted logs, the value is used for security_result.severity . A detection field with key severity and value of the severity field is added to security_result.detection_fields . |
Need more help? Get answers from Community members and Google SecOps professionals.