question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Custom SSH Credentials

See original GitHub issue

I can’t rely on an ssh agent to provide a private key. Sometimes I need to provide a password, sometimes I need to manually load the key file. But the docker-py code only connects with this in SSHHTTPAdapter:

self.ssh_client.connect(
    parsed.hostname, parsed.port, parsed.username,
)

There is no flexibility here. How am I supposed to connect with a custom key or password? I thought I might hack my way in by reassigning APIClient._custom_adapter to my own subclass of SSHHTTPAdapter, but then I realized the APIClient.__init__ is a huge mess that does way too much. That method would always raise an exception so I would also have to totally reimplement that method in a subclass. This is too much maintenance overhead for my deployment script that I would like to keep as simple as possible.

It should be exposed in SSHHTTPAdapter. I might even recommend doing both of these:

  1. Add optional key and password parameters to SSHHTTPAdapter so you don’t have to write your own subclass of it just to use custom credentials
  2. Add optional ssh_client parameter to SSHHTTPAdapter to be used instead of instantiating one in __init__.

It should also be exposed somehow in APIClient.__init__, for example:

  1. Expose password and private key with… a. Explicit parameters (a bit messy considering this is not an SSH specific class) b. General purpose configuration object (dict or better yet custom configuration class)
  2. Enable programmer to provide their own SSHClient to APIClient. This is not ideal for the same reason as 1a.
  3. Enable programmer to provide their own instance of a BaseHTTPAdapter to be used as self._custom_adapter. I think this is the best solution but there are some open questions. Like what’s the best way to handle all the usages of base_url when it is no longer required to establish a connection.

I’m happy to take the lead on this and submit a PR, but I would like to get some feedback first.

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:4
  • Comments:10

github_iconTop GitHub Comments

3reactions
dnutcommented, Aug 27, 2019

Hey, thanks for your reply, but there are some issues with your recommendations.

first-class adapter modularity

What does this mean?

Password in URL

You can already provide a custom password through the base_url parameter, e.g. ssh://user:mypassword@host.com:22

This is not right. I get the following exception:

  File "docker/client.py", line 40, in __init__
    self.api = APIClient(*args, **kwargs)
  File "docker/api/client.py", line 133, in __init__
    base_url, IS_WINDOWS_PLATFORM, tls=bool(tls)
  File "docker/utils/utils.py", line 265, in parse_host
    'Invalid bind address format: {}'.format(addr)
docker.errors.DockerException: Invalid bind address format: ssh://user:mypassword@host.com:22

Also as you can see in the source I quoted in my original comment, there is no way that the password would be used for the ssh connection, even if the url were valid.

Setting a Custom Adapter

So regardless of whether you want to use a password or a custom key file, you would definitely need to provide a custom Adapter class. And your recommended code to do so does not work because it will try to connect to a host called “bogus” on line two. If you leave out base_url, it changes it to http+unix and tries to connect to the local docker daemon. If there is no local docker daemon, it fails here.

There’s no way to instantiate an APIClient without it trying to connect to a docker daemon. This is what I was talking about with __init__ doing too much and was the whole reason why I made this ticket.

A better design would be that APIClient does not even try to connect unless you explicitly call a method that needs a connection. There needs to be a way to provide a custom adapter or at least ssh credentials. APIClient.__init__ should really be broken up into several methods and SSHHTTPAdapter needs some changes too.

Does SSH work at all?

I actually tried using a hostname that my ssh agent can provide a key for and I got a valid SSH connection. But then I saw this error whenever I tried to do anything. It looks like it’s treating the ssh connection like it can make GET requests directly over that connection which doesn’t seem right.

  File "docker/api/container.py", line 210, in containers
    res = self._result(self._get(u, params=params), True)
  File "docker/utils/decorators.py", line 46, in inner
    return f(self, *args, **kwargs)
  File "docker/api/client.py", line 235, in _get
    return self.get(url, **self._set_request_timeout(kwargs))
  File "requests/sessions.py", line 546, in get
    return self.request('GET', url, **kwargs)
  File "requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "requests/sessions.py", line 646, in send
    r = adapter.send(request, **kwargs)
  File "requests/adapters.py", line 498, in send
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', BadStatusLine('No status line received - the server has closed the connection',))
2reactions
rtubiocommented, Apr 1, 2021

Got the same issue here. I am using this sdk but, I had to shift to the CLI option since it was not clear to me whether authenticating with SSH credentials was an option for the sdk.

  • In an ideal world, I would expect an ssh parameter to exist as a keyword to the build method; mimicking the usage of the docker command line utility to reduce the learning curve.

The answer provided by @cmcga1125 helps, but a slightly more elaborated step-by-step would really be super nice! 😃

  • Would it be possible at least to document the process to use an external SSH key?
Read more comments on GitHub >

github_iconTop Results From Across the Web

Use custom SSH authentication mechanism (OpenSSH)
I have a collection of servers (Debian/Ubuntu) for which I need to create a custom ssh authentication mechanism.
Read more >
How to create a custom SSH password changer
1. Select Remote Password Changing from the ADMIN menu. · 2. Click Configure Password Changers, then scroll to the bottom of the page...
Read more >
Define SSH Host Credentials
An SSH host credential enables you to run custom or industry standard compliance assessments. You first configure the credential store, and then add...
Read more >
How To Configure Custom Connection Options for your ...
The first ones we will cover are the minimum settings necessary to connect to a remote host. Namely, the hostname, username, and port...
Read more >
custom SSH and Login authentication - server
I am trying to figure out how to change the authorization process for ssh and normal logins. I have used public and private...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found