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()
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.