Well, you could do that "full Go", I think.
The SSH part and port-forwarding
I'd start with something like this (I failed to google a better example).
Note two problems with this code:
It's not actually correct: it connects to a remote socket
before accepting a client connection
while it should do the reverse: accept a client connection to
a port-forwarded local socket then use the active SSH session to connect
to the remote socket and if this succeeds, spawn two goroutines to shovel
the data between those two sockets.
When configuring the SSH client, it explicitly allows password-based
authentication for unknown reason. You don't need this as you're using
pubkey-based auth.
An obstacle which might trip you there is managing an access to your SSH key.
The problem with it is that a good key should be protected by a passphrase.
You say the key's password is "stored in valut" and I honestly have no idea what "the valut" is.
On the systems I use, an SSH client either asks for the password to decrypt the key or work with a so-called "SSH agent":
- On Linux-based systems it's typically an OpenSSH's
ssh-agent
binary working in the background which is accessed via a Unix-domain socket, and located by inspecting an environment variable named SSH_AUTH_SOCK
.
- On Windows I use PuTTY, and it has its own agent,
pageant.exe
.
I'm don't know which means PuTTY SSH client uses to locate it.
To access the OpenSSH agent, golang.org/x/crypto/ssh
provides the agent
subpackage which can be used to locate the agent and communicate with it.
If you need to obtain keys from pageant
, I'm afraid you'll need to figure out what protocol that uses and implement it.
The MySQL part
The next step would be to integrate this with go-sql-driver
.
I'd start the simplest way possible:
- When you have your SSH port forwarding working,
make it listen for incoming connections on a random port on localhost.
When the connection is opened, get the port from the returned connection
object.
- Use that port number to constuct the connection string to pass to an instance of
sql.DB
you will create to use go-sql-driver
.
The driver will then connect to your port-forwarded port, and your SSH layer will do the rest.
After you have this working, I'd explore whether the driver of your choice
allows some more fine-grained tweaking like allowing you to directly pass it an instance of io.ReadWriter
(an opened socket) so that you could skip the port-forwarding setup entirely and just produce new TCP connections forwarded through SSH, that is, skip the "listening locally" step.