From 96052d7ec3a1521652934b1c57553dbe3dacba80 Mon Sep 17 00:00:00 2001 From: SimoneDutto Date: Tue, 14 Jan 2025 09:43:49 +0100 Subject: [PATCH] add config ssh jump server --- cmd/jimmsrv/main.go | 15 ++++++++++++++- internal/ssh/ssh.go | 24 +++++++----------------- internal/ssh/ssh_test.go | 30 ++++++++++++++++++++++-------- internal/ssh/types.go | 25 +++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 26 deletions(-) create mode 100644 internal/ssh/types.go diff --git a/cmd/jimmsrv/main.go b/cmd/jimmsrv/main.go index 5624b807f..0d59b467f 100644 --- a/cmd/jimmsrv/main.go +++ b/cmd/jimmsrv/main.go @@ -1,4 +1,4 @@ -// Copyright 2024 Canonical. +// Copyright 2025 Canonical. package main @@ -209,5 +209,18 @@ func start(ctx context.Context, s *service.Service) error { }) s.Go(httpsrv.ListenAndServe) zapctx.Info(ctx, "Successfully started JIMM server") + + // // this is to show the integration, we will uncommented it once the ssh implementation is ready. + // sshJumpServer, err := ssh.NewJumpSSHServer(ctx, ssh.SSHServerConfig{ + // Port: os.Getenv("JIMM_SSH_PORT"), + // HostKey: []byte(os.Getenv("JIMM_SSH_HOST_KEY")), + // MaxConcurrentConnections: os.Getenv("JIMM_SSH_MAX_CONCURRENT_CONNECTIONS"), + // }, jimmsvc.JIMM().SSHManager()) + // if err != nil { + // return err + // } + // s.Go(sshJumpServer.ListenAndServe) + // zapctx.Info(ctx, "Successfully started JIMM ssh jump server") + return nil } diff --git a/internal/ssh/ssh.go b/internal/ssh/ssh.go index 5a554be58..94250c9af 100644 --- a/internal/ssh/ssh.go +++ b/internal/ssh/ssh.go @@ -25,23 +25,8 @@ type Resolver interface { AddrFromModelUUID(ctx context.Context, user openfga.User, modelUUID string) (string, error) } -// fowardMessage is the struct holding the information about the jump message received by the ssh client. -type forwardMessage struct { - DestAddr string - DestPort uint32 - SrcAddr string - SrcPort uint32 -} - -// Server is the custom struct to embed the gliderlabs.ssh server and a resolver. -type Server struct { - *ssh.Server - - resolver Resolver -} - // NewJumpSSHServer creates the jump server struct. -func NewJumpSSHServer(ctx context.Context, port int, resolver Resolver) (Server, error) { +func NewJumpSSHServer(ctx context.Context, config SSHServerConfig, resolver Resolver) (Server, error) { zapctx.Info(ctx, "NewSSHServer") if resolver == nil { @@ -49,7 +34,7 @@ func NewJumpSSHServer(ctx context.Context, port int, resolver Resolver) (Server, } server := Server{ Server: &ssh.Server{ - Addr: fmt.Sprintf(":%d", port), + Addr: fmt.Sprintf(":%s", config.Port), ChannelHandlers: map[string]ssh.ChannelHandler{ "direct-tcpip": directTCPIPHandler(resolver), }, @@ -59,6 +44,11 @@ func NewJumpSSHServer(ctx context.Context, port int, resolver Resolver) (Server, }, resolver: resolver, } + s, err := gossh.ParsePrivateKey([]byte(config.HostKey)) + if err != nil { + return Server{}, fmt.Errorf("Cannot parse hostkey.") + } + server.AddHostKey(s) return server, nil } diff --git a/internal/ssh/ssh_test.go b/internal/ssh/ssh_test.go index 687afcbaa..8b24826a4 100644 --- a/internal/ssh/ssh_test.go +++ b/internal/ssh/ssh_test.go @@ -36,6 +36,7 @@ type sshSuite struct { jumpSSHServer ssh.Server jumpServerPort int privateKey gossh.Signer + hostKey gossh.Signer testInDestinationServerF func(fm ssh.ForwardMessage) received chan bool } @@ -71,13 +72,29 @@ func (s *sshSuite) Init(c *qt.C) { port, err = jimmtest.GetFreePort() c.Assert(err, qt.IsNil) s.jumpServerPort = port - s.jumpSSHServer, err = ssh.NewJumpSSHServer(context.Background(), port, resolver{}) + k, err := rsa.GenerateKey(rand.Reader, 2048) + c.Assert(err, qt.IsNil) + hostKey := pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(k), + }, + ) + s.hostKey, err = gossh.ParsePrivateKey(hostKey) + c.Assert(err, qt.IsNil) + + s.jumpSSHServer, err = ssh.NewJumpSSHServer(context.Background(), + ssh.SSHServerConfig{ + Port: fmt.Sprint(port), + HostKey: hostKey}, + resolver{}, + ) c.Assert(err, qt.IsNil) go func() { _ = s.jumpSSHServer.ListenAndServe() }() - k, err := rsa.GenerateKey(rand.Reader, 2048) + k, err = rsa.GenerateKey(rand.Reader, 2048) c.Assert(err, qt.IsNil) keyPEM := pem.EncodeToMemory( &pem.Block{ @@ -98,8 +115,7 @@ func (s *sshSuite) Init(c *qt.C) { func (s *sshSuite) TestSSHJump(c *qt.C) { client, err := gossh.Dial("tcp", fmt.Sprintf(":%d", s.jumpServerPort), &gossh.ClientConfig{ - //nolint:gosec // this will be removed once we handle hostkeys - HostKeyCallback: gossh.InsecureIgnoreHostKey(), + HostKeyCallback: gossh.FixedHostKey(s.hostKey.PublicKey()), Auth: []gossh.AuthMethod{ gossh.PublicKeys(s.privateKey), }, @@ -130,8 +146,7 @@ func (s *sshSuite) TestSSHJump(c *qt.C) { func (s *sshSuite) TestSSHJumpDialFail(c *qt.C) { _, err := gossh.Dial("tcp", fmt.Sprintf(":%d", 1), &gossh.ClientConfig{ - //nolint:gosec // this will be removed once we handle hostkeys - HostKeyCallback: gossh.InsecureIgnoreHostKey(), + HostKeyCallback: gossh.FixedHostKey(s.hostKey.PublicKey()), Auth: []gossh.AuthMethod{ gossh.PublicKeys(s.privateKey), }, @@ -142,8 +157,7 @@ func (s *sshSuite) TestSSHJumpDialFail(c *qt.C) { func (s *sshSuite) TestSSHFinalDestinationDialFail(c *qt.C) { client, err := gossh.Dial("tcp", fmt.Sprintf(":%d", s.jumpServerPort), &gossh.ClientConfig{ - //nolint:gosec // this will be removed once we handle hostkeys - HostKeyCallback: gossh.InsecureIgnoreHostKey(), + HostKeyCallback: gossh.FixedHostKey(s.hostKey.PublicKey()), Auth: []gossh.AuthMethod{ gossh.PublicKeys(s.privateKey), }, diff --git a/internal/ssh/types.go b/internal/ssh/types.go new file mode 100644 index 000000000..beeb05a6e --- /dev/null +++ b/internal/ssh/types.go @@ -0,0 +1,25 @@ +// Copyright 2025 Canonical. +package ssh + +import "github.com/gliderlabs/ssh" + +// fowardMessage is the struct holding the information about the jump message received by the ssh client. +type forwardMessage struct { + DestAddr string + DestPort uint32 + SrcAddr string + SrcPort uint32 +} + +// Server is the custom struct to embed the gliderlabs.ssh server and a resolver. +type Server struct { + *ssh.Server + + resolver Resolver +} + +type SSHServerConfig struct { + Port string + HostKey []byte + MaxConcurrentConnections string +}