diff --git a/management/server/types/account.go b/management/server/types/account.go index 870333a60..d51b975a5 100644 --- a/management/server/types/account.go +++ b/management/server/types/account.go @@ -892,7 +892,12 @@ func (a *Account) GetPeerConnectionResources(ctx context.Context, peer *nbpeer.P generateResources(rule, sourcePeers, FirewallRuleDirectionIN) } - if peerInDestinations && rule.Protocol == PolicyRuleProtocolNetbirdSSH { + // Auth is collected when this peer serves the rule. For bidirectional + // rules the peer-in-sources side also serves inbound traffic, so it + // must be treated as a destination too. + peerServesAuth := peerInDestinations || (rule.Bidirectional && peerInSources) + + if peerServesAuth && rule.Protocol == PolicyRuleProtocolNetbirdSSH { sshEnabled = true switch { case len(rule.AuthorizedGroups) > 0: @@ -924,7 +929,7 @@ func (a *Account) GetPeerConnectionResources(ctx context.Context, peer *nbpeer.P default: authorizedUsers[auth.Wildcard] = a.getAllowedUserIDs() } - } else if peerInDestinations && policyRuleImpliesLegacySSH(rule) && peer.SSHEnabled { + } else if peerServesAuth && policyRuleImpliesLegacySSH(rule) && peer.SSHEnabled { sshEnabled = true authorizedUsers[auth.Wildcard] = a.getAllowedUserIDs() } diff --git a/management/server/types/account_components.go b/management/server/types/account_components.go index 2b4f7e051..5a6e471d0 100644 --- a/management/server/types/account_components.go +++ b/management/server/types/account_components.go @@ -341,7 +341,12 @@ func (a *Account) getPeersGroupsPoliciesRoutes( for _, srcGroupID := range rule.Sources { relevantGroupIDs[srcGroupID] = a.GetGroup(srcGroupID) } + } + // SSH auth requirements are gathered whenever this peer serves + // the rule. For bidirectional rules the peer-in-sources side + // also serves inbound traffic and must be treated as a destination. + if peerInDestinations || (rule.Bidirectional && peerInSources) { if rule.Protocol == PolicyRuleProtocolNetbirdSSH { switch { case len(rule.AuthorizedGroups) > 0: diff --git a/management/server/types/networkmap_components.go b/management/server/types/networkmap_components.go index 3a7e20ec5..3237e6224 100644 --- a/management/server/types/networkmap_components.go +++ b/management/server/types/networkmap_components.go @@ -221,7 +221,12 @@ func (c *NetworkMapComponents) getPeerConnectionResources(targetPeerID string) ( generateResources(rule, sourcePeers, FirewallRuleDirectionIN) } - if peerInDestinations && rule.Protocol == PolicyRuleProtocolNetbirdSSH { + // Auth is collected when this peer serves the rule. For bidirectional + // rules the peer-in-sources side also serves inbound traffic, so it + // must be treated as a destination too. + peerServesAuth := peerInDestinations || (rule.Bidirectional && peerInSources) + + if peerServesAuth && rule.Protocol == PolicyRuleProtocolNetbirdSSH { sshEnabled = true switch { case len(rule.AuthorizedGroups) > 0: @@ -252,7 +257,7 @@ func (c *NetworkMapComponents) getPeerConnectionResources(targetPeerID string) ( default: authorizedUsers[auth.Wildcard] = c.getAllowedUserIDs() } - } else if peerInDestinations && policyRuleImpliesLegacySSH(rule) && targetPeer.SSHEnabled { + } else if peerServesAuth && policyRuleImpliesLegacySSH(rule) && targetPeer.SSHEnabled { sshEnabled = true authorizedUsers[auth.Wildcard] = c.getAllowedUserIDs() } @@ -557,7 +562,6 @@ func (c *NetworkMapComponents) getRoutingPeerRoutes(peerID string) (enabledRoute return enabledRoutes, disabledRoutes } - func (c *NetworkMapComponents) filterRoutesByGroups(routes []*route.Route, groupListMap LookupMap) []*route.Route { var filteredRoutes []*route.Route for _, r := range routes {