[client] Add opt-in --allow-server-rdp flag, reuse SSH ACL, dynamic DLL registration

- Add ServerRDPAllowed field to daemon proto, EngineConfig, and profile config
- Add --allow-server-rdp flag to `netbird up` (opt-in, defaults to false)
- Wire RDP server start/stop in engine based on the flag
- Reuse SSH ACL (SSHAuth proto) for RDP authorization via sshauth.Authorizer
- Register/unregister credential provider COM DLL dynamically when flag is toggled
- Ship DLL alongside netbird.exe, register via regsvr32 at runtime (not install time)
- Update SetConfig tests to cover the new field

https://claude.ai/code/session_01C38bCDyYzLgxYLVwJkcUng
This commit is contained in:
Claude
2026-04-11 17:48:53 +00:00
parent c5186f1483
commit 4949ca6194
13 changed files with 252 additions and 10 deletions
+21 -6
View File
@@ -12,6 +12,8 @@ import (
"time"
log "github.com/sirupsen/logrus"
sshauth "github.com/netbirdio/netbird/client/ssh/auth"
)
const (
@@ -45,6 +47,7 @@ type Server struct {
pipeServer PipeServer
jwtValidator JWTValidator
authorizer Authorizer
sshAuthorizer *sshauth.Authorizer // reuses SSH ACL for RDP access control
networkAddr netip.Prefix // WireGuard network for source IP validation
mu sync.Mutex
@@ -76,14 +79,21 @@ func New(cfg *Config) *Server {
pending := NewPendingStore(ttl)
return &Server{
pending: pending,
pipeServer: newPipeServer(pending),
jwtValidator: cfg.JWTValidator,
authorizer: cfg.Authorizer,
networkAddr: cfg.NetworkAddr,
pending: pending,
pipeServer: newPipeServer(pending),
jwtValidator: cfg.JWTValidator,
authorizer: cfg.Authorizer,
sshAuthorizer: sshauth.NewAuthorizer(),
networkAddr: cfg.NetworkAddr,
}
}
// UpdateRDPAuth updates the RDP authorization config (reuses SSH ACL).
func (s *Server) UpdateRDPAuth(config *sshauth.Config) {
s.sshAuthorizer.Update(config)
log.Debugf("RDP auth: updated authorization config")
}
// Start begins listening for sideband auth requests on the given address.
func (s *Server) Start(ctx context.Context, addr netip.AddrPort) error {
s.mu.Lock()
@@ -219,12 +229,17 @@ func (s *Server) processAuthRequest(peerIP netip.Addr, req *AuthRequest) *AuthRe
return &AuthResponse{Status: StatusDenied, Reason: "JWT validation failed"}
}
// Check authorization
// Check authorization - try explicit authorizer first, then SSH ACL
if s.authorizer != nil {
if _, err := s.authorizer.Authorize(userID, req.RequestedUser); err != nil {
log.Warnf("RDP auth denied for user %s -> %s: %v", userID, req.RequestedUser, err)
return &AuthResponse{Status: StatusDenied, Reason: "not authorized for this user"}
}
} else if s.sshAuthorizer != nil {
if _, err := s.sshAuthorizer.Authorize(userID, req.RequestedUser); err != nil {
log.Warnf("RDP auth denied (SSH ACL) for user %s -> %s: %v", userID, req.RequestedUser, err)
return &AuthResponse{Status: StatusDenied, Reason: "not authorized for this user"}
}
}
return s.createSession(peerIP, req, userID)