[SSH] Minor Server Changes (#2088)

ui/offscreen-diff-contents
Johannes Batzill 2024-06-10 20:09:35 +00:00 committed by Harness
parent 7899ebd3a3
commit 90680e24f7
4 changed files with 54 additions and 41 deletions

View File

@ -5,6 +5,8 @@ web/dist
release
.idea
coverage.out
*.rsa
*.rsa.pub
# ignore any executables we build
/gitness

8
.gitignore vendored
View File

@ -15,11 +15,9 @@ release
coverage.out
gitness.session.sql
web/cypress/node_modules
*.rsa
*.rsa.pub
node_modules/
# ignore any executables we build
/gitness
node_modules/
ssh/gitness.rsa
ssh/gitness.rsa.pub

View File

@ -75,12 +75,8 @@ var (
"hmac-sha2-256",
"hmac-sha2-512",
}
defaultServerKeys = []string{"ssh/gitness.rsa"}
KeepAliveMsg = "keepalive@openssh.com"
)
var (
ErrHostKeysAreRequired = errors.New("host keys are required")
defaultServerKeyPath = "ssh/gitness.rsa"
KeepAliveMsg = "keepalive@openssh.com"
)
type Server struct {
@ -96,7 +92,7 @@ type Server struct {
KeyExchanges []string
MACs []string
HostKeys []string
KeepAliveInterval int
KeepAliveInterval time.Duration
Verifier publickey.Service
RepoCtrl *repo.Controller
@ -119,10 +115,6 @@ func (s *Server) sanitize() error {
s.MACs = defaultMACs
}
if len(s.HostKeys) == 0 {
s.HostKeys = defaultServerKeys
}
if s.KeepAliveInterval == 0 {
s.KeepAliveInterval = 5000
}
@ -169,34 +161,22 @@ func (s *Server) ListenAndServe() error {
}
func (s *Server) setupHostKeys() error {
if len(s.HostKeys) == 0 {
return ErrHostKeysAreRequired
}
keys := make([]string, 0, len(s.HostKeys))
// check if file exists and append to slice keys
for _, key := range s.HostKeys {
_, err := os.Stat(key)
if err != nil {
log.Err(err).Msgf("unable to check if %s exists", key)
continue
return fmt.Errorf("failed to read provided host key %q: %w", key, err)
}
keys = append(keys, key)
}
// if there is no keys found then create one from HostKeys field
if len(keys) == 0 {
fullpath := s.HostKeys[0]
filePath := filepath.Dir(fullpath)
if err := os.MkdirAll(filePath, os.ModePerm); err != nil {
return fmt.Errorf("failed to create dir %s: %w", filePath, err)
}
err := GenerateKeyPair(fullpath)
log.Debug().Msg("no host key provided - setup default key if it doesn't exist yet")
err := createKeyIfNotExists(defaultServerKeyPath)
if err != nil {
return fmt.Errorf("failed to generate private key: %w", err)
return fmt.Errorf("failed to setup default key %q: %w", defaultServerKeyPath, err)
}
keys = append(keys, fullpath)
keys = append(keys, defaultServerKeyPath)
}
// set keys to internal ssh server
@ -206,6 +186,7 @@ func (s *Server) setupHostKeys() error {
log.Err(err).Msg("failed to set host key to ssh server")
}
}
return nil
}
@ -268,7 +249,7 @@ func (s *Server) sessionHandler(session ssh.Session) {
// set keep alive connection
if s.KeepAliveInterval > 0 {
go s.sendKeepAliveMsg(ctx, session)
go sendKeepAliveMsg(ctx, session, s.KeepAliveInterval)
}
err = s.RepoCtrl.GitServicePack(
@ -302,8 +283,8 @@ func (s *Server) sessionHandler(session ssh.Session) {
}
}
func (s *Server) sendKeepAliveMsg(ctx context.Context, session ssh.Session) {
ticker := time.NewTicker(time.Duration(s.KeepAliveInterval))
func sendKeepAliveMsg(ctx context.Context, session ssh.Session, interval time.Duration) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
log.Ctx(ctx).Debug().Str("remote_addr", session.RemoteAddr().String()).Msgf("sendKeepAliveMsg")
@ -312,8 +293,11 @@ func (s *Server) sendKeepAliveMsg(ctx context.Context, session ssh.Session) {
case <-ctx.Done():
return
case <-ticker.C:
log.Ctx(ctx).Debug().Msg("connection: sendKeepAliveMsg: send keepalive message to a client")
_, _ = session.SendRequest(KeepAliveMsg, true, nil)
log.Ctx(ctx).Debug().Msg("send keepalive message to ssh client")
_, err := session.SendRequest(KeepAliveMsg, true, nil)
if err != nil {
log.Ctx(ctx).Debug().Err(err).Msg("failed to send keepalive message to ssh client")
}
}
}
}
@ -332,8 +316,12 @@ func (s *Server) publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool {
}
principal, err := s.Verifier.ValidateKey(ctx, key, enum.PublicKeyUsageAuth)
if errors.IsNotFound(err) {
log.Debug().Err(err).Msg("public key is unknown")
return false
}
if err != nil {
log.Error().Err(err).Msg("failed to validate public key")
log.Warn().Err(err).Msg("failed to validate public key")
return false
}
@ -365,6 +353,31 @@ func sshConnectionFailed(conn net.Conn, err error) {
log.Err(err).Msgf("failed connection from %s with error: %v", conn.RemoteAddr(), err)
}
func createKeyIfNotExists(path string) error {
_, err := os.Stat(path)
if err == nil {
// if the path already exists there's nothing we have to do
return nil
}
if !os.IsNotExist(err) {
return fmt.Errorf("failed to check for for existence of key: %w", err)
}
log.Debug().Msgf("generate new key at %q", path)
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return fmt.Errorf("failed to create dir %q for key: %w", dir, err)
}
err = GenerateKeyPair(path)
if err != nil {
return fmt.Errorf("failed to generate key pair: %w", err)
}
return nil
}
// GenerateKeyPair make a pair of public and private keys for SSH access.
func GenerateKeyPair(keyPath string) error {
privateKey, err := rsa.GenerateKey(rand.Reader, 4096)

View File

@ -138,7 +138,7 @@ type Config struct {
}
SSH struct {
Enable bool `envconfig:"GITNESS_SSH_ENABLE" default:"true"`
Enable bool `envconfig:"GITNESS_SSH_ENABLE" default:"false"`
Host string `envconfig:"GITNESS_SSH_HOST"`
Port int `envconfig:"GITNESS_SSH_PORT" default:"22"`
// DefaultUser holds value for generating urls {user}@host:path and force check
@ -152,7 +152,7 @@ type Config struct {
TrustedUserCAKeys []string `envconfig:"GITNESS_SSH_TRUSTED_USER_CA_KEYS"`
TrustedUserCAKeysFile string `envconfig:"GITNESS_SSH_TRUSTED_USER_CA_KEYS_FILENAME"`
TrustedUserCAKeysParsed []gossh.PublicKey
KeepAliveInterval int `envconfig:"GITNESS_SSH_KEEP_ALIVE_INTERVAL" default:"5000"`
KeepAliveInterval time.Duration `envconfig:"GITNESS_SSH_KEEP_ALIVE_INTERVAL" default:"5s"`
}
// CI defines configuration related to build executions.