wisski-cloud-distillery/internal/dis/component/ssh/ssh.go
2022-11-16 13:07:17 +01:00

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...)
}