From 1efb4d37bcac29f0fee1c9de6eda57b954bad5de Mon Sep 17 00:00:00 2001 From: Fabrice Aneche Date: Thu, 12 Sep 2024 22:53:07 -0400 Subject: [PATCH] added private host key --- cmd/sshjump/kubernetes.go | 2 +- cmd/sshjump/main.go | 17 ++++++++- cmd/sshjump/server.go | 22 ++++++++++- deployment/sshjump-configmap.yaml | 4 ++ deployment/sshjump-deployment.yaml | 60 +++++++++++++++--------------- 5 files changed, 73 insertions(+), 32 deletions(-) diff --git a/cmd/sshjump/kubernetes.go b/cmd/sshjump/kubernetes.go index 6a6cdab..567f550 100644 --- a/cmd/sshjump/kubernetes.go +++ b/cmd/sshjump/kubernetes.go @@ -42,7 +42,7 @@ func (srv *Server) KubernetesPortsForUser(ctx context.Context, user string) (des } } - // Get the list of services in the default namespace + // Get the list of services in all namespaces services, err := srv.clientset.CoreV1().Services("").List(ctx, metav1.ListOptions{}) if err != nil { return nil, fmt.Errorf("can't fetch services list %w", err) diff --git a/cmd/sshjump/main.go b/cmd/sshjump/main.go index d67dc2b..3f093d7 100644 --- a/cmd/sshjump/main.go +++ b/cmd/sshjump/main.go @@ -12,6 +12,7 @@ import ( "github.com/caarlos0/env/v11" "github.com/gliderlabs/ssh" + gossh "golang.org/x/crypto/ssh" "golang.org/x/sync/errgroup" "google.golang.org/grpc" "google.golang.org/grpc/health" @@ -73,6 +74,7 @@ func main() { ConfigPath string `env:"CONFIG_PATH" envDefault:"sshjump.yaml"` Host string `env:"HOST" envDefault:"0.0.0.0"` Port int `env:"PORT" envDefault:"2222"` + PrivateKeyPath string `env:"PRIVATE_KEY_PATH" envDefault:"key.sa"` HealthPort int `env:"HEALTH_PORT" envDefault:"6666"` KubeConfigPath string `env:"KUBE_CONFIG_PATH"` // Set the path of a kubeconfig file if sshjump is running outside of a cluster } @@ -174,7 +176,20 @@ func main() { return grpcHealthServer.Serve(hln) }) - s := NewServer(logger, keys, clientset) + // reading private key + pemBytes, err := os.ReadFile(envCfg.PrivateKeyPath) + if err != nil { + logger.Error("can't read private key", "error", err) + os.Exit(2) + } + + key, err := gossh.ParsePrivateKey(pemBytes) + if err != nil { + logger.Error("can't parse private key", "error", err) + os.Exit(2) + } + + s := NewServer(logger, key, keys, clientset) // ssh server g.Go(func() error { diff --git a/cmd/sshjump/server.go b/cmd/sshjump/server.go index ceb254a..ffd4398 100644 --- a/cmd/sshjump/server.go +++ b/cmd/sshjump/server.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "io/ioutil" "log/slog" "net" "strings" @@ -15,6 +16,12 @@ import ( "k8s.io/client-go/kubernetes" ) +var ( + // TODO: parametrize + DeadlineTimeout = 30 * time.Second + IdleTimeout = 10 * time.Second +) + type Server struct { logger *slog.Logger *ssh.Server @@ -33,7 +40,7 @@ type localForwardChannelData struct { OriginPort uint32 } -func NewServer(logger *slog.Logger, keys map[string]Permission, clientset *kubernetes.Clientset) *Server { +func NewServer(logger *slog.Logger, privateKey gossh.Signer, keys map[string]Permission, clientset *kubernetes.Clientset) *Server { s := &Server{ logger: logger, permissions: keys, @@ -51,8 +58,12 @@ func NewServer(logger *slog.Logger, keys map[string]Permission, clientset *kuber "direct-tcpip": s.DirectTCPIPHandler, "session": ssh.DefaultSessionHandler, }, + MaxTimeout: DeadlineTimeout, + IdleTimeout: IdleTimeout, } + s.AddHostKey(privateKey) + publicKeyOption := ssh.PublicKeyAuth(s.PublicKeyHandler) sshServer.SetOption(publicKeyOption) @@ -224,3 +235,12 @@ func (srv *Server) DirectTCPIPHandler(s *ssh.Server, conn *gossh.ServerConn, new io.Copy(dconn, ch) }() } + +func ReadPrivateKeyFromFile(path string) (ssh.Signer, error) { + keyBytes, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + + return key, nil +} diff --git a/deployment/sshjump-configmap.yaml b/deployment/sshjump-configmap.yaml index 264a11c..306025e 100644 --- a/deployment/sshjump-configmap.yaml +++ b/deployment/sshjump-configmap.yaml @@ -17,3 +17,7 @@ data: - name: "benthos" ports: - 8080 + key.rsa: | + -----BEGIN OPENSSH PRIVATE KEY----- + XXXXX + -----END OPENSSH PRIVATE KEY----- diff --git a/deployment/sshjump-deployment.yaml b/deployment/sshjump-deployment.yaml index c12fd37..18912b8 100644 --- a/deployment/sshjump-deployment.yaml +++ b/deployment/sshjump-deployment.yaml @@ -13,38 +13,40 @@ spec: labels: app: sshjump annotations: - prometheus.io/scrape: 'true' - prometheus.io/port: '8888' + prometheus.io/scrape: "true" + prometheus.io/port: "8888" spec: serviceAccountName: sshjump-reader-sa containers: - - name: sshjump - image: akhenakh/sshjump:1.0 - env: - - name: LOG_LEVEL - value: DEBUG - - name: HEALTH_PORT - value: "6666" - - name: CONFIG_PATH - value: /app/config/config.yaml - ports: - - containerPort: 8888 - name: http-metrics - - containerPort: 2222 - name: ssh - livenessProbe: - grpc: - port: 6666 - initialDelaySeconds: 2 - periodSeconds: 4 - readinessProbe: - grpc: - port: 6666 - initialDelaySeconds: 2 - periodSeconds: 4 - volumeMounts: - - name: config-volume - mountPath: /app/config + - name: sshjump + image: akhenakh/sshjump:1.0 + env: + - name: LOG_LEVEL + value: DEBUG + - name: HEALTH_PORT + value: "6666" + - name: CONFIG_PATH + value: /app/config/config.yaml + - name: PRIVATE_KEY_PATH + value: /app/config/ssh_host_rsa_key + ports: + - containerPort: 8888 + name: http-metrics + - containerPort: 2222 + name: ssh + livenessProbe: + grpc: + port: 6666 + initialDelaySeconds: 2 + periodSeconds: 4 + readinessProbe: + grpc: + port: 6666 + initialDelaySeconds: 2 + periodSeconds: 4 + volumeMounts: + - name: config-volume + mountPath: /app/config volumes: - name: config-volume configMap: