finish readme

This commit is contained in:
Boshi Lian 2022-07-05 20:30:41 +00:00
parent 6b3ebecf9e
commit e1aa1c9823
5 changed files with 180 additions and 183 deletions

294
README.md
View file

@ -1,15 +1,24 @@
# SSH Piper
# sshpiper 🖇
![Go](https://github.com/tg123/sshpiper/workflows/Go/badge.svg)
[![Go Report Card](https://goreportcard.com/badge/github.com/tg123/sshpiper)](https://goreportcard.com/report/github.com/tg123/sshpiper)
[![Docker Image](https://img.shields.io/docker/pulls/farmer1992/sshpiperd.svg)](https://hub.docker.com/r/farmer1992/sshpiperd)
SSH Piper works as a proxy-like ware, and route connections by `username`, `src ip` , etc.
`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](https://github.com/tg123/sshpiper/tree/v0)
### Overview and Terminology
* `downstream`: the client side, typicall ssh client
* `upstream`: the server side, typicall sshd server
* `plugin`: handles the routing from `downstream` to `upstream`. the `plugin` are also repsonsible for the mapping authentication methods to upstream. for exmaple, the downstream may use password as authentication method, but the upstream may receive public key authentication mapped by `sshpiper`.
* `addtional chanllenge`: some `plugin` will not do routing but add an additional challenges to ssh authentication to `upstream`. for example, the `downstream` may be asked for two factor authentication provided by the `plugin`.
```
+---------+ +------------------+ +-----------------+
| | | | | |
| Bob +----ssh -l bob----+ | SSH Piper +-------------> Bob' machine |
| Bob +----ssh -l bob----+ | sshpiper +-------------> Bob' machine |
| | | | | | | |
+---------+ | | | | +-----------------+
+---> pipe-by-name--+ |
@ -20,140 +29,89 @@ SSH Piper works as a proxy-like ware, and route connections by `username`, `src
+---------+ +------------------+ +-----------------+
Downstream SSH Piper Upstream
downstream sshpiper upstream
```
## Demo
[![asciicast](https://asciinema.org/a/222825.svg)](https://asciinema.org/a/222825)
## Quick start
Just run `showme.sh` in [sshpiperd example directory](sshpiperd/example)
or
Copy paste command below to run
### Build
```
git clone https://github.com/tg123/sshpiper
cd sshpiper
git submodule update --init --recursive
cd sshpiperd/example/
./showme.sh
mkdir out
go build -o out ./...
```
the example script will setup a sshpiper server using
```
bitbucket -> bitbucket@bitbucket.org:22 # ssh 127.0.0.1 -p 2222 -l bitbucket
github -> github@github.com:22 # ssh 127.0.0.1 -p 2222 -l github
gitlab -> gitlab@gitlab.com:22 # ssh 127.0.0.1 -p 2222 -l gitlab
```
## Run simple demo
connect to gitlab
### start dummy sshd server
```
$ ssh 127.0.0.1 -p 2222 -l gitlab
Permission denied (publickey).
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 targetting the dummy sshd server
```
sudo ./out/sshpiperd ./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 `addional challenge` before the `fixed` plugin.
```
sudo ./out/sshpiperd --log-level=trace ./out/simplemath -- ./out/fixed --target 127.0.0.1:5522
```
## Plugins
### icons
* 🔀: routing plugin
* 🔒: addtional challenge plugin
Plugin list
* [workingdir](plugin/workingdir/) 🔀: ask for working directory before login, demo purpose
* [azdevicecode](plugin/azdevicecode/) 🔒: ask user to enter [azure device code](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code) before login
* [fixed](plugin/fixed/) 🔀: fixed targetting the dummy sshd server
* [simplemath](plugin/simplemath/) 🔒: ask for very simple math question before login, demo purpose
## Screening recording
`sshpiperd` support recording the screen in `typescript` format (not the lang). The format is compatible with [scriptreplay(1)](https://linux.die.net/man/1/scriptreplay)
To use it, start sshpiperd with `--typescript-log-dir loggingdir`
Example:
```
ssh user_name@127.0.0.1 -p 2222
... do some commands
exit
$ cd loggingdir/user_name
$ ls *.timing *.typescript
1472847798.timing 1472847798.typescript
$ scriptreplay -t 1472847798.timing 1472847798.typescript # will replay the ssh session
```
connect to github.com
```
$ ssh 127.0.0.1 -p 2222 -l github
Permission denied (publickey).
```
## Install
### Build yourself [Go 1.18]
```
git clone https://github.com/tg123/sshpiper.git
cd sshpiper
git submodule update --init --recursive
cd sshpiperd
go build
```
### with [Docker image](https://registry.hub.docker.com/r/farmer1992/sshpiperd/)
```
docker run farmer1992/sshpiperd
```
Run with [Workding Dir upstream driver](sshpiperd/upstream/workingdir/README.md)
```
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---challenger-driver)
### with [Snap](https://snapcraft.io/sshpiperd)
[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-white.svg)](https://snapcraft.io/sshpiperd)
```
sudo snap install sshpiperd
```
configure with snap
```
sudo snap set sshpiperd 'port=3333'
sudo snap restart sshpiperd
```
_NOTE:_
* Default working dir for snap verion is `/var/snap/sshpiperd/common`
## Configuration
sshpiper provides 3 pluginable components to highly customize your piper
* [Upstream Driver](#upstream-Driver---upstream-driver)
* [Additional Challenge](#additional-challenge---challenger-driver)
* [Auditor](#auditor-for-pipes---auditor-driver)
`sshpiperd daemon -h` to learn more
### Upstream Driver (`--upstream-driver=`)
Upstream driver helps sshpiper to find which upstream host to connect and how to connect.
For example, you can change the username when connecting to upstream sshd by config upstream driver
Available Upstream Drivers
* [Workding Directory](sshpiperd/upstream/workingdir/README.md)
Working Dir is a /home-like directory. SSHPiperd read files from workingdir/[username]/ to know upstream's configuration.
* [YAML](sshpiperd/upstream/yaml/README.md)
YAML based config file driver
* [gRPC Driver](sshpiperd/upstream/grpcupstream/README.md)
Everything on remote gRPC server, including the private key, no state stored on sshpiperd server.
* [Database Driver](sshpiperd/upstream/database/README.md)
Database upstream driver connected to popular databases, such as mysql, pg or sqlite etc to provide upstream's information.
* [Kubernetes Driver](sshpiperd/upstream/kubernetes/README.md)
Kubernetes drive can configure pipe with CRD.
#### How to do public key authentication when using sshpiper
## Public key authentication when using sshpiper (Private key remapping)
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`.
@ -163,19 +121,18 @@ However, sshpiper actually holds two ssh connection, and it is doing what `the m
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 provided by upstream driver.
e.g. (`id_rsa`) in the `workingdir/[username]/`.
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 | | SSH Piper |
| client | | sshpiper |
| PK_X +--------> | |
| | | v |
| | | Check PK_X |
+------------+ | in authorized_keys |
| | | Check Permission |
+------------+ | | |
| | |
| | | +----------------+
| v | | |
@ -186,93 +143,16 @@ How this work
+------------------------+ +----------------+
```
e.g.
## Migrating from `v0`
on client
### What's the major change in `v1`
```
ssh-copy-id -i PK_X test@sshpiper
```
* low level sshpiper api is fully redesigned to support more routing protocols.
* plugins system totally redesigned to be more flexible and extensible.
* plugins are now sperated from main process and no longer a single big binary, this allow user to write their own plugins without touching `sshpiperd` code.
* `grpc` is first class now, the plugins are built on top of it
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 (`--challenger-driver=`)
sshpiper allows you to add 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.
#### Available Challengers
* azdevcode
Support Azure AD device code grant, [More info](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code)
sshpier will ask user to login using webpage
```
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code ****** to authenticate.
```
* authy
Support token and onetouch from <https://authy.com/>
#### OpenSSH Native way to do 2FA (No SSHPiper)
in `sshd_config`
```
AuthenticationMethods publickey,keyboard-interactive:pam
```
Enable 2FA PAM, for example, `pam_yubico` or `pam_google_authenticator`.
### Auditor for pipes (`--auditor-driver=`)
Auditor provides hook for messages transfered by SSH Piper which cloud log messages onto disks or filter some specific message on the fly.
#### Available Auditor
* SSH Session logging (`--auditor-driver=typescript-logger`)
When `record_typescript` is allowed, each piped connection would be recorded into [typescript](https://en.wikipedia.org/wiki/Script_(Unix)) in `--auditor-typescriptlogger-outputdir`.
The file format is compatible with [scriptreplay(1)](https://linux.die.net/man/1/scriptreplay)
Example:
```
$ ./sshpiperd daemon --auditor-driver=typescript-logger
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
```
## Manage pipes with sshpiper command
SSH Piper comes with tools to list/add/remove pipes.
`sshpiperd pipe -h` to learn more.
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](https://github.com/tg123/sshpiper/tree/v0)
## License
MIT

View file

@ -0,0 +1,19 @@
# Azure Device Code for sshpiperd
Support Azure AD device code grant, [More info](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code)
sshpier will ask user to login using webpage
```
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code ****** to authenticate.
```
NOTE: This is an additional challenge plugin. 🔒 you must use it with other routing plugins.
## Usage
Note: you may want to set `login-grace-time` to larger value (default: 30s) to avoid being kicked by `sshpiperd` if code was not entered in time.
```
sshpiperd --login-grace-time=2m azdevicecode --tenant-id 00000000-0000-0000-0000-000000000000 --client-id 00000000-0000-0000-0000-000000000000 -- other-plugin --other-option
```

10
plugin/fixed/README.md Normal file
View file

@ -0,0 +1,10 @@
# fixed plugin for sshpiperd
Targeting the fixed sshd endpoint. Note, key mapping is not supported. which means you cannot use public to login to remote sshd.
## Usage
```
sshpiperd fixed --target 127.0.0.1:5522
```

View file

@ -0,0 +1,17 @@
# simple math plugin for sshpiperd
## Usage
Note: this is an additional challenge plugin. 🔒 you must use it with other routing plugins.
```
sshpiperd simplemath -- other-plugin --other-option
```
### Demo
```
$ ssh 127.0.0.1 -l user -p 2222
lets do math
what is 7 + 9 =
```

View file

@ -0,0 +1,71 @@
# Working Directory plugin for sshpiperd
`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.
## Usage
```
sshpiperd workingdir --root /var/sshpiper
```
### options (allow supported read from environments)
```
--allow-baduser-name allow bad username (default: false) [$SSHPIPERD_WORKINGDIR_ALLOWBADUSERNAME]
--no-check-perm disable 0400 checking (default: false) [$SSHPIPERD_WORKINGDIR_NOCHECKPERM]
--root value path to root working directory (default: "/var/sshpiper") [$SSHPIPERD_WORKINGDIR_ROOT]
--strict-hostkey upstream host public key must be in known_hosts file, otherwise drop the connection (default: false) [$SSHPIPERD_WORKINGDIR_STRICTHOSTKEY]
```
## 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`). `downstream`'s public key must be in this file to get verified in order to use `id_rsa` to login to `upstream`.
* id_rsa
RSA key for upstream.
* known_hosts
when `--strict-hostkey` is set, upstream server's public key must present in known_hosts