mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-21 22:29:08 +02:00
Replace VNC JWT auth with a Noise_IK handshake bound to ACL-pushed pubkeys
This commit is contained in:
@@ -849,7 +849,7 @@ func (a *Account) UserGroupsRemoveFromPeers(userID string, groups ...string) map
|
||||
// GetPeerConnectionResources for a given peer
|
||||
//
|
||||
// This function returns the list of peers and firewall rules that are applicable to a given peer.
|
||||
func (a *Account) GetPeerConnectionResources(ctx context.Context, peer *nbpeer.Peer, validatedPeersMap map[string]struct{}, groupIDToUserIDs map[string][]string) ([]*nbpeer.Peer, []*FirewallRule, map[string]map[string]struct{}, map[string]map[string]struct{}, bool) {
|
||||
func (a *Account) GetPeerConnectionResources(ctx context.Context, peer *nbpeer.Peer, validatedPeersMap map[string]struct{}, groupIDToUserIDs map[string][]string) ([]*nbpeer.Peer, []*FirewallRule, map[string]map[string]struct{}, map[string]map[string]struct{}, []VNCSessionPubKey, bool) {
|
||||
generateResources, getAccumulatedResources := a.connResourcesGenerator(ctx, peer)
|
||||
ctxState := &peerConnResolveState{
|
||||
authorizedUsers: make(map[string]map[string]struct{}),
|
||||
@@ -869,7 +869,7 @@ func (a *Account) GetPeerConnectionResources(ctx context.Context, peer *nbpeer.P
|
||||
}
|
||||
|
||||
peers, fwRules := getAccumulatedResources()
|
||||
return peers, fwRules, ctxState.authorizedUsers, ctxState.vncAuthorizedUsers, ctxState.sshEnabled
|
||||
return peers, fwRules, ctxState.authorizedUsers, ctxState.vncAuthorizedUsers, ctxState.vncSessionPubKeys, ctxState.sshEnabled
|
||||
}
|
||||
|
||||
func (a *Account) applyPolicyRule(
|
||||
|
||||
@@ -49,6 +49,7 @@ type NetworkMap struct {
|
||||
ForwardingRules []*ForwardingRule
|
||||
AuthorizedUsers map[string]map[string]struct{}
|
||||
VNCAuthorizedUsers map[string]map[string]struct{}
|
||||
VNCSessionPubKeys []VNCSessionPubKey
|
||||
EnableSSH bool
|
||||
}
|
||||
|
||||
|
||||
@@ -167,6 +167,7 @@ func (c *NetworkMapComponents) Calculate(ctx context.Context) *NetworkMap {
|
||||
RoutesFirewallRules: append(networkResourcesFirewallRules, routesFirewallRules...),
|
||||
AuthorizedUsers: connRes.authorizedUsers,
|
||||
VNCAuthorizedUsers: connRes.vncAuthorizedUsers,
|
||||
VNCSessionPubKeys: connRes.vncSessionPubKeys,
|
||||
EnableSSH: connRes.sshEnabled,
|
||||
}
|
||||
}
|
||||
@@ -177,6 +178,7 @@ type peerConnectionResult struct {
|
||||
firewallRules []*FirewallRule
|
||||
authorizedUsers map[string]map[string]struct{}
|
||||
vncAuthorizedUsers map[string]map[string]struct{}
|
||||
vncSessionPubKeys []VNCSessionPubKey
|
||||
sshEnabled bool
|
||||
}
|
||||
|
||||
@@ -210,6 +212,7 @@ func (c *NetworkMapComponents) getPeerConnectionResources(targetPeerID string) p
|
||||
firewallRules: fwRules,
|
||||
authorizedUsers: state.authorizedUsers,
|
||||
vncAuthorizedUsers: state.vncAuthorizedUsers,
|
||||
vncSessionPubKeys: state.vncSessionPubKeys,
|
||||
sshEnabled: state.sshEnabled,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,21 @@ import (
|
||||
type peerConnResolveState struct {
|
||||
authorizedUsers map[string]map[string]struct{}
|
||||
vncAuthorizedUsers map[string]map[string]struct{}
|
||||
vncSessionPubKeys []VNCSessionPubKey
|
||||
sshEnabled bool
|
||||
}
|
||||
|
||||
// VNCSessionPubKey carries an ephemeral X25519 static public key the
|
||||
// dashboard registered via temporary-access. The daemon uses it as the
|
||||
// allowed-client side of a Noise_IK handshake; a successful handshake
|
||||
// authenticates the connection as UserID.
|
||||
type VNCSessionPubKey struct {
|
||||
// PubKey is the base64-encoded 32-byte X25519 public key.
|
||||
PubKey string
|
||||
// UserID is the unhashed user identity the pubkey authenticates as.
|
||||
UserID string
|
||||
}
|
||||
|
||||
// ruleAuthCallbacks lets Account and NetworkMapComponents share the per-rule
|
||||
// direction-and-auth logic while keeping their own context/state plumbing for
|
||||
// authorized-user collection and allowed-user lookups.
|
||||
@@ -57,6 +69,12 @@ func applyResolvedRuleToState(
|
||||
return
|
||||
}
|
||||
cb.collectVNCUsers(rule, state.vncAuthorizedUsers)
|
||||
if rule.SessionPubKey != "" && rule.AuthorizedUser != "" {
|
||||
state.vncSessionPubKeys = append(state.vncSessionPubKeys, VNCSessionPubKey{
|
||||
PubKey: rule.SessionPubKey,
|
||||
UserID: rule.AuthorizedUser,
|
||||
})
|
||||
}
|
||||
case policyRuleImpliesLegacySSH(rule) && targetPeerSSHEnabled:
|
||||
if !peerInDestinations {
|
||||
return
|
||||
|
||||
@@ -88,6 +88,12 @@ type PolicyRule struct {
|
||||
|
||||
// AuthorizedUser is a list of userIDs that are authorized to access local resources via ssh
|
||||
AuthorizedUser string
|
||||
|
||||
// SessionPubKey is the base64 Ed25519 public key the AuthorizedUser
|
||||
// will sign session-binding challenges with. Set together with
|
||||
// AuthorizedUser when the rule was created via temporary-access for
|
||||
// a VNC scope; empty otherwise.
|
||||
SessionPubKey string
|
||||
}
|
||||
|
||||
// Copy returns a copy of a policy rule
|
||||
@@ -109,6 +115,7 @@ func (pm *PolicyRule) Copy() *PolicyRule {
|
||||
PortRanges: make([]RulePortRange, len(pm.PortRanges)),
|
||||
AuthorizedGroups: make(map[string][]string, len(pm.AuthorizedGroups)),
|
||||
AuthorizedUser: pm.AuthorizedUser,
|
||||
SessionPubKey: pm.SessionPubKey,
|
||||
}
|
||||
copy(rule.Destinations, pm.Destinations)
|
||||
copy(rule.Sources, pm.Sources)
|
||||
@@ -136,7 +143,8 @@ func (pm *PolicyRule) Equal(other *PolicyRule) bool {
|
||||
pm.Protocol != other.Protocol ||
|
||||
pm.SourceResource != other.SourceResource ||
|
||||
pm.DestinationResource != other.DestinationResource ||
|
||||
pm.AuthorizedUser != other.AuthorizedUser {
|
||||
pm.AuthorizedUser != other.AuthorizedUser ||
|
||||
pm.SessionPubKey != other.SessionPubKey {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user