Encaminhamento de chave DSA usando Paramiko?
Estou usando o Paramiko para executar scripts bash em um servidor remoto. Em alguns desses scripts, há conexões ssh com outros servidores. Se eu usar apenas bash, sem Python, minha chave DSA será encaminhada e usada pelo script bash no primeiro servidor remoto para conectar-se ao segundo servidor remoto. Quando uso Paramiko, não é o caso.
Exemplo de festança:
Jean@mydesktop:~ & ssh root@firstserver
root@firstserver:~ # ssh root@secondserver hostname
secondserver.mydomain.org
Usando 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 root@secondserver hostname')
A saída é:
[SEND ] >> hostname
[RECEIVE] << [root@firstserver ~]# hostname ; echo CLIENT_EXPECT_CMD_OK
[RECEIVE] << firstserver.mydomain.fr
[SEND ] >> ssh root@secondserver hostname
[RECEIVE] << [root@firstserver ~]# ssh root@secondserver hostname ; echo CLIENT_EXPECT_CMD_OK
[RECEIVE] << Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
Eu tentei:
self.transport = self.ssh_client.get_transport()
self.channel = self.transport.open_forward_agent_channel()
ao invés de :
self.channel = self.ssh_client.invoke_shell()
mas então eu recebo um erro:
paramiko.ssh_exception.ChannelException: Administratively prohibited
Alguém sabe se isso é possível? Encontrei discussões sugerindo que é isso, mas ainda não sei como fazer isso.