The |fmg_api| is based on the JSON RPC standard.
The same HTTP body structure will be used for all kind of requests (login, provisioning, monitoring, operating, logout):
HTTP method and URL will be of the form:
POST https://<fmg_ip>/jsonrpc
HTTP body will be using the JSON RPC standard format:
{ "id": <id>, "method": "<method, could be exec, add, set, delete, etc.>", "params": [<this is where all the stuff is done], "session": <session_id> }
In the rest of this document, a request will be always represented with its payload (i.e., the HTTP method and URL, since always the same, won't be represented).
For instance:
.. tab-set::
.. tab-item:: REQUEST
.. code-block:: json
{
"id": 1,
"method": "exec",
"params": [
{
"data": [
{
"passwd": "fortinet",
"user": "admin"
}
],
"url": "sys/login/user"
}
],
"session": null,
}
A login operation is required in order to get a session ID.
This session ID will then have to be used in all subsequent |fmg_api| requests.
To login, you can use any kind of FortiManager users: locally defined or defined on some external LDAP, RADIUS, TACACS servers. 2FA is also supported (but won’t be seen in this document).
The definition of a FortiManager user has to be slightly modified with the
rpc-permit attribute in in order to be used as an |fmg_api| user:
config system admin user
edit <user>
set rpc-permit read-write
next
end
To API login a FortiManager, the |json_rpc_u| sys/login/user with
|json_rpc_m| exec can be used.
.. tab-set::
.. tab-item:: REQUEST
.. code-block:: json
{
"id": 1,
"method": "exec",
"params": [
{
"data": [
{
"passwd": "fortinet",
"user": "admin"
}
],
"url": "sys/login/user"
}
],
"session": null,
"verbose": 1
}
.. note::
- You can omit the ``session`` attribute when login in to FortiManager
- If you prefer to keep it, just set it with the ``null`` value
.. tab-item:: RESPONSE
.. code-block:: json
{
"id": 1,
"result": [
{
"status": {
"code": 0,
"message": "OK"
},
"url": "sys/login/user"
}
],
"session": "y5I9dOaJyotAoco6nY3VfUcgTwp7Alk7jib3tX5ECEv4WabzSllv9umEzfAFVJxI4azqZE9xEh3lEWLi1AOYbw=="
}
From now on, the returned session value should be used in all subsequent
|fmg_api| requests.
Starting with FortiManager 7.2.2 (#0809732), it is now possible to use a pre-defined API key or token.
The API key (or token) is obtained by:
Defining an API user in FortiManager GUI or CLI
As you can see below, an API user is a normal FortiManager user with the
user_typeattribute set toapi:config system admin user edit api_001 set user_type api set rpc-permit read-write next endNote
You still have to set the
rpc-permitattribute if you want this user to be able to operate the FortiManager using the |fmg_api|.Generating the API key using the FortiManager GUI or CLI:
Use the following FortiManager CLI command:
execute api-user generate-key api_001
It will return the API key:
New API key: 33fzwipq4amujunzgzn46mg1to9p8wbi
The generated API key is permanent (i.e., never expires).
However, you can renew it whenever you want using the FortiManager GUI or CLI as shown above.
You can now interact with the |fmg_api| without issuing an explicit login (or logout) operation.
You just need to insert the API key:
Using the
AuthorizationHTTP header with the bearer form:POST https://{{fmg_ip}}/jsonrpc HTTP/1.1 [...] Authorization: Bearer 33fzwipq4amujunzgzn46mg1to9p8wbi [...]Using the
access_tokenURL query string:POST https://fmg_ip}}/jsonrpc?access_token=33fzwipq4amujunzgzn46mg1to9p8wbi [...]
Warning
Starting with FortiManager 7.4.7/7.6.2, you can no pass the API key using the access_token query string (#1084776).
Starting with FortiManager 7.6.7/8.0.0 (#1179653), you can also specify the API
user name to be used using the access_user header as shown below:
POST https://{{fmg_ip}}/jsonrpc HTTP/1.1
[...]
Authorization: Bearer 33fzwipq4amujunzgzn46mg1to9p8wbi
access_user: {{ api_user_name }}
[...]
It mainly helps with the first request when you have multiple API users defined in FortiManager. Subsequent requests use the cache, so access_user becomes irrelevant in those cases. When handling many requests, access_user only provides a marginal benefit — most of the performance gain comes from the cached API token.
Before starting reading this section, there are some pre-requisites:
Make sure you have an IAM API User declared in the FortiCloud account hosting your FortiManager Cloud instance
Make sure you know the URL of your FortiManager Cloud instance
You can easily obtain it when you're connected to it via your browser.
Just take the URL visible in your browser, it should be something like:
https://{account_id}.{region}.fortimanager.forticloud.comFor instance:
https://123456.eu-central-1.fortimanager.forticloud.com
To API authenticate your FortiManager Cloud instance, you need to follow this multi steps process:
Get a FortiCloud Token
This step is documented :bdg-link-primary-line:`here <https://docs.fortinet.com/document/fortiauthenticator/6.1.2/rest-api-solution-guide/498666/oauth-server-token-oauth-token>`
You will need to build the following JSON payload:
{ "username": "{IAM API user's apiId}", "password": "{IAM API user's password}", "client_id": "FortiManager", "grant_type": "password" }Based on the above example, create a
forticloud_token.jsonfile using the information from your IAM API user:{ "username": "E8766032-7309-409F-902A-REDACTEDD045", "password": "a6455940eefREDACTED4a458dddcb2c2!1Aa", "client_id": "FortiManager", "grant_type": "password" }To get the FortiCloud Token using the
curlcommand:curl -s -k -X POST -H "Content-Type: application/json" \ https://customerapiauth.fortinet.com/api/v1/oauth/token/ \ -d @forticloud_token.json | jq
Note
- The
jqcommand will produce a pretty JSON output
You should obtain the following output:
{ "access_token": "srgkxUG9SqqREDACTEDK5qG27tqktk", "expires_in": 3600, "message": "successfully authenticated", "refresh_token": "jie6v6qV62REDACTEDwmL6GEcmZgst", "scope": "read write", "status": "success", "token_type": "Bearer" }- The
Your FortiCloud Token is the value in the
access_tokenattribute
Obtain a FortiManager API session ID
Like with an on-prem FortiManager instance, you need to obtain a FortiManager API session ID.
You will follow a slightly modifed Session-based authentication (see :ref:`Session based authentication`) process described in next step
Note
FortiManager Cloud doesn't support Token-based authentication (see :ref:`Token-based authentication`)
The FortiManager Cloud API base URL to be used is also slightly different than with a normal FortiManager instance. It has the following form:
https://{account_id}.{region}.fortimanager.forticloud.com/p/forticloud_jsonrpc_login/For instance:
https://123456.eu-central-1.fortimanager.forticloud.com/p/forticloud_jsonrpc_login/
The JSON payload to be used is also different than the usual JSON RPC one used when login in a normal FortiManager instance:
It has the following format:
{ "access_token": "{access_token}" }where
access_tokenis the FortiCloud Token obtained in previous step Get a FortiCloud Token
Create the fmg_cloud_login.json JSON file with following content:
{ "access_token": "srgkxUG9SqqREDACTEDK5qG27tqktk" }You can now obtain your FortiManager API session ID using the following
curlcommandcurl -s -k -X POST -H "Content-Type: application/json" \ https://123456.eu-central-1.fortimanager.forticloud.com/p/forticloud_jsonrpc_login/ \ -d @fmg_cloud_login.json --https1.1 | jq
Note
- Why using
--https1.1? Because of #0893680. - The
jqcommand will produce a pretty JSON output
You should obtain the following output:
{ "session": "/cl0oZgKn3trxIIkRJEqV09+0pqk8TwfOVz2x9wB0Vjk5Bgs+ADpIo1aREDACTEDF23qAjP+LaZg6iM19ia85w==" }- Why using
API the FortiManager Cloud!
You can now API the FortiManager Cloud using the normal base URL and JSON payload
The base URL form is like:
https://{account_id}.{region}.fortimanager.forticloud.com/jsonrpcFor instance:
https://123456.eu-central-1.fortimanager.forticloud.com/jsonrpc
The JSON payload is the normal JSON RPC payload
{ "id": 3, "method": "get", "params": [ { "url": "/cli/global/system/status" } ], "session": "{{session}}" }where
sessionis the FortiManager API session ID obtained in Obtain a FortiManager API session IDFor instance:
{ "id": 3, "method": "get", "params": [ { "url": "/cli/global/system/status" } ], "session": "/cl0oZgKn3trxIIkRJEqV09+0pqk8TwfOVz2x9wB0Vjk5Bgs+ADpIo1aREDACTEDF23qAjP+LaZg6iM19ia85w==" }
Warning
This is only applicable if a login operation using the session-based authentication was used (see :ref:`Session based authentication`).
To API logout from a FortiManager, |json_rpc_u| sys/logout with |json_rpc_m|
exec can be used.
.. tab-set::
.. tab-item:: REQUEST
.. code-block:: json
{
"id": 1,
"jsonrpc": "1.0",
"method": "exec",
"params": [
{
"url": "sys/logout"
}
],
"session": "y5I9dOaJyotAoco6nY3VfUcgTwp7Alk7jib3tX5ECEv4WabzSllv9umEzfAFVJxI4azqZE9xEh3lEWLi1AOYbw==",
"verbose": 1
}
.. tab-item:: RESPONSE
.. code-block:: json
{
"id": 1,
"result": [
{
"status": {
"code": 0,
"message": "OK"
},
"url": "sys/logout"
}
]
}
To manage Network & System settings for managed devices - all the operations performed under the Device Manager module of FortiManager - the |fmg_api| is using one of the following JSON RPC url:
For global scope settings (i.e. config global)
/pm/config/device/<device>/global/<cli>
For VDOM scope settings (i.e. config vdom):
/pm/config/device/<device>/vdom/<vdom>/<cli>
The first form (global sco[e settings) applies when you need to configure global settings like DNS, SNMP, etc.
In that case <device> refers to the device name as displayed in Device
Manager under column Device Name.
<cli> refers to the FortiGate CLI without the config keyword and where
spaces are replaced by /.
For instance, to configure the DNS settings (i.e. config system dns) of
managed device FGT1 the FMG JSON RPC url will be:
/pm/config/device/FGT1/global/system/dns
We have to use that form even if the managed device isn't having the VDOM status turned on.
Warning
Even though interfaces (i.e. config system interface) are assigned to
VDOMa, it is required to use the global scope settings form to operate them.
For instance, to configure interface port1 (i.e. config system
interface + edit port1) for managed device FGT1, the FMG JSON RPC
url will be:
/pm/config/device/FGT1/global/system/interface/port1
The second form (VDOM scope settings) has to be used when you need to configure per-VDOM settings like VPN Phase1/Phase2, Static or Dynamic Routing, etc.
In that case <device> refers to the device name as displayed in Device
Manager under column Device Name.
<vdom> refers to the VDOM name.
<cli> refers to the FortiGate CLI without the config keyword and where
spaces are replaced by /.
For instance, to manage static routes (i.e. config router static) for device
FGT1 and its VDOM vd1, the FMG JSON RPC url will be:
/pm/config/device/FGT1/vdom/vd1/router/static
FortiManager allows to install pending network and system settings changes only!
It means that no pending security settings changes (like new/edited objects or policies) will be pushed down to managed devices during the Install Device Settings operation.
The main JSON RPC url will be:
/securityconsole/install/device
The JSON RPC method will be exec (i.e. execute)
Here is an example to install pending network & system settings changes for
device FG600C-194-77, with no VDOM (i.e. default root VDOM), from ADOM
FOOBAR:
REQUEST:
{
"id": 1,
"method": "exec",
"params": [
{
"data": {
"adom": "FOOBAR",
"dev_rev_comments": "A comment",
"flags": [
"none"
],
"scope": [
{
"name": "FG600C-194-77",
"vdom": "root"
}
]
},
"url": "/securityconsole/install/device"
}
],
"session": "cEeh7eax9AbTauJpEAtapIogYlWT5IQazR1vGvw7QAKsmUy3E7ZJ4FQINA1GMSatBQTOpFZ1fceuH7UqLRYfzMJwUYo9T5/F",
"verbose": 1
}RESPONSE:
{
"id": 1,
"result": [
{
"data": {
"task": 2066
},
"status": {
"code": 0,
"message": "OK"
},
"url": "/securityconsole/install/device"
}
]
}The response contains a task ID (here it is 2066).
It is required to monitor the install progress and final status.
See section Monitoring a task.
To manage Security objects for managed devices - all the operations performed under the Policy & Objects module of FortiManager - the |fmg_api| is using the following JSON RPC url:
For objects:
/pm/config/adom/<adom>/obj/<cli>
where <adom> refers to the ADOM name.
<cli> refers to the FortiGate CLI without the config keyword and where
spaces are replaced by /.
For instance, to manage Firewall Address (i.e. config firewall address)
objects in ADOM ADOM1 the JSON RPC url will be:
/pm/config/adom/ADOM1/obj/firewall/address
For policy packages:
/pm/config/adom/<adom>/pkg/<pkg>/firewall/policy
where <adom> refers to the ADOM name.
<pkg> refers to the policy package name.
For instance, to manage policy ID 11 (i.e. config firewall policy +
edit 11) from policy package PP_001 in ADOM ADOM1, the JSON RPC url
will be:
/pm/config/adom/ADOM1/pkg/PP_001/firewall/policy/11
When triggering a policy package installation, FortiManager is installing both:
- Pending device settings (network and system settings changes) (see Managing Device Settings above)
- Pending security settings (objects and policy packages changes) (see Managing Security Settings above)
The JSON RPC url will be:
/securityconsole/install/package
with JSON RPC method being exec (i.e. execute).
For instance, to install policy package PP_FG600C-194-77 from ADOM
FOOBAR, on managed device FG600C-194-77 with no VDOM (i.e. default
root VDOM):
REQUEST:
{
"id": 1,
"method": "exec",
"params": [
{
"data": {
"adom": "CARWASH",
"flags": [
"none"
],
"pkg": "PP_FG600C-194-77",
"scope": [
{
"name": "FG600C-194-77",
"vdom": "root"
}
]
},
"url": "/securityconsole/install/package"
}
],
"session": "hJdopAeMzkgdJ6uQbfIgz48Eq+aXy8B/IvkNnrUuBbT1ni6eQ8GbrZPlUv6enG1pAXVqwS4tWmkaC13jAa0RnJBxW4xcC6xi",
"verbose": 1
}RESPONSE:
{
"id": 1,
"result": [
{
"data": {
"task": 2071
},
"status": {
"code": 0,
"message": "OK"
},
"url": "/securityconsole/install/package"
}
]
}The response contains a task ID (here it is 2071).
It is required to monitor the install progress and final status.
See section Monitoring a task.
For API calls wich could require time, FortiManager prefers to immediately return with a task ID.
This task ID can then be used to monitor the progress of the operation and also to get its final status.
The JSON RPC url will be:
/task/task/<id>
To monitor a task, the JSON RPC method get can be used.
For instance to monitor task ID 2066:
REQUEST:
{
"id": 1,
"method": "get",
"params": [
{
"url": "/task/task/2066"
}
],
"session": "lfNHxnG2uuGLwjaGiLFPvNSpeKD/0rc4bH0yiGnWK3VGpOPpAmmBY7hib9q3Wig7HGwL/hUMWdRTRYEBY4soYMHpz8ENRiMG",
"verbose": 1
}RESPONSE:
{
"id": 1,
"result": [
{
"data": {
"adom": 364,
"end_tm": 1515752051,
"flags": 0,
"history": [
{
"detail": "2018-01-12 02:13:44:start to install dev(FG600C-194-77)",
"name": "FG600C-194-77",
"percent": 0,
"vdom": null
},
{
"detail": "2018-01-12 02:13:46:init state: start to get pre-checksum",
"name": "FG600C-194-77",
"percent": 15,
"vdom": null
},
{
"detail": "2018-01-12 02:13:53:get pre-checksum state: start get diff(chkout=1)",
"name": "FG600C-194-77",
"percent": 25,
"vdom": null
},
{
"detail": "2018-01-12 02:13:53:script done state: start to FGFM install",
"name": "FG600C-194-77",
"percent": 35,
"vdom": null
},
{
"detail": "2018-01-12 02:13:55:fgfm install state: prepare to post-checksum",
"name": "FG600C-194-77",
"percent": 80,
"vdom": null
},
{
"detail": "2018-01-12 02:14:01:post-checksum state: start verification",
"name": "FG600C-194-77",
"percent": 90,
"vdom": null
},
{
"detail": "2018-01-12 02:14:06:install and save finished status=OK",
"name": "FG600C-194-77",
"percent": 100,
"vdom": null
},
{
"detail": "2018-01-12 02:13:46:Start copying shared objs to devdb, device(FG600C-194-77), vdomid(root)",
"name": "FG600C-194-77(root)[copy]",
"percent": 1,
"vdom": "root"
},
{
"detail": "2018-01-12 02:13:46:Initiate request to install to real device",
"name": "FG600C-194-77(root)[copy]",
"percent": 80,
"vdom": "root"
},
{
"detail": "2018-01-12 02:13:46:Copy to device done",
"name": "FG600C-194-77(root)[copy]",
"percent": 90,
"vdom": "root"
},
{
"detail": "2018-01-12 02:14:11:Installation to real device done",
"name": "FG600C-194-77(root)[copy]",
"percent": 100,
"vdom": "root"
}
],
"id": 2066,
"line": [
{
"detail": "install and save finished status=OK",
"err": 0,
"ip": null,
"name": "FG600C-194-77",
"oid": 366,
"percent": 100,
"state": "done",
"vdom": null
},
{
"detail": "Installation to real device done",
"err": 0,
"ip": "192.168.194.77",
"name": "FG600C-194-77(root)[copy]",
"oid": 366,
"percent": 100,
"state": "done",
"vdom": "root"
}
],
"num_done": 2,
"num_err": 0,
"num_lines": 2,
"num_warn": 0,
"percent": 100,
"pid": 26153,
"src": "install device",
"start_tm": 1515752024,
"state": "done",
"title": "Install Device",
"tot_percent": 200,
"user": "admin"
},
"status": {
"code": 0,
"message": "OK"
},
"url": "/task/task/2066"
}
]
}FortiManager is returning the whole history (or part of it if in the middle of the operation) and most importantly some global attributes that allow to figure out whether the task did succeed or not:
num_lines: The number of sub tasks; a task could be composed of multiple sub tasks. Here it is 2 meaning the Install Device Settings operation is generating two sub taskstot_percent: The progress of all the sub tasks. Here it is 200 because we have two sub tasks (2 x 100)num_err: The number of failed sub tasks. Here it is 0 meaning that the Install Device Settings task did succeednum_warn: The number of sub tasks completed with warningpercent: The global task progress
To monitor a task, it is required to get the task ID multiple times; preferably using a loop.
The loop could stop when percent is equal to 100.
The task is successful when num_err is equal to 0.
This is the art of regoupring multiple API operations in a single request.
The params attribute of the JSON RPC payload is a list.
It is possible to pass multiple elements in this list as shown in the next sessions.
Seen in #0767076.
You can use the following request to get the webfilter profiles of multiple ADOMs:
.. tab-set::
.. tab-item:: REQUEST
.. code-block:: json
{
"id": 1,
"method": "get",
"params": [
{
"url": "pm/config/adom/adom_001/obj/webfilter/profile",
"fields": [
"name"
],
"loadsub": 0
},
{
"url": "pm/config/adom/adom_002/obj/webfilter/profile",
"fields": [
"name"
],
"loadsub": 0
},
{
"url": "pm/config/adom/adom_003/obj/webfilter/profile",
"fields": [
"name"
],
"loadsub": 0
}
],
"session": "{{session_id}}"
}
To get the list of managed devices and FortiGate ADOMs:
REQUEST:
{
"id": 3,
"method": "get",
"params": [
{
"fields": [
"name"
],
"loadsub": 0,
"url": "/dvmdb/device"
},
{
"fields": [
"name"
],
"filter": [
"restricted_prds",
"==",
"fos"
],
"loadsub": 0,
"url": "/dvmdb/adom"
}
],
"session": "tCnuMMWQhq0rT4oEROMN5I5v5U+k3Ody1wBvcSHOZ9iyOJRbTlwIlRzTngW7CfLnmZ6Gtd2KpUw6YRqtFeuFwQ=="
}RESPONSE:
{
"id": 3,
"result": [
{
"data": [
{
"name": "fgt_dc1",
"oid": 164
},
{
"name": "fgt_dc2",
"oid": 227
}
],
"status": {
"code": 0,
"message": "OK"
},
"url": "/dvmdb/device"
},
{
"data": [
{
"name": "adom_dc1",
"oid": 160
},
{
"name": "adom_dc2",
"oid": 162
},
{
"name": "root",
"oid": 3
},
{
"name": "rootp",
"oid": 10
}
],
"status": {
"code": 0,
"message": "OK"
},
"url": "/dvmdb/adom"
}
]
}To get the firewall policy statistics for all managed devices belonging to ADOM
dc_emea along with all available interfaces for all managed managed devices
belonging to ADOM dc_amer:
REQUEST:
{
"id": 1,
"method": "exec",
"params": [
{
"data": {
"action": "get",
"resource": "/api/v2/monitor/firewall/policy",
"target": [
"/adom/dc_emea/group/All_FortiGate"
]
},
"url": "/sys/proxy/json"
},
{
"data": {
"action": "get",
"resource": "/api/v2/monitor/system/available-interfaces?format=name|ipv4_addresses",
"target": [
"/adom/dc_amer/group/All_FortiGate"
]
},
"url": "/sys/proxy/json"
}
],
"session": "{{session}}"
}RESPONSE:
{
"id": 1,
"result": [
{
"data": [
{
"response": {
"action": "",
"build": 1255,
"http_method": "GET",
"name": "policy",
"path": "firewall",
"results": [
{
"active_sessions": 0,
"asic_bytes": 0,
"asic_packets": 0,
"bytes": 0,
"packets": 0,
"policyid": 0,
"software_bytes": 0,
"software_packets": 0
}
],
"serial": "FGVMMLTM23000162",
"status": "success",
"vdom": "root",
"version": "v7.2.2"
},
"status": {
"code": 0,
"message": "OK"
},
"target": "dut_fgt_03"
},
{
"response": {
"action": "",
"build": 234,
"http_method": "GET",
"name": "policy",
"path": "firewall",
"results": [
{
"1_week_ipv4": {
"bytes": [
9073,
246710,
117978,
0,
0,
0,
0,
0
],
"hit_count": [
82,
2281,
1092,
0,
0,
0,
0,
0
],
"packets": [
83,
2281,
1092,
0,
0,
0,
0,
0
]
},
"active_sessions": 0,
"bytes": 374481,
"first_used": 1673472304,
"hit_count": 3465,
"last_used": 1674124082,
"packets": 3466,
"policyid": 0
},
{
"active_sessions": 0,
"bytes": 0,
"packets": 0,
"policyid": 1,
"uuid": "d5da7da8-81ef-51ed-613b-60e3503a06a1"
},
{
"active_sessions": 0,
"bytes": 0,
"packets": 0,
"policyid": 2,
"uuid": "b2cfeacc-90f5-51ed-12ba-ca7a5af8e4a7"
}
],
"serial": "FGVMMLTM22006608",
"status": "success",
"vdom": "root",
"version": "v7.0.2"
},
"status": {
"code": 0,
"message": "OK"
},
"target": "dut_fgt_01"
}
],
"status": {
"code": 0,
"message": "OK"
},
"url": "/sys/proxy/json"
},
{
"data": [
{
"response": {
"action": "",
"build": 1255,
"http_method": "GET",
"name": "available-interfaces",
"path": "system",
"results": [
{
"name": "any"
},
{
"ipv4_addresses": [
{
"cidr_netmask": 23,
"ip": "10.210.35.104",
"netmask": "255.255.254.0"
}
],
"name": "port1"
},
{
"ipv4_addresses": [
{
"cidr_netmask": 24,
"ip": "10.2.0.1",
"netmask": "255.255.255.0"
}
],
"name": "port2"
},
{
"name": "port3"
},
{
"name": "port4"
},
{
"name": "naf.root"
},
{
"name": "l2t.root"
},
{
"name": "ssl.root"
},
{
"ipv4_addresses": [
{
"cidr_netmask": 24,
"ip": "10.255.1.1",
"netmask": "255.255.255.0"
}
],
"name": "fortilink"
},
{
"name": "virtual-wan-link"
}
],
"revision": "1674589859.651219",
"serial": "FGVMMLTM23000178",
"status": "success",
"vdom": "root",
"version": "v7.2.2"
},
"status": {
"code": 0,
"message": "OK"
},
"target": "dut_fgt_04"
},
{
"response": {
"action": "",
"build": 1390,
"http_method": "GET",
"name": "available-interfaces",
"path": "system",
"results": [
{
"name": "any"
},
{
"ipv4_addresses": [
{
"cidr_netmask": 23,
"ip": "10.210.35.105",
"netmask": "255.255.254.0"
}
],
"name": "port1"
},
{
"ipv4_addresses": [
{
"cidr_netmask": 27,
"ip": "172.18.0.30",
"netmask": "255.255.255.224"
}
],
"name": "port2"
},
{
"ipv4_addresses": [
{
"cidr_netmask": 24,
"ip": "10.3.0.1",
"netmask": "255.255.255.0"
}
],
"name": "port3"
},
{
"name": "port4"
},
{
"name": "naf.root"
},
{
"name": "l2t.root"
},
{
"name": "ssl.root"
},
{
"ipv4_addresses": [
{
"cidr_netmask": 24,
"ip": "10.255.1.1",
"netmask": "255.255.255.0"
}
],
"name": "fortilink"
},
{
"ipv4_addresses": [
{
"cidr_netmask": 32,
"ip": "172.16.255.253",
"netmask": "255.255.255.255"
}
],
"name": "HUB1-Lo"
},
{
"name": "virtual-wan-link"
}
],
"revision": "1674589859.655205",
"serial": "FGVMMLTM22002644",
"status": "success",
"vdom": "root",
"version": "v7.2.4"
},
"status": {
"code": 0,
"message": "OK"
},
"target": "dut_fgt_05"
},
{
"response": {
"action": "",
"build": 1390,
"http_method": "GET",
"name": "available-interfaces",
"path": "system",
"results": [
{
"name": "any"
},
{
"ipv4_addresses": [
{
"cidr_netmask": 23,
"ip": "10.210.35.102",
"netmask": "255.255.254.0"
}
],
"name": "port1"
},
{
"name": "naf.root"
},
{
"name": "l2t.root"
},
{
"name": "ssl.root"
},
{
"ipv4_addresses": [
{
"cidr_netmask": 24,
"ip": "10.255.1.1",
"netmask": "255.255.255.0"
}
],
"name": "fortilink"
},
{
"name": "virtual-wan-link"
}
],
"revision": "1674589859.656882",
"serial": "FGVMMLTM22006609",
"status": "success",
"vdom": "root",
"version": "v7.2.4"
},
"status": {
"code": 0,
"message": "OK"
},
"target": "dut_fgt_02"
}
],
"status": {
"code": 0,
"message": "OK"
},
"url": "/sys/proxy/json"
}
]
}FortiManager JSON API can work with both numerical and symbolic or (human readable) values.
For instance, to create a host firewall address we can specify the type in two ways:
Numerical:
"type": 0
Symbolic:
"type": "ipmask"
The symbolic form is obviously more intuitive and when used, it produces more readable and easier to understand code.
It works for any provisioning operations made with the FortiManager JSON API
(method: add, update, set, etc.).
However, when retrieving (i.e., method is get) objects, FortiManager
returns by default a JSON output with numerical values.
With the verbose attribute set, you can instruct FortiManager to return
objects using the symbolic way.
The verbose attribute can be placed in the JSON RPC request as shown below:
{
"id": 1,
"verbose": 1,
"method": "get",
"params": [ ... ],
"session": "..."
}
This section is to explain some important mechanism related to tables, their objects, and their attributes.
This section aims to clarify a common issue that arises, particularly for those new to using the FortiManager API. Often, when you add new entries to a table or delete existing ones, other existing entries may unexpectedly be removed.
In FortiManager, a table refers to a structured configuration entity that holds a collection of related entries. For example, firewall.address and firewall.addrgrp are tables that manage firewall address objects and address groups, respectively. Below are their API paths:
/pm/config/adom/{adom}/obj/firewall/address
/pm/config/adom/{adom}/obj/firewall/addrgrp
TBD.
The capability to unset a specific attribute was added in FMG 5.4.1 (#0365372).
To unset the IP address the dmz interface from managed device TEST-FGT:
REQUEST:
{
"id": 1,
"method": "set",
"params": [
{
"data": {
"name": "dmz",
"unset attrs": [
"ip"
]
},
"url": "pm/config/device/TEST-FGT/global/system/interface"
}
],
"session": "w4KqkMrExJNUibihOZakWE/0j8VCeKGP1MbeG3Pne6ac5m5FBSJuBd20uuocfPHUZJGzYA/N10ZPTjWmPbJ9AA==",
"verbose": 1
}RESPONSE:
{
"id": 1,
"result": [
{
"status": {
"code": 0,
"message": "OK"
},
"url": "pm/config/device/TEST-FGT/global/system/interface"
}
]
}Sometimes, it seems just enough to unset an attribute by ommiting it when
doing the set (captured in #891341).
In following example, to unset the secondary attribute of a System Template,
you just need to set the System Template without mentioning the attribute:
.. tabs::
.. tab:: REQUEST
.. code-block:: json
{
"session": "{{sess_id}}",
"method": "set",
"params": [
{
"data": {
"seq": 1,
"value": {
"alt-primary": "0.0.0.0",
"alt-secondary": "0.0.0.0",
"cache-notfound-responses": 0,
"dns-cache-limit": 5000,
"dns-cache-ttl": 1800,
"domain": null,
"interface": null,
"interface-select-method": 0,
"ip6-primary": "::",
"ip6-secondary": "::",
"log": 0,
"primary": "192.168.199.230",
"protocol": 1,
"retry": 2,
"server-hostname": null,
"server-select-method": 1,
"source-ip": "0.0.0.0",
"ssl-certificate": "Fortinet_Factory",
"timeout": 5
},
},
"url": "pm/config/adom/SF70/devprof/system_branch_default_78/device/template/widget/dns/action-list"
}
]
}
A normal administrator is a user with attribute
system.admin.user.user_type different than api, sso or group.
On the FortiManager side, you have to define an API user and assign it at least two things:
- A permission profile,
- A
system.admin.user.rpc-permitvalue.
When rpc-permit is none, the API user can simply not log in to
FortiManager:
REQUEST:
{
"id": 1,
"method": "exec",
"params": [
{
"data": {
"user": "devops",
"passwd": "fortinet"
},
"url": "/sys/login/user"
}
],
"session": null
}RESPONSE:
{
"id": 1,
"result": [
{
"status": {
"code": -11,
"message": "No permission for the resource"
},
"url": "/sys/login/user"
}
]
}When rpc-permit is read, the API user cannot read-write anything, even
if associated permission profile allows read-write permission:
For instance, the API user associated with permission profile Super_User but
with rpc-permit set to read can't create a new firewall address:
REQUEST:
{
"id": 3,
"method": "add",
"params": [
{
"data": {
"name": "host_1001",
"subnet": "10.0.0.2/32"
},
"url": "/pm/config/adom/dc_amer/obj/firewall/address"
}
],
"session": "nMMf3m/6Pp28Azuhx/3PT/JinJT74r8zHNZ/a7BV9vKoklrpB4ca66y7uR20KDi31acSTKOSFf4bH1COB6mKDA=="
}RESPONSE:
{
"id": 3,
"result": [
{
"status": {
"code": -11,
"message": "No permission for the resource"
},
"url": "/pm/config/adom/dc_amer/obj/firewall/address"
}
],
"session": 13807
}It is also applicable if the API user attempts to add a firewall object directly
in the managed device using the sys/proxy/json:
REQUEST:
{
"id": 3,
"method": "exec",
"params": [
{
"data": {
"action": "post",
"payload": {
"color": 13,
"name": "host_1006",
"subnet": "10.0.0.6/32"
},
"resource": "/api/v2/cmdb/firewall/address",
"target": [
"/adom/dc_amer/device/dut_fgt_03"
]
},
"url": "/sys/proxy/json"
}
],
"session": "TJSY8zbQOyMSVsZxIU4xL5Tj3es06do42OVDi2MVmattWPhxpDhpVIy4C0VbvNwt02Z+SOErU1Nb/2geB18jHg=="
}RESPONSE:
{
"id": 3,
"result": [
{
"status": {
"code": -11,
"message": "No permission for the resource"
},
"url": "/sys/proxy/json"
}
]
}(Benefit of #0601553)
Of course, such user can get (read) object:
REQUEST:
{
"id": 3,
"method": "get",
"params": [
{
"fields": [
"name",
"subnet"
],
"loadsub": 0,
"url": "/pm/config/adom/dc_amer/obj/firewall/address/host_001"
}
],
"session": "E3tjmsND1L4zCe5qNw3V6xJAynVK1PYeZ3f1fNPI0Q/rLez1t9qMpSkUNkkScbjrJOPvDKHPUaNf3c7YQNvZig=="
}RESPONSE:
{
"id": 3,
"result": [
{
"data": {
"name": "host_001",
"oid": 4805,
"subnet": [
"21.103.33.206",
"255.255.255.255"
]
},
"status": {
"code": 0,
"message": "OK"
},
"url": "/pm/config/adom/dc_amer/obj/firewall/address/host_001"
}
]
}When rpc-permit is read-write, the API user can read-write what the
permission profile is allowing him to read-write.
For instance, the API user associated with permission profile rw_all but
only for ADOM dc_amer can't create a firewall address in ADOM dc_us:
REQUEST:
{
"id": 3,
"method": "add",
"params": [
{
"data": {
"name": "host_1001",
"subnet": "10.0.0.2/32"
},
"url": "/pm/config/adom/dc_us/obj/firewall/address"
}
],
"session": "+sdy+ca8+NbZhTXxhjZOgByoZJiqCMhzEwo+9ufQ40z2zTjK/sLhFhxt1+atozzGwJ8wPHGBx50smv5hkekYgg=="
}RESPONSE:
{
"id": 3,
"result": [
{
"status": {
"code": -11,
"message": "No permission for the resource"
},
"url": "/pm/config/adom/dc_us/obj/firewall/address"
}
],
"session": 21
}When rpc-permit is read-write, and the user is also assigned with a
device group, then the API user can't read-write a device which doesn't belong
to the device group: BUG!!!! (tested with FMG 7.2.3-INTERIM build 1360)
In below example, device dut_fgt_03 doesn't belong to the device group
assigned to the API user...
REQUEST:
{
"id": 3,
"method": "add",
"params": [
{
"data": {
"name": "host_1001",
"subnet": "10.0.0.2/32"
},
"url": "/pm/config/device/dut_fgt_03/vdom/root/firewall/address"
}
],
"session": "RiMtKVLNZH/zc5nVkZ/Y4XNFXAWCvCBnOXEySrUCNUrsdNJQpDqUrFa+5yYF7e2K1uRFq146GAQ8BKxIoLMvNQ=="
}RESPONSE:
{
"id": 3,
"result": [
{
"data": {
"name": "host_1001"
},
"status": {
"code": 0,
"message": "OK"
},
"url": "/pm/config/device/dut_fgt_03/vdom/root/firewall/address"
}
]
}Neither if he attempts to read-write directly a managed device which doesn't
belong to the assigned device group, using sys/proxy/json: BUG!!!! (tested
with FMG 7.2.3-INTERIM build 1360)
In below example, device dut_fgt_03 doesn't belong to the device group
assigned to the API user...
REQUEST:
{
"id": 3,
"method": "exec",
"params": [
{
"data": {
"action": "post",
"payload": {
"color": 13,
"name": "host_1007",
"subnet": "10.0.0.7/32"
},
"resource": "/api/v2/cmdb/firewall/address",
"target": [
"/adom/dc_amer/device/dut_fgt_03"
]
},
"url": "/sys/proxy/json"
}
],
"session": "kOB0O/NuH7JPaTGVKsXCn5jWf8qkfAreEMFx2tElofuDioiKOfL42GJNMVBieEs1eTNe+0ehQY4sEkT4/gZJSQ=="
}RESPONSE:
{
"id": 3,
"result": [
{
"data": [
{
"response": {
"build": 1396,
"http_method": "POST",
"http_status": 200,
"mkey": "host_1007",
"name": "address",
"old_revision": "0105b076d0779621cfe555d34b1f6986",
"path": "firewall",
"revision": "3f2780027733bd7a9ba00b76d7197892",
"revision_changed": true,
"serial": "FGVMMLTM23000162",
"status": "success",
"vdom": "root",
"version": "v7.2.4"
},
"status": {
"code": 0,
"message": "OK"
},
"target": "dut_fgt_03"
}
],
"status": {
"code": 0,
"message": "OK"
},
"url": "/sys/proxy/json"
}
]
}Straight forward...
Can only be used to add non-existing object. If object already exists, it JSON API throws an error.
To update an objects.
Can be used to add non-existing and existing objects. If object already exists, it gets overwritten. You could consider it as a combination of ADD+UPDATE method.
From #1192822.
The UPDATE method will keep child table data. If you want to remove all child table content, use the REPLACE method.
To operate the FortiManager, like login in, login out, triggering a Policy Package Install, etc.
When setting a scope, you can specify either a device or a device group.
In both cases, you must use the name attribute. For example, to specify a device, you could use:
"_scope": [
{
"name": "dev_001"
}
]Similarly, to specify a device group, you could use:
"_scope": [
{
"name": "dev_grp_001"
}
]As you can see, FortiManager cannot determine from the name attribute alone whether it refers to a device or a device group.
For this reason, the name attribute by itself is always implicitly
interpreted as a device group.
If you want to specify a device, you must add the vdom attribute.
Even if the device does not use VDOMs, it always has an implicit root VDOM.
Therefore, to specify the device dev_001, you must use the following form:
"_scope": [
{
"name": "dev_001",
"vdom": "root"
}
]In scenarios where scope supports both devices and device groups, and where the
device’s VDOM name is optional, you can include an additional attribute, is
group, to explicitly indicate that the scope member should be treated as a
device group.
In this specific case, if this attribute is not provided, the scope member is interpreted as a device by default:
"_scope": [
{
"name": "dev_grp_001",
"is group": true
}
]Note
The is group attribute is a JSON boolean. It can be either true or
false.