Palo Alto Netmiko Example

Overview

Netmiko, a popular Python library used in Network Automation, provides a simple and easy-to-use interface for interacting with Networking Devices.

In this blog post, we will take an in-depth look at Netmiko and explore how it can be used to interact with Palo Alto devices including Panorama. We will cover the basic concepts of Netmiko, including how it works and what it can do.

Installing Netmiko

Netmiko is not part of the standard Python library so, you will have to install it using pip as shown below. The process is similar for other operating systems such as macOS or Linux.

C:\Users\vsurr\Documents>pip install netmiko
Collecting netmiko
  Using cached netmiko-4.0.0-py3-none-any.whl (207 kB)
Requirement already satisfied: setuptools>=38.4.0 in 

*** TRUNCATED ***

  Using cached pycparser-2.21-py2.py3-none-any.whl (118 kB)
Installing collected packages: tenacity, six, future, textfsm, pycparser, cffi, pynacl, cryptography, bcrypt, paramiko, scp, ntc-templates, pyserial, netmiko
Successfully installed bcrypt-3.2.0 cffi-1.15.0 cryptography-36.0.2 future-0.18.2 netmiko-4.0.0 ntc-templates-3.0.0 paramiko-2.10.3 pycparser-2.21 pynacl-1.5.0 pyserial-3.5 scp-0.14.4 six-1.16.0 tenacity-8.0.1 textfsm-1.1.2
WARNING: You are using pip version 20.2.3; however, version 22.0.4 is available.
You should consider upgrading via the 'c:\users\vsurr\appdata\local\programs\python\python39\python.exe -m pip install --upgrade pip' command.

Connecting to the Firewall

Now that we installed the Netmiko library, let's try and connect to a Palo Alto firewall with a simple Python script.

💡
Please ensure that the Palo Alto firewall is correctly configured for SSH access and that the Python workstation can successfully SSH into the device.
from netmiko import ConnectHandler
import getpass

passwd = getpass.getpass('Please enter your password: ')

firewall = {
    "device_type": "paloalto_panos",
    "host": "192.168.10.10",
    "username": "admin",
    "password": passwd
}

connection = ConnectHandler(**firewall) # unpacking the dictionary
output = connection.send_command("show system info", expect_string=r">")
connection.disconnect()

print(output)

Here is the breakdown of the code.

  1. from netmiko import ConnectHandler: This line imports the ConnectHandler class from the netmiko library. The ConnectHandler class is used to establish a connection with a network device, such as a Palo Alto firewall, and interact with it.
  2. import getpass: This line imports the getpass module, which provides a secure way to handle password input without echoing it to the console.
  3. passwd = getpass.getpass('Please enter your password: '): This line prompts the user to enter their password securely. The entered password is stored in the variable passwd.
  4. firewall = {...}: This block of code creates a dictionary named firewall containing the required information to connect to the Palo Alto firewall, such as device type, IP address, username, and password.
  5. connection = ConnectHandler(**firewall): This line establishes a connection with the Palo Alto firewall using the ConnectHandler class. The **firewall syntax is used to unpack the dictionary, passing its key-value pairs as keyword arguments to the class.
  6. output = connection.send_command("show system info", expect_string=r">"): This line sends the command "show system info" to the Palo Alto firewall and waits for the specified expect_string (in this case, the ">" prompt) to appear before considering the output complete. The output is then stored in the variable output.
  7. connection.disconnect(): This line gracefully disconnects from the Palo Alto firewall, closing the SSH session.
  8. print(output): Finally, this line prints the output of the "show system info" command to the console.
#output

hostname: test_fw
ip-address: 192.168.10.10
public-ip-address: unknown
netmask: 255.255.255.0
default-gateway: 192.168.10.1
ip-assignment: static
ipv6-default-gateway: 
mac-address: d4:f4:ab:23:6f:3d
time: Thu Apr 27 14:39:45 2023
uptime: 115 days, 15:09:26

{.... abbreviated ....}

You might have noticed that I'm using the expect_string=r">" argument when executing the command. Strangely, without this argument, the output appears empty, as detailed in this bug report: https://github.com/ktbyers/netmiko/issues/2864.

I believe this behaviour occurs because when you run a 'show' command on the firewall, it initially produces an empty line before displaying the actual output. It seems that Netmiko interprets the blank output as the end of the response.

The expect_string argument allows you to define a custom string or regular expression pattern that Netmiko should wait for before deeming the output complete and returning it to the user. This is particularly helpful when the default behaviour of waiting for the device prompt isn't adequate, or when you need to wait for specific output from the device.

As you know, when you run show commands on the firewall, after running the command, the prompt always come back to >. For example, the prompt of my firewall looks like this.

admin@test_fw>

So, as a workaround, I always use the expect_string argument with the send_command method so, Netmiko will wait until the > prompt appears.

Connecting to Panorama

The process is exactly the same as before, just replace the firewall IP with the Panorama one.

from netmiko import ConnectHandler
import getpass

passwd = getpass.getpass('Please enter your password: ')

firewall = {
    "device_type": "paloalto_panos",
    "host": "192.168.10.11",
    "username": "admin",
    "password": passwd
}

connection = ConnectHandler(**firewall) # unpacking the dictionary
output = connection.send_command("show system info", expect_string=r">")
connection.disconnect()

print(output)

I only changed the IP and ran the script and here is the output.

hostname: test_panorama
ip-address: 192.168.10.11

{.... abbreviated ....}

uptime: 105 days, 22:40:21
family: pc
model: Panorama
cloud-mode: cloud
vm-mode: Amazon AWS

Configurations Commands

Now that we've learnt how to send show commands, let's look at an example of how to make configuration changes. I'm going to create a new Address Object on the Panorama. Please note that the procedure is exactly the same on the firewall (except for the set commands of course)

from netmiko import ConnectHandler
import getpass

passwd = getpass.getpass('Please enter your password: ')

firewall = {
    "device_type": "paloalto_panos",
    "host": "192.168.10.11",
    "username": "admin",
    "password": passwd
}

connection = ConnectHandler(**firewall) # unpacking the dictionary
connection.config_mode() # enter configuration mode
connection.send_command("set device-group global address netmiko_test ip-netmask 8.8.8.8/32")
connection.disconnect()
  1. connection.config_mode(): This line instructs Netmiko to enter the configuration mode on the Palo Alto firewall. In configuration mode, you can make changes to the device configuration.
  2. connection.send_command("set device-group global address netmiko_test ip-netmask 8.8.8.8/32"): This line sends a command to the Palo Alto firewall to create a new address object named "netmiko_test" with an IP address of 8.8.8.8 and a subnet mask of /32, in the global device-group.
  3. connection.disconnect(): This line gracefully disconnects from the Palo Alto firewall, closing the SSH session.

As you can see above, the script has just created the Address Object in the Panorama.