Categorygithub.com/glycerine/sshego
modulepackage
7.0.3+incompatible
Repository: https://github.com/glycerine/sshego.git
Documentation: pkg.go.dev

# README

sshego, a usable ssh library for Go

executive summary

Google's "golang.org/x/crypto/ssh" library offers a fantastic full implementation of the ssh client and server protocols. However this library is minimalistic by design, cumbersome to figure out how to use with RSA keys, and needs additional code to support support tunneling and receiving connections as an sshd.

sshego bridges this usability gap, providing a drop-in Go library to secure your tcp connections. In places sshego can be used in preference to a virtual-private-network (VPN), for both convenience and speed. Moreover the SSH protocol's man-in-the-middle attack protection is better than a VPN in almost all cases.

usable three-factor auth in an embeddable sshd

For strong security, our embedded sshd offers three-factor auth (3FA). The three security factors are: a passphrase ("what you know"); a 6-digit Google authenticator code (TOTP/RFC 6238; "what you have": your phone); and the use of PKI in the form of 4096-bit RSA keys.

To promote strong passphrases, we follow the inspiration of https://xkcd.com/936/, and offer a user- friendly 3-word starting prompt (the user completes the sentence) to spark the user's imagination in creating a strong and memorizable passphrase. Passphrases of up to 100 characters are supported.

Although not for the super-security conscious, if desired and configured, passphrases can automatically be backed up to email (via the Mailgun email service).

On new account creation with gosshtun -adduser yourlogin, we will attempt to pop-up the QR-code on your local desktop for quick Google Authenticator setup on your phone.

introducing sshego: a gopher's do-it-yourself ssh tunneling library

sshego is a golang (Go) library for ssh tunneling (secure port forwarding). It also offers an embeddable 3-factor authentication sshd server, which can be useful for securing reverse forwards.

This means you can easily create an ssh-based vpn with 3-factor authentication requrirements: the embedded sshd requires passphrase, RSA keys, and a TOTP Google Authenticator one-time password.

In addition to the libary, gosshtun is also a command line utility (see the cmd/ subdir) that demonstrates use of the library and may prove useful on its own.

The intent of having a Go library is so that it can be used to secure (via SSH tunnel) any other traffic that your Go application would normally have to do over cleartext TCP.

While you could always run a tunnel as a separate process, by running the tunnel in process with your application, you know the tunnel is running when the process is running. It's just simpler to administer; only one thing to start instead of two.

Also this is much simpler, and much faster, than using a virtual private network (VPN). For a speed comparison, consider [1] where SSH is seen to be at least 2x faster than OpenVPN.

[1] http://serverfault.com/questions/653211/ssh-tunneling-is-faster-than-openvpn-could-it-be

In its principal use, sshego is the equivalent to using the ssh client and giving -L and/or -R. It acts like an ssh client without a remote shell; it simply tunnels other TCP connections securely. There are also options to run an embedded SSHD. This can be useful for securing reverse forwards, if allowed.

For example,

gosshtun -listen 127.0.0.1:89  -sshd jumpy:55  -remote 10.0.1.5:80 -user alice -key ~/.ssh/id_rsa_nopw

is equivalent to

ssh -N -L 89:10.0.1.5:80 alice@jumpy -port 55

with the addendum that gosshtun requires the use of passwordless private -key file, and will never prompt you for a password at the keyboard. This makes it ideal for embedding inside your application to secure your (e.g. mysql, postgres, other cleartext) traffic. As many connections as you need will be multiplexed over the same ssh tunnel.

grain of access

If you don't trust the other users on the host where your process is running, you can also use sshego to (a) secure a direct TCP connection (see DialConfig.Dial() and the example in cli_test.go; https://github.com/glycerine/sshego/blob/master/cli_test.go#L72); or (b) forward via a file-system secured unix-domain sockets.

The first option (a) would disallow any other process (even under the same user) from multiplexing your original connection, and the second (b) would disallow any other user from accessing your tunnel, so long as you use the file-system permissions to make the unix-domain socket path inaccessible to others.

In either case, note that keys are by default stored on disk under the user's $HOME/.ssh folder, so as usual that folder should not be readable by others. Using a direct connection as in (a) in no way prevents you from starting another process (from the same executable or another) that reads the same keys and starts its own direct tcp connection.

theory of operation

gosshtun and sshego will check the sshd server's host key. We prevent MITM attacks by only allowing new servers if -new (a.k.a. SshegoConfig.AddIfNotKnown == true) is given.

When running the standalone gosshtun to test a foward, you should give -new only once at setup time.

Then the lack of -new protects you on subsequent runs, because the server's host key must match what we were given the very first time.

flags accepted, see gosshtun -h for complete list

