FortiGate (FortiOS REST API)
Connect a FortiGate's management API with a read-only REST API admin: what the agents read, what the estate harvest draws, and the read gate. Drafted from Fortinet's public docs.
How-to · Updated 2026-10-28 · Describes release 0.1.164
Drafted from Fortinet's public documentation, then validated against a FortiGate-VM running FortiOS 8.0.2 in October 2026: the read-only REST API admin, the estate harvest (device, interfaces, routes, address objects, policies with hit counts) and the traffic log read below. Other FortiOS versions may answer differently; Sources lists the public docs. When your device answers differently, the harvest notes and the agent's evidence say so.
Overview
A FortiGate connection reads the firewall's management API, never its data path: the Incident agent looks up which policy a flow meets, whether traffic really hits it (the policy hit counters), interface and route state and the recent denies in the traffic log, and the estate harvest puts the firewall, its interfaces and the traffic its policies allow on the estate map, each policy with its hit count and last use. FortiGate on AWS runs as a VM on EC2; connect the management interface, the one its REST API admins log in to.
A built-in skill, fortigate-flow-check, walks the agent through a flow that crosses the firewall. The agent sees it only in a workspace with a FortiGate connection.
Setup
Before you start
- The
datasources.managepermission; the built-in owner and operator roles carry it. - A REST API admin on the FortiGate whose administrator profile is read-only (Installation), and its API key.
- A network path from the platform to the management URL, or a private-network agent where the platform cannot reach it. The trusted host on the REST API admin must be the address the platform or the agent connects from.
Installation
On the FortiGate:
- Choose a read-only administrator profile. The built-in
super_admin_readonlygives generic read-only access. For a narrower one, create a profile and set every area the agent reads toRead: firewall (policy, address, service), network (interfaces, routing), system, and log & report. Set every other area toNone. No area may beRead/Write, and do not usesuper_admin. - Go to
System > Administrators, selectCreate New > REST API Admin, give it a name such asaiops-reader, assign the profile, and add a trusted host for the address the platform or your private-network agent connects from (FortiOS does not accept0.0.0.0/0there). A REST API admin of its own keeps the platform's calls apart from people's logins in the FortiGate's logs. - Select
OKand copy the API key: FortiOS shows it once. The CLI equivalent isconfig system api-userwithset accprofileand aconfig trusthostentry, thenexecute api-user generate-key <name>.
The platform sends the key as Authorization: Bearer <key>, the header FortiOS recommends. It never sends it as access_token in the URL, where it would land in web server and proxy logs; FortiOS accepts that only with set rest-api-key-url-query enable under config system global, which the platform does not need. The read gate below is a floor, not a substitute for a read-only profile.
Configuration
- Open Settings · Data in → Data sources and select Connect datasource.
- Under Type, choose FortiGate (FortiOS REST API). Enter a Connection name; the connected list shows it, and the agent's tool is named after it (
<name>_request). - Fill the fields; the TLS-skip field sits under Advanced connection settings:
| Field (portal label) | API key | Value |
|---|---|---|
| Management URL (https://<fortigate>[:<admin port>], without /api/v2) | url |
The management interface, with the admin port when it is not 443 |
| REST API admin token (read-only admin profile) | api_key |
The REST API admin's key; stored write-only |
| VDOM (optional — blank = the REST API admin's own VDOM) | vdom |
Set only on a multi-VDOM unit; the harvest sends it as ?vdom= |
| Skip TLS verify for a self-signed cert (optional — type: true) | insecure |
true for the factory self-signed management certificate |
- Optionally, open Optional · describe this environment and say in What should AIOps know about it? what the firewall protects and which VDOM matters.
- Under Use this connection for, choose Investigate only and select Connect and verify.
The same connection through the API (POST /api/aiops/{tenant_id}/datasources, requires datasources.manage; the key goes in secret_values):
{
"type_key": "fortigate",
"name": "edge-fgt",
"description": "Internet edge FortiGate-VM in the shared-services VPC; port1 is WAN, port2 the app subnets.",
"config": {
"url": "https://fortigate.example.com",
"vdom": "root",
"insecure": "true"
},
"secret_values": {
"api_key": "<REST API admin key>"
},
"role": "read",
"enabled": true
}
Validation
Connect and verify, and Test on the row later, sends a GET to /api/v2/monitor/system/status (the API's get system status) with the key as Authorization: Bearer. You should see a dialog titled <connection name> is connected with Connected — verified from the control plane, and later in the row's Last test ok · HTTP 200 /api/v2/monitor/system/status — {"http_method":"GET","results":{…. A 401 means the key is wrong or the platform's address is not a trusted host; a 403 means the profile does not read system.
If something fails
The dialog shows Needs a fix, what to fix and the check's own detail; the row is saved either way. Select Edit, correct the field the detail names and save again, or select Retry once a cause outside the form (network, trusted host, profile) is fixed. Every verdict this connector produces is in Troubleshooting below.
Data collected
Tools the agent gets
<name>_traffic_log— one page of the traffic log, read-only:source(memory, the default, ordisk),subtype(forward, the default,local,multicastorsniffer), up to fourfiltersANDed (field<op>valuewith==,!=,=@,!@,<=,>=,<or>, for exampledstip==10.0.1.5),rows(at most 100) andstart(the answer'snext_startreads the next page). A search the firewall is still running is read again with its session, at most three times. Each row keeps the flow fields (time, action, policy, interfaces, addresses, ports, service, application, bytes, duration); who sent it (user, group, device name, MAC address, OS) is never returned, and the rest is scrubbed like every tool output, with your workspace's own PII settings. It sendsGET /api/v2/log/<source>/traffic/<subtype>: the REST API admin's profile needs read access to the logs. That request (memory, forward,rows, asrcip==filter, the VDOM) answered on FortiOS 8.0.2; the tool's paging and its re-read of a search still running have not run on a device yet.<name>_request— the HTTP tool against the management URL with the key:method,path,query,body,content_type. The skill usesGET /api/v2/monitor/firewall/policy-lookup(which policy a flow meets),GET /api/v2/cmdb/firewall/policy/<id>,GET /api/v2/monitor/firewall/policywithpolicyid(that policy's hit counters:hit_count,bytes,first_used,last_usedin epoch seconds),GET /api/v2/cmdb/firewall/address/<name>,GET /api/v2/monitor/router/lookupand/api/v2/monitor/router/ipv4,GET /api/v2/monitor/system/interfaceandGET /api/v2/log/memory/traffic/forwardwith afilter(diskin place ofmemoryon a unit that logs to disk).
Responses are capped at 20,000 characters per call.
Read surface
Only GET reads. POST, PUT, DELETE and even HEAD are refused in an investigation, never offered for approval: Investigation connections are read-only. This operation was not executed; prepare an incident change using a write connection and obtain approval. Some GETs return secrets and are refused too: the configuration backup (/api/v2/monitor/system/config/backup) and the tables that hold credentials — system/admin, system/api-user, user/local, vpn.ipsec/phase1 and phase1-interface, vpn.certificate/local. A request that carries access_token in its query is refused as well: the key belongs in the header. Clearing the policy counters is a POST and so refused. The full rule table is under The read/write gate in detail in Connections and remediation access.
Estate harvest
Harvest now on the row, the daily inventory job and an estate x-ray scan read six GETs: monitor/system/status, cmdb/system/interface, cmdb/firewall/address, monitor/firewall/policy (the policy hit counters), cmdb/firewall/policy and monitor/router/ipv4. They become:
- one Firewall node named after the hostname, carrying the vendor, model, FortiOS version and build, serial and the counts of policies (allow, deny, disabled), interfaces, address objects and routes;
- one interface node per interface, with its address, subnet (
cidr), status, role and the route destinations that leave through it; - one policy node per enabled
acceptpolicy, linked to its destination interfaces (applies to) and source interfaces (allows from), with its sources and destinations summarised asname=valuefrom the address objects, its services, andworld_openwhen the source isall. The rules then derive that the destination interface is reachable from the source one, which is the traffic the firewall lets through. Each policy node also carries its usage:hit_countandbytes(the IPv4 and IPv6 counters added up),first_usedandlast_usedin UTC.last_usedreadsneverfor a policy with no hit since its counters were last cleared: an allow rule nothing uses, worth a rule review. When the profile cannot read the counters, the harvest notes the refusal and the policies carry no usage at all, which means unknown, not unused. The counters move with traffic, so the scan report's estate changes never list them as a change; - one policy node per enabled
denypolicy, with itsaction, its sources, destinations and services and the same usage, but no link to an interface and noworld_open: a deny never reads as traffic the firewall lets through. Anipsecpolicy, which sends traffic into a VPN tunnel, is drawn the same way, without interface links.
Deny policies are drawn with their action and usage and no interface links; disabled policies are counted, not drawn. Interfaces and policies are leaf detail: on the Estate map (in the product: /portal/estate) they show when you tick Show every object, rules and interfaces included or focus the firewall. The firewall counts for the map's firewall check and the x-ray report's Firewall line, and an enabled FortiGate connection counts on its own before the first harvest. A denied or failed read is a note on the harvest, never a crash, and what it would have listed is not marked stale. Not read yet: zones (a policy that names a zone keeps the name in its props), address groups and VIPs. A FortiGate VM the AWS harvest also lists as an instance is joined to it by address (an interface's address is the private address of the instance or of one of its network interfaces): it counts as one firewall, and its row in a service group carries the enabled policies and the connection that read them. An address two instances or two firewalls hold joins nothing.
Troubleshooting
| What you see | Cause | What to do |
|---|---|---|
failed · HTTP 401 /api/v2/monitor/system/status |
The key is wrong, or the platform's address is not a trusted host of the REST API admin. | Check the trusted host first, then regenerate the key and replace it on Edit. |
failed · HTTP 403 /api/v2/monitor/system/status |
The administrator profile does not read system. | Set system to Read in the profile. |
failed · HTTP 404 /api/v2/monitor/system/status |
The URL already ends in /api/v2, or points at a port that is not the admin port. |
Enter the management root only, with the admin port. |
failed · ConnectError: … or a certificate error |
Wrong port, a management interface the platform cannot reach, or the self-signed certificate. | Use the admin port, a private-network agent, or insecure: true. |
The harvest notes HTTP 403 on one listing (fortigate GET /api/v2/cmdb/firewall/policy: …) |
The profile does not read that area. | Set the area to Read; the next harvest fills it in. |
A POST, PUT or a config backup answers Investigation connections are read-only. |
The write gate. | Expected. |
The generic verdict strings are explained in Test a connection and read the failure. Every connection status word is in the status and error reference.
Next steps
- Choose Harvest now on the connection's row in Data sources (in the product:
/portal/datasources) to draw the firewall on the map: Estate harvest. - Select Discover this connection in the success dialog to find the services behind the firewall: Launch a scan.
- Give approved firewall changes their own credential: Write connections and approved fixes.
Sources
- REST API administrator (least privilege,
super_admin_readonly, trusted hosts, the key shown once,config system api-user): https://docs.fortinet.com/document/fortigate/7.4.6/administration-guide/399023/rest-api-administrator - The key as
Authorization: Bearer, recommended over the URL query and itsrest-api-key-url-querysetting: https://docs.fortinet.com/document/fortigate/7.6.5/administration-guide/940602 - The key as
Authorization: Bearerand themonitor/system/statusanswer: https://community.fortinet.com/fortigate-3/technical-tip-python-script-example-for-fortigate-rest-api-211989 - The policy hit counters (
monitor/firewall/policy) read by a separate REST API admin: https://community.fortinet.com/fortigate-3/technical-tip-testing-the-fortigate-rest-api-to-pull-firewall-policy-hit-count-and-other-cmdb-monitor-data-using-a-windows-batch-script-230279; their fields and epoch-second times as a device printed them: https://community.fortinet.com/support-forum-92/fortigate-api-date-format-82 - Policy, interface and address fields: https://ansible-galaxy-fortios-docs.readthedocs.io/en/latest/gen/fortios_firewall_policy.html, https://ansible-galaxy-fortios-docs.readthedocs.io/en/latest/gen/fortios_system_interface.html, https://ansible-galaxy-fortios-docs.readthedocs.io/en/latest/gen/fortios_firewall_address.html
- The routing table monitor (third-party client reference; the official FortiOS API reference needs a Fortinet Developer Network login): https://hfortix-fortios.readthedocs.io/en/latest/endpoints/monitor/router/ipv4.html