Python automation for Cisco AireOS WLCs – Part 2 – Handling Sensitive Info

Handling Sensitive Info

In Part 1, we created a Python script that gathered the current WLANs configured on a device, but the password to do so is in plain text in the script. This is bad. Anyone with access to the script file can grab those creds and use them. Let’s look at a few different ways of handling sensitive info in our Python scripts.

The ‘getpass‘ Module

The primary purpose of the ‘getpass‘ module is to prompt the user for a password or other sensitive information without echoing what they type on the screen. It’s also included in Python’s standard library, which means if you have Python installed, you have ‘getpass‘ installed!

To start, add ‘import getpass‘ to the top of your script file. This tells Python to load this module when the script is ran.

import getpass

We’re now going to use this to prompt the user for the password to use to connect to our device by adding the following line:

password = getpass.getpass(prompt='Enter your password: ')

When ‘getpass.getpass()‘ is called, it displays the prompt (if any) and waits for the user to type in their password. The input characters are not displayed on the screen, providing security against shoulder-surfing attacks.

For DEMONSTRATION PURPOSES ONLY, I’m going to add the line ‘print(password)‘ to my script. I’m doing this to validate that even though the password prompt doesn’t show any characters, it’s still taking them correctly. Here’s my simple three-liner script:

import getpass

password = getpass.getpass(prompt='Enter your password: ')

print(password)

Let’s run this and validate it’s working as expected:

It worked! But in my opinion, it’s all kind of squished together and ugly. Let’s format it a bit to make it a little easier to read.

String manipulation

In any Python string, you can add certain special characters to manipulate said strings. In this case, I’m going to be adding ‘\n‘ in a few spots. ‘\n‘ is the equivalent of ‘print()‘, i.e. printing a blank line. I’ll add both to demonstrate:

import getpass

password = getpass.getpass(prompt='\nEnter your password: ')

print(password)
print()

Now, the output is a little easier to understand:

You can see that both the ‘\n‘ and the ‘print()‘ added a blank line where I told them to; right before printing ‘Enter your password:‘ and right after printing the password that was entered.

Putting It Together

Now, let’s adapt these to our ‘show wlan summary‘ script by:

  1. Import the ‘getpass‘ module
  2. Prompt for the user’s password with the ‘getpass‘ module and store it in the variable ‘password
  3. Use the ‘password‘ variable in place of our admin password in the Netmiko device credentials
import getpass
from netmiko import ConnectHandler

password = getpass.getpass(prompt='\nEnter your password: ')

device = {
    'device_type': 'cisco_wlc',
    'ip': '192.168.11.12',
    'username': 'admin',
    'password': password
}

net_connect = ConnectHandler(**device)

output = net_connect.send_command(command_string='show wlan summary')
print(output)

net_connect.disconnect()

Running this script obscures the password, but still retrieves the configured WLANs on the device.

Expand the credentials to include the username

Hiding the password is great, but let’s say that not everyone that uses the script will use or know the password for the ‘admin‘ user. Let’s also add a variable, called ‘username‘, to also have the user enter their own username to use. To accomplish this, we’ll use the built-in function ‘input‘ to prompt the user for a username.

This function doesn’t require any installation or adding lines to the top of the script to import, it’s a native Python function. It also keeps any text entered in plain text, it doesn’t hide anything like ‘getpass()‘ does.

To use this function, we’ll add the following line to our script (before the device details):

username = input(prompt='\nEnter your username: ')

This line will prompt the user for a username (after sending a new-line character with ‘\n‘), then storing the users answer to the variable ‘username‘. Adding it to the script, it will look something like this:

import getpass
from netmiko import ConnectHandler

username = input('\nEnter your username: ')
password = getpass.getpass(prompt='Enter your password: ')

device = {
    'device_type': 'cisco_wlc',
    'ip': '192.168.11.12',
    'username': 'admin',
    'password': password
}

net_connect = ConnectHandler(**device)

output = net_connect.send_command(command_string='show wlan summary')
print(output)

net_connect.disconnect()

Note: I changed a few of the new-line characters to keep the readability simple.

Adding this prompt for the username is great and all, but once that is saved to the ‘username‘ variable….what do we do with it? In the device details, notice we still have ‘admin‘ set as the username. When we run this as-is, it will prompt the user for both a username and password to use, but only the password is being passed to the device details. Let’s update the device details to use the ‘username‘ variable instead of the static ‘admin‘ username:

import getpass
from netmiko import ConnectHandler

username = input('\nEnter your username: ')
password = getpass.getpass(prompt='Enter your password: ')

device = {
    'device_type': 'cisco_wlc',
    'ip': '192.168.11.12',
    'username': username,
    'password': password
}

net_connect = ConnectHandler(**device)

output = net_connect.send_command(command_string='show wlan summary')
print(output)

net_connect.disconnect()

Now both the username and passwords are dynamic for our script and it’s not locked down to only the ‘admin’ creds, so let’s run it and see what happens:

Success! Now anyone with valid credentials can run this script and get the configured WLANs on a device! Here’s the full scripts with comments added:

import getpass  # Import the getpass module to securely input the password
from netmiko import ConnectHandler  # Import the ConnectHandler factory function that will handle the SSH connection to the device

username = input('\nEnter your username: ')
password = getpass.getpass(prompt='Enter your password: ')  # Prompt the user to enter their password securely

device = {
    'device_type': 'cisco_wlc',  # Set device type as 'cisco_wlc', which for Netmiko is AireOS-based WLCs (not IOS-XE)
    'ip': '192.168.10.2',  # Your device's IP address
    'username': username,  # Username variable that was set earlier
    'password': password  # Password variable that was set earlier
}

net_connect = ConnectHandler(**device)  # Establish an SSH connection to the device using the device dictionary:

# Send some commands to the device and print the output:
output = net_connect.send_command_timing(command_string='show wlan summary')
print(output)

net_connect.disconnect()  # Disconnect from the device

One response to “Python automation for Cisco AireOS WLCs – Part 2 – Handling Sensitive Info”

  1. […] that we’ve gotten down the basics of how to connect to a device (see Part 2), let’s learn how to gather and store info for further processing, i.e. check or change […]

    Like

Leave a comment