Compare commits
No commits in common. "master" and "v0.0.1" have entirely different histories.
@ -66,7 +66,7 @@ See the [serial](https://gitea.elara.ws/Elara6331/seashell/wiki/Backends#serial)
|
|||||||
|
|
||||||
Seashell can proxy another SSH server. In this case, your client will authenticate to seashell and then seashell will authenticate to the target server, so you should provide seashell with a private key to use for authentication and encryption. If you don't provide this, seashell will ask the authenticating user for the target server's password.
|
Seashell can proxy another SSH server. In this case, your client will authenticate to seashell and then seashell will authenticate to the target server, so you should provide seashell with a private key to use for authentication and encryption. If you don't provide this, seashell will ask the authenticating user for the target server's password.
|
||||||
|
|
||||||
Here's an example command:
|
The proxy backend takes no extra arguments, so the `ssh` command only requires your username and the routing path:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh user:myproxy@ssh.example.com
|
ssh user:myproxy@ssh.example.com
|
||||||
|
@ -27,8 +27,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gliderlabs/ssh"
|
"github.com/gliderlabs/ssh"
|
||||||
@ -43,8 +41,8 @@ import (
|
|||||||
|
|
||||||
// proxySettings represents settings for the proxy backend.
|
// proxySettings represents settings for the proxy backend.
|
||||||
type proxySettings struct {
|
type proxySettings struct {
|
||||||
Host *string `cty:"host"`
|
Server string `cty:"server"`
|
||||||
Hosts *cty.Value `cty:"hosts"`
|
Port *uint `cty:"port"`
|
||||||
User *string `cty:"user"`
|
User *string `cty:"user"`
|
||||||
PrivkeyPath *string `cty:"privkey"`
|
PrivkeyPath *string `cty:"privkey"`
|
||||||
UserMap *cty.Value `cty:"user_map"`
|
UserMap *cty.Value `cty:"user_map"`
|
||||||
@ -55,6 +53,9 @@ type proxySettings struct {
|
|||||||
func Proxy(route config.Route) router.Handler {
|
func Proxy(route config.Route) router.Handler {
|
||||||
return func(sess ssh.Session, arg string) error {
|
return func(sess ssh.Session, arg string) error {
|
||||||
user, _ := sshctx.GetUser(sess.Context())
|
user, _ := sshctx.GetUser(sess.Context())
|
||||||
|
if !route.Permissions.IsAllowed(user, "*") {
|
||||||
|
return router.ErrUnauthorized
|
||||||
|
}
|
||||||
|
|
||||||
var opts proxySettings
|
var opts proxySettings
|
||||||
err := gocty.FromCtyValue(route.Settings, &opts)
|
err := gocty.FromCtyValue(route.Settings, &opts)
|
||||||
@ -77,56 +78,14 @@ func Proxy(route config.Route) router.Handler {
|
|||||||
opts.User = &user.Name
|
opts.User = &user.Name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
matched := false
|
if opts.Port == nil {
|
||||||
addr := arg
|
port := uint(22)
|
||||||
var portstr, pattern string
|
opts.Port = &port
|
||||||
if opts.Host == nil {
|
|
||||||
hosts := ctyTupleToStrings(opts.Hosts)
|
|
||||||
if len(hosts) == 0 {
|
|
||||||
return errors.New("no host configuration provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, hostPattern := range hosts {
|
|
||||||
pattern, portstr, ok = strings.Cut(hostPattern, ":")
|
|
||||||
if !ok {
|
|
||||||
// addr is already set by the above statement, so just set the default port
|
|
||||||
portstr = "22"
|
|
||||||
}
|
|
||||||
|
|
||||||
matched, err = path.Match(pattern, arg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if matched {
|
|
||||||
addr = arg
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
addr, portstr, ok = strings.Cut(*opts.Host, ":")
|
|
||||||
if !ok {
|
|
||||||
// addr is already set by the above statement, so just set the default port
|
|
||||||
portstr = "22"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !route.Permissions.IsAllowed(user, addr) {
|
|
||||||
return router.ErrUnauthorized
|
|
||||||
}
|
|
||||||
|
|
||||||
if !matched {
|
|
||||||
return errors.New("provided argument doesn't match any host patterns in configuration")
|
|
||||||
}
|
|
||||||
|
|
||||||
port, err := strconv.ParseUint(portstr, 10, 16)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auth := goph.Auth{
|
auth := goph.Auth{
|
||||||
gossh.PasswordCallback(requestPassword(opts, sess, addr)),
|
gossh.PasswordCallback(requestPassword(opts, sess)),
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.PrivkeyPath != nil {
|
if opts.PrivkeyPath != nil {
|
||||||
@ -146,8 +105,8 @@ func Proxy(route config.Route) router.Handler {
|
|||||||
c, err := goph.NewConn(&goph.Config{
|
c, err := goph.NewConn(&goph.Config{
|
||||||
Auth: auth,
|
Auth: auth,
|
||||||
User: *opts.User,
|
User: *opts.User,
|
||||||
Addr: addr,
|
Addr: opts.Server,
|
||||||
Port: uint(port),
|
Port: *opts.Port,
|
||||||
Callback: func(host string, remote net.Addr, key gossh.PublicKey) error {
|
Callback: func(host string, remote net.Addr, key gossh.PublicKey) error {
|
||||||
found, err := goph.CheckKnownHost(host, remote, key, "")
|
found, err := goph.CheckKnownHost(host, remote, key, "")
|
||||||
if !found {
|
if !found {
|
||||||
@ -214,9 +173,9 @@ func Proxy(route config.Route) router.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// requestPassword asks the client for the remote server's password
|
// requestPassword asks the client for the remote server's password
|
||||||
func requestPassword(opts proxySettings, sess ssh.Session, addr string) func() (secret string, err error) {
|
func requestPassword(opts proxySettings, sess ssh.Session) func() (secret string, err error) {
|
||||||
return func() (secret string, err error) {
|
return func() (secret string, err error) {
|
||||||
_, err = fmt.Fprintf(sess.Stderr(), "Password for %s@%s: ", *opts.User, addr)
|
_, err = fmt.Fprintf(sess.Stderr(), "Password for %s@%s: ", *opts.User, opts.Server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -20,16 +20,7 @@ route "srv" {
|
|||||||
backend = "proxy"
|
backend = "proxy"
|
||||||
match = "srv"
|
match = "srv"
|
||||||
settings = {
|
settings = {
|
||||||
host = "1.2.3.4"
|
server = "1.2.3.4"
|
||||||
privkey = "/home/elara/.ssh/id_ed25519"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
route "cluster" {
|
|
||||||
backend = "proxy"
|
|
||||||
match = "cluster\\.(.+)"
|
|
||||||
settings = {
|
|
||||||
hosts = ["node*", "nas", "192.168.1.*"]
|
|
||||||
privkey = "/home/elara/.ssh/id_ed25519"
|
privkey = "/home/elara/.ssh/id_ed25519"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user