This is very similar to my previous post for creating network objects (found here) but in this instance we are going to create some new port objects on the FMC using a Python script and a CSV file.

The script loops through each line in the CSV file and creates it on the FMC, this script does not update or delete objects.

The CSV file should only contain new objects, as this is a POST (create) and not a PUT (update) call. You will get a status code of 400 if the object already exists, my script hung if I received 10 of these error codes (your experience may differ). You may also receive an error code 400 for invalid query parameters, including unrecognized parameters, missing parameters, or invalid values.

At the end of the script, a log file will be created in the same directory as the Python script which includes all of the JSON dumps inside

Here’s a simple CSV file that’s stored in the same directory as my Python script titled ‘ports.csv’ which contains 4 port objects and their values. This filename is statically defined in the script, if you need to have the CSV file called something different or located in another directory, then you must update the file/path name in the script on line 44.

name,protocol,port
Custom_Port-1,tcp,9601
Custom_Port-2,tcp,7001
Custom_Port-3,udp,8085
Custom_Port-4,udp,8201

And here is the script used in this demo. You will need to update the FMC server address, username and password and the domain ID in the API_Path to match your environment. (You’re best of viewing the code in a separate window)

import csv
import json
import sys
import requests
import os

server = "https://192.168.99.5

username = "username"
if len(sys.argv) > 1:
    username = sys.argv[1]
password = "password"
if len(sys.argv) > 2:
    password = sys.argv[2]

r = None
headers = {'Content-Type': 'application/json'}
api_auth_path = "/api/fmc_platform/v1/auth/generatetoken"
auth_url = server + api_auth_path

print('\nAttempting connection to FMC...')

try:
    requests.packages.urllib3.disable_warnings()
    r = requests.post(auth_url, headers=headers, auth=requests.auth.HTTPBasicAuth(username,password), verify=False)
    auth_headers = r.headers
    auth_token = auth_headers.get('X-auth-access-token', default=None)
    if auth_token == None:
        print("auth_token not found. Exiting...")
        sys.exit()
except Exception as err:
    print ("Error in generating auth token --> "+str(err))
    sys.exit()

headers['X-auth-access-token'] = auth_token

print('\nConnected! Auth token collected successfully (' + auth_token + (')\n'))
api_path = "/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/object/protocolportobjects"

url = server + api_path
if (url[-1] == '/'):
    url = url[:-1]

f = open("ports.csv")
objectsfile = csv.DictReader(f)

for object in objectsfile:
    post_data = {
        "name": object["name"],
        "type": "ProtocolPortObject",
        "port": object["port"],
        "protocol": object["protocol"],
    }
    print('Creating object ' + object["name"])
    try:
        r = requests.post(url, data=json.dumps(post_data), headers=headers, verify=False)
        status_code = r.status_code
        resp = r.text
        log = open('POST_Create-FMC-Ports.log', 'a')   
        print("Status code: "+str(status_code))
        json_resp = json.loads(resp)
        log.write('\n---------------------------------------------------------------------\n')
        log.write(json.dumps(json_resp,sort_keys=True,indent=4, separators=(',', ': ')))  
        
        if status_code == 201 or status_code == 202:
            print (object["name"] + " was successfully created\n")
            #print(json.dumps(json_resp,sort_keys=True,indent=4, separators=(',', ': ')))
        elif status_code == 400:
            print (object["name"] + " already exists!\n")
        else:
            r.raise_for_status()
            print (object["name"] + " encountered an error during POST --> "+ resp +'\n')
            
    except requests.exceptions.HTTPError as err:
        print ("Error in connection --> "+str(err))
    finally:
        if r: r.close()

print('Log file "POST_Create-FMC-Ports.log" updated\n')
os.system('pause')

Checking the Ports in the FMC you can see the new objects have been created successfully:

The Firepower REST API implements rate limiting to reduce network load. It’s important not to exceed more than 120 requests (objects being created) per minute otherwise you will receive a 429 status code (too many requests). It will only allow 10 simultaneous connections per IP address. These are not configurable parameters.


5 Comments

Anderson · November 27, 2019 at 2:08 pm

Olá, tudo bom?
Executei o script com as informações mencionadas. Mas quando rodo o script ele da a seguinte mensagem:
python script_Python.py

Attempting connection to FMC…

Connected! Auth token collected successfully (4b63f7c1-d243-4767-8425-eba41c682953)

Traceback (most recent call last):
File “script_Python.py”, line 49, in
“name”: object[“name”],
KeyError: ‘name’

Pode me ajudar?
Obrigado

    Tom · November 27, 2019 at 2:13 pm

    Hello – I believe the problem is within your CSV file. Ensure it begins with ‘name’ like in my CSV example, with no spaces before it.

    [“name”] < this is what the script looks for as a header in the CSV file. Hope this helps.

    Tom · November 27, 2019 at 2:13 pm

    Olá – Acredito que o problema esteja no seu arquivo CSV. Verifique se ele começa com “nome”, como no meu exemplo de CSV, sem espaços antes dele.

    [“Nome”] <é o que o script procura como um cabeçalho no arquivo CSV. Espero que isto ajude

      Anderson · November 29, 2019 at 7:26 pm

      Thank you for your help.
      Checking my .csv file does not start with space. follows a print of the file.

      name,protocol,port
      finger,tcp,79

        Tom · December 3, 2019 at 12:06 pm

        Hmm I am not sure, I have just used this script again with the same CSV file as in the example and it worked OK for me.

        Please ensure your CSV file is called ‘ports.csv’ – if it is called something else please change the details in line 44 in the script to match.

        Thanks,
        Tom

Leave a Reply to Anderson Cancel reply

Your email address will not be published. Required fields are marked *