2014-04-11 43 views
3

我使用Paramiko在遠程服務器上執行bash腳本。在其中一些腳本中,有其他服務器的ssh連接。如果我僅使用bash,不使用Python,則我的DSA密鑰將被轉發,並由第一臺遠程服務器上的bash腳本用於連接到第二臺遠程服務器。當我使用Paramiko時,情況並非如此。使用Paramiko的DSA密鑰轉發?

擊例如:

[email protected]:~ & ssh [email protected] 
[email protected]:~ # ssh [email protected] hostname 
secondserver.mydomain.org 

使用的paramiko:

#!/usr/bin/python3 
# -*- coding: utf-8 -*- 

import paramiko 

class SSHSession: 


    def __init__(self, server_address, user='root', port=22): 
     self.connected = False 
     self.server_address = server_address 
     self.user   = user 
     self.port   = port 


    def connect(self, clear_channel=True): 
     try: 
      if self.server_address == None: 
       raise ValueError('No hostname') 
     except: 
      raise ValueError('No hostname') 
     else: 
      try: 
       self.ssh_client = paramiko.SSHClient() 
       self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
       self.ssh_client.connect(self.server_address, username=self.user) 
       #self.transport = self.ssh_client.get_transport() 
       #self.channel = self.transport.open_forward_agent_channel() 
       self.channel = self.ssh_client.invoke_shell() 
      except: 
       self.connected = False 
       return False 
      else: 
       self.connected = True 
       return True 

    def exec_command(self, command, newline='\r'): 
     if not self.connected: 
      raise Exception('Not connected') 
     else: 
      timeout = 31536000 # 365 days in seconds 
      self.channel.settimeout(timeout) 
      line_buffer = '' 
      channel_buffer = '' 
      end_string  = 'CLIENT_EXPECT_CMD_OK' 
      print('[SEND ] >>', command) 
      self.channel.send(command + ' ; echo ' + end_string + newline) 
      while True: 
       channel_buffer = self.channel.recv(1).decode('UTF-8') 
       if len(channel_buffer) == 0: 
        raise Exception('connection lost with server: ' + self.server_address) 
        break 
       channel_buffer = channel_buffer.replace('\r', '') 
       if channel_buffer != '\n': 
        line_buffer += channel_buffer 
       else: 
        if line_buffer == end_string: 
         break 
        print('[RECEIVE] <<', line_buffer) 
        line_buffer = '' 


    def disconnect(self): 
     self.ssh_client.close() 


    def __enter__(self): 
     self.connect() 
     return self 


    def __exit__(self, _type, value, traceback): 
     self.disconnect() 


if __name__ == "__main__": 
    server_address = 'firstserver' 
    ssh_user  = 'root' 
    with SSHSession(server_address) as ssh_session: 
     ssh_session.exec_command('hostname') 
     ssh_session.exec_command('ssh [email protected] hostname') 

輸出是:

[SEND ] >> hostname 
[RECEIVE] << [[email protected] ~]# hostname ; echo CLIENT_EXPECT_CMD_OK 
[RECEIVE] << firstserver.mydomain.fr 
[SEND ] >> ssh [email protected] hostname 
[RECEIVE] << [[email protected] ~]# ssh [email protected] hostname ; echo CLIENT_EXPECT_CMD_OK 
[RECEIVE] << Permission denied (publickey,gssapi-keyex,gssapi-with-mic). 

我嘗試:

self.transport = self.ssh_client.get_transport() 
self.channel = self.transport.open_forward_agent_channel() 

代替:

self.channel = self.ssh_client.invoke_shell() 

但後來我得到一個錯誤:

paramiko.ssh_exception.ChannelException: Administratively prohibited 

是否有人知道這是否可能?我發現discutions暗示這是它,但我不知道如何做到這一點。

回答

4

好吧,它現在的作品。我發現這些有用的帖子:

Add paramiko ssh agent forwarding (optional) #4100
open_forward_agent_channel vs. open_session #89

最後的代碼是:

#!/usr/bin/python3 
# -*- coding: utf-8 -*- 

import paramiko 

class SSHSession: 


    def __init__(self, server_address, user='root', port=22): 
     self.connected  = False 
     self.server_address = server_address 
     self.user   = user 
     self.port   = port 


    def connect(self): 
     try: 
      self.ssh_client = paramiko.SSHClient() 
      self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
      self.ssh_client.connect(self.server_address, username=self.user) 
      self.transport  = self.ssh_client.get_transport() 
      self.agent_channel = self.transport.open_session() 
      self.agent_handler = paramiko.agent.AgentRequestHandler(self.agent_channel) 
      self.channel  = self.ssh_client.invoke_shell() 
     except: 
      self.connected = False 
     else: 
      self.connected = True 
     return self.connected 

    def exec_command(self, command, newline='\r'): 
     if not self.connected: 
      raise Exception('Not connected') 
     else: 
      timeout = 31536000 # 365 days in seconds 
      self.channel.settimeout(timeout) 
      line_buffer = '' 
      channel_buffer = '' 
      end_string  = 'CLIENT_EXPECT_CMD_OK' 
      print('[SEND ] >>', command) 
      self.channel.send(command + ' ; echo ' + end_string + newline) 
      while True: 
       channel_buffer = self.channel.recv(1).decode('UTF-8') 
       if len(channel_buffer) == 0: 
        raise Exception('connection lost with server: ' +  self.server_address) 
        break 
       channel_buffer = channel_buffer.replace('\r', '') 
       if channel_buffer != '\n': 
        line_buffer += channel_buffer 
       else: 
        if line_buffer == end_string: 
         break 
        print('[RECEIVE] <<', line_buffer) 
        line_buffer = '' 


    def disconnect(self): 
     self.ssh_client.close() 


    def __enter__(self): 
     self.connect() 
     return self 


    def __exit__(self, _type, value, traceback): 
     self.disconnect() 


if __name__ == "__main__": 
    server_address = 'firstserver' 
    ssh_user  = 'root' 
    with SSHSession(server_address) as ssh_session: 
     ssh_session.exec_command('hostname') 
     ssh_session.exec_command('ssh [email protected] hostname') 

輸出是:

[SEND ] >> hostname 
[RECEIVE] << [[email protected] ~]# hostname ; echo CLIENT_EXPECT_CMD_OK 
[RECEIVE] << firstserver.mydomain.fr 
[SEND ] >> ssh [email protected] hostname 
[RECEIVE] << [[email protected] ~]# ssh [email protected] hostname ; echo CLIENT_EXPECT_CMD_OK 
[RECEIVE] << secondserver.mydomain.fr 

的代碼,使代理轉發的重要組成部分是:

self.agent_channel = self.transport.open_session() 
self.agent_handler = paramiko.agent.AgentRequestHandler(self.agent_channel) 
0

應設置連接時key_filename

key_filename(STR或列表(STR)) - 文件名或文件名列表,可選的私有密鑰(S)的 嘗試進行身份驗證

+0

你的意思是這樣的嗎? 'self.ssh_client.connect(self.server_address,username = self.user,key_filename ='/ home/jean/.ssh/id_dsa')' 我試過了,行爲是一樣的。其實我想用我的Linux桌面的ssh代理,而不必指定一個密鑰。我的腳本必須由多個用戶使用,每個用戶都有自己的密鑰。 –

相關問題