ktbyers / netmiko

Multi-vendor library to simplify Paramiko SSH connections to network devices
MIT License
3.49k stars 1.26k forks source link

Hope to connect to network device locally through jumphost without username and password #3432

Closed softputer closed 1 month ago

softputer commented 1 month ago

Description of Issue/Question

Question: Cannot use the ssh connection to send command by netmiko

Description: I have developed an golang application which can connect network device directly without the need to input username and password. Like the command below, I can connect network device: locallly, we can hide the username and password of the network device from common users.

ssh <ip>

Now I want to reuse the ssh connnect for netmiko to send command, i have reviewed the doc: https://pynet.twb-tech.com/blog/netmiko-ssh-proxy-support.html

But it seems like i still need to input the username and password, which does not satisfy our requirements. Below is the expected configuration: with only device type, host or ip and ssh_config_file

device = {
    "device_type": "cisco_ios",
    "host": "cisco1.lasthop.io",
    "ssh_config_file": "./ssh_config",
}

The ssh config file use proxy command,

local ssh ---> agent (use jumpost as proxy and connect with username and password)----> jumphost ----> network device

It seems like netmiko does not support it yet. So any plan to support it? or how could i change netmiko locally to support it ?

ktbyers commented 1 month ago

@softputer Are you executing your Go application from the Jumphost then?

I am confused on your issue--what is it that is not working?

Probably need to include the relevant Netmiko code, and the SSH config file (simplified, you can obviously hide/obscure usernames and passwords), and the error/exception that you run into.

Another option (given your setup) is just use Netmiko linux device_type to connect to the jumphost (I am assuming it is Linux) and then have Netmiko execute your Go application on the jumphost (I am assuming that is where it is running).

softputer commented 1 month ago

Well, let me give you a detailed introduction.

Original Way to access Network Device:

Local Host --->   JumpHost ---> NetworkDevice

Each time we want to do some operations: login into devices, upload or download files, we need to login into jumphost first. Then it is ok to use ssh or scp to do the operations.

But we have tens of thousands of network devices , we need to control the accessing and record the operations, which lead to the design

Local Host --->   Agent   Service ---> JumpHost ---> NetworkDevice

In this design, the users have no need to know anything about the jump host, as long as they are authorized to access some network devices, they can ssh into network device in their local host. Of course, agent service will check if the user can access the network device the specified.

Agent service is run in any server which can connect jumphost, there are no extra services running in jumhost, we just use ssh protocol to access jumphost

In this way, we can ssh into devices, upload files into remote network devices, and download files locally from remote network devices.

But there is one case we cannot support for now, that is: our engineers get used to use netmiko to run patch jobs on the jumphost in the past. how to support them to run these python scripts locally?

Actually I have reviewed the netmiko and paramiko code, netmiko just use the ssh session created from paramiko and use the ssh session to do operations.

BUT paramiko cannot use our ssh config to create ssh connection correctly Our ssh config example is as below:

Host *
  StrictHostKeyChecking no
  HostName %h
  UserKnownHostsFile /dev/null
  LogLevel ERROR
  IdentityFile /XXXXX/ssh_private_key
  IdentitiesOnly yes
  ServerAliveInterval 60

  ProxyCommand ssh -i "/XXXX/ssh_private_key" -o "UserKnownHostsFile=/XXXXXX/ssh_known_hosts" -p XXXX -F /dev/null DOMAINXXXX -W %h:%p
  SendEnv LANG LC_* TOC_*

This ssh config is used to connect to Agent service, The agent will connect network devices through jumphost.

As long as paramiko can use this ssh config to connect out agent to create ssh connection , everything goes well then.

ktbyers commented 1 month ago

Can you expand on this a bit i.e. why it doesn't work in Paramiko (so I don't have to go and try to reverse engineer it in Paramiko)?

BUT paramiko cannot use our ssh config to create ssh connection correctly

Your SSH config doesn't work with openssh so here is a somewhat close proximity that I could get to work with openSSH and with Netmiko.

I had to decouple the jumphost entry to be separate and make the -F argument work. Not clear to me why I had to do this as when I looked at the Python debugger and the popen call that Paramiko made--it looked correct, but it would still fail.

host jumphost
  IdentitiesOnly yes
  IdentityFile ~/.ssh/test_rsa
  User admin
  HostName jump.domain.com
  ServerAliveInterval 60
  UserKnownHostsFile ~/.ssh/known_hosts
  StrictHostKeyChecking no

Host * !jumphost
  StrictHostKeyChecking no
  HostName %h
  UserKnownHostsFile /dev/null
  LogLevel ERROR
  IdentityFile ~/.ssh/test_rsa
  IdentitiesOnly yes
  ServerAliveInterval 60
  ProxyCommand ssh -i "~/.ssh/test_rsa" -o "UserKnownHostsFile=~/.ssh/known_hosts" -p 22 -F ~/.ssh/ssh_config -W %h:%p jumphost
#  ProxyCommand ssh -i "/XXXX/ssh_private_key" -o "UserKnownHostsFile=/XXXXXX/ssh_known_hosts" -p XXXX -F /dev/null DOMAINXXXX -W %h:%p
  SendEnv LANG LC_* TOC_*

Obviously at this point a lot of the entries in the second stanza ("Host * !jumphost) are not needed. I also got rid of your DOMAINXXXX--what is that for here?

softputer commented 1 month ago

The way you write the ssh config is exactly the same as mine. And after I write device as below, then i can use netmiko locally to connect remote network devices, thanks for your time

device = {
    'device_type': 'XXX', 
    'ip': '172.20.161.129',   # network device ip
    'key_file': 'XXXXX/ssh_private_key',   
    'ssh_config_file': "/XXXXX/ssh_config",  #ssh config i have written above
}

key_file and ssh_config_file should be provided at the same time.