104 lines
2.2 KiB
Go
104 lines
2.2 KiB
Go
package ssh
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
|
|
"github.com/FAU-CDI/wisski-distillery/pkg/sshx"
|
|
"github.com/gliderlabs/ssh"
|
|
"github.com/tkw1536/goprogram/stream"
|
|
"github.com/tkw1536/proxyssh/feature"
|
|
)
|
|
|
|
type SSH struct {
|
|
component.Base
|
|
Instances *instances.Instances
|
|
}
|
|
|
|
const (
|
|
etx rune = 3
|
|
eot rune = 4
|
|
)
|
|
|
|
const welcomeMessage = `Welcome to the WissKI SSH Server.
|
|
You've successfully authenticated, but we don't provide shell access to the main server.
|
|
You may use this connection as part of a proxy jump to connect to your server.
|
|
For example:
|
|
|
|
ssh -J %s:2222 www-data@%s
|
|
|
|
Press CTRL-C to close this connection.
|
|
`
|
|
|
|
// Server returns an ssh server that implements the main ssh server
|
|
func (s *SSH) Server(context context.Context, ios stream.IOStream) (*ssh.Server, error) {
|
|
var server ssh.Server
|
|
|
|
banner := fmt.Sprintf(welcomeMessage, s.Config.DefaultDomain, "example."+s.Config.DefaultDomain)
|
|
|
|
server.Handle(func(session ssh.Session) {
|
|
io.WriteString(session, banner)
|
|
|
|
buffer := bufio.NewReader(session)
|
|
for {
|
|
res, _, err := buffer.ReadRune()
|
|
if err != nil {
|
|
return
|
|
}
|
|
if res == etx || res == eot {
|
|
return
|
|
}
|
|
}
|
|
|
|
})
|
|
server.PublicKeyHandler = feature.AuthorizeKeys(
|
|
slogger{IOStream: ios},
|
|
func(ctx ssh.Context) (keys []ssh.PublicKey, err error) {
|
|
keys, err = s.GlobalKeys()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
instances, err := s.Instances.All()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, instance := range instances {
|
|
ikeys, err := instance.SSH().Keys()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
keys = append(keys, ikeys...)
|
|
}
|
|
return keys, nil
|
|
})
|
|
return &server, nil
|
|
}
|
|
|
|
func (s *SSH) GlobalKeys() ([]ssh.PublicKey, error) {
|
|
file, err := s.Environment.Open(s.Config.GlobalAuthorizedKeysFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
bytes, err := io.ReadAll(file)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return sshx.ParseAllKeys(bytes), nil
|
|
}
|
|
|
|
type slogger struct {
|
|
stream.IOStream
|
|
}
|
|
|
|
func (s slogger) Print(v ...any) {
|
|
fmt.Fprint(s.Stderr, v...)
|
|
}
|
|
func (s slogger) Printf(format string, v ...any) {
|
|
fmt.Fprintf(s.Stderr, format, v...)
|
|
}
|