Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add config ssh jump server #1522

Merged
merged 4 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cmd/jimmsrv/main.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Canonical.
// Copyright 2025 Canonical.

package main

Expand Down Expand Up @@ -209,5 +209,6 @@ func start(ctx context.Context, s *service.Service) error {
})
s.Go(httpsrv.ListenAndServe)
zapctx.Info(ctx, "Successfully started JIMM server")

return nil
}
22 changes: 17 additions & 5 deletions internal/ssh/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ 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.
// forwardMessage is the struct holding the information about the jump message received by the ssh client.
type forwardMessage struct {
DestAddr string
DestPort uint32
Expand All @@ -40,16 +40,23 @@ type Server struct {
resolver Resolver
}

// NewJumpSSHServer creates the jump server struct.
func NewJumpSSHServer(ctx context.Context, port int, resolver Resolver) (Server, error) {
zapctx.Info(ctx, "NewSSHServer")
// Config is the struct holding the configuration for the jump server.
type Config struct {
Port string
HostKey []byte
MaxConcurrentConnections string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why isn't the resolver field on the Config struct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the resolver is not a config but a service needed to operate the ssh server. I would leave it as a separate argument.

Don't you agree?

}

// 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.")
}
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),
},
Expand All @@ -59,6 +66,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
}
Expand Down
30 changes: 22 additions & 8 deletions internal/ssh/ssh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no constant for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've looked around and it's always a string, no types.

even in the godoc of this field:
Type string // The type, taken from the preamble (i.e. "RSA PRIVATE KEY").

Bytes: x509.MarshalPKCS1PrivateKey(k),
},
)
s.hostKey, err = gossh.ParsePrivateKey(hostKey)
c.Assert(err, qt.IsNil)

s.jumpSSHServer, err = ssh.NewJumpServer(context.Background(),
ssh.Config{
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{
Expand All @@ -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),
},
Expand Down Expand Up @@ -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),
},
Expand All @@ -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),
},
Expand Down
Loading