mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-04 04:29:06 +02:00
[management] fix posture check evaluation for direct peers in policy definition (#7348)
This commit is contained in:
@@ -577,7 +577,7 @@ func peerPostureChecksFromData(nmData *networkmap.NetworkMapData, peerID string)
|
||||
if policy == nil || !policy.Enabled || len(policy.SourcePostureChecks) == 0 {
|
||||
continue
|
||||
}
|
||||
if !isPeerInPolicySourceGroupsFromData(nmData, peerID, policy) {
|
||||
if !isPeerInPolicySourcesFromData(nmData, peerID, policy) {
|
||||
continue
|
||||
}
|
||||
for _, checkID := range policy.SourcePostureChecks {
|
||||
@@ -590,11 +590,14 @@ func peerPostureChecksFromData(nmData *networkmap.NetworkMapData, peerID string)
|
||||
return maps.Values(peerPostureChecks)
|
||||
}
|
||||
|
||||
func isPeerInPolicySourceGroupsFromData(nmData *networkmap.NetworkMapData, peerID string, policy *nmdata.Policy) bool {
|
||||
func isPeerInPolicySourcesFromData(nmData *networkmap.NetworkMapData, peerID string, policy *nmdata.Policy) bool {
|
||||
for _, rule := range policy.Rules {
|
||||
if rule == nil || !rule.Enabled {
|
||||
continue
|
||||
}
|
||||
if rule.SourceResource.Type == string(types.ResourceTypePeer) && rule.SourceResource.ID == peerID {
|
||||
return true
|
||||
}
|
||||
for _, groupID := range rule.Sources {
|
||||
if group := nmData.Groups[groupID]; group != nil && slices.Contains(group.Peers, peerID) {
|
||||
return true
|
||||
@@ -1314,7 +1317,7 @@ func computeForwarderPortFromVersions(wtVersions []string, requiredVersion strin
|
||||
|
||||
// addPolicyPostureChecks adds posture checks from a policy to the peer posture checks map if the peer is in the policy's source groups.
|
||||
func addPolicyPostureChecks(account *types.Account, peerID string, policy *types.Policy, peerPostureChecks map[string]*posture.Checks) error {
|
||||
isInGroup, err := isPeerInPolicySourceGroups(account, peerID, policy)
|
||||
isInGroup, err := isPeerInPolicySources(account, peerID, policy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1334,13 +1337,17 @@ func addPolicyPostureChecks(account *types.Account, peerID string, policy *types
|
||||
return nil
|
||||
}
|
||||
|
||||
// isPeerInPolicySourceGroups checks if a peer is present in any of the policy rule source groups.
|
||||
func isPeerInPolicySourceGroups(account *types.Account, peerID string, policy *types.Policy) (bool, error) {
|
||||
// isPeerInPolicySources checks if a peer is a source of the policy, directly or through a source group.
|
||||
func isPeerInPolicySources(account *types.Account, peerID string, policy *types.Policy) (bool, error) {
|
||||
for _, rule := range policy.Rules {
|
||||
if !rule.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
if rule.SourceResource.Type == types.ResourceTypePeer && rule.SourceResource.ID == peerID {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
for _, sourceGroup := range rule.Sources {
|
||||
group := account.GetGroup(sourceGroup)
|
||||
if group == nil {
|
||||
|
||||
@@ -4,35 +4,65 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
"github.com/netbirdio/netbird/shared/management/types"
|
||||
)
|
||||
|
||||
func TestPeerPostureChecksFromData_ReturnsTwinsUnchanged(t *testing.T) {
|
||||
check := &nmdata.PostureChecks{
|
||||
ID: "pc1",
|
||||
Checks: nmdata.ChecksDefinition{
|
||||
NBVersionCheck: &nmdata.NBVersionCheck{MinVersion: "0.30.0"},
|
||||
OSVersionCheck: &nmdata.OSVersionCheck{Linux: &nmdata.MinKernelVersionCheck{MinKernelVersion: "6.1"}},
|
||||
func postureSelectionData(policies ...*nmdata.Policy) *networkmap.NetworkMapData {
|
||||
return &networkmap.NetworkMapData{
|
||||
Groups: map[string]*nmdata.Group{"g-src": {ID: "g-src", Peers: []string{"peer-group"}}},
|
||||
Policies: policies,
|
||||
PostureChecks: map[string]*nmdata.PostureChecks{
|
||||
"pc1": {ID: "pc1", Checks: nmdata.ChecksDefinition{NBVersionCheck: &nmdata.NBVersionCheck{MinVersion: "0.30.0"}}},
|
||||
},
|
||||
}
|
||||
nmData := &networkmap.NetworkMapData{
|
||||
Groups: map[string]*nmdata.Group{"g1": {ID: "g1", Peers: []string{"peer1"}}},
|
||||
Policies: []*nmdata.Policy{{
|
||||
ID: "policy1",
|
||||
Enabled: true,
|
||||
SourcePostureChecks: []string{"pc1"},
|
||||
Rules: []*nmdata.PolicyRule{{ID: "rule1", Enabled: true, Sources: []string{"g1"}}},
|
||||
}},
|
||||
PostureChecks: map[string]*nmdata.PostureChecks{"pc1": check},
|
||||
}
|
||||
|
||||
func gatedPolicy(id string, rule *nmdata.PolicyRule, checkIDs ...string) *nmdata.Policy {
|
||||
return &nmdata.Policy{ID: id, Enabled: true, SourcePostureChecks: checkIDs, Rules: []*nmdata.PolicyRule{rule}}
|
||||
}
|
||||
|
||||
func checkIDs(checks []*nmdata.PostureChecks) []string {
|
||||
ids := make([]string, 0, len(checks))
|
||||
for _, c := range checks {
|
||||
ids = append(ids, c.ID)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func TestPeerPostureChecksFromData_SelectsPolicySourcePeers(t *testing.T) {
|
||||
groupRule := &nmdata.PolicyRule{ID: "r-group", Enabled: true, Sources: []string{"g-src"}, Destinations: []string{"g-dst"}}
|
||||
directRule := &nmdata.PolicyRule{ID: "r-direct", Enabled: true, SourceResource: nmdata.Resource{ID: "peer-direct", Type: string(types.ResourceTypePeer)}, Destinations: []string{"g-dst"}}
|
||||
|
||||
t.Run("source group member and direct source peer both get the checks", func(t *testing.T) {
|
||||
nmData := postureSelectionData(gatedPolicy("p1", groupRule, "pc1"), gatedPolicy("p2", directRule, "pc1"))
|
||||
|
||||
assert.Equal(t, []string{"pc1"}, checkIDs(peerPostureChecksFromData(nmData, "peer-group")))
|
||||
assert.Equal(t, []string{"pc1"}, checkIDs(peerPostureChecksFromData(nmData, "peer-direct")))
|
||||
assert.Empty(t, peerPostureChecksFromData(nmData, "peer-elsewhere"))
|
||||
})
|
||||
|
||||
t.Run("source resource of a non-peer type never matches a peer", func(t *testing.T) {
|
||||
hostRule := &nmdata.PolicyRule{ID: "r-host", Enabled: true, SourceResource: nmdata.Resource{ID: "peer-direct", Type: string(types.ResourceTypeHost)}, Destinations: []string{"g-dst"}}
|
||||
nmData := postureSelectionData(gatedPolicy("p1", hostRule, "pc1"))
|
||||
|
||||
assert.Empty(t, peerPostureChecksFromData(nmData, "peer-direct"))
|
||||
})
|
||||
|
||||
t.Run("same check through two policies is returned once", func(t *testing.T) {
|
||||
nmData := postureSelectionData(gatedPolicy("p1", groupRule, "pc1"), gatedPolicy("p2", groupRule, "pc1"))
|
||||
|
||||
assert.Equal(t, []string{"pc1"}, checkIDs(peerPostureChecksFromData(nmData, "peer-group")))
|
||||
})
|
||||
|
||||
got := peerPostureChecksFromData(nmData, "peer1")
|
||||
require.Len(t, got, 1)
|
||||
assert.Same(t, check, got[0])
|
||||
assert.Len(t, got[0].GetChecks(), 2)
|
||||
t.Run("disabled policy, disabled rule and dangling check are ignored", func(t *testing.T) {
|
||||
disabledPolicy := gatedPolicy("p-off", groupRule, "pc1")
|
||||
disabledPolicy.Enabled = false
|
||||
disabledRule := &nmdata.PolicyRule{ID: "r-off", Enabled: false, Sources: []string{"g-src"}}
|
||||
nmData := postureSelectionData(disabledPolicy, gatedPolicy("p-rule-off", disabledRule, "pc1"), gatedPolicy("p-dangling", groupRule, "pc-missing"))
|
||||
|
||||
assert.Empty(t, peerPostureChecksFromData(nmData, "peer-outside-source-group"))
|
||||
assert.Empty(t, peerPostureChecksFromData(nmData, "peer-group"))
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user