Netmiko Secrets - How to Secure Your Network Automation Credentials

Netmiko Secrets - How to Secure Your Network Automation Credentials
In: Netmiko Python NetDevOps

Netmiko is arguably one of the great tools for Network Automation. I've been using it for a couple of years now and have been using it for a wide variety of tasks. One of the issues that you may have come across with Netmiko is hiding passwords and secrets while using it.

In this blog post, we will go through some of the ways you can hide secrets from your scripts. If you are unfamiliar with Netmiko, I highly recommend checking out my previous posts below.

Part 1 - https://www.packetswitch.co.uk/netmiko-intro/

Part 2 - https://www.packetswitch.co.uk/netmiko-par2/

Part 3 - https://www.packetswitch.co.uk/netmiko-and-textfsm-example/

Part 4 - https://www.packetswitch.co.uk/netmikos-real-world-use-cases/

A Typical Netmiko Script

Your typical Netmiko script may look like the following where you can see the password is visible in plain-text. It is highly recommended to hide the passwords from the script especially if you are publishing your code to Git repos.

from netmiko import ConnectHandler

cisco_01 = {
    "device_type": "cisco_ios",
    "host": "10.10.20.17",
    "username": "cisco",
    "password": "cisco123"
}

connection = ConnectHandler(**cisco_01) # unpacking the dictionary

output = connection.send_command('show interface desc')
print(output)

print('Closing Connection')
connection.disconnect()

Let's look at a few ways that you can hide the secrets from the script.

Option 1 - Getpass

The most straightforward way of hiding the password is by using the getpass() library. Getpass prompts the user for a value, password in our case, without echoing what the user types to the terminal. getpass then reads input from the user and saves it as a string.

from netmiko import ConnectHandler
import getpass

passwd = getpass.getpass('Please enter the password: ') # Reads the output from the user and save it as a string

cisco_01 = {
    "device_type": "cisco_ios",
    "host": "10.10.20.17",
    "username": "cisco",
    "password": passwd, # Log in password from getpass
    "secret": passwd # Enable password from getpass
}

connection = ConnectHandler(**cisco_01)
connection.enable() # Go to Priv EXEC mode

output = connection.send_command('show interface desc')
print(output)

connection.disconnect()
sureshv@mac:~/Documents/netmiko_hide_screts|⇒  python netmiko_hide_secr.py
Please enter the password: 

In this example, the input is saved into a variable called passwd The variable is then used wherever a password is required (lines #10 and #11)

getuser()

You can also use the getuser() function to retrieve the username from the OS. The function displays the login name of the user by checking the environment variables LOGNAME, USER, LNAME and USERNAME, in order, and returns the value of the first non-empty string.

cisco_01 = {
    "device_type": "cisco_ios",
    "host": "10.1.255.104",
    "username": getpass.getuser(),
    "password": passwd, # Log in password from getpass
    "secret": passwd # Enable password from getpass
}

Of course, if you are using a different username such as admin or cisco it will not work.

Option 2 - Environment Variables

Environment variables are implemented through the os package, specifically os.environ. To find out what is the current value for specific environment variables in your session you can use os.environ.get()method. This retrieves the value of an environment variable currently set on your system.

For this example, first, let's set the environment variable using the export command.

export PASSWD='Cisco123'

Then, reference this environment variable in your script as shown below.

  • Line 2 - Import the os library
  • Line 4 - Reference the passwd variable to use the env variable
  • Lines 10 & 11 - Use it as the password
from netmiko import ConnectHandler
import os

passwd = os.environ.get('PASSWD')

cisco_01 = {
    "device_type": "cisco_ios",
    "host": "10.1.255.104",
    "username": 'cisco',
    "password": passwd, 
    "secret": passwd
}

connection = ConnectHandler(**cisco_01)
connection.enable() # Go to Priv EXEC mode

output = connection.send_command('show interface desc')
print(output)

connection.disconnect()
💡
Please note that the env variables are not persistent meaning if you close your terminal session then your environments will disappear. You will need to redefine it.

Option 3 - python-dotenv

If you are looking for a permanent solution then python-dotenv can be useful. Python-dotenv reads key-value pairs from a .env file and can set them as environment variables. You can install it using pip as shown below.

pip3 install python-dotenv

dotenv loads the environment variable by reading them from a .env file in the same directory. First, let's define the env variables inside the .env file in the same directory as the script.

#.env file
USER_NAME=cisco
PASSWD=Cisco123

Then, reference the env variables in your script. (Lines 3, 5, 7, 8, 13, 14 and 15)

from netmiko import ConnectHandler
import os
from dotenv import load_dotenv

load_dotenv()

username = os.environ.get('USER_NAME')
passwd = os.environ.get('PASSWD')

cisco_01 = {
    "device_type": "cisco_ios",
    "host": "10.1.255.104",
    "username": username,
    "password": passwd,
    "secret": passwd
}

connection = ConnectHandler(**cisco_01)
connection.enable() # Go to Priv EXEC mode

output = connection.send_command('show interface desc')
print(output)

connection.disconnect()

Closing Thoughts

If you are looking for one-time ad-hoc tasks then getpass() or Environment variables can be useful. If you are looking for more of a permanent solution then, python-dotenv is your best shot.

Be safe, and happy coding.

Table of Contents
Written by
Suresh Vina
Tech enthusiast sharing Networking, Cloud & Automation insights. Join me in a welcoming space to learn & grow with simplicity and practicality.
Comments
More from Packetswitch
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to Packetswitch.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.