Archive
, Super Contributor
Archive
Junos NETCONF and SSH tunneling (Part 2)
Nov 4, 2013

VERIFY NETCONF CONNECTIVITY

 

Now that we've established SSH tunneling through the network, we can verify a NETCONF session directly.  When I use the ssh command I specify the sub-command netconf using the -s parameter as illustrated.  Note that the netconf sub-command is after the hostname:

 

[jeremy@jeremy-pc.corp.net]$ ssh -s srx3600.jumpy netconf
Warning: Permanently added '[localhost]:8001' (RSA) to the list of known hosts. <!-- No zombies were killed during the creation of this user interface --> <!-- user jeremy, class j-super-user --> <hello> <capabilities> <capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:candidate:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:confirmed-commit:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:validate:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:url:1.0?protocol=http,ftp,file</capability> <capability>http://xml.juniper.net/netconf/junos/1.0</capability> <capability>http://xml.juniper.net/dmi/system/1.0</capability> </capabilities> <session-id>22595</session-id> </hello> ]]>]]>

 

What you see here is the actual NETCONF "hello" message in response to the connection.  If you do not see this, then one of two things is not setup correctly:

 

  1. Your Junos device is not configured with NETCONF enabled.  You can verify this by checking the [edit system services] stanza.  If you are using an SRX, then you also need to enable NETCONF on the security-zone/interface.

     

  2. Your network/firewall is blocking TCP/830, which is the default port for NETCONF

You can close the NETCONF session using <Ctrl-C>.

 

SAMPLE PYTHON SCRIPT

 

I am going to demonstrate a Python script using a module called jnpr.eznc.  This is an active open-source project that is relatively new.  I will write more detailed blog on this module in the near term, but for now, if you'd like to get started using it, please see the github repo and README files located here.

 

Let's first take a look at a script that is *NOT* in an ssh-tunnelled environment.  Let's say I simply want to connect to the Junos device, display the serial-number and version, and then close the connection.  It would look like the following:

 

from jnpr.junos import Device

dev = Device(host='srx3600.corp.net', user='jeremy', password='logmein')

dev.open()

print dev.facts['serialnumber']
print dev.facts['version']
dev.close()

 

The above example illustrates making a connection providing the user name and password.  If you are using ssh-keys, then you simply do not provide the password.

 

Now to do the tunneling use-case, we know that we are connecting through a local port forward.  We could do something like the following:

 

from jnpr.junos import Device

# srx3600-1.jumpy uses port 8001 dev = Device(host='localhost', port=8001, user='jeremy') dev.open() print dev.facts['serialnumber'] print dev.facts['version'] dev.close()

 

But now we've duplicated information between our script and the ssh config file.  What we really want to do is use the ssh config file to extract the port associated with srx3600-1.jumpy so we can connect by the host name directly.

 

I am using the Python paramiko module to illustrate the technique to load the ssh config file and extract the information based on the host name defined in the config file, e.g. "srx3600-1.jumpy":

 

import paramiko
import os
from jnpr.junos import Device # load the $HOME/.ssh/config file and do a lookup on the
# host name "srx3600-1.jumpy"
config_file = os.path.join(os.getenv('HOME'),'.ssh/config') ssh_config = paramiko.SSHConfig() ssh_config.parse(open(config_file,'r')) got_lkup = ssh_config.lookup( "srx3600-1.jumpy" )
# now open the NETCONF connection using the information
# we retreived from the ssh config file
dev = Device(user='jeremy', host=got_lkup['hostname'], port=got_lkup['port'])
dev.open()
print dev.facts['serialnumber'] print dev.facts['version'] dev.close()

 

(UPDATED NOTE: 2014-Apr-15:  The above paramiko code is *not* required as of later version of the py-junos-eznc module.  This functionality was directly incorporated into the "Device" class.  So long as you have an SSH config file defined correctly and an active SSH tunnel, you will be able to connect through a jumphost when you invoke the Device.open() method).

 

JUNOS AUTOMATION WITH PYTHON

 

Writing Python scripts for Junos automation tasks can be easy (and fun!).  With a little bit of practice and the right set of modules (like jnpr.junos), you can quickly create very powerful automation tools with a high degree of confidence.

 

 

 

 

Apr 29, 2015
Juniper Employee

Hi dalonso,

 

It seems you are hitting some sort of generic exception.  You can try to get more information using:

 

from jnpr.junos.exception import ConnectError

try:
dev.open()
except ConnectError as e:
print e._orig

