1

I am learning python. I am at a step where I must connect with SSH and retrieve information. Direct connection to server A is OK. Direct connection to server B is OK. Now I'd like to make it work to connect to SSH to A and via A connect to SSH to B (because outside of my lab, there are security features that make me do that).

I went far, looked everything on the internet, but Paramiko and SSH agent don't seem to work for me. I use public key authentication on my linux servers (all linux servers btw).

I enabled detailed logs, and Here is the full error message anonymized:

INFO:paramiko.transport:Authentication (publickey) successful!
DEBUG:paramiko.transport:[chan 0] Max packet in: 32768 bytes
DEBUG:paramiko.transport:[chan 0] Max packet out: 32768 bytes
DEBUG:paramiko.transport:Secsh channel 0 opened.
DEBUG:paramiko.transport:[chan 1] Max packet in: 32768 bytes
DEBUG:paramiko.transport:[chan 1] Max packet out: 32768 bytes
DEBUG:paramiko.transport:Secsh channel 1 opened.
DEBUG:paramiko.transport:[chan 1] Sesch channel 1 request ok
DEBUG:paramiko.transport:[chan 1] Sesch channel 1 request ok
('[SEND ] >>', 'hostname')
('[RECEIVE] <<', u'Last login: Wed Jan 9 19:51:01 2019 from myserver')
('[RECEIVE] <<', u'hostname ; echo CLIENT_EXPECT_CMD_OK')
('[RECEIVE] <<', u'/----- Welcome to proxy jump server ----------')
('[RECEIVE] <<', u'| CentOS release 6.6 (Final)')
('[RECEIVE] <<', u'[mylogin@proxy_jump_server ~]$ hostname ; echo 
CLIENT_EXPECT_CMD_OK')
('[RECEIVE] <<', u'proxy_jump_server')
('[SEND ] >>', 'ssh mylogin@final_server hostname')
('[RECEIVE] <<', u'[mylogin@proxy_jump_server ~]$ ssh mylogin@final_server 
hostname ; echo CLIENT_EXPECT_CMD_OK')
DEBUG:paramiko.transport:Incoming forward agent connection
DEBUG:paramiko.transport:[chan 2] Max packet in: 32768 bytes
DEBUG:paramiko.transport:[chan 2] Max packet out: 16384 bytes
DEBUG:paramiko.transport:Secsh channel 2 (auth-agent@openssh.com) opened.
Exception in thread Thread-3:
Traceback (most recent call last):
File "/usr/lib64/python2.7/threading.py", line 812, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/site-packages/paramiko/agent.py", line 122, in run
raise AuthenticationException("Unable to connect to SSH agent")
AuthenticationException: Unable to connect to SSH agent

On final_server login log (looks fine =/ !):

2019-01-09T19:50:12.417066+00:00 final_server sshd[7968]: Accepted 
publickey for mylogin from IP port 42360 ssh2
2019-01-09T19:50:12.428465+00:00 final_server sshd[7968]: 
pam_unix(sshd:session): session opened for user mylogin by (uid=0)
2019-01-09T19:50:12.521360+00:00 final_server sshd[7968]: 
pam_unix(sshd:session): session closed for user mylogin

Full code anonymized ( adapted from DSA key forwarding using Paramiko?):

#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
import paramiko
class SSHSession:


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


    def connect(self):

        try:
            k = paramiko.RSAKey.from_private_key_file("/mypath/mykey.ppk",password='blabla')
            self.ssh_client = paramiko.SSHClient()
            paramiko.common.logging.basicConfig(level=paramiko.common.DEBUG) 
            self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            self.ssh_client.connect(self.server_address, username=self.user, pkey=k)
            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 = 'proxy_jump_server'
        ssh_user = 'mylogin'
        with SSHSession(server_address) as ssh_session:
            ssh_session.exec_command('hostname')
            ssh_session.exec_command('ssh mylogin@final_server hostname' )

Any feedback is welcome ! Been stuck for the whole day on that point.

Jundullah
  • 115
  • 2
  • 11
Galgu
  • 35
  • 5
  • Please fix your indentation on the anonymized code. Note that the [mcve] definition requires that code given to demonstrate a problem actually be runnable to see the problem being asked about (incorporated in both "complete" and "verifiable" requirements). – Charles Duffy Jan 09 '19 at 21:12
  • sorry, first post, tried to read all rules. Thanks Jundullah for proper indentation – Galgu Jan 09 '19 at 21:44
  • Ahh, this is much more readable now. So, this code is trying to connect to a separate local agent on the host where you're invoking it. Is there one running? – Charles Duffy Jan 09 '19 at 22:06
  • Paramiko will forward to a local agent, or it'll act as a client to an agent. I don't know that it has any support for acting as an agent itself, but if you expect the private key file that you're loading to be used to answer remote requests without having a separate agent process running, that's what you need. – Charles Duffy Jan 09 '19 at 22:08
  • ssh-agent is running on all servers indeed. eval 'ssh-agent' So would this solution work ? Do you have any advice on how to do what I try to do any other way ? thanks for the quick answer by the way – Galgu Jan 09 '19 at 23:03
  • "All servers" meaning the *local* system you're running the `paramiko`-based client on, or are you referring only to the systems you're logging into? (Just commenting for the moment, not answering, since I haven't taken the time to actually run a reproducer yet; TBD whether/when that opportunity will present itself). – Charles Duffy Jan 09 '19 at 23:07
  • Yes, All servers in the chain currently run ssh-agent. – Galgu Jan 10 '19 at 13:24
  • The servers don't need to run it. Only the client needs to run it. – Charles Duffy Jan 10 '19 at 14:32
  • ...that's the *whole point* of agent forwarding, that the systems you log into get access to the agent running on your client system. – Charles Duffy Jan 10 '19 at 14:44

1 Answers1

0

Why do you run command-line ssh for the second step?

Use port forwarding instead.

See Nested SSH using Python Paramiko.

Martin Prikryl
  • 167,268
  • 50
  • 405
  • 846