Posted on September 18, 2019 by admin
Fortigate API Python Script
Fortinet Provide a REST API which allows you to configure and monitor pretty much any aspect of a fortigate device,As it stands this is pretty locked down in terms of documentation and you must have access to the Fortinet Developer network to get their API documentation.I recently aquired access and also stumbled accross this a while back which is a great easy way to get started.
Clone the repo
The REPO is availiable on github and is provided as is.
First make sure you have python installed on your system and install pip / setuptools.
You will need libxml or urllib3
I am running Python 2.7 for this
1 2 3 4 5 6 7 8 9 |
davidbrierley@pythonhost:~/fortigate_api$ python -V Python 2.7.16 # Check you have urlib installed davidbrierley@pythonhost:~/fortigate_api$ pip list | grep urllib urllib3 1.25.3 # If you don't then install it davidbrierley@pythonhost:~/fortigate_api$ pip install urllib3 |
If you have this installed you can then clone the repo.
I did not create the script just showing you how to use it, it supports very basic usage out of the box but I will document other ways of using it and examples.
Make sure you have git installed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# Centos yum install git # ubuntu / debian apt-get install git # then clone the repo git clone https://github.com/eoprede/fortigate_api.git This should create the following: davidbrierley@pythonhost:~$ ls fortigate_api # Change directory to the fortigate_api davidbrierley@pythonhost:~$ cd fortigate_api/ davidbrierley@pythonhost:~/fortigate_api$ |
Edit the script
The main script is the fw_api_test.py
the file looks like this, you will need to edit the script and then run it either using python fw_api_test.py or ./fw_api_test.py
you can uncomment the getpass section if you have a static password and append a port number to it,
I will aim to add more guides detailing the endpoints and looping round onto multiple fortigates. if you have any ideas of what else we should blog please let us know.
Points to note
The script does not do any sort of error handling.
You can append a port number to the IP address if you are using none standard ports.
the API is pretty limited in fortiOS V5.2.x its not totally noticeable if you are doing basic changes but they have introduced a lot more endpoints in later versions.
This script ideally works on later versions of fortiOS.
The script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
#!/usr/bin/env python import pprint import requests import getpass class fortigate_api: _secure=True def __init__(self, ip, un, pw, verify=False, proxies=None, disable_warnings=True, secure=True): if disable_warnings: requests.packages.urllib3.disable_warnings() unpw = {'username':un,'secretkey':pw} self._secure=secure self.verify = verify self.ip = ip self.proxies=proxies if self._secure: http='https://' else: http='http://' auth = requests.post(http+self.ip+'/logincheck', data=unpw, verify=self.verify, proxies=self.proxies) self.cookies = auth.cookies for cookie in self.cookies: if cookie.name == "ccsrftoken": csrftoken = cookie.value[1:-1] # token stored as a list self.header = {"X-CSRFTOKEN": csrftoken} def __enter__(self): return self def __del__(self): if self._secure: http='https://' else: http='http://' try: requests.post(http+self.ip+'/logout', verify=self.verify, cookies=self.cookies, proxies=self.proxies) except AttributeError: print ("Looks like connection to "+self.ip+" has never been established") def __exit__(self, *args): pass def get(self, path, api='v2', params=None): if isinstance(path, list): path = '/'.join(path) + '/' if self._secure: http='https://' else: http='http://' return requests.get(http+self.ip+'/api/'+api+'/'+path, cookies=self.cookies, verify=self.verify, proxies=self.proxies, params=params) def put(self, path, api='v2', params=None, data=None): if isinstance(path, list): path = '/'.join(path) + '/' if self._secure: http='https://' else: http='http://' return requests.put(http+self.ip+'/api/'+api+'/'+path, headers=self.header,cookies=self.cookies, verify=self.verify, proxies=self.proxies, params=params, json={'json': data}) def post(self, path, api='v2', params=None, data=None, files=None): if isinstance(path, list): path = '/'.join(path) + '/' if self._secure: http='https://' else: http='http://' return requests.post(http+self.ip+'/api/'+api+'/'+path, headers=self.header,cookies=self.cookies, verify=self.verify, proxies=self.proxies, params=params, json={'json': data}, files=files) def delete(self, path, api='v2', params=None, data=None): if isinstance(path, list): path = '/'.join(path) + '/' if self._secure: http='https://' else: http='http://' return requests.delete(http+self.ip+'/api/'+api+'/'+path, headers=self.header,cookies=self.cookies, verify=self.verify, proxies=self.proxies, params=params, json={'json': data}) def show(self, path, api='v2', params=None): response = self.get(path, api=api, params=params) return response.json() def edit(self, path, api='v2', params=None, data=None): response = self.put(path, api=api, params=params, data=data) return response.json() def create(self, path, api='v2', params=None, data=None, files=None): response = self.post(path, api=api, params=params, data=data, files=files) return response.json() def remove(self, path, api='v2', params=None, data=None): response = self.delete(path, api=api, params=params, data=data) return response.json() @staticmethod def print_data(response, verbose=False): if response['status']=='success': if verbose: pprint.pprint (response) elif response['http_method']=='GET': pprint.pprint (response['results']) else: print ('OK!') else: print ('Fail!') pprint.pprint (response) def main(): un = "admin" pw = getpass.getpass() #proxy={'http': 'socks5://127.0.0.1:9000'} proxy = None fw = '192.168.3.19' intf = { "name": "testagg", "vdom": "root", "allowaccess": "ping", "ip": "1.1.1.1 255.255.255.0", "role": "lan", "type": "aggregate", "member": [ { "interface-name": "port6" }, { "interface-name": "port7" } ] } try: t = fortigate_api(fw, un, pw, proxies=proxy) t.print_data (t.show('cmdb/system/interface')) t.print_data (t.create('cmdb/system/interface', data=intf)) except: print ('something went wrong') raise if __name__ == "__main__": main() |
Leave A Comment
What’s happening in your mind about this post !