Usage of gosshtun:
  -cfg string
        path to our config file
  -esshd string
        (optional) start an in-process embedded sshd (server),
        binding this host:port, with both RSA key and 2FA
        checking; useful for securing -revfwd connections.
  -esshd-host-db string
        (only matters if -esshd is also given) path
        to database holding sshd persistent state
        such as our host key, registered 2FA secrets, etc.
        (default "$HOME/.ssh/.sshego.sshd.db")        
  -key string
        private key for sshd login (default "$HOME/.ssh/id_rsa_nopw")
  -known-hosts string
        path to gosshtun's own known-hosts file (default
        "$HOME/.ssh/.sshego.cli.known.hosts")
  -listen string
        (forward tunnel) We listen on this host:port locally,
        securely tunnel that traffic to sshd, then send it
        cleartext to -remote. The forward tunnel is active
        if and only if -listen is given.  If host starts with
        a '/' then we treat it as the path to a unix-domain
        socket to listen on, and the port can be omitted.
  -new
        allow connecting to a new sshd host key, and store it
        for future reference. Otherwise prevent MITM attacks by
        rejecting unknown hosts.
  -quiet
        if -quiet is given, we don't log to stdout as each
        connection is made. The default is false; we log
        each tunneled connection.        
  -remote string
        (forward tunnel) After traversing the secured forward
        tunnel, -listen traffic flows in cleartext from the
        sshd to this host:port. The foward tunnel is active
        only if -listen is given too.  If host starts with a
        '/' then we treat it as the path to a unix-domain
        socket to forward to, and the port can be omitted.
  -revfwd string
        (reverse tunnel) The gosshtun application will receive
        securely tunneled connections from -revlisten on the
        sshd side, and cleartext forward them to this host:port.
        For security, it is recommended that this be 127.0.0.1:22,
        so that the sshd service on your gosshtun host
        authenticates all remotely initiated traffic.
        See also the -esshd option which can be used to
        secure the -revfwd connection as well.
        The reverse tunnel is active only if -revlisten is given
        too. (default "127.0.0.1:22")
  -revlisten string
        (reverse tunnel) The sshd will listen on this host:port,
        securely tunnel those connections to the gosshtun application,
        whence they will cleartext connect to the -revfwd address.
        The reverse tunnel is active if and only if -revlisten is given.  
  -sshd string
        The remote sshd host:port that we establish a secure tunnel to;
        our public key must have been already deployed there.
  -user string
        username for sshd login (default is $USER)
  -v    verbose debug mode
  -write-config string
        (optional) write our config to this path before doing
        connections

installation

go get github.com/glycerine/sshego/...

example use of the command

$ gosshtun -listen localhost:8888 -sshd 10.0.1.68:22 -remote 127.0.0.1:80

means the following two network hops will happen, when a local browser connects to localhost:8888

                       `gosshtun`             `sshd`
local browser ----> localhost:8888 --(a)--> 10.0.1.68:22 --(b)--> 127.0.0.1:80
  `host A`             `host A`               `host B`              `host B`

where (a) takes place inside the previously established ssh tunnel.

Connection (b) takes place over basic, un-adorned, un-encrypted TCP/IP. Of course you could always run gosshtun again on the remote host to secure the additional hop as well, but typically -remote is aimed at the 127.0.0.1, which will be internal to the remote host itself and so needs no encryption.

specifying username to login to sshd host with

The -user flag should be used if your local $USER is different from that on the sshd host.

source code for gosshtun command

See github.com/glycerine/sshego/cmd/gosshtun/main.go for the source code. This also serves as an example of how to use the library.

host key storage location (default)

~/.ssh/.sshego.known.hosts.json.snappy

prep before running

a) install your passwordless ssh-private key in ~/.ssh/id_rsa_nopw or use -key to say where it is.

b) add the corresponding public key to the user's .ssh/authorized_keys file on the sshd host.

config file format

a) see demo.env for an example

b) run gosshtun -write-config - to generate a sample config file to stdout

c) comments are allowed; lines must start with #, comments continue until end-of-line

d) fields recognized (see gosshtun -write-config - for a full list)

#
# config file for sshego:
#
SSHD_ADDR="1.2.3.4:22"
FWD_LISTEN_ADDR="127.0.0.1:8888"
FWD_REMOTE_ADDR="127.0.0.1:22"
REV_LISTEN_ADDR=""
REV_REMOTE_ADDR=""
SSHD_LOGIN_USERNAME="$USER"
SSH_PRIVATE_KEY_PATH="$HOME/.ssh/id_rsa_nopw"
SSH_KNOWN_HOSTS_PATH="$HOME/.ssh/.sshego.known.hosts"
#
# optional in-process sshd
#
EMBEDDED_SSHD_HOST_DB_PATH="$HOME/.ssh/.sshego.sshd.db"
EMBEDDED_SSHD_LISTEN_ADDR="127.0.0.1:2022"

d) special environment reads

  • The SSHD_LOGIN_USERNAME will subsitute $USER from the environment, if present.

  • The *PATH keys will substitute $HOME from the environment, if present.

MIT license

See the LICENSE file.

Author

Jason E. Aten, Ph.D.

# Packages

No description provided by the author
No description provided by the author
No description provided by the author

# Functions

No description provided by the author
No description provided by the author
No description provided by the author
Use crypto/rand to get an random int64.
No description provided by the author
No description provided by the author
DialRemoteUnixDomain initiates a connection to udpath from the remote host using c as the ssh client.
DiscardRequestsExceptKeepalives accepts and responds to requests of type "[email protected]" that want reply; these are used as ping/pong messages to detect ssh connection failure.
EmptyUHPChan is helper utility.
Fingerprint performs a SHA256 BASE64 fingerprint of the PublicKey, similar to OpenSSH.
GenRSAKeyPair generates an RSA keypair of length bits.
TODO: Finish this-- specified but password based encryption not implemented.
No description provided by the author
GetAvailPort asks the OS for an unused port, returning a bound net.Listener and the port number to which it is bound.
GetExternalIP tries to determine the external IP address used on this host.
No description provided by the author
IsRoutableIPv4 returns true if the string in ip represents an IPv4 address that is not private.
KnownHostsEqual compares two instances of KnownHosts structures for equality.
LoadRSAPrivateKey reads a private key from path on disk.
TODO: Finish this-- specified but password based encryption not implemented.
LoadRSAPublicKey reads a public key from path on disk.
LoadSshKnownHosts reads a ~/.ssh/known_hosts style file from path, see the SSH_KNOWN_HOSTS FILE FORMAT section of http://manpages.ubuntu.com/manpages/zesty/en/man8/sshd.8.html or the local sshd(8) man page.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
NewBasicServer in listen.go provides net.Listen() compatibility for running an embedded sshd.
No description provided by the author
NewForward is called to produce a Forwarder structure for each new forward connection.
NewKnownHosts creats a new KnownHosts structure.
No description provided by the author
No description provided by the author
No description provided by the author
NewTricorder has got to wait to allocate ssh.Channel until requested.
NewUHPTower makes a new UHPTower.
No description provided by the author
PromptForPassword ask.
No description provided by the author
RSAToSSHPublicKey convert an RSA Public Key to the SSH authorized_keys format.
No description provided by the author
SetWinsize sets the size of the given pty.
SourceVersion returns the git source code version this code was built from.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
UHPEqual returns true iff a and b are both not nil and they have equal fields.
No description provided by the author
No description provided by the author
waitUntilAddrAvailable returns -1 if the addr was always unavailable after tries sleeps of dur time.

# Constants

AddedNew means the -new flag was given and we allowed the addition of a new host-key for the first time.
Banned means the host has been marked as forbidden.
CustomInprocStreamChanName is how sshego/reptile specific channels are named.const CustomInprocStreamChanName = "custom-inproc-stream".
No description provided by the author
No description provided by the author
No description provided by the author
KnownOK means the host key matches one we have previously allowed.
KnownRecordMismatch means we have a records for this IP/host-key, but either the IP or the host-key has varied and so it could be a Man-in-the-middle attack.
268435462.
No description provided by the author
Unknown means we don't have a matching stored host key.
Verbose can be set to true for debug output.

# Variables

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Structs

AddrHostPort is used to specify tunnel endpoints.
No description provided by the author
AuthState holds the authorization information that doesn't change after startup; each fresh PerAttempt gets a pointer to one of these.
Address satisfies the net.Addr interface, which BasicListener.Addr() returns.
BasicListener satifies the net.Listener interface.
BasicServer configures a simple embedded sshd server that only expects RSA key (or other) based authentication, and doesn't expect TOTP or passphase.
No description provided by the author
No description provided by the author
DialConfig provides Dial() with what it needs in order to establish an encrypted and authenticated ssh connection.
Esshd is our embedded sshd server, running from inside this libary.
No description provided by the author
Forwarder represents one bi-directional forward (sshego to sshd) tcp connection.
No description provided by the author
only these fields are actually saved/restored.
No description provided by the author
KnownHosts represents in Hosts a hash map of host identifier (ip or name) and the corresponding public key for the server.
LoginRecord is per public key.
MailgunConfig sets up sending backup emails through Mailgun.
PerAttempt holds the auth state that should be reset anew on each login attempt; plus a pointer to the invariant State.
Reverse represents one bi-directional (initiated at sshd, tunneled to sshego) tcp connection.
ServerPubKey stores the RSA public keys for a particular known server.
SshegoConfig is the top level, main config.
No description provided by the author
No description provided by the author
No description provided by the author
Tricorder records (holds) three key objects: an *ssh.Client, the underlyign net.Conn, and a set of ssh.Channel(s).
TunnelSpec represents either a forward or a reverse tunnel in SshegoConfig.
UHP provides User and HostPort strings to identify a remote destination.
UHPTower is an 1:M non-blocking value-loadable channel.
User represents a user authorized to login to the embedded sshd.
Winsize stores the Height and Width of a terminal.

# Type aliases

CustomChannelHandlerCB is a callback that is configured in the cfg.CustomChannelHandlers map.
HostState recognizes host keys are legitimate or impersonated, new, banned, or consitent with what we've seen before and so OK.
No description provided by the author