Working with the FortiGate REST API
This post is part of my upcoming book, Full Stack Network Automation, where I explore how APIs can help network engineers build scalable and intelligent automation workflows.
In this short post, we’ll go through how to set up the REST API on a FortiGate firewall. For this demonstration, we’ll use the evaluation version of the firewall, which you can download from Fortinet’s official website.
To get started, we first need to set up an API admin user with the correct security profile. You can either create a new profile with custom permissions or use one of the existing ones. For this simple lab, we’ll use the built-in super_admin profile. However, in a production environment, it’s strongly recommended to start with a read-only profile and grant permissions incrementally as needed.
forti-1 # config system api-user
forti-1 (api-user) # edit api-admin
new entry 'api-admin' added
forti-1 (api-admin) # set accprofile super_admin
forti-1 (api-admin) # set vdom "root"
forti-1 # execute api-user generate-key api-admin
New API key: some_api_key
Now that we’ve created an API user, we can begin writing Python code to consume the REST API provided by FortiGate.
Part of Full Stack Automation Book by Shahzad Qadir
import requests
class FortiAPI:
def __init__(self, auth_token: str, device_ip: str):
self.auth_token = auth_token
self.base_url = f"http://{device_ip}/api/v2/cmdb"
self.headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.auth_token}"
}
def print_interfaces(self):
response = requests.get(
url=f"{self.base_url}/system/interface/",
headers=self.headers
)
for result in response.json()['results']:
for key, value in result.items():
if key == 'name':
print(f"Interface: {value}")
if key == 'ip':
print(f"IP Address: {value}")
if key == 'allowaccess':
print(f"Allowed Access: {value}")
print("***************************")
if __name__ == "__main__":
api_obj = FortiAPI("xxxx", "x.x.x.x")
api_obj.print_interfaces()
This simple class includes an initializer (init) and a method called print_interfaces. The initializer takes an authentication token and the device IP address, which it stores as part of the object. This way, we don’t have to pass these parameters for every method call. It also defines the authorization header and the base URL for all subsequent API requests.
The print_interfaces method extends the base URL with /system/interface/ and performs a GET request to the firewall. The response is a JSON object containing key-value pairs, which we loop through to extract the interface name, IP address, and allowed access methods.
Finally, in the main section, we create an instance of the FortiAPI class by passing in the device IP and authentication token, and then call the print_interfaces() method to display information about all interfaces on the firewall.
Example Execution
python3 forti_api.py
Interface: fortilink
IP Address: 10.255.1.1 255.255.255.0
Allowed Access: ping fabric
***************************
Interface: l2t.root
IP Address: 0.0.0.0 0.0.0.0
Allowed Access:
***************************
Interface: naf.root
IP Address: 0.0.0.0 0.0.0.0
Allowed Access:
***************************
Interface: port1
IP Address: 172.16.101.2 255.255.255.248
Allowed Access: ping https ssh fgfm
***************************
Interface: port2
IP Address: 172.16.21.1 255.255.255.0
Allowed Access: ping https ssh
***************************
Interface: port3
IP Address: 0.0.0.0 0.0.0.0
Allowed Access:
***************************
Interface: port4
IP Address: 10.10.99.1 255.255.255.0
Allowed Access: ping https ssh http
***************************
Interface: ssl.root
IP Address: 0.0.0.0 0.0.0.0
Allowed Access:
***************************
You can find the complete code for this post on GitHub: 👉 https://github.com/shahzadqadir/fortigate_api
Feel free to clone, fork, and extend it.
This class is part of my book on Full Stack Network Automation which covers Python Basics, Object Oriented Programming, Python Libraries like Paramiko, REST APIs, and full stack application development using Django, and SQLite.