Skip to content

Instantly share code, notes, and snippets.

@kryptek
Forked from toejough/ssh-agent-forward.md
Created August 18, 2017 17:42
Show Gist options
  • Save kryptek/f03fb8c96947dbbe055d61bc8793bcbd to your computer and use it in GitHub Desktop.
Save kryptek/f03fb8c96947dbbe055d61bc8793bcbd to your computer and use it in GitHub Desktop.
SSH Agent Forwarding in Python: Paramiko's undocumented API

What

A how-to for ssh-agent forwarding via Paramiko. Specifically, I used Paramiko v1.15.2 in this example.

Why

Paramiko's docs do not document the API required to do ssh-agent forwarding. I ended up finding out how by reading pull requests for ssh-agent forwarding features in frameworks that use Paramiko under the covers, like fabric and ansible.

Update:

Besides attempting to document this process here, I've opened a bug with Paramiko to document this API in their official docs.

How

# get a paramiko transport - get it directly, or from a client. call it "t"
session = t.get_session()
paramiko.agent.AgentRequestHandler(s)  # <---UNDOCUMENTED
# do whatever you want with your session

Full example

agent.py:

# Author: toejough
# Website: https://github.com/toejough


'''
Tries to hop connections via 'Public-key' auth type and SSH agent.
'''


# [ Imports ]
# [ - Python ]
from argparse import ArgumentParser
import sys
import time
# [ - Third Party ]
import paramiko


# [ Main ]
# Arg parsing
p = ArgumentParser(description=__doc__)
p.add_argument(
    'host',
    help='The host to connect to',
    metavar='<hostname>'
)
p.add_argument(
    'port',
    help='The port to connect to',
    metavar='<port>',
    type=int
)
p.add_argument(
    'username',
    help='The username to connect as',
    metavar='<username>'
)
p.add_argument(
    '--debug',
    help='Print verbose messages and full stack traces on internal failures',
    action='store_true'
)
args = p.parse_args()
host, port, username = args.host, args.port, args.username
# Connection Attempt
try:
    # Start the client
    client = paramiko.client.SSHClient()
    client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
    client.load_system_host_keys()
    client.connect(host, port, username)
    # get a session
    s = client.get_transport().open_session()
    # set up the agent request handler to handle agent requests from the server
    paramiko.agent.AgentRequestHandler(s)  # <--UNDOCUMENTED??!!
    # get a shell
    s.get_pty()
    s.invoke_shell()
except Exception as e:
    # if debugging, just re-raise the error so the full stacktrace is printed
    if args.debug:
        raise
    # On failure, print failure only (not full bt, as is the default without the try/catch)
    print e
    exit(1)


def recv():
    while s.recv_ready():
            print s.recv(sys.maxint)
    while s.recv_stderr_ready():
        print >> sys.stderr, s.recv_sterr(sys.maxint)


def send(text):
    s.sendall(text + "\n")
    time.sleep(0.1)
    recv()


time.sleep(0.1)
recv()
# Play.
import pdb; pdb.set_trace()  # XXX BREAKPOINT
exit(0)

Now, from Bash:

eval `ssh-agent`
ssh-add ~/.ssh/id_rsa
python agent.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment