{"id":1677,"date":"2025-08-25T11:07:26","date_gmt":"2025-08-25T10:07:26","guid":{"rendered":"https:\/\/www.labtinker.net\/?p=1677"},"modified":"2025-08-25T11:07:26","modified_gmt":"2025-08-25T10:07:26","slug":"fortigate-api","status":"publish","type":"post","link":"http:\/\/18.135.13.153\/?p=1677","title":{"rendered":"FortiGate API"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">I don&#8217;t really do any automation or DevOps in my job but in the interests of tinkering I have got as far as writing a couple of FortiGate API scripts so I thought I&#8217;d share the process and scripts here.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The first script takes a backup of the FortiGate. It could be modified to encrypt the backup and then email it and I may well do that in subsequent versions. The script uses an embedded API token &#8211; which is not good practice so please bear this in my mind before deploying it anywhere. In my next post I plan to get this working with secrets (AWS or some roll your own option) . This podcast is a good listen on the alternatives available in this space.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-wp-embed is-provider-packet-pushers wp-block-embed-packet-pushers\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"UiE6wruinZ\"><a href=\"https:\/\/packetpushers.net\/podcasts\/packet-protector\/pp067-protecting-secrets-with-vault-and-trufflehog\/\">PP067: Protecting Secrets With Vault and TruffleHog<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"\u201cPP067: Protecting Secrets With Vault and TruffleHog\u201d \u2014 Packet Pushers\" src=\"https:\/\/packetpushers.net\/podcasts\/packet-protector\/pp067-protecting-secrets-with-vault-and-trufflehog\/embed\/#?secret=4IsvRzmjeT#?secret=UiE6wruinZ\" data-secret=\"UiE6wruinZ\" width=\"600\" height=\"338\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fortinet Developer Network<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Fortinet Developer Network is a portal which gives you details of all the API calls for Fortinet kit. To get a login, you need to request it from Fortinet themselves. I found it easy enough but then I work for a Fortinet partner which probably helped.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/fndn.fortinet.net\/index.php?\/login\/&amp;ref=aHR0cHM6Ly9mbmRuLmZvcnRpbmV0Lm5ldA==\">https:\/\/fndn.fortinet.net\/index.php?\/login\/&amp;ref=aHR0cHM6Ly9mbmRuLmZvcnRpbmV0Lm5ldA==<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>FortiGate API Administrator<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To use API scripts, we need to create a RESP API Adminstrator on the firewall which is done in <em>System\/Administrators<\/em> from the GUI:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"291\" height=\"231\" src=\"http:\/\/18.135.13.153\/wp-content\/uploads\/2025\/08\/image-3.png\" alt=\"\" class=\"wp-image-1682\" style=\"width:293px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Then define the administrator&#8217;s properties&#8230;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"644\" height=\"367\" src=\"http:\/\/18.135.13.153\/wp-content\/uploads\/2025\/08\/image-4.png\" alt=\"\" class=\"wp-image-1683\" srcset=\"http:\/\/18.135.13.153\/wp-content\/uploads\/2025\/08\/image-4.png 644w, http:\/\/18.135.13.153\/wp-content\/uploads\/2025\/08\/image-4-300x171.png 300w\" sizes=\"auto, (max-width: 644px) 100vw, 644px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The PKI group is for certificate authentication which although a good idea will take some setting up. However, I would recommend inputting the ip address of the server(s) the script will be run from in &#8216;Trusted Hosts&#8217; as this is an easy win.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When you complete the api admin creation you will be given the token to use for the access so take a copy of this.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"715\" height=\"213\" src=\"http:\/\/18.135.13.153\/wp-content\/uploads\/2025\/08\/image-5.png\" alt=\"\" class=\"wp-image-1684\" srcset=\"http:\/\/18.135.13.153\/wp-content\/uploads\/2025\/08\/image-5.png 715w, http:\/\/18.135.13.153\/wp-content\/uploads\/2025\/08\/image-5-300x89.png 300w\" sizes=\"auto, (max-width: 715px) 100vw, 715px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">(Although, I created <em>api-admin,<\/em> here I use <em>api-user <\/em>in subsequent examples as I&#8217;d already created and tested this)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Admin Profile<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now, I found that to get a full backup configuration using the API admin it was necessary to use the highest level of profile access (<em>super_admin<\/em>).  You cannot select this level of access from the GUI and need to amend it from the CLI. (This is another reason to secure this script.)<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"478\" height=\"412\" src=\"http:\/\/18.135.13.153\/wp-content\/uploads\/2025\/08\/image-6.png\" alt=\"\" class=\"wp-image-1685\" srcset=\"http:\/\/18.135.13.153\/wp-content\/uploads\/2025\/08\/image-6.png 478w, http:\/\/18.135.13.153\/wp-content\/uploads\/2025\/08\/image-6-300x259.png 300w\" sizes=\"auto, (max-width: 478px) 100vw, 478px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">If you select a lower admin profile \u2013 the backup file will be created, but be incomplete. When I first wrote this on an older version of Forti code it just missed out sections with <em>super_admin <\/em>administrators but having re-tested it, I got a file with a 403 error in it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>The Script<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can access the REST API in a number of ways but I used a python3 script. The script has three variables.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>firewall=&#8221;192.168.200.99&#8243; # The address on fqdn on which to access the firewall.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>fname=&#8221;FGT&#8221; # the firewall name used in the filename of the backup<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>api_token =&#8221;xxx&#8221; # As mentioned above, you probably shouldn&#8217;t be putting api tokens in scripts but this is a PoC.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The relevant parts of the script are:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>api_url = &#8220;https:\/\/&#8221;+firewall+&#8221;\/api\/v2\/monitor\/system\/config\/backup?destination=file&amp;file_format=fos&amp;scope=global&#8221;<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And the following which sends the HTTP GET:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>response = requests.get(api_url,headers={&#8220;Content-Type&#8221;:&#8221;application\/json&#8221;,&#8221;accept&#8221;:&#8221;application\/json&#8221;,&#8221;Authorization&#8221;:&#8221;Bearer&#8221;+api_token},verify=False)<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When this script is run it creates a backup file of the firewall in the same directory it is run from. The script can be found here&#8230;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/tinkergar\/fortiapi\">https:\/\/github.com\/tinkergar\/fortiapi<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is incidentally my first upload to GitHub. It&#8217;s amazing how long you can be in this industry and still find yourself doing fairly fundamental things for the first time if you venture out of your silo. I blithely mentioned secret managers above, and although I know of them and have passed exams based on my so-say knowledge thereof I have never used them in anger. Every day&#8217;s a school day. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>I don&#8217;t really do any automation or DevOps in my job but in the interests of tinkering I have got as far as writing a couple of FortiGate API scripts so I thought I&#8217;d share the process and scripts here. The first script takes a backup of the FortiGate. It could be modified to encrypt [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[],"class_list":["post-1677","post","type-post","status-publish","format-standard","hentry","category-firewalls"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/18.135.13.153\/index.php?rest_route=\/wp\/v2\/posts\/1677","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/18.135.13.153\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/18.135.13.153\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/18.135.13.153\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/18.135.13.153\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1677"}],"version-history":[{"count":0,"href":"http:\/\/18.135.13.153\/index.php?rest_route=\/wp\/v2\/posts\/1677\/revisions"}],"wp:attachment":[{"href":"http:\/\/18.135.13.153\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1677"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/18.135.13.153\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1677"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/18.135.13.153\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1677"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}