If you need further assitance please open a new issue here:  https://groups.google.com/forum/#!forum/junos-python-ez

 

Thanks,

-Rick

 

May 16, 2016

Hello guys,

I'm deploying a new playbook in order to provision some devices and working with netconify is working fine, but when i want to upgrade the junos through the jump server i'm having issues with paramiko authentication. It is failing no matter is I use keys or password it just doesn't work.

I have a ssh tunnel to the device using ./.ssh/config like this

 

Host tunnel
Hostname jumpbox
ForwardX11Trusted yes
LocalForward 8001 10.210.0.157:22
ControlPath ~/.ssh/master-%l-%r@jumpbox:%p
ControlMaster auto

 

Host distant
User local
Hostname localhost
Port 8001
ForwardX11Trusted yes

 

Host *
ForwardAgent yes
Protocol 2
StrictHostKeyChecking no
UserKnownHostsFile=/dev/null

 

On the jump box my ./.ssh/config is like this

 

Host *
ForwardX11Trusted yes
ForwardAgent yes
Protocol 2

 

SO basically I want to use the module junos_install_os in order to upgrade the switches. The module junos_install_config is working fine it load merges the configuration and commits with no issue through the ssh tunnel and the playboom looks like this.

 

- name: Load merge a configuration to a device running Junos OS
hosts: local
roles:
- Juniper.junos
connection: local
gather_facts: no

vars:
user: local,
password: pass
hostname: distanthost
hostnameip: 127.0.0.1
port: 8001

tasks:
- name: load merge a configuration file
junos_install_config:
host={{ hostnameip }}
file=/Users/lab/Documents/Ansible-Configs/{{ hostname }}.txt
user={{ user }}
passwd={{ password }}
port={{ port }}
overwrite=true
logfile=/usr/local/etc/ansible/logs/{{ hostname }}.log

Like I said this one is working just fine. So when I try to use the module junos_install_os to upgrade the junos I have the issue.

The playbook looks like this

---
- name: Install Junos OS
hosts: local
roles:
- Juniper.junos
connection: local
gather_facts: no
vars:
wait_time: 3600
user: local
password: c00lb0x
host: 127.0.0.1
port: 8001
OS_version: 14.1X53-D36.3
OS_package: /Users/cdassy/Downloads/jinstall-qfx-5-14.1X53-D35.3-domestic-signed.tgz

tasks:
- name: Install Junos OS package
junos_install_os:
host={{ host }}
user={{ user }}
passwd={{ password }}
port={{ port }}
reboot=yes
version={{ OS_version }}
package={{ OS_package }}
logfile=/usr/local/etc/ansible/logs/software.log
register: sw
notify:
- wait_reboot

handlers:
- name: wait_reboot
wait_for: host=172.0.0.1 port=8001 timeout={{ wait_time }}
when: not sw.check_mode

 

And when i run this the log gives me this

 

2016-05-16 18:49:47,258:127.0.0.1:Starting the software upgrade process: /Users/cdassy/Downloads/jinstall-qfx-5-14.1X53-D35.3-domestic-signed.tgz
2016-05-16 18:49:47,258:127.0.0.1:computing local checksum on: /Users/cdassy/Downloads/jinstall-qfx-5-14.1X53-D35.3-domestic-signed.tgz
2016-05-16 18:49:48,750:127.0.0.1:cleaning filesystem ...
2016-05-16 18:49:48,750:ncclient.operations.rpc:Requesting 'ExecuteRpc'
2016-05-16 18:50:10,771:paramiko.transport:Connected (version 2.0, client OpenSSH_6.9)
2016-05-16 18:50:10,855:paramiko.transport:Authentication (publickey) failed.
2016-05-16 18:50:10,896:paramiko.transport:Authentication (keyboard-interactive) failed.


SSH and SCP work perfectly through the tunnel I tested and it's fine. If run it with -vvv the output is the following


$ ansible-playbook ./playbooks/upgrade-tor.yaml --ask-vault-pass -vvv
No config file found; using defaults

PLAYBOOK: upgrade-tor.yaml *****************************************************
1 plays in ./playbooks/upgrade-tor.yaml

PLAY [Install Junos OS] ********************************************************

