sshpiper 🖇

E2E Go Report Card Docker Image

sshpiper is the reverse proxy for sshd. all protocols, including ssh, scp, port forwarding, running on top of ssh are supported.

Note: this is v1 version, checkout legacy v0 here

Overview and Terminology

+---------+                      +------------------+          +-----------------+
|         |                      |                  |          |                 |
|   Bob   +----ssh -l bob----+   |   sshpiper    +------------->   Bob' machine  |
|         |                  |   |               |  |          |                 |
+---------+                  |   |               |  |          +-----------------+
                             +---> pipe-by-name--+  |                             
+---------+                  |   |               |  |          +-----------------+
|         |                  |   |               |  |          |                 |
|  Alice  +----ssh -l alice--+   |               +------------->  Alice' machine |
|         |                      |                  |          |                 |
+---------+                      +------------------+          +-----------------+


 downstream                         sshpiper                        upstream                     

Quick start

Build

git clone https://github.com/tg123/sshpiper
cd sshpiper

mkdir out
go build -tags full -o out ./...
(cd cmd/sshpiperd && go build -o ../../out/ .)

Run simple demo

start dummy sshd server

docker run -d -e USER_NAME=user -e USER_PASSWORD=pass -e PASSWORD_ACCESS=true -p 127.0.0.1:5522:2222 lscr.io/linuxserver/openssh-server

start sshpiperd with fixed plugin targeting the dummy sshd server

./out/sshpiperd -i /tmp/sshpiperkey --server-key-generate-mode notexist --log-level=trace ./out/fixed --target 127.0.0.1:5522

test ssh connection (password: pass)

ssh 127.0.0.1 -l user -p 2222

âž• math before login?

Here illustrates the example of additional challenge before the fixed plugin.

./out/sshpiperd -i /tmp/sshpiperkey --server-key-generate-mode notexist --log-level=trace ./out/simplemath -- ./out/fixed --target 127.0.0.1:5522

More examples

For Docker Compose demos (including username routing and Lua publickey git routing), see examples/.

Admin UI (sshpiperd-webadmin)

sshpiperd can optionally expose a small admin gRPC API that lets external tools list live SSH sessions, view their terminal output in real time, and kill them. This API is off by default and is enabled by passing a non-zero --admin-grpc-port. By default the API requires TLS, so a server cert/key must be supplied:

./out/sshpiperd --admin-grpc-port 8222 \
  --admin-grpc-tls-cert server.crt \
  --admin-grpc-tls-key server.key \
  ... <plugin> ...

For mutual TLS (recommended for production), also pass --admin-grpc-tls-cacert ca.crt so clients must present a certificate signed by ca.crt. To opt out of TLS entirely on a trusted network, pass --admin-grpc-insecure.

A separate binary, sshpiperd-webadmin, aggregates one or more sshpiperd admin endpoints and serves a browser dashboard plus a JSON HTTP API:

./out/sshpiperd-webadmin \
  --sshpiperd 127.0.0.1:8222 \
  --sshpiperd piper-2.internal:8222 \
  --tls-cacert ca.crt --tls-cert client.crt --tls-key client.key \
  -l 127.0.0.1 -p 8080

Then open http://127.0.0.1:8080. Endpoints can also be supplied via the SSHPIPERD_WEBADMIN_ENDPOINTS env var (comma-separated). Pass --insecure on the webadmin side when sshpiperd is started with --admin-grpc-insecure. The same client library (libadmin/) is structured so a future CLI tool (sshpiperd-admin) can reuse the discovery + aggregator code.

Plugins

icons

Plugin list

Screen recording

asciicast

recording the screen in asciicast format https://docs.asciinema.org/manual/asciicast/v2/

To use it, start sshpiperd with --screen-recording-format asciicast and --screen-recording-dir /path/to/recordingdir

Example:

```
ssh user_name@
... do some commands
exit

asciinema play /path/to/recordingdir/<conn_guid>/shell-channel-0.cast

```

typescript

recording the screen in typescript format (not the lang). The format is compatible with scriptreplay(1)

To use it, start sshpiperd with --screen-recording-format typescript and --screen-recording-dir /path/to/recordingdir

Example:

```
ssh user_name@127.0.0.1 -p 2222
... do some commands
exit


$ cd /path/to/recordingdir/<conn_guid>
$ ls *.timing *.typescript
1472847798.timing 1472847798.typescript

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

Public key authentication when using sshpiper (Private key remapping)

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 routing plugin must provide a new private key for the upstream to sign the session_id. This new private key is called mapping key.

How this work

+------------+        +------------------------+                       
|            |        |                        |                       
|   client   |        |   sshpiper             |                       
|   PK_X     +-------->      |                 |                       
|            |        |      v                 |                       
|            |        |   Check Permission     |                       
+------------+        |      |                 |                       
                      |      |                 |                       
                      |      |                 |     +----------------+
                      |      v                 |     |                |
                      |   sign again           |     |   server       |
                      |   using PK_Y  +-------------->   check PK_Y   |
                      |                        |     |                |
                      |                        |     |                |
                      +------------------------+     +----------------+

Ports to other platforms

Migrating from v0

What's the major change in v1

For plugins already in v1, you need change params to new params. However, not all plugins are migrated to v1 yet, they are being migrated gradually. you can still use the old plugins in v0 branch

Contributing

see CONTRIBUTING.md

License

MIT