From a6170703e4da8b11a047495a80f5c6914dc8b65a Mon Sep 17 00:00:00 2001 From: Scott Leggett Date: Thu, 3 Feb 2022 20:32:00 +0800 Subject: [PATCH] feat: add ability to configure a persistent host key If no host key is defined, a non-persistent host key will be generated at server start. --- cmd/ssh-portal/serve.go | 16 +++++++++++++--- go.mod | 2 +- internal/sshserver/serve.go | 15 ++++++++++++--- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/cmd/ssh-portal/serve.go b/cmd/ssh-portal/serve.go index aa31e7a5..6e279972 100644 --- a/cmd/ssh-portal/serve.go +++ b/cmd/ssh-portal/serve.go @@ -15,8 +15,11 @@ import ( // ServeCmd represents the serve command. type ServeCmd struct { - NATSServer string `kong:"required,env='NATS_URL',help='NATS server URL (nats://... or tls://...)'"` - SSHServerPort uint `kong:"default='2222',env='SSH_SERVER_PORT',help='Port the SSH server will listen on for SSH client connections'"` + NATSServer string `kong:"required,env='NATS_URL',help='NATS server URL (nats://... or tls://...)'"` + SSHServerPort uint `kong:"default='2222',env='SSH_SERVER_PORT',help='Port the SSH server will listen on for SSH client connections'"` + HostKeyECDSA string `kong:"env='HOST_KEY_ECDSA',help='PEM encoded ECDSA host key'"` + HostKeyED25519 string `kong:"env='HOST_KEY_ED25519',help='PEM encoded Ed25519 host key'"` + HostKeyRSA string `kong:"env='HOST_KEY_RSA',help='PEM encoded RSA host key'"` } // Run the serve command to service API requests. @@ -45,6 +48,13 @@ func (cmd *ServeCmd) Run(log *zap.Logger) error { if err != nil { return fmt.Errorf("couldn't create k8s client: %v", err) } + // check for persistent host key arguments + var hostkeys [][]byte + for _, hk := range []string{cmd.HostKeyECDSA, cmd.HostKeyED25519, cmd.HostKeyRSA} { + if len(hk) > 0 { + hostkeys = append(hostkeys, []byte(hk)) + } + } // start serving SSH connection requests - return sshserver.Serve(ctx, log, nc, l, c) + return sshserver.Serve(ctx, log, nc, l, c, hostkeys) } diff --git a/go.mod b/go.mod index cc118f48..a55a8ceb 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/go-sql-driver/mysql v1.6.0 github.com/google/uuid v1.3.0 github.com/jmoiron/sqlx v1.3.4 + github.com/moby/spdystream v0.2.0 github.com/nats-io/nats.go v1.13.1-0.20211018182449-f2416a8b1483 github.com/prometheus/client_golang v1.11.0 go.opentelemetry.io/otel v1.3.0 @@ -34,7 +35,6 @@ require ( github.com/googleapis/gnostic v0.5.5 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/nats-io/nats-server/v2 v2.6.4 // indirect diff --git a/internal/sshserver/serve.go b/internal/sshserver/serve.go index d077fc3b..bb745a4d 100644 --- a/internal/sshserver/serve.go +++ b/internal/sshserver/serve.go @@ -2,6 +2,7 @@ package sshserver import ( "context" + "fmt" "net" "github.com/gliderlabs/ssh" @@ -12,7 +13,15 @@ import ( // Serve contains the main ssh session logic func Serve(ctx context.Context, log *zap.Logger, nc *nats.Conn, - l net.Listener, c *k8s.Client) error { - return ssh.Serve(l, sessionHandler(log, c), - ssh.PublicKeyAuth(pubKeyAuth(log, nc, c))) + l net.Listener, c *k8s.Client, hostKeys [][]byte) error { + srv := ssh.Server{ + Handler: sessionHandler(log, c), + PublicKeyHandler: pubKeyAuth(log, nc, c), + } + for _, hk := range hostKeys { + if err := srv.SetOption(ssh.HostKeyPEM(hk)); err != nil { + return fmt.Errorf("invalid host key: %v", err) + } + } + return srv.Serve(l) }