Example #1
0
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()
}
Example #2
0
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
}