{"id":4658,"date":"2021-03-21T20:12:02","date_gmt":"2021-03-21T20:12:02","guid":{"rendered":"https:\/\/karneliuk.com\/?p=4658"},"modified":"2021-03-21T20:22:15","modified_gmt":"2021-03-21T20:22:15","slug":"pygnmi-9-the-safest-way-to-store-credentials-for-network-devices","status":"publish","type":"post","link":"https:\/\/karneliuk.com\/2021\/03\/pygnmi-9-the-safest-way-to-store-credentials-for-network-devices\/","title":{"rendered":"pygnmi 9. The safest way to store credentials for network devices."},"content":{"rendered":"\n<p>Hello my friend,<\/p>\n\n\n\n<p>Recently we were asked, what is the safest way to store the credentials for network devices to your automation tools (e.g., the one based on <a href=\"http:\/\/bit.ly\/2wmAIWw\" target=\"_blank\" rel=\"noreferrer noopener\">Python<\/a> and <a href=\"https:\/\/bit.ly\/32UL5Pn\" target=\"_blank\" rel=\"noreferrer noopener\">gNMI<\/a>). Building the network automation solutions for a while, we have a good answer to you.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p> <\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/><\/div><\/td><td><div class=\"text codecolorer\">No part of this blogpost could be reproduced, stored in a <br \/>\nretrieval system, or transmitted in any form or by any <br \/>\nmeans, electronic, mechanical or photocopying, recording, <br \/>\nor otherwise, for commercial purposes without the <br \/>\nprior permission of the author.<\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">What is the most promising network automation protocol ? <\/h2>\n\n\n\n<p>gNMI was created by Google to manage their data centres and backbone network and is widely used by other biggest companies worldwide. However, it doesn&#8217;t mean that only the big guys can benefit from that. Every company and network can get the advantage of a single protocol for the configuration, operation, and streaming telemetry in their network provided your network devices support that.<\/p>\n\n\n<div class='code-block code-block-1' style='margin: 8px auto; text-align: center; display: block; clear: both;'>\n<p><a href=\"http:\/\/bit.ly\/2mP3SJy\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" class=\"aligncenter wp-image-4479 size-large\" src=\"https:\/\/karneliuk.com\/wp-content\/uploads\/2022\/08\/4_trainings.jpg\" alt=\"\"\/><\/a><\/p><\/div>\n\n\n\n\n<p>At our trainings, <a rel=\"noreferrer noopener\" href=\"http:\/\/bit.ly\/2mP3SJy\" target=\"_blank\">advanced network automation<\/a> and <a href=\"https:\/\/bit.ly\/3obN0XQ\" target=\"_blank\" rel=\"noreferrer noopener\">automation with Nornir<\/a> (2nd step after advanced network automation), we give you detailed knowledge of all the technologies relevant:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Data encoding (free-text, XML, JSON, YAML, Protobuf)<\/li><li>Model-driven network automation with YANG, NETCONF, RESTCONF, GNMI.<\/li><li>Full configuration templating with Jinja2 based on the source of truth (NetBox).<\/li><li>Best automation programming languages (Python, Bash), configuration management tools (Ansible) and automation frameworks (Nornir).<\/li><li>Network automation infrastructure (Linux, Linux networking, KVM, Docker).<\/li><\/ul>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>This training showed me the holistic picture of network automation and I know now where I need to focus the most of my time and efforts.<\/p><cite>Network Automation Student @ Karneliuk.com<\/cite><\/blockquote>\n\n\n\n<p>Moreover, we put all mentions technologies in the context of the real use cases, which our team has solved and are solving in various projects in the service providers, enterprise and data centre networks and systems across the Europe and USA. That gives you opportunity to ask questions to understand the solutions in-depts and have discussions about your own projects. And on top of that, each technology is provided with online demos and you are doing the lab afterwards to master your skills. Such a mixture creates a unique learning environment, which all students value so much. Join us and unleash your potential.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p><a href=\"https:\/\/bit.ly\/2ZexI9M\" target=\"_blank\" rel=\"noreferrer noopener\">Start your automation training today.<\/a><\/p><\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">Brief description<\/h2>\n\n\n\n<p>In the previous blogpost about the gNMI we have shared the approach to <a rel=\"noreferrer noopener\" href=\"https:\/\/bit.ly\/3vidN95\" target=\"_blank\">how use the self-signed certificate to connect to the network device<\/a>. However, by the way how the gNMI is implemented in the network devices nowadays, it is needed to send the credentials (username and password) when you communicate with the network element for each operation. The reason for that is the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Certificate<\/strong> (self-signed or PKI based) validates the endpoint and allows the encrypted gRPC channel to be established between the host running the <a rel=\"noreferrer noopener\" href=\"https:\/\/bit.ly\/2RPF8gi\" target=\"_blank\">GNMI client<\/a> and the network device.<\/li><li><strong>Credentials<\/strong> authorise the user to perform certain operations (e.g., NOC technician can only gather the operational information, whereas the network operations are allowed to make a change).<\/li><\/ul>\n\n\n\n<p>As such, both credentials and certificates are equally important for the gNMI operation. The challenge, which arises is how we can store the credentials then?<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Storing the file with the clear text credentials is huge security vulnerability. <\/li><li>Storing the file with the passwords in an encrypted format requires someone to provide another password to decrypt it, so the automation requires a human intervention or we again somewhere store that-another-passowrd in a clear text.<\/li><\/ul>\n\n\n\n<p>There is a solution to break that vicious circle, though, which my brothers in arms from system administrators shared with me, which is usage of a Linux <strong>environment variables<\/strong> in Linux.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Usage<\/h2>\n\n\n\n<p>Let&#8217;s take a closer look how it works.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">#1. Setting environment variables<\/h3>\n\n\n\n<p>First of all, what is an environment variable in <strong>Linux<\/strong>? In a nutshell, this is a variable which is available for you in Linux for your current session. To validate all the variables, you need to type an <strong>env<\/strong> command in your Linux session:<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/><\/div><\/td><td><div class=\"text codecolorer\">$ env<br \/>\nTERM_PROGRAM=Apple_Terminal<br \/>\nSHELL=\/bin\/bash<br \/>\nTERM=xterm-256color<br \/>\nTMPDIR=\/var\/folders\/g_\/qzk59n7n7m12d0k39gt2q4z00000gp\/T\/<br \/>\nTERM_PROGRAM_VERSION=433<br \/>\nTERM_SESSION_ID=CA088303-0C09-4A18-894D-C17945BAD7AE<br \/>\n!<br \/>\n! Further output is truncated for brevity<\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>This approach works for any Linux and Mac OS.<\/p><\/blockquote>\n\n\n\n<p>The interesting thing about the environment variables is that there are two types of them:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Defined as part of you profile, which is <strong>persistent across all the sessions<\/strong>. This is not secure way.<\/li><li>Created by you during the session and <strong>existing only within that particular session<\/strong>. This is quite a secure approach.<\/li><\/ul>\n\n\n\n<p>It is very easy to created the second version of environment variables, just type in CLI of your Linux or MAX this command:<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/><\/div><\/td><td><div class=\"text codecolorer\">$ export PYGNMI_USER=pygnmi<\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n<\/pre>\n\n\n\n<p>Voila. The environment variable is created.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">#2. Checking they are available only for you<\/h3>\n\n\n\n<p>We believe that you may have some questions at this stage, so we will try to answer all of them.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Is the variable created?<\/h4>\n\n\n\n<p>Yes, you have created the environment variable <strong>PYGNMI_USER<\/strong> and set its value to the string &#8220;<strong>pygnmi<\/strong>&#8220;.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">How do I check that?<\/h4>\n\n\n\n<p>You can run the command <strong>env<\/strong> again and look visually for the variable, or add the filtering using <strong>grep<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/><\/div><\/td><td><div class=\"text codecolorer\">$ env | grep PYGNMI<br \/>\nPYGNMI_USER=pygnmi<\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">How can I use it?<\/h4>\n\n\n\n<p>Later in this blogpost you will see how to use it in the <a rel=\"noreferrer noopener\" href=\"http:\/\/bit.ly\/2wmAIWw\" target=\"_blank\">Python script<\/a> together with the pyGNMI. Directly from the CLI you can simple call that as using the <strong>echo<\/strong> tool with the argument <strong>${variable_name}<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/><\/div><\/td><td><div class=\"text codecolorer\">$ echo ${PYGNMI_USER}<br \/>\npygnmi<\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Is that available only for this shell session?<\/h4>\n\n\n\n<p>Yes, it is. It is very easy to check that. Just open another window inside your terminal client or connect to the destination host, if you have created that variable there using the SSH and try to run the command used to check check the value. You will see the empty string:<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/><\/div><\/td><td><div class=\"text codecolorer\">$ ssh aaa@localhost<br \/>\nPassword:<br \/>\n<br \/>\n$ echo ${PYGNMI_USER}<\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n<\/pre>\n\n\n\n<p>The default behaviour of the Bash is to show the empty string for the value even if the variable does not exist.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>In <a href=\"http:\/\/bit.ly\/2mP3SJy\" target=\"_blank\" rel=\"noreferrer noopener\">our network automation training<\/a> you may learn this and a lot of user useful Linux life-hacks for your network automation.<\/p><\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">#3. Using environment variables in your pyGNMI script<\/h3>\n\n\n\n<p>Finally we reach the point, where we can bring this knowledge into operation. First of all, let&#8217;s create the environment variables for our credentials, which are username and password:<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/><\/div><\/td><td><div class=\"text codecolorer\">$ export PYGNMI_USER=pygnmi<br \/>\n$ export PYGNMI_PASS=pygnmi<\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n<\/pre>\n\n\n\n<p>Once completed you can create a script using <strong><a rel=\"noreferrer noopener\" href=\"https:\/\/bit.ly\/32UL5Pn\" target=\"_blank\">pyGNMI<\/a><\/strong> and <strong><a rel=\"noreferrer noopener\" href=\"https:\/\/docs.python.org\/3\/library\/os.html\" target=\"_blank\">os<\/a><\/strong>, which is a standard Python library. The latter have a function <strong>evnironb<\/strong>, which collects the environment variables and make them available in your script:<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/>23<br \/>24<br \/>25<br \/>26<br \/>27<br \/>28<br \/>29<br \/>30<br \/>31<br \/>32<br \/>33<br \/>34<br \/>35<br \/>36<br \/>37<br \/>38<br \/><\/div><\/td><td><div class=\"text codecolorer\">$ cat capabilities_env.py<br \/>\n#!\/usr\/bin\/env python<br \/>\n<br \/>\n# Int is requred to create two environemnt variables:<br \/>\n# PYGNMI_USER, which will be used to store the username to connect to the network function<br \/>\n# PYGNMI_PASS, which will be used to store the password to connect to the network function<br \/>\n<br \/>\n# Modules<br \/>\nfrom pygnmi.client import gNMIclient<br \/>\nimport os<br \/>\n<br \/>\n# Variables<br \/>\nhosts = &amp;#91;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;ip_address&quot;: &quot;192.168.100.10&quot;,<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;nos&quot;: &quot;arista-eos&quot;,<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;port&quot;: 57400<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;ip_address&quot;: &quot;192.168.100.11&quot;,<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;nos&quot;: &quot;nokia-sros&quot;,<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;port&quot;: 57400<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; ]<br \/>\n<br \/>\n# Body<br \/>\nif __name__ == &quot;__main__&quot;:<br \/>\n&nbsp; &nbsp; gnmi_user = &quot;default&quot; if &quot;PYGNMI_USER&quot; not in os.environ or not os.environ&amp;#91;&quot;PYGNMI_USER&quot;] else os.environ&amp;#91;&quot;PYGNMI_USER&quot;]<br \/>\n&nbsp; &nbsp; gnmi_pass = &quot;default&quot; if &quot;PYGNMI_PASS&quot; not in os.environ or not os.environ&amp;#91;&quot;PYGNMI_PASS&quot;] else os.environ&amp;#91;&quot;PYGNMI_PASS&quot;]<br \/>\n&nbsp; &nbsp; <br \/>\n&nbsp; &nbsp; for host in hosts:<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; with gNMIclient(target=(host&amp;#91;&quot;ip_address&quot;], host&amp;#91;&quot;port&quot;]), username=gnmi_user,<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; password=gnmi_pass, insecure=True) as gc:<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result = gc.capabilities()<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; print(f&quot;{host&amp;#91;'ip_address']}: {result}\\n\\n&quot;)<\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>As a basis for this script we <a href=\"https:\/\/bit.ly\/3iXzNhZ\" target=\"_blank\" rel=\"noreferrer noopener\">use the Capabilities RPC<\/a>.<\/p><\/blockquote>\n\n\n\n<p>The class <strong>gNMIclient<\/strong> from our pyGNMI library requires  the username and password to be provided at the time you create an object, which is used to communicate with the network devices. To provide them, we use the <strong>os.environ<\/strong> function, which dumps for us all the variables, which we put into <a rel=\"noreferrer noopener\" href=\"https:\/\/bit.ly\/2Wwvm6l\" target=\"_blank\">conditional<\/a>:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>If the environment variable <em>PYGNMI_USER<\/em> (or <em>PYGNMI_PASS<\/em> for password) exists and its value is defined, then use that value.<\/li><li>If it doesn&#8217;t exist or value is an empty string, then use the default value predefined in the script.<\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">#4. Validating the execution<\/h3>\n\n\n\n<p>First of all, let&#8217;s check that environment variables are defined:<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/><\/div><\/td><td><div class=\"text codecolorer\">$ env | grep PYGNMI<br \/>\nPYGNMI_PASS=pygnmi<br \/>\nPYGNMI_USER=pygnmi<\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n<\/pre>\n\n\n\n<p>Now execute the Python script with pyGNMI:<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/><\/div><\/td><td><div class=\"text codecolorer\">$ python capabilities_env.py <br \/>\n192.168.100.10: {'supported_models': &amp;#91;{'name': 'openconfig-packet-match-types', 'organization': 'OpenConfig working group', 'version': '1.0.2'}, {'name': 'arista-qos-augments', 'organization': 'Arista Networks, Inc.', 'version': ''}, {'name': 'openconfig-platform-cpu', 'organization': 'OpenConfig working group', 'version': '0.1.1'}, {'name': 'arista-relay-agent-deviations', 'organization': 'Arista Networks &amp;lt;http:\/\/arista.com\/&amp;gt;<br \/>\n!<br \/>\n! Some output is truncated for brevity<br \/>\n!<br \/>\n192.168.100.11: {'supported_models': &amp;#91;{'name': 'nokia-conf', 'organization': 'Nokia', 'version': '20.10.R3'}, <br \/>\n!<br \/>\n! Furter output is truncated for brevity<\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n<\/pre>\n\n\n\n<p>You see that the connectivity to the devices is successful and you can grab the information. Now ssh to your host with pyGNMI again and check that there is no variables <em>PYGNMI_USER<\/em> and <em>PYGNMI_PASS<\/em> defined.<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/><\/div><\/td><td><div class=\"text codecolorer\">$ ssh aaa@localhost<br \/>\nPassword:<br \/>\n<br \/>\n$ env | grep PYGNMI<\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n<\/pre>\n\n\n\n<p>Run the Python script again:<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/><\/div><\/td><td><div class=\"text codecolorer\">$ python capabilities_env.py <br \/>\nHost: 192.168.100.10:57400<br \/>\nError: Authentication failed<br \/>\nCRITICAL:root:Host: 192.168.100.10:57400, Error: Authentication failed<\/div><\/td><\/tr><\/tbody><\/table><\/div>\n\n<\/pre>\n\n\n\n<p>The Python script used the default variables and, as they deviates from the one configured on the device, the authentication is not successful. In the same time, usage of the default variables allows you to make sure that the script ends with the meaningful error (Authentication failed), rather than having a traceback caused by the usage of undefined variables<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">GitHub and PyPI <\/h2>\n\n\n\n<p>You can see this and others examples of the pygnmi usage in our <a href=\"https:\/\/bit.ly\/32UL5Pn\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub repository<\/a>. Moreover, it is also available in PyPI, what makes the installation process very easy.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">If you prefer video<\/h2>\n\n\n\n<p>You can watch this demo on our YouTube channel:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<div class=\"youtube_embed_wrapper alia_embed_wrapper\"><!--ALIA start embed content--><iframe loading=\"lazy\" title=\"pygnmi. Demo of using environment variables to store credentials\" width=\"880\" height=\"660\" src=\"https:\/\/www.youtube.com\/embed\/WPICbeUN6aU?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><!--AliA end embed content--><\/div>\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Lessons learned<\/h2>\n\n\n\n<p>To be honest, when the colleagues shown that to me and explain how that works, I was quite impressed. On the other hand, if not used properly, it may lead to the problems. For instance, if you put them as part of your environment file to make sure that they are persistent after the system reboot (or if you dockerize your application and therefore provide the password in there). In that case it is even less secure than having them in a plain text in a file with the tool itself. So don&#8217;t get into that trap.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Everything can be hacked, that is an important truth. So one of our goals, as network engineers and network automators, is to make sure the tools we are building and using are secure enough to reduce the possibility of sensitive information leak as much as possible. And usage of the environment variables helps us here a lot. Take care and good bye.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Support us<\/h2>\n\n\n\n<style>\r\n        .wpedon-container .wpedon-select,\r\n        .wpedon-container .wpedon-input {\r\n            width: 171px;\r\n            min-width: 171px;\r\n            max-width: 171px;\r\n        }\r\n    <\/style><div class='wpedon-container wpedon-align-center'><label id='wpedon-1919-name-label'>Support new interop and automation articles at karneliuk.com<br \/><span class='price'><\/span>EUR<\/label><br \/>\r\n\t\t<script>\r\n\t\tjQuery(document).ready(function(){\r\n\t\t\tjQuery('#dd_7c923f42677d03afd19270d827313255').on('change', function() {\r\n\t\t\t  jQuery('#amount_7c923f42677d03afd19270d827313255').val(this.value);\r\n              jQuery('#price_7c923f42677d03afd19270d827313255').val(this.value);\r\n\t\t\t});\r\n\t\t});\r\n\t\t<\/script>\r\n\t\t<br \/><label style='font-size:11pt !important;'>I want to support with:<\/label><br \/><select class='wpedon-select' name='dd_7c923f42677d03afd19270d827313255' id='dd_7c923f42677d03afd19270d827313255'><option value='9.99'>9.99 EUR<\/option><option value='4.99'>4.99 EUR<\/option><option value='24.99'>24.99 EUR<\/option><option value='49.99'>49.99 EUR<\/option><option value='99.99'>99.99 EUR<\/option><option value='199.99'>199.99 EUR<\/option><\/select><br \/><br \/><form target='_blank' action='https:\/\/www.paypal.com\/cgi-bin\/webscr' method='post' class='wpedon-form'><input type='hidden' name='cmd' value='_donations' \/><input type='hidden' name='business' value='MZVY3WH2X7HPN' \/><input type='hidden' name='currency_code' value='EUR' \/><input type='hidden' name='notify_url' value='https:\/\/karneliuk.com\/wp-admin\/admin-post.php?action=add_wpedon_button_ipn'><input type='hidden' name='lc' value='en_US'><input type='hidden' name='bn' value='WPPlugin_SP'><input type='hidden' name='return' value='http:\/\/karneliuk.com\/thanks\/' \/><input type='hidden' name='cancel_return' value='' \/><input class='wpedon_paypalbuttonimage' type='image' src='https:\/\/www.paypal.com\/en_US\/i\/btn\/btn_donateCC_LG.gif' border='0' name='submit' alt='Make your payments with PayPal. It is free, secure, effective.' style='border: none;'><img alt='' border='0' style='border:none;display:none;' src='https:\/\/www.paypal.com\/en_US\/i\/scr\/pixel.gif' width='1' height='1'><input type='hidden' name='amount' id='amount_7c923f42677d03afd19270d827313255' value='9.99' \/><input type='hidden' name='price' id='price_7c923f42677d03afd19270d827313255' value='9.99' \/><input type='hidden' name='item_number' value='karneliuk.com-general' \/><input type='hidden' name='item_name' value='Support new interop and automation articles at karneliuk.com' \/><input type='hidden' name='name' value='Support new interop and automation articles at karneliuk.com' \/><input type='hidden' name='custom' value='1919'><input type='hidden' name='no_shipping' value='1'><input type='hidden' name='no_note' value='0'><input type='hidden' name='currency_code' value='EUR'><\/form><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">P.S.<\/h2>\n\n\n\n<p>If you have further questions or you need help with your networks, we are happy to assist you, <a href=\"http:\/\/karneliuk.com\/contact\/\">just send us a message<\/a>. Also don\u2019t forget to share the article on your social media, if you like it.<\/p>\n\n\n\n<p>BR,<\/p>\n\n\n\n<p>Anton Karneliuk <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello my friend, Recently we were asked, what is the safest way to store the credentials for network devices to your automation tools (e.g., the one based on Python and gNMI). Building the network automation solutions for a while, we have a good answer to you.<\/p>\n","protected":false},"author":1,"featured_media":4684,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16],"tags":[142,131,191,70,208,166,121],"class_list":{"0":"post-4658","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-network","8":"tag-arista","9":"tag-automation","10":"tag-gnmi","11":"tag-nokia","12":"tag-pygnmi","13":"tag-python","14":"tag-security"},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/karneliuk.com\/wp-json\/wp\/v2\/posts\/4658","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/karneliuk.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/karneliuk.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/karneliuk.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/karneliuk.com\/wp-json\/wp\/v2\/comments?post=4658"}],"version-history":[{"count":24,"href":"https:\/\/karneliuk.com\/wp-json\/wp\/v2\/posts\/4658\/revisions"}],"predecessor-version":[{"id":4687,"href":"https:\/\/karneliuk.com\/wp-json\/wp\/v2\/posts\/4658\/revisions\/4687"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/karneliuk.com\/wp-json\/wp\/v2\/media\/4684"}],"wp:attachment":[{"href":"https:\/\/karneliuk.com\/wp-json\/wp\/v2\/media?parent=4658"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/karneliuk.com\/wp-json\/wp\/v2\/categories?post=4658"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/karneliuk.com\/wp-json\/wp\/v2\/tags?post=4658"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}