sshd: guard trustedKeys/trustedCAs with a mutex to fix a concurrent map crash on reload (#1787)

This commit is contained in:
Nate Brown
2026-07-07 15:50:06 -05:00
committed by GitHub
parent 942ee522e0
commit 7bd0bc285a
+15
View File
@@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"log/slog" "log/slog"
"net" "net"
"sync"
"github.com/armon/go-radix" "github.com/armon/go-radix"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
@@ -18,6 +19,8 @@ type SSHServer struct {
certChecker *ssh.CertChecker certChecker *ssh.CertChecker
// authLock guards trustedKeys and trustedCAs
authLock sync.RWMutex
// Map of user -> authorized keys // Map of user -> authorized keys
trustedKeys map[string]map[string]bool trustedKeys map[string]map[string]bool
trustedCAs []ssh.PublicKey trustedCAs []ssh.PublicKey
@@ -45,6 +48,8 @@ func NewSSHServer(ctx context.Context, l *slog.Logger) (*SSHServer, error) {
cc := ssh.CertChecker{ cc := ssh.CertChecker{
IsUserAuthority: func(auth ssh.PublicKey) bool { IsUserAuthority: func(auth ssh.PublicKey) bool {
s.authLock.RLock()
defer s.authLock.RUnlock()
for _, ca := range s.trustedCAs { for _, ca := range s.trustedCAs {
if bytes.Equal(ca.Marshal(), auth.Marshal()) { if bytes.Equal(ca.Marshal(), auth.Marshal()) {
return true return true
@@ -57,6 +62,8 @@ func NewSSHServer(ctx context.Context, l *slog.Logger) (*SSHServer, error) {
pk := string(pubKey.Marshal()) pk := string(pubKey.Marshal())
fp := ssh.FingerprintSHA256(pubKey) fp := ssh.FingerprintSHA256(pubKey)
s.authLock.RLock()
defer s.authLock.RUnlock()
tk, ok := s.trustedKeys[c.User()] tk, ok := s.trustedKeys[c.User()]
if !ok { if !ok {
return nil, fmt.Errorf("unknown user %s", c.User()) return nil, fmt.Errorf("unknown user %s", c.User())
@@ -105,11 +112,15 @@ func (s *SSHServer) SetHostKey(hostPrivateKey []byte) error {
} }
func (s *SSHServer) ClearTrustedCAs() { func (s *SSHServer) ClearTrustedCAs() {
s.authLock.Lock()
s.trustedCAs = []ssh.PublicKey{} s.trustedCAs = []ssh.PublicKey{}
s.authLock.Unlock()
} }
func (s *SSHServer) ClearAuthorizedKeys() { func (s *SSHServer) ClearAuthorizedKeys() {
s.authLock.Lock()
s.trustedKeys = make(map[string]map[string]bool) s.trustedKeys = make(map[string]map[string]bool)
s.authLock.Unlock()
} }
// AddTrustedCA adds a trusted CA for user certificates // AddTrustedCA adds a trusted CA for user certificates
@@ -119,7 +130,9 @@ func (s *SSHServer) AddTrustedCA(pubKey string) error {
return err return err
} }
s.authLock.Lock()
s.trustedCAs = append(s.trustedCAs, pk) s.trustedCAs = append(s.trustedCAs, pk)
s.authLock.Unlock()
s.l.Info("Trusted CA key", "sshKey", pubKey) s.l.Info("Trusted CA key", "sshKey", pubKey)
return nil return nil
} }
@@ -131,6 +144,7 @@ func (s *SSHServer) AddAuthorizedKey(user, pubKey string) error {
return err return err
} }
s.authLock.Lock()
tk, ok := s.trustedKeys[user] tk, ok := s.trustedKeys[user]
if !ok { if !ok {
tk = make(map[string]bool) tk = make(map[string]bool)
@@ -138,6 +152,7 @@ func (s *SSHServer) AddAuthorizedKey(user, pubKey string) error {
} }
tk[string(pk.Marshal())] = true tk[string(pk.Marshal())] = true
s.authLock.Unlock()
s.l.Info("Authorized ssh key", s.l.Info("Authorized ssh key",
"sshKey", pubKey, "sshKey", pubKey,
"sshUser", user, "sshUser", user,