TASK [Install Junos OS package] ************************************************
task path: /usr/local/etc/ansible/playbooks/upgrade-tor.yaml:18
ESTABLISH LOCAL CONNECTION FOR USER: ansible
localhost EXEC /bin/sh -c '( umask 22 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1463438979.26-166095963959870 `" && echo "` echo $HOME/.ansible/tmp/ansible-tmp-1463438979.26-166095963959870 `" )'
localhost PUT /var/folders/fq/y7x_08tx17j_c94q7qbwv1c00000gn/T/tmphgHnIZ TO /Users/ansible/.ansible/tmp/ansible-tmp-1463438979.26-166095963959870/junos_install_os
localhost EXEC /bin/sh -c 'LANG=en_CA.UTF-8 LC_ALL=en_CA.UTF-8 LC_MESSAGES=en_CA.UTF-8 /usr/bin/env python /Users/ansible/.ansible/tmp/ansible-tmp-1463438979.26-166095963959870/junos_install_os; rm -rf "/Users/ansible/.ansible/tmp/ansible-tmp-1463438979.26-166095963959870/" > /dev/null 2>&1'
An exception occurred during task execution. The full traceback is:
Traceback (most recent call last):
File "/Users/ansible/.ansible/tmp/ansible-tmp-1463438979.26-166095963959870/junos_install_os", line 2251, in <module>
main()
File "/Users/ansible/.ansible/tmp/ansible-tmp-1463438979.26-166095963959870/junos_install_os", line 256, in main
results = junos_install_os(module, dev)
File "/Users/ansible/.ansible/tmp/ansible-tmp-1463438979.26-166095963959870/junos_install_os", line 198, in junos_install_os
ok = sw.install(package, **sw_args)
File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/jnpr/junos/utils/sw.py", line 399, in install
checksum=checksum)
File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/jnpr/junos/utils/sw.py", line 274, in safe_copy
self.put(package, remote_path, progress)
File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/jnpr/junos/utils/sw.py", line 132, in put
with SCP(self._dev, progress=progress) as scp:
File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/jnpr/junos/utils/scp.py", line 122, in __enter__
return self.open(**self._scpargs)
File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/jnpr/junos/utils/scp.py", line 107, in open
sock=sock
File "/usr/local/Cellar/ansible/2.0.2.0/libexec/vendor/lib/python2.7/site-packages/paramiko/client.py", line 367, in connect
look_for_keys, gss_auth, gss_kex, gss_deleg_creds, gss_host)
File "/usr/local/Cellar/ansible/2.0.2.0/libexec/vendor/lib/python2.7/site-packages/paramiko/client.py", line 584, in _auth
raise saved_exception
paramiko.ssh_exception.BadAuthenticationType: ('Bad authentication type', [u'publickey', u'keyboard-interactive']) (allowed_types=[u'publickey', u'keyboard-interactive'])

fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "invocation": {"module_name": "junos_install_os"}, "module_stderr": "Traceback (most recent call last):\n File \"/Users/ansible/.ansible/tmp/ansible-tmp-1463438979.26-166095963959870/junos_install_os\", line 2251, in <module>\n main()\n File \"/Users/ansible/.ansible/tmp/ansible-tmp-1463438979.26-166095963959870/junos_install_os\", line 256, in main\n results = junos_install_os(module, dev)\n File \"/Users/ansible/.ansible/tmp/ansible-tmp-1463438979.26-166095963959870/junos_install_os\", line 198, in junos_install_os\n ok = sw.install(package, **sw_args)\n File \"/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/jnpr/junos/utils/sw.py\", line 399, in install\n checksum=checksum)\n File \"/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/jnpr/junos/utils/sw.py\", line 274, in safe_copy\n self.put(package, remote_path, progress)\n File \"/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/jnpr/junos/utils/sw.py\", line 132, in put\n with SCP(self._dev, progress=progress) as scp:\n File \"/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/jnpr/junos/utils/scp.py\", line 122, in __enter__\n return self.open(**self._scpargs)\n File \"/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/jnpr/junos/utils/scp.py\", line 107, in open\n sock=sock\n File \"/usr/local/Cellar/ansible/2.0.2.0/libexec/vendor/lib/python2.7/site-packages/paramiko/client.py\", line 367, in connect\n look_for_keys, gss_auth, gss_kex, gss_deleg_creds, gss_host)\n File \"/usr/local/Cellar/ansible/2.0.2.0/libexec/vendor/lib/python2.7/site-packages/paramiko/client.py\", line 584, in _auth\n raise saved_exception\nparamiko.ssh_exception.BadAuthenticationType: ('Bad authentication type', [u'publickey', u'keyboard-interactive']) (allowed_types=[u'publickey', u'keyboard-interactive'])\n", "module_stdout": "", "msg": "MODULE FAILURE", "parsed": false}

NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit @./playbooks/upgrade-tor.retry

PLAY RECAP *********************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1


I also tried to run in forcing ansible to use ssh instead of paramiko with ansible_connection: ssh and the result is this


$ ansible-playbook ./playbooks/upgrade-tor.yaml --ask-vault-pass -vvv
No config file found; using defaults
Vault password:

PLAYBOOK: upgrade-tor.yaml *****************************************************
1 plays in ./playbooks/upgrade-tor.yaml

PLAY [Install Junos OS] ********************************************************

TASK [Install Junos OS package] ************************************************
task path: /usr/local/etc/ansible/playbooks/upgrade-tor.yaml:19
<localhost> ESTABLISH SSH CONNECTION FOR USER: ansible
<localhost> SSH: EXEC sshpass -d20 ssh -C -q -o ControlMaster=auto -o ControlPersist=60s -o Port=22 -o User=ansible -o ConnectTimeout=10 -o ControlPath=/Users/ansible/.ansible/cp/ansible-ssh-%h-%p-%r localhost '/bin/sh -c '"'"'( umask 22 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1463439407.61-32299045715305 `" && echo "` echo $HOME/.ansible/tmp/ansible-tmp-1463439407.61-32299045715305 `" )'"'"''
<localhost> PUT /var/folders/fq/y7x_08tx17j_c94q7qbwv1c00000gn/T/tmpgVMgai TO /Users/ansible/.ansible/tmp/ansible-tmp-1463439407.61-32299045715305/junos_install_os
<localhost> SSH: EXEC sshpass -d20 sftp -b - -C -o ControlMaster=auto -o ControlPersist=60s -o Port=22 -o User=ansible -o ConnectTimeout=10 -o ControlPath=/Users/ansible/.ansible/cp/ansible-ssh-%h-%p-%r '[localhost]'
<localhost> ESTABLISH SSH CONNECTION FOR USER: ansible
<localhost> SSH: EXEC sshpass -d20 ssh -C -q -o ControlMaster=auto -o ControlPersist=60s -o Port=22 -o User=ansible -o ConnectTimeout=10 -o ControlPath=/Users/ansible/.ansible/cp/ansible-ssh-%h-%p-%r -tt localhost '/bin/sh -c '"'"'LANG=en_CA.UTF-8 LC_ALL=en_CA.UTF-8 LC_MESSAGES=en_CA.UTF-8 /usr/bin/env python /Users/ansible/.ansible/tmp/ansible-tmp-1463439407.61-32299045715305/junos_install_os; rm -rf "/Users/ansible/.ansible/tmp/ansible-tmp-1463439407.61-32299045715305/" > /dev/null 2>&1'"'"''
fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "invocation": {"module_args": {"host": "127.0.0.1", "logfile": "/usr/local/etc/ansible/logs/software.log", "no_copy": false, "package": "/Users/ansible/Downloads/jinstall-qfx-5-14.1X53-D35.3-domestic-signed.tgz", "passwd": "pass", "port": 8001, "reboot": "yes", "reboot_pause": 10, "user": "local", "version": "14.1X53-D36.3"}, "module_name": "junos_install_os"}, "msg": "junos-eznc >= 1.2.2 is required for this module"}

NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit @./playbooks/upgrade-tor.retry

PLAY RECAP *********************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1

 

Can anyone help me here I've been troubleshooting for days I'm stuck now and the switch has netconf service ssh activated btw.

 

All the junos-eznc file are installed and updated

cffi (1.6.0)
cryptography (1.3.2)
enum34 (1.1.6)
idna (2.1)
ipaddress (1.0.16)
Jinja2 (2.8)
junos-eznc (1.3.1)
junos-netconify (1.0.3)
lxml (3.6.0)
MarkupSafe (0.23)
ncclient (0.4.7)
netaddr (0.7.18)
paramiko (2.0.0)
pip (8.1.2)
pyasn1 (0.1.9)
pycparser (2.14)
pycrypto (2.6.1)
pyserial (3.0.1)
PyYAML (3.11)
scp (0.10.2)
setuptools (21.0.0)
six (1.10.0)
wheel (0.26.0)

 

ansible 2.0.2.0
config file = configured module search path = Default w/o overrides

 

Python 2.7.11

 

Thanks in advance and bets regards,

CD

Feedback