feat: Add username-router plugin for SSHPiper to route connections based on username (#599)
* feat: Add username-router plugin for SSHPiper to route connections based on username * feat: Add username-router plugin to GoReleaser configuration
This commit is contained in:
parent
706a36b40e
commit
f56c4b67e5
4 changed files with 87 additions and 0 deletions
|
|
@ -117,6 +117,20 @@ builds:
|
|||
binary: plugins/failtoban
|
||||
tags:
|
||||
- full
|
||||
- id: plugin_username_router
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
main: ./plugin/username-router
|
||||
binary: plugins/username-router
|
||||
tags:
|
||||
- full
|
||||
|
||||
archives:
|
||||
- formats: ['tar.gz']
|
||||
|
|
@ -141,6 +155,7 @@ archives:
|
|||
- plugin_failtoban
|
||||
- plugin_docker
|
||||
- plugin_kubernetes
|
||||
- plugin_username_router
|
||||
dockers:
|
||||
- image_templates:
|
||||
- "farmer1992/sshpiperd:v{{ .Version }}-amd64"
|
||||
|
|
@ -248,6 +263,7 @@ snapcrafts:
|
|||
- plugin_yaml
|
||||
- plugin_fixed
|
||||
- plugin_failtoban
|
||||
- plugin_username_router
|
||||
name: sshpiperd
|
||||
name_template: "sshpiperd_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
||||
summary: The missing reverse proxy for ssh scp
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ Plugin list
|
|||
* [kubernetes](plugin/kubernetes/) 🔀: manage pipes via Kubernetes CRD.
|
||||
* [azdevicecode](https://github.com/tg123/sshpiper-plugins/tree/main/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 targeting the dummy sshd server
|
||||
* [username-router](plugin/username-router/) 🔀: route based on username, the username format is `target+username`, where `target` is the target host and `username` is the username to use for that target.
|
||||
* [simplemath](plugin/simplemath/) 🔒: ask for very simple math question before login, demo purpose
|
||||
* [githubapp](https://github.com/tg123/sshpiper-gh) 🔀: login ssh with your github account
|
||||
* [restful](https://github.com/11notes/docker-sshpiper) by [@11notes](https://github.com/11notes) 🔀🔒: The rest plugin for sshpiperd is a simple plugin that allows you to use a restful backend for authentication and challenge.
|
||||
|
|
|
|||
11
plugin/username-router/README.md
Normal file
11
plugin/username-router/README.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# username-router plugin for sshpiper
|
||||
|
||||
Supports routing based on username. This plugin allows you to route connections to different targets based on the username provided during the SSH connection.
|
||||
The username format is `target+username`, where `target` is the target host and `username` is the username to use for that target.
|
||||
`target` can be an IP address or a hostname, and it can also include a port number in the format `target:port`.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
sshpiperd username-router
|
||||
```
|
||||
59
plugin/username-router/main.go
Normal file
59
plugin/username-router/main.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
//go:build full || e2e
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/tg123/sshpiper/libplugin"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func parseTargetUser(raw string) (target string, username string, err error) {
|
||||
// Expect format: [target:port]+user
|
||||
parts := strings.SplitN(raw, "+", 2)
|
||||
if len(parts) != 2 {
|
||||
err = fmt.Errorf("invalid format (expected target:port+user)")
|
||||
return
|
||||
}
|
||||
|
||||
target = parts[0]
|
||||
username = parts[1]
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
libplugin.CreateAndRunPluginTemplate(&libplugin.PluginTemplate{
|
||||
Name: "username-router",
|
||||
Usage: "routing based on target inside username, format: 'target:port+realuser@sshpiper-host'",
|
||||
CreateConfig: func(c *cli.Context) (*libplugin.SshPiperPluginConfig, error) {
|
||||
|
||||
return &libplugin.SshPiperPluginConfig{
|
||||
PasswordCallback: func(conn libplugin.ConnMetadata, password []byte) (*libplugin.Upstream, error) {
|
||||
|
||||
address, user, err := parseTargetUser(conn.User())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid username format %q: %w", conn.User(), err)
|
||||
}
|
||||
|
||||
host, port, err := libplugin.SplitHostPortForSSH(address)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid target address %q: %w", address, err)
|
||||
}
|
||||
|
||||
log.Info("routing to address ", address, " with user ", user)
|
||||
return &libplugin.Upstream{
|
||||
UserName: user,
|
||||
Host: host,
|
||||
Port: int32(port),
|
||||
IgnoreHostKey: true,
|
||||
Auth: libplugin.CreatePasswordAuth(password),
|
||||
}, nil
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue