315 lines
9.8 KiB
Markdown
315 lines
9.8 KiB
Markdown
# SSH Piper
|
|
|
|
[](https://travis-ci.org/tg123/sshpiper)
|
|
[](https://gitter.im/tg123/sshpiper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
|
[](https://goreportcard.com/report/github.com/tg123/sshpiper)
|
|
[](https://godoc.org/github.com/tg123/sshpiper/ssh)
|
|

|
|
|
|
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 -u github.com/tg123/sshpiper/sshpiperd
|
|
```
|
|
|
|
with pam module support
|
|
|
|
```
|
|
go get -u -tags pam github.com/tg123/sshpiper/sshpiperd
|
|
```
|
|
|
|
## [Docker image](https://registry.hub.docker.com/u/farmer1992/sshpiperd/)
|
|
|
|
Pull
|
|
|
|
```
|
|
docker pull farmer1992/sshpiperd
|
|
```
|
|
|
|
Run [:question: what is WORKING_DIR](#files-inside-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](#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](sshpiperd/example)
|
|
```
|
|
$GOPATH/src/github.com/tg123/sshpiper/sshpiperd/example/showme.sh
|
|
```
|
|
|
|
the example script will setup a sshpiper server using
|
|
```
|
|
github@127.0.0.1:2222 -> pipe to github.com:22
|
|
linode@127.0.0.1:2222 -> pipe to lish-atlanta.linode.com:22
|
|
```
|
|
|
|
connect to linode
|
|
|
|
```
|
|
$ ssh 127.0.0.1 -p 2222 -l linode.com:22
|
|
linode@127.0.0.1'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
|
|
|
|
* 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 "0.0.0.0")
|
|
--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
|
|
|
|
e.g.
|
|
|
|
```
|
|
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
|
|
|
|
e.g.
|
|
|
|
```
|
|
$ 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.
|
|
|
|
git@github.com
|
|
|
|
google.com:12345
|
|
|
|
```
|
|
|
|
* 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](http://tools.ietf.org/html/rfc4252#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](http://tools.ietf.org/html/rfc4253#section-7).
|
|
|
|
|
|
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](https://github.com/google/google-authenticator) together. OpenSSH do not support use publickey and other auth together.
|
|
|
|
|
|
#### Available Challengers
|
|
|
|
* pam
|
|
|
|
[Linux-PAM](http://www.linux-pam.org/) 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](https://en.wikipedia.org/wiki/Script_(Unix)) in working_dir.
|
|
|
|
The file format is compatible with scriptreplay(1)
|
|
|
|
Example:
|
|
|
|
```
|
|
$ ./sshpiperd --record_typescript
|
|
|
|
ssh user_name@127.0.0.1 -p 2222
|
|
... do some commands
|
|
exit
|
|
|
|
|
|
$ cd workingdir/user_name
|
|
$ ls *.timing *.typescript
|
|
1472847798.timing 1472847798.typescript
|
|
|
|
$ scriptreplay -t 1472847798.timing 1472847798.typescript # will replay the ssh session
|
|
```
|
|
|
|
|
|
## API @ [](https://godoc.org/github.com/tg123/sshpiper/ssh#SSHPiperConfig)
|
|
|
|
Package ssh in sshpiper is compatible with [golang.org/x/crypto/ssh](http://golang.org/x/crypto/ssh).
|
|
All func and datatype left unchanged. You can use it like [golang.org/x/crypto/ssh](http://golang.org/x/crypto/ssh).
|
|
|
|
SSHPiper additional API
|
|
|
|
* [NewSSHPiperConn](https://godoc.org/github.com/tg123/sshpiper/ssh#NewSSHPiperConn)
|
|
* [SSHPiperConfig](https://godoc.org/github.com/tg123/sshpiper/ssh#SSHPiperConfig)
|
|
|
|
|
|
## TODO List
|
|
|
|
* live upgrade
|
|
* man page
|
|
* hostbased auth support
|
|
* ssh-copy-id support or tools
|
|
* challenger: menu challenger
|
|
* sshpiperd: user@subhost@host support
|