func main() { // Create logger writer := log.NewConcurrentWriter(os.Stdout) logger := log.NewLogger(writer, "sshh") // Get private key privateKey, err := ssh.ParsePrivateKey([]byte(privateKey)) if err != nil { logger.Warn("Private key could not be parsed", "error", err.Error()) } // Setup server config config := sshh.Config{ Deadline: time.Second, Logger: logger, Bind: ":9022", Handlers: map[string]sshh.SSHHandler{ "session": NewShellHandler(logger), }, PrivateKey: privateKey, PasswordCallback: func(conn ssh.ConnMetadata, password []byte) (perm *ssh.Permissions, err error) { if conn.User() == "admin" && string(password) == "password" { // Add username to permissions perm = &ssh.Permissions{ Extensions: map[string]string{ "username": conn.User(), }, } } else { err = fmt.Errorf("Invalid username or password") } return }, AuthLogCallback: func(conn ssh.ConnMetadata, method string, err error) { if err == nil { logger.Info("Successful login", "user", conn.User(), "method", method) } }, // PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (perm *ssh.Permissions, err error) { // return nil, fmt.Errorf("Unauthorized") // }, } // Create SSH server sshServer, err := sshh.NewSSHServer(&config) if err != nil { logger.Error("SSH Server could not be configured", "error", err.Error()) return } // Start servers sshServer.Start() // Handle signals sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, os.Kill) // Wait for signal logger.Info("Ready to serve requests") // Block until signal is received <-sig // Stop listening for signals and close channel signal.Stop(sig) close(sig) // Shut down SSH server logger.Info("Shutting down servers.") sshServer.Stop() }
func NewServer(c *DatabaseConfig) (server *Server, err error) { // Create logger if c.LogOutput == nil { c.LogOutput = log.NewConcurrentWriter(os.Stdout) } logger := log.NewLogger(c.LogOutput, "kappa") // Create data directory if err = os.MkdirAll(c.DataPath, 0755); err != nil { logger.Warn("Could not create data directory", "err", err) // logger.Warn("Could not create data directory", "err", err.Error()) return } // Connect to database cwd, err := os.Getwd() if err != nil { logger.Error("Could not get working directory", "error", err.Error()) return } file := path.Join(cwd, c.DataPath, "meta.db") logger.Info("Connecting to database", "file", file) system, err := datamodel.NewSystem(file) if err != nil { logger.Error("Could not connect to database", "error", err.Error()) return } // Get SSH Key file sshKeyFile := c.SSHPrivateKeyFile logger.Info("Reading private key", "file", sshKeyFile) privateKey, err := auth.ReadPrivateKey(logger, sshKeyFile) if err != nil { return } // Get admin certificate adminCertFile := c.AdminCertificateFile logger.Info("Reading admin public key", "file", adminCertFile) // Read admin certificate cert, err := ioutil.ReadFile(adminCertFile) if err != nil { logger.Error("admin certificate could not be read", "filename", c.AdminCertificateFile) return } // Add admin cert to key ring userStore, err := system.Users() if err != nil { logger.Error("could not get user store", "error", err.Error()) return } // Create admin account admin, err := userStore.Create("admin") if err != nil { logger.Error("error creating admin account", "error", err.Error()) return } // Add admin certificate keyRing := admin.KeyRing() fingerprint, err := keyRing.AddPublicKey(cert) if err != nil { logger.Error("admin certificate could not be added", "error", err.Error()) return } logger.Info("Added admin certificate", "fingerprint", fingerprint) // Read root cert rootPem, err := ioutil.ReadFile(c.CACertificateFile) if err != nil { logger.Error("root certificate could not be read", "filename", c.CACertificateFile) return } // Create certificate pool roots := x509.NewCertPool() if ok := roots.AppendCertsFromPEM(rootPem); !ok { logger.Error("failed to parse root certificate") return } // Setup SSH Server sshLogger := log.NewLogger(c.LogOutput, "ssh") pubKeyCallback, err := PublicKeyCallback(system) if err != nil { logger.Error("failed to create PublicKeyCallback", err) return } // Setup server config config := sshh.Config{ Deadline: c.SSHConnectionDeadline, Logger: sshLogger, Bind: c.SSHBindAddress, PrivateKey: privateKey, PublicKeyCallback: pubKeyCallback, AuthLogCallback: func(meta ssh.ConnMetadata, method string, err error) { if err == nil { sshLogger.Info("login success", "user", meta.User()) } else if err != nil && method == "publickey" { sshLogger.Info("login failure", "user", meta.User(), "err", err.Error()) } }, Handlers: map[string]sshh.SSHHandler{ "kappa-client": &EchoHandler{}, }, } // Create SSH server sshServer, err := sshh.NewSSHServer(&config) if err != nil { logger.Error("SSH Server could not be configured", "error", err.Error()) return } // Setup Serf handlers mgr := NewNodeList() reconcilerCh := make(chan serf.Member, 32) serfEventCh := make(chan serf.Event, 256) userEventCh := make(chan serf.UserEvent, 256) serfer := serfer.NewSerfer(serfEventCh, serfer.SerfEventHandler{ Logger: log.NewLogger(c.LogOutput, "serf"), ServicePrefix: "kappa", ReconcileOnJoin: true, ReconcileOnLeave: true, ReconcileOnFail: true, ReconcileOnUpdate: true, ReconcileOnReap: true, NodeJoined: &SerfNodeJoinHandler{ mgr, log.NewLogger(c.LogOutput, "serf:node-join")}, NodeUpdated: &SerfNodeUpdateHandler{ mgr, log.NewLogger(c.LogOutput, "serf:node-update")}, NodeLeft: &SerfNodeLeaveHandler{ mgr, log.NewLogger(c.LogOutput, "serf:node-left")}, NodeFailed: &SerfNodeLeaveHandler{ mgr, log.NewLogger(c.LogOutput, "serf:node-fail")}, NodeReaped: &SerfNodeLeaveHandler{ mgr, log.NewLogger(c.LogOutput, "serf:node-reap")}, UserEvent: &SerfUserEventHandler{ log.NewLogger(c.LogOutput, "serf:user-events"), userEventCh}, UnknownEventHandler: &SerfUserEventHandler{ log.NewLogger(c.LogOutput, "serf:unknown-event"), userEventCh}, Reconciler: &SerfReconciler{reconcilerCh}, IsLeader: func() bool { // TODO: Replace with Raft IsLeader check return true }, }) // Create database server s := &Server{ config: c, logger: logger, sshServer: &sshServer, serfer: serfer, localKappas: make(map[string]*NodeDetails), serfEventCh: serfEventCh, kappaEventCh: userEventCh, reconcileCh: reconcilerCh, } // Create serf server s.serf, err = s.setupSerf() if err != nil { err = logger.Error("Failed to start serf: %v", err) return } return s, nil }