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