374742d8e8
Signed-off-by: Evan Hazlett <ejhazlett@gmail.com>
114 lines
2.3 KiB
Go
114 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
"github.com/gliderlabs/ssh"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type ServerConfig struct {
|
|
ListenPort int
|
|
DBPath string
|
|
KeysPath string
|
|
HostKeyPath string
|
|
RedisURL string
|
|
Subnet string
|
|
}
|
|
|
|
type Server struct {
|
|
cfg *ServerConfig
|
|
publicKeys []ssh.PublicKey
|
|
mu *sync.Mutex
|
|
}
|
|
|
|
func NewServer(cfg *ServerConfig) (*Server, error) {
|
|
if cfg.ListenPort == 0 {
|
|
cfg.ListenPort = 2222
|
|
}
|
|
return &Server{
|
|
cfg: cfg,
|
|
mu: &sync.Mutex{},
|
|
}, nil
|
|
}
|
|
|
|
func (s *Server) Run() error {
|
|
if err := s.loadKeys(); err != nil {
|
|
return err
|
|
}
|
|
|
|
ssh.Handle(func(session ssh.Session) {
|
|
//authorizedKey := gossh.MarshalAuthorizedKey(session.PublicKey())
|
|
id := s.getID(session.PublicKey())
|
|
ip, ipnet, err := s.getOrAllocateIP(id, s.cfg.Subnet)
|
|
if err != nil {
|
|
logrus.Error(err)
|
|
return
|
|
}
|
|
logrus.Debugf("config: id=%s ip=%s net=%s", id, ip, ipnet)
|
|
io.WriteString(session, ip.String()+"\n")
|
|
})
|
|
|
|
pubKeyOption := ssh.PublicKeyAuth(func(ctx ssh.Context, key ssh.PublicKey) bool {
|
|
return s.isAuthorized(ctx, key)
|
|
})
|
|
|
|
logrus.Infof("starting ssh server on port %d", s.cfg.ListenPort)
|
|
opts := []ssh.Option{
|
|
pubKeyOption,
|
|
}
|
|
if _, err := os.Stat(s.cfg.HostKeyPath); err == nil {
|
|
opts = append(opts, ssh.HostKeyFile(s.cfg.HostKeyPath))
|
|
}
|
|
return ssh.ListenAndServe(fmt.Sprintf(":%d", s.cfg.ListenPort), nil, pubKeyOption)
|
|
}
|
|
|
|
func (s *Server) loadKeys() error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
if s.cfg.KeysPath == "" {
|
|
return nil
|
|
}
|
|
|
|
keys, err := ioutil.ReadDir(s.cfg.KeysPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pubKeys := []ssh.PublicKey{}
|
|
for _, k := range keys {
|
|
logrus.Debugf("loading public key %s", k.Name())
|
|
p := filepath.Join(s.cfg.KeysPath, k.Name())
|
|
data, err := ioutil.ReadFile(p)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
k, _, _, _, err := ssh.ParseAuthorizedKey(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
pubKeys = append(pubKeys, k)
|
|
}
|
|
|
|
s.publicKeys = pubKeys
|
|
return nil
|
|
}
|
|
|
|
func (s *Server) isAuthorized(ctx ssh.Context, key ssh.PublicKey) bool {
|
|
for _, k := range s.publicKeys {
|
|
if ssh.KeysEqual(key, k) {
|
|
return true
|
|
}
|
|
}
|
|
logrus.WithFields(logrus.Fields{
|
|
"user": ctx.User(),
|
|
"addr": ctx.RemoteAddr(),
|
|
}).Warn("access denied")
|
|
return false
|
|
}
|