Firepyer – Automating Cisco FTD in FDM mode with Python


In planning for some upcoming work for a client I started looking into options for automating the deployment and configuration of Cisco’s FTD (Firepower Threat Defense) devices. This is Cisco’s latest attempt at a NGFW, bringing together a unified platform containing the best bits from their long-standing ASA firewall and their Sourcefire IDP acquisition.

As of version 6.2.something, Cisco offers two methods of managing FTD devices. The first is using FMC (Firepower Management Center), a centralised management controller, which comes in either virtual or physical appliance format and can be used to manage a number of devices. The second option, which is the focus of this post is FDM (Firepower Device Manager) which is a local ‘on-box’ method of managing a standalone (or HA pair) appliance.

I won’t discuss the pros and cons of each, but currently there is no ability to migrate from one management option to the other, so choose wisely. If you find FDM fits your needs and you have a large number of devices to configure or just want some automation then read on…

Enter Firepyer

There’s plenty out there for automating devices configured to use FMC, but not much for standalone FDM devices. I found a few Ansible modules here and there and a bulk config tool, but these only cover a small portion of the FDM feature set, so I decided to create Firepyer.

Firepyer consumes the REST API that becomes available when you select FDM mode and provides some easy to use Python methods to interact with your NGFW and get/send structured data. Currently there’s only a hand full of operations that are implemented, but my aim is to get full CRUD (Create, Read, Update, Delete) support for the majority of popular features. The list of current features are shown in the Firepyer Docs.

Using Firepyer

If you’re familiar with Python then the docs should be enough to get you started using Firepyer, but if you’re pretty new then here’s how to get going (some commands may be different depending on your platform)…

1. It’s always good to use a virtual environment to separate dependencies between projects and system-level packages:

python -m venv venv

2. Then enter your new venv…

in Linux:

source ./venv/bin/activate

or in Windows:


3. As Firepyer is available on PyPI (the Python Package Index) you can then easily install it into your venv:

pip install firepyer

4. Now start an interactive Python shell, import the Fdm class, create an object with your FTD details and start automating:

(venv) C:\Users\username> python
>>> from firepyer import Fdm
>>> fdm = Fdm(host='', username='admin', password='Admin123')
>>> print(fdm.get_vrfs())

[{'description': "Customer A's VRF",
  'id': '67e4d858-503d-11eb-aab5-2921a41f8ca3',
  'interfaces': [{'hardwareName': 'GigabitEthernet0/2',
                  'id': 'aeb5b238-4d44-11eb-9e04-cd44159d2943',
                  'name': 'customer_a',
                  'type': 'physicalinterface',
                  'version': 'nh7piq3rw7pzs'}],
  'isSystemDefined': False,
  'links': {'self': ''},
  'name': 'Customer-A',
  'type': 'virtualrouter',
  'version': 'crdwtc44cg5pu'},
 {'description': "Customer B's VRF",
  'id': '7360254c-503d-11eb-aab5-41ec0935f001',
  'interfaces': [{'hardwareName': 'GigabitEthernet0/3',
                  'id': 'afb288c9-4d44-11eb-9e04-41c0f86d8474',
                  'name': 'customer_b',
                  'type': 'physicalinterface',
                  'version': 'ocdhtp76zpfzz'}],
  'isSystemDefined': False,
  'links': {'self': ''},
  'name': 'Customer-B',
  'type': 'virtualrouter',
  'version': 'nl7onsmfqdujm'},
 {'description': 'This is a Global Virtual Router',
  'id': '42e95fbf-fd5a-42bf-a95f-bffd5a42bfd6',
  'interfaces': [{'hardwareName': 'Management0/0',
                  'id': 'b0b5a0ea-4d44-11eb-9e04-43089048338b',
                  'name': 'diagnostic',
                  'type': 'physicalinterface',
                  'version': 'inmqiea7woymm'},
                 {'hardwareName': 'GigabitEthernet0/1',
                  'id': 'ad6a9497-4d44-11eb-9e04-63d0b1958967',
                  'name': 'inside',
                  'type': 'physicalinterface',
                  'version': 'eqotynhtlcuyf'},
                 {'hardwareName': 'GigabitEthernet0/0',
                  'id': '8d6c41df-3e5f-465b-8e5a-d336b282f93f',
                  'name': 'outside',
                  'type': 'physicalinterface',
                  'version': 'h4kqp4iu2yvff'}],
  'isSystemDefined': True,
  'links': {'self': ''},
  'name': 'Global',
  'type': 'virtualrouter',
  'version': 'cna3vbajed6et'}]

5. View the docs to see everything else you can do!

Disclaimer: Firepyer is still in early development so I take no responsibility if your network goes up in flames!

Extension Mobility Remote Login/Logout without PIN in Python

Whilst trying to automate some mundane networking tasks in Python, I’ve started looking our UC environment. This lead me to a great post (thanks!) here:

I’m by no means a coder, but I’ve converted the PowerShell script from there into a Python version (feel free to suggest a more PEP8 improvement), that uses the Requests library.

Some uses for this is to make a web app to see who is logged in where and give the ability to log them out remotely. Alternatively, provide a Windows login/log off script that automatically logs a user into their handset (users with no roles can log themselves in/out, whilst users with the EM Authentication Proxy Rights role can login/logout any user).

Ingredients Used:

If you want to try this out it should work on most UCM versions and I think in Py3, but to rule out any incompatibilities, my environment was:

  • Python 2.7
  • Requests 2.9.1
  • CUCM 10.5(1)
  • Softphone

The Code:

Change the hard coded variables for your own and comment in/out the logout/in respectively:

#! /usr/bin/env python
import getpass
import requests

cucm_server = "CUCM"
mac = "000000000002"
device = "SEP" + mac
emuser = "emuser"
appEmProxyUser = "appemadmin"
appPw = getpass.getpass(prompt="Enter the EMProxyUser password: ")

uri = "http://" + cucm_server + ":8080/emservice/EMServiceServlet"
headers = {"Content-Type":

parameters = "<request>"
parameters += "<appInfo><appID>" + appEmProxyUser +\
 "</appID><appCertificate>" + appPw + "</appCertificate></appInfo>"

# parameters += "<logout><deviceName>" + device + "</deviceName></logout>"
parameters += "<login><deviceName>" + device + "</deviceName><userID>" +\
 emuser + "</userID></login>"

parameters += "</request>"

r =,