【发布时间】:2019-01-10 16:05:24
【问题描述】:
我正在学习 python。我正处于必须连接 SSH 并检索信息的一步。直接连接到服务器 A 是可以的。直接连接到服务器 B 是可以的。现在我想让 SSH 连接到 A 并通过 A 连接到 SSH 到 B (因为在我的实验室之外,有一些安全功能让我这样做)。
我走了很远,查看了互联网上的所有内容,但 Paramiko 和 SSH 代理似乎对我不起作用。我在我的 linux 服务器(顺便说一句,所有 linux 服务器)上使用公钥身份验证。
我启用了详细日志,这是匿名的完整错误消息:
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
在 final_server 登录日志上(看起来不错 =/ !):
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
完整代码匿名化(改编自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' )
欢迎任何反馈!在那一点上被困了一整天。
【问题讨论】:
-
请修正您对匿名代码的缩进。请注意,minimal reproducible example 定义要求为演示问题而给出的代码实际上可以运行以查看所询问的问题(包含在“完整”和“可验证”要求中)。
-
抱歉,第一次发帖,尝试阅读所有规则。感谢 Jundullah 的正确缩进
-
啊,现在可读性更高了。因此,此代码正在尝试连接到您正在调用它的主机上的单独本地代理。有一个在运行吗?
-
Paramiko 将转发给本地代理,或者它将充当代理的客户端。我不知道它对充当代理本身有任何支持,但是如果您希望您正在加载的私钥文件用于在没有单独的代理进程运行的情况下回答远程请求,那么这就是您所需要的。
-
ssh-agent 确实在所有服务器上运行。 eval 'ssh-agent' 那么这个解决方案会起作用吗?你对如何做我尝试做的任何其他方式有什么建议吗?顺便感谢您的快速回答