SSH Piper

SSH Piper works as a proxy-like ware, and route connections by username, src ip , etc.
+---------+ +------------------+ +-----------------+
| | | | | |
| Bob +----ssh -l bob----+ | SSH Piper +-------------> Bob' machine |
| | | | | | | |
+---------+ | | | | +-----------------+
+---> pipe-by-name--+ |
+---------+ | | | | +-----------------+
| | | | | | | |
| Alice +----ssh -l alice--+ | +-------------> Alice' machine |
| | | | | |
+---------+ +------------------+ +-----------------+
Downstream SSH Piper Upstream
Install
go get github.com/tg123/sshpiper/sshpiperd
go install github.com/tg123/sshpiper/sshpiperd
with pam module support
go get -tags pam github.com/tg123/sshpiper/sshpiperd
go install -tags pam github.com/tg123/sshpiper/sshpiperd
Pull
docker pull farmer1992/sshpiperd
Run ❓ what is WORKING_DIR
docker run -d -p 2222:2222 \
-v /etc/ssh/ssh_host_rsa_key:/etc/ssh/ssh_host_rsa_key \
-v /YOUR_WORKING_DIR:/var/sshpiper \
farmer1992/sshpiperd
Run with Additional Challenge
use env SSHPIPERD_CHALLENGER to specify which challenger to use
docker run -d -p 2222:2222 \
-e SSHPIPERD_CHALLENGER=pam \
-v /YOUR_PAM_CONFIG:/etc/pam.d/sshpiperd \
-v /etc/ssh/ssh_host_rsa_key:/etc/ssh/ssh_host_rsa_key \
-v /YOUR_WORKING_DIR:/var/sshpiper \
farmer1992/sshpiperd
Quick start
Just run showme.sh in sshpiperd exmaple directory
$GOPATH/src/github.com/tg123/sshpiper/sshpiperd/example/showme.sh
the example script will setup a sshpiper server using
[email protected]:2222 -> pipe to github.com:22
[email protected]:2222 -> pipe to lish-atlanta.linode.com:22
connect to linode
$ ssh 127.0.0.1 -p 2222 -l linode.com:22
[email protected]'s password:
connect to github.com:22
$ ssh 127.0.0.1 -p 2222 -l github
Permission denied (publickey).
Configuration
You can use three forms below together. Note: Command-line > Environment variables > Config file
$ sshpiperd -h
Usage of ./sshpiperd:
-c, --challenger="" Additional challenger name, e.g. pam, emtpy for no additional challenge
--config="/etc/sshpiperd.conf" Config file path. Note: any option will be overwrite if it is set by commandline
-h, --help=false Print help and exit
-i, --server_key="/etc/ssh/ssh_host_rsa_key" Key file for SSH Piper
-l, --listen_addr="0.0.0.0" Listening Address
--log="" Logfile path. Leave emtpy or any error occurs will fall back to stdout
-p, --port=2222 Listening Port
--version=false Print version and exit
-w, --working_dir="/var/sshpiper" Working Dir
sshpiperd --challenger pam
is same as
env SSHPIPERD_CHALLENGER=pam sshpiperd
$ cat sshpiperd.conf
SERVER_KEY = /path/to/key
Files inside Working Dir
Working Dir is a /home-like directory.
SSHPiperd read files from workingdir/[username]/ to know upstream's configuration.
e.g.
workingdir tree
.
├── github
│ └── sshpiper_upstream
└── linode
└── sshpiper_upstream
when ssh sshpiper_host -l github,
sshpiper reads workingdir/github/sshpiper_upstream and the connect to the upstream.
User files
These file MUST NOT be accessible to group or other. (chmod og-rwx filename)
-
sshpiper_upstream
- line starts with
# are treated as comment
- only the first not comment line will be parsed
- if no port was given, 22 will be used as default
- if
user@ was defined, username to upstream will be the mapped one
# comment
[user@]upstream[:22]
e.g.
[email protected]
google.com:12345
Publickey sign again
During SSH publickey auth, RFC 4252 Section 7,
ssh client sign session_id and some other data using private key into a signature sig.
This is for server to verify that the connection is from the client not the man in the middle.
However, sshpiper actually holds two ssh connection, and it is doing what the man in the middle does.
the two ssh connections' session_id will never be the same, because they are hash of the shared secret. RFC 4253 Section 7.2.
To support publickey auth, sshpiper will modify the sig using a private key (id_rsa) in the workingdir/[username]/.
How this work
+------------+ +------------------------+
| | | |
| client | | SSH Piper |
| PK_X +--------> | |
| | | v |
| | | Check PK_X |
+------------+ | in authorized_keys |
| | |
| | | +----------------+
| v | | |
| sign agian | | server |
| using PK_Y +--------------> check PK_Y |
| | | |
| | | |
+------------------------+ +----------------+
e.g.
on client
ssh-copy-id -i PK_X test@sshpiper
on ssh piper server
ln -s ~test/.ssh/authorized_keys workingdir/test/authorized_keys
ssh-keygen -N '' -f workingdir/test/id_rsa # this is PK_Y
ssh-copy-id -i workingdir/test/id_rsa test@server
now ssh test@sshpiper -i -i PK_X, sshpiper will send PK_Y to server instead of PK_X.
Additional Challenge
ssh piper allows you run your own challenge before dialing to the upstream.
if a client failed in this challenge, connection will be closed.
however, the client has to pass the upstream server's auth in order to establish the whole connection.
Additional Challenge is required, but not enough.
This is useful when you want use publickey and something like google-authenticator together. OpenSSH do not support use publickey and other auth together.
Available Challengers
API @ 
Package ssh in sshpiper is compatible with golang.org/x/crypto/ssh.
All func and datatype left unchanged. You can use it like golang.org/x/crypto/ssh.
SSHPiper additional API
TODO List
- live upgrade
- man page
- hostbased auth support
- ssh-copy-id support or tools
- challenger: menu challenger
- sshpiperd: user@subhost@host support