2016-01-23 2 views
4

Я пытаюсь выполнить ssh-туннель с ПК -> server1 ---> server2 ----> switch1 Это возможно через обычный терминал с простым: ssh switch1 он ссылается на мой ssh_config, который гласит:paramiko.ssh_exception.ProxyCommandFailure: 'Broken pipe')

Host server1 
    user bill 
    Hostname server1 
    ForwardAgent yes 
    IdentityFile ~/.ssh/id_rsa 
    ProxyCommand none 

Host server2 
    user bill 
    Hostname server2 
    IdentityFile ~/.ssh/id_rsa 
    ProxyCommand ssh server1 /usr/bin/nc %h %p 

Host switch1 
    user bill 
    Hostname %h.omniture.com 
    ProxyCommand ssh server2 /usr/bin/nc %h %p 

Не проблема с обычного терминала. Но попытка создать скрипт python для этого оказалась непростой.

Сценарий выглядит следующим образом:

import paramiko 
import subprocess 
import getpass 
import os 


def ssh_command(ip, user, passwd, command): 
    client = paramiko.SSHClient() 
    client.load_host_keys('/Users/bill/.ssh/known_hosts') 
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
    config = paramiko.SSHConfig() 
    if os.path.exists('/etc/ssh/ssh_config'): 
     config.parse(open('/etc/ssh/ssh_config')) 
    if os.path.exists(os.path.expanduser('~/.ssh/config')): 
     config.parse(open(os.path.expanduser('~/.ssh/config'))) 

    host = config.lookup(ip) 
    if 'proxycommand' in host: 
       proxy = paramiko.ProxyCommand(
       subprocess.check_output(
       [os.environ['SHELL'], '-c', 'echo %s' % 
       host['proxycommand']] 
       ).strip() 
      ) 
    else: 
     proxy = None 

    client.connect(host['hostname'], username='bill', 
    password=getpass.getpass(), sock=proxy) 
    ssh_session = client.get_transport().open_session() 
    if ssh_session.active: 
     ssh_session.exec_command(command) 
     print ssh_session.recv(1024) 
    return 
ssh_command('sw-a-102.sin2', 'bill', getpass.getpass(), 'show ver') 

Ошибки я получаю:

No handlers could be found for logger "paramiko.transport" 
Traceback (most recent call last): 
    File "/Users/bill/git/tools/python/dns-check/proxy-test.py", line 34, in <module> 
    ssh_command('switch1', 'bill', getpass.getpass(), 'show ver') 
    File "/Users/bill/git/tools/python/dns-check/proxy-test.py", line 28, in ssh_command 
    client.connect(host['hostname'], username='bill', password=getpass.getpass(), sock=proxy) 
    File "/Library/Python/2.7/site-packages/paramiko/client.py", line 265, in connect 
    t.start_client() 
    File "/Library/Python/2.7/site-packages/paramiko/transport.py", line 406, in start_client 
    raise e 
paramiko.ssh_exception.ProxyCommandFailure: ('ssh server2 /usr/bin/nc switch1 22', 'Broken pipe') 

Если я могу получить эту работу, используя paramiko, что было бы здорово, если кто-то знает лучше, это тоже хорошо. Спасибо за ваше время.

ответ

0

Существует лучше способ, все еще с Paramiko, но без ProxyCommand конфигурации.

Причина, по которой команда прокси-сервера paramiko является ошибкой и подвержена условиям гонки, что является причиной ошибки выше.

OTOH, SSH имеет встроенную поддержку туннелирования в самом протоколе и не требует внешних инструментов для его достижения.

import paramiko 

# Make clients 
client = paramiko.SSHClient() 
client.set_missing_host_key_policy(paramiko.MissingHostKeyPolicy()) 
server2_client = paramiko.SSHClient() 
server2_client.set_missing_host_key_policy(paramiko.MissingHostKeyPolicy()) 
switch1_client = paramiko.SSHClient() 
switch1_client.set_missing_host_key_policy(paramiko.MissingHostKeyPolicy()) 

# Connect to server1 normally 
client.connect('server1') 

# Make channel server1 -> server2 
server2_chan = client.get_transport().open_channel('direct-tcpip', ('<server2 ip>', 22,), ('127.0.0.1', 0)) 

# Connect to server2 via server1's channel 
server2_client.connect('<server2 ip>', sock=server1_chan) 

# Make channel server2 -> switch1 
switch1_chan = server2_client.get_transport().open_channel('direct-tcpip', ('<switch1 ip>', 22,), ('127.0.0.1', 0)) 

# Finally connect to switch1 via server2 channel 
switch1_client.connect('switch1', sock=server2_chan) 
switch1_client.exec_command(<command>) 

Заменить имена серверов и коммутаторов их IP-адресами.

См. Также parallel SSH client based on paramiko с поддержкой встроенного туннелирования SSH.