dbcli / pgcli

Postgres CLI with autocompletion and syntax highlighting

Home Page:http://pgcli.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Distinguishing localhost SSH tunnels

Smylers opened this issue · comments

Description

I have some databases and an SSH tunnel configured, and working, like this:

[alias_dsn]
zlopp = postgresql://localhost/zlopp
zwapp = postgresql://localhost/zwapp

[ssh tunnels]
^localhost$ = db1.example.com

When I use one of those databases, pgcli uses the sshtunnel library to create an SSH connection to db1.example.com and then set up a tunnel from a random port on this end of the connection to localhost port 5432 at the far end.

The problem is that the [ssh tunnels] config applies that to all uses of localhost:

  • It would also match a connection to a local PostgreSQL server I'm running, which I actually want to be on the local, untunnelled, localhost.
  • It prevents having a second set of databases which are on a different server, say db2.example.com, which also needs a tunnel setting up in the same way: both of their configs will say localhost as the host.

It may seem like I could avoid this by using db1.example.com in the DSNs, in place of localhost. But the PostgreSQL server on db1.example.com has been configured only to allow connections on (its) localhost, not on any networked IP address — for obvious security reasons. If I SSHed in there at a command-line and tried to connect, I can use pgcli -h localhost zlopp, but not pgcli -h db1 zlopp.

So all the DSNs end up saying localhost in them, regardless of which server they are actually on, and the [ssh tunnels] server-matching config has no way of distinguishing them.

The only workaround I can think of is to define multiple aliases for localhost in /etc/hosts, so I have a separate localhost-like name for each server. But that's icky: a server shouldn't need to have an alias for localhost which is unique across any other servers that a user may also wish to connect to (and there's no way of enforcing that uniqueness).

Potential solutions:

  • Have an [ssh tunnels] variant which matches against database names rather than hostnames. This would be awkward syntactically, because there's nothing in the current config syntax which marks existing hostname regexes as being hostnames.

    It also may not be that convenient, especially for somebody with many databases: each one would need to be specified in two parts, once for its DSN alias, and then a second time in a different section.

  • If the server name specified by a DSN is identical to the server specified for its SSH tunnel, then automatically use localhost (or 127.0.0.1) for the hostname at the far end of the connection.

    This would work for my case, and it would probably work well for many real-world uses. But it'd break anybody with a weird set-up that is precisely the opposite config to mine: a PostgreSQL server which only listens on its network address and not on localhost.

  • Extra config for specifying the hostname to use at the remote end of a tunnel. So instead of the above I would have something like:

     [alias_dsn]
     zlopp = postgresql://db1.example.com/zlopp
     zwapp = postgresql://db1.example.com/zwapp
     
     [ssh tunnels]
     ^db1\.example\.com$ = db1.example.com~localhost
    

    (picking ~ as an arbitrary punctuation character which shouldn't already be in a hostname).

    This makes the syntax slightly repetitive and verbose. If all connections are like this, a user ends up with specifying tunnels by putting the hostname twice (once as a regexp on the left of the equals sign and a second time on the right of the equals) followed by ~localhost. So maybe instead it could be special-cased to be something like:

     [ssh tunnels]
     ^db1\.example\.com$ = ~localhost
    

    to mean that for the specified server, set up a tunnel to that server which connects to localhost at the far end? And since server names are regexes, that could even allow:

     [ssh tunnels]
     ^db[12]\.example\.com$ = ~localhost
    

    to allow specifying multiple tunnels at once, each connecting to their own localhost.

    If the tilde is a problem, maybe the general idea would still work but with /localhost or <localhost> instead of ~localhost?

Thanks.

Your environment

Ubuntu 20.04 LTS, running pgcli version 3.4.1