From c19138c08de904875bf210f6f29f0df48c6175a7 Mon Sep 17 00:00:00 2001 From: SimoneDutto Date: Tue, 14 Jan 2025 09:43:49 +0100 Subject: [PATCH 1/3] 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 +} From 48be1cb85cd0d114b63d23f2bcc601cc19c640c0 Mon Sep 17 00:00:00 2001 From: SimoneDutto Date: Tue, 14 Jan 2025 10:06:31 +0100 Subject: [PATCH 2/3] pr comments --- cmd/jimmsrv/main.go | 12 ------------ internal/ssh/ssh.go | 6 +++--- internal/ssh/ssh_test.go | 4 ++-- internal/ssh/types.go | 3 ++- 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/cmd/jimmsrv/main.go b/cmd/jimmsrv/main.go index 0d59b467f..07bf8cba9 100644 --- a/cmd/jimmsrv/main.go +++ b/cmd/jimmsrv/main.go @@ -210,17 +210,5 @@ 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 94250c9af..a459003a8 100644 --- a/internal/ssh/ssh.go +++ b/internal/ssh/ssh.go @@ -25,9 +25,9 @@ type Resolver interface { AddrFromModelUUID(ctx context.Context, user openfga.User, modelUUID string) (string, error) } -// NewJumpSSHServer creates the jump server struct. -func NewJumpSSHServer(ctx context.Context, config SSHServerConfig, resolver Resolver) (Server, error) { - zapctx.Info(ctx, "NewSSHServer") +// NewJumpServer creates the jump server struct. +func NewJumpServer(ctx context.Context, config Config, resolver Resolver) (Server, error) { + zapctx.Info(ctx, "NewJumpServer") if resolver == nil { return Server{}, fmt.Errorf("Cannot create JumpSSHServer with a nil resolver.") diff --git a/internal/ssh/ssh_test.go b/internal/ssh/ssh_test.go index 8b24826a4..ae7ff18b3 100644 --- a/internal/ssh/ssh_test.go +++ b/internal/ssh/ssh_test.go @@ -83,8 +83,8 @@ func (s *sshSuite) Init(c *qt.C) { s.hostKey, err = gossh.ParsePrivateKey(hostKey) c.Assert(err, qt.IsNil) - s.jumpSSHServer, err = ssh.NewJumpSSHServer(context.Background(), - ssh.SSHServerConfig{ + s.jumpSSHServer, err = ssh.NewJumpServer(context.Background(), + ssh.Config{ Port: fmt.Sprint(port), HostKey: hostKey}, resolver{}, diff --git a/internal/ssh/types.go b/internal/ssh/types.go index beeb05a6e..92871fa3b 100644 --- a/internal/ssh/types.go +++ b/internal/ssh/types.go @@ -1,4 +1,5 @@ // Copyright 2025 Canonical. + package ssh import "github.com/gliderlabs/ssh" @@ -18,7 +19,7 @@ type Server struct { resolver Resolver } -type SSHServerConfig struct { +type Config struct { Port string HostKey []byte MaxConcurrentConnections string From faa4cdb83704bbc52803792b620173ed3e3e0852 Mon Sep 17 00:00:00 2001 From: SimoneDutto Date: Tue, 14 Jan 2025 14:11:41 +0100 Subject: [PATCH 3/3] pr comments --- internal/ssh/ssh.go | 22 ++++++++++++++++++++++ internal/ssh/types.go | 26 -------------------------- 2 files changed, 22 insertions(+), 26 deletions(-) delete mode 100644 internal/ssh/types.go diff --git a/internal/ssh/ssh.go b/internal/ssh/ssh.go index a459003a8..127a3d7df 100644 --- a/internal/ssh/ssh.go +++ b/internal/ssh/ssh.go @@ -25,6 +25,28 @@ type Resolver interface { AddrFromModelUUID(ctx context.Context, user openfga.User, modelUUID string) (string, error) } +// forwardMessage 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 +} + +// Config is the struct holding the configuration for the jump server. +type Config struct { + Port string + HostKey []byte + MaxConcurrentConnections string +} + // NewJumpServer creates the jump server struct. func NewJumpServer(ctx context.Context, config Config, resolver Resolver) (Server, error) { zapctx.Info(ctx, "NewJumpServer") diff --git a/internal/ssh/types.go b/internal/ssh/types.go deleted file mode 100644 index 92871fa3b..000000000 --- a/internal/ssh/types.go +++ /dev/null @@ -1,26 +0,0 @@ -// 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 Config struct { - Port string - HostKey []byte - MaxConcurrentConnections string -}