Public | Automated Build

Last pushed: a year ago
Short Description
Ixis modified SSHPiper
Full Description

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                     


go get
go install

with pam module support

go get -tags pam
go install -tags pam

Docker image


docker pull farmer1992/sshpiperd

Run :question: 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 \

Run with Additional Challenge

use env SSHPIPERD_CHALLENGER to specify which challenger to use

docker run -d -p 2222:2222 \
  -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 \

Quick start

Just run in sshpiperd exmaple directory


the example script will setup a sshpiper server using

github@ -> pipe to
linode@ -> pipe to

connect to linode

$ ssh -p 2222 -l
linode@'s password:

connect to

$ ssh -p 2222 -l github
Permission denied (publickey).


You can use three forms below together. Note: Command-line > Environment variables > Config file

  • Command-line
$ sshpiperd -h
Usage of ./sshpiperd:
      --allow_bad_username   Disable username check while search the working dir
  -c, --challenger string    Additional challenger name, e.g. pam, emtpy for no additional challenge
      --config string        Config file path. Note: any option will be overwrite if it is set by commandline (default "/etc/sshpiperd.conf")
  -h, --help                 Print help and exit
  -l, --listen_addr string   Listening Address (default "")
      --log string           Logfile path. Leave emtpy or any error occurs will fall back to stdout
      --no_check_perm        Disable 0400 checking when using files in the working dir
  -p, --port uint            Listening Port (default 2222)
      --record_typescript    record screen output into the working dir with typescript format
  -i, --server_key string    Key file for SSH Piper (default "/etc/ssh/ssh_host_rsa_key")
      --version              Print version and exit
  -w, --working_dir string   Working Dir (default "/var/sshpiper")
  • Environment variables

    SSHPiperd will read from SSHPIPERD_ + long command param name


sshpiperd --challenger pam
is same as
env SSHPIPERD_CHALLENGER=pam sshpiperd
  • Config file

    SSHPiperd will read from long command param name in config file if --config was defined


$ 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.


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

  • authorized_keys

    OpenSSH format authorized_keys (see ~/.ssh/authorized_keys). Used for publickey sign again(see below).

  • id_rsa

    RSA key for publickey sign again(see below).

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   |
                      |                        |     |                |
                      |                        |     |                |
                      +------------------------+     +----------------+


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

  • pam

    Linux-PAM challenger

    this module use the pam service called sshpiperd

    you can configure the rule at /etc/pam.d/sshpiperd

SSH Session logging (--record_typescript)

When record_typescript is allowed, each piped connection would be recorded into typescript) in working_dir.

The file format is compatible with scriptreplay(1)


  $ ./sshpiperd  --record_typescript

  ssh user_name@ -p 2222
  ... do some commands

  $ cd workingdir/user_name
  $ ls *.timing *.typescript
  1472847798.timing 1472847798.typescript

  $ scriptreplay -t 1472847798.timing 1472847798.typescript # will replay the ssh session


Package ssh in sshpiper is compatible with
All func and datatype left unchanged. You can use it like

SSHPiper additional API


  • live upgrade
  • man page
  • hostbased auth support
  • ssh-copy-id support or tools
  • challenger: menu challenger
  • sshpiperd: user@subhost@host support
Docker Pull Command
Source Repository