github.com/cilium/cilium@v1.16.2/pkg/policy/distillery_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package policy 5 6 import ( 7 "bytes" 8 "errors" 9 "fmt" 10 "io" 11 stdlog "log" 12 "net/netip" 13 "strings" 14 "sync" 15 "testing" 16 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 "golang.org/x/exp/maps" 20 21 "github.com/cilium/cilium/api/v1/models" 22 "github.com/cilium/cilium/pkg/container/bitlpm" 23 "github.com/cilium/cilium/pkg/identity" 24 "github.com/cilium/cilium/pkg/labels" 25 "github.com/cilium/cilium/pkg/option" 26 "github.com/cilium/cilium/pkg/policy/api" 27 "github.com/cilium/cilium/pkg/policy/trafficdirection" 28 "github.com/cilium/cilium/pkg/policy/types" 29 "github.com/cilium/cilium/pkg/testutils" 30 "github.com/cilium/cilium/pkg/u8proto" 31 ) 32 33 var ( 34 ep1 = testutils.NewTestEndpoint() 35 ep2 = testutils.NewTestEndpoint() 36 ) 37 38 func localIdentity(n uint32) identity.NumericIdentity { 39 return identity.NumericIdentity(n) | identity.IdentityScopeLocal 40 41 } 42 func TestCacheManagement(t *testing.T) { 43 repo := NewPolicyRepository(nil, nil, nil) 44 cache := repo.policyCache 45 identity := ep1.GetSecurityIdentity() 46 require.Equal(t, identity, ep2.GetSecurityIdentity()) 47 48 // Nonsense delete of entry that isn't yet inserted 49 deleted := cache.delete(identity) 50 require.Equal(t, false, deleted) 51 52 // Insert identity twice. Should be the same policy. 53 policy1 := cache.insert(identity) 54 policy2 := cache.insert(identity) 55 require.Equal(t, policy2, policy1) 56 57 // Despite two insert calls, there is no reference tracking; any delete 58 // will clear the cache. 59 cacheCleared := cache.delete(identity) 60 require.True(t, cacheCleared) 61 cacheCleared = cache.delete(identity) 62 require.Equal(t, false, cacheCleared) 63 64 // Insert two distinct identities, then delete one. Other should still 65 // be there. 66 ep3 := testutils.NewTestEndpoint() 67 ep3.SetIdentity(1234, true) 68 identity3 := ep3.GetSecurityIdentity() 69 require.NotEqual(t, identity, identity3) 70 policy1 = cache.insert(identity) 71 policy3 := cache.insert(identity3) 72 require.NotEqual(t, policy3, policy1) 73 _ = cache.delete(identity) 74 policy3 = cache.lookupOrCreate(identity3, false) 75 require.NotNil(t, policy3) 76 } 77 78 func TestCachePopulation(t *testing.T) { 79 repo := NewPolicyRepository(nil, nil, nil) 80 repo.revision.Store(42) 81 cache := repo.policyCache 82 83 identity1 := ep1.GetSecurityIdentity() 84 require.Equal(t, identity1, ep2.GetSecurityIdentity()) 85 policy1 := cache.insert(identity1) 86 87 // Calculate the policy and observe that it's cached 88 updated, err := cache.updateSelectorPolicy(identity1) 89 require.NoError(t, err) 90 require.True(t, updated) 91 updated, err = cache.updateSelectorPolicy(identity1) 92 require.NoError(t, err) 93 require.Equal(t, false, updated) 94 policy2 := cache.insert(identity1) 95 idp1 := policy1.(*cachedSelectorPolicy).getPolicy() 96 idp2 := policy2.(*cachedSelectorPolicy).getPolicy() 97 require.Equal(t, idp2, idp1) 98 99 // Remove the identity and observe that it is no longer available 100 cacheCleared := cache.delete(identity1) 101 require.True(t, cacheCleared) 102 updated, err = cache.updateSelectorPolicy(identity1) 103 require.Error(t, err) 104 105 // Attempt to update policy for non-cached endpoint and observe failure 106 ep3 := testutils.NewTestEndpoint() 107 ep3.SetIdentity(1234, true) 108 _, err = cache.updateSelectorPolicy(ep3.GetSecurityIdentity()) 109 require.Error(t, err) 110 require.Equal(t, false, updated) 111 112 // Insert endpoint with different identity and observe that the cache 113 // is different from ep1, ep2 114 policy1 = cache.insert(identity1) 115 idp1 = policy1.(*cachedSelectorPolicy).getPolicy() 116 require.NotNil(t, idp1) 117 identity3 := ep3.GetSecurityIdentity() 118 policy3 := cache.insert(identity3) 119 require.NotEqual(t, policy1, policy3) 120 updated, err = cache.updateSelectorPolicy(identity3) 121 require.NoError(t, err) 122 require.True(t, updated) 123 idp3 := policy3.(*cachedSelectorPolicy).getPolicy() 124 require.NotEqual(t, idp1, idp3) 125 126 // If there's an error during policy resolution, update should fail 127 //repo.err = fmt.Errorf("not implemented!") 128 //repo.revision++ 129 //_, err = cache.updateSelectorPolicy(identity3) 130 //require.Error(t, err) 131 } 132 133 // Distillery integration tests 134 func key(id uint32, port uint16, hdr uint8, dir uint8) Key { 135 mask := uint16(0xffff) 136 if port == 0 { 137 mask = 0 138 } 139 return keyWithPortMask(id, port, mask, hdr, dir) 140 } 141 142 // keyWithPortMask returns a key with a specific port mask. 143 // Note: This method inverts the portMask on the key for the caller. 144 func keyWithPortMask(id uint32, port, portMask uint16, hdr uint8, dir uint8) Key { 145 return types.Key{ 146 Identity: id, 147 DestPort: port, 148 InvertedPortMask: ^portMask, 149 Nexthdr: hdr, 150 TrafficDirection: dir, 151 } 152 } 153 154 var ( 155 // Identity, labels, selectors for an endpoint named "foo" 156 identityFoo = uint32(100) 157 labelsFoo = labels.ParseSelectLabelArray("foo", "blue") 158 selectFoo_ = api.NewESFromLabels(labels.ParseSelectLabel("foo")) 159 allowFooL3_ = selectFoo_ 160 denyFooL3__ = selectFoo_ 161 162 // Identity, labels, selectors for an endpoint named "bar" 163 identityBar = uint32(200) 164 labelsBar = labels.ParseSelectLabelArray("bar", "blue") 165 selectBar_ = api.NewESFromLabels(labels.ParseSelectLabel("bar")) 166 allowBarL3_ = selectBar_ 167 168 // API rule sections for composability 169 // L4 rule sections 170 allowAllL4_ []api.PortRule 171 allowPort80 = []api.PortRule{{ 172 Ports: []api.PortProtocol{ 173 {Port: "80", Protocol: api.ProtoTCP}, 174 }, 175 }} 176 allowNamedPort80 = []api.PortRule{{ 177 Ports: []api.PortProtocol{ 178 {Port: "port-80", Protocol: api.ProtoTCP}, 179 }, 180 }} 181 denyAllL4_ []api.PortDenyRule 182 denyPort80 = []api.PortDenyRule{{ 183 Ports: []api.PortProtocol{ 184 {Port: "80", Protocol: api.ProtoTCP}, 185 }, 186 }} 187 // L7 rule sections 188 allowHTTPRoot = &api.L7Rules{ 189 HTTP: []api.PortRuleHTTP{ 190 {Method: "GET", Path: "/"}, 191 }, 192 } 193 // API rule definitions for default-deny, L3, L3L4, L3L4L7, L4, L4L7 194 lbls____NoAllow = labels.ParseLabelArray("no-allow") 195 rule____NoAllow = api.NewRule(). 196 WithLabels(lbls____NoAllow). 197 WithIngressRules([]api.IngressRule{{}}) 198 lblsL3____Allow = labels.ParseLabelArray("l3-allow") 199 ruleL3____Allow = api.NewRule(). 200 WithLabels(lblsL3____Allow). 201 WithIngressRules([]api.IngressRule{{ 202 IngressCommonRule: api.IngressCommonRule{ 203 FromEndpoints: []api.EndpointSelector{allowFooL3_}, 204 }, 205 ToPorts: allowAllL4_, 206 }}) 207 lblsL3L4__Allow = labels.ParseLabelArray("l3l4-allow") 208 ruleL3L4__Allow = api.NewRule(). 209 WithLabels(lblsL3L4__Allow). 210 WithIngressRules([]api.IngressRule{{ 211 IngressCommonRule: api.IngressCommonRule{ 212 FromEndpoints: []api.EndpointSelector{allowFooL3_}, 213 }, 214 ToPorts: allowPort80, 215 }}) 216 ruleL3npL4__Allow = api.NewRule(). 217 WithLabels(lblsL3L4__Allow). 218 WithIngressRules([]api.IngressRule{{ 219 IngressCommonRule: api.IngressCommonRule{ 220 FromEndpoints: []api.EndpointSelector{allowFooL3_}, 221 }, 222 ToPorts: allowNamedPort80, 223 }}) 224 lblsL3L4L7Allow = labels.ParseLabelArray("l3l4l7-allow") 225 ruleL3L4L7Allow = api.NewRule(). 226 WithLabels(lblsL3L4L7Allow). 227 WithIngressRules([]api.IngressRule{{ 228 IngressCommonRule: api.IngressCommonRule{ 229 FromEndpoints: []api.EndpointSelector{allowFooL3_}, 230 }, 231 ToPorts: combineL4L7(allowPort80, allowHTTPRoot), 232 }}) 233 ruleL3npL4L7Allow = api.NewRule(). 234 WithLabels(lblsL3L4L7Allow). 235 WithIngressRules([]api.IngressRule{{ 236 IngressCommonRule: api.IngressCommonRule{ 237 FromEndpoints: []api.EndpointSelector{allowFooL3_}, 238 }, 239 ToPorts: combineL4L7(allowNamedPort80, allowHTTPRoot), 240 }}) 241 lbls__L4__Allow = labels.ParseLabelArray("l4-allow") 242 rule__L4__Allow = api.NewRule(). 243 WithLabels(lbls__L4__Allow). 244 WithIngressRules([]api.IngressRule{{ 245 ToPorts: allowPort80, 246 }}) 247 rule__L4__AllowAuth = api.NewRule(). 248 WithLabels(lbls__L4__Allow). 249 WithIngressRules([]api.IngressRule{{ 250 ToPorts: allowPort80, 251 Authentication: &api.Authentication{ 252 Mode: api.AuthenticationModeRequired, 253 }, 254 }}) 255 rule__npL4__Allow = api.NewRule(). 256 WithLabels(lbls__L4__Allow). 257 WithIngressRules([]api.IngressRule{{ 258 ToPorts: allowNamedPort80, 259 }}) 260 lbls__L4L7Allow = labels.ParseLabelArray("l4l7-allow") 261 rule__L4L7Allow = api.NewRule(). 262 WithLabels(lbls__L4L7Allow). 263 WithIngressRules([]api.IngressRule{{ 264 ToPorts: combineL4L7(allowPort80, allowHTTPRoot), 265 }}) 266 rule__npL4L7Allow = api.NewRule(). 267 WithLabels(lbls__L4L7Allow). 268 WithIngressRules([]api.IngressRule{{ 269 ToPorts: combineL4L7(allowNamedPort80, allowHTTPRoot), 270 }}) 271 lblsL3__AllowFoo = labels.ParseLabelArray("l3-allow-foo") 272 ruleL3__AllowFoo = api.NewRule(). 273 WithLabels(lblsL3__AllowFoo). 274 WithIngressRules([]api.IngressRule{{ 275 IngressCommonRule: api.IngressCommonRule{ 276 FromEndpoints: []api.EndpointSelector{allowFooL3_}, 277 }, 278 }}) 279 lblsL3__AllowBar = labels.ParseLabelArray("l3-allow-bar") 280 ruleL3__AllowBar = api.NewRule(). 281 WithLabels(lblsL3__AllowBar). 282 WithIngressRules([]api.IngressRule{{ 283 IngressCommonRule: api.IngressCommonRule{ 284 FromEndpoints: []api.EndpointSelector{allowBarL3_}, 285 }, 286 }}) 287 lblsL3L4AllowBar = labels.ParseLabelArray("l3l4-allow-bar") 288 ruleL3L4AllowBarAuth = api.NewRule(). 289 WithLabels(lblsL3L4AllowBar). 290 WithIngressRules([]api.IngressRule{{ 291 ToPorts: allowPort80, 292 IngressCommonRule: api.IngressCommonRule{ 293 FromEndpoints: []api.EndpointSelector{allowBarL3_}, 294 }, 295 Authentication: &api.Authentication{ 296 Mode: api.AuthenticationModeAlwaysFail, 297 }, 298 }}) 299 ruleL3__AllowBarAuth = api.NewRule(). 300 WithLabels(lblsL3__AllowBar). 301 WithIngressRules([]api.IngressRule{{ 302 IngressCommonRule: api.IngressCommonRule{ 303 FromEndpoints: []api.EndpointSelector{allowBarL3_}, 304 }, 305 Authentication: &api.Authentication{ 306 Mode: api.AuthenticationModeAlwaysFail, 307 }, 308 }}) 309 lbls____AllowAll = labels.ParseLabelArray("allow-all") 310 rule____AllowAll = api.NewRule(). 311 WithLabels(lbls____AllowAll). 312 WithIngressRules([]api.IngressRule{{ 313 IngressCommonRule: api.IngressCommonRule{ 314 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 315 }, 316 }}) 317 rule____AllowAllAuth = api.NewRule(). 318 WithLabels(lbls____AllowAll). 319 WithIngressRules([]api.IngressRule{{ 320 IngressCommonRule: api.IngressCommonRule{ 321 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 322 }, 323 Authentication: &api.Authentication{ 324 Mode: api.AuthenticationModeRequired, 325 }, 326 }}) 327 lblsAllowAllIngress = labels.LabelArray{ 328 labels.NewLabel(LabelKeyPolicyDerivedFrom, LabelAllowAnyIngress, labels.LabelSourceReserved), 329 } 330 331 lbls_____NoDeny = labels.ParseLabelArray("deny") 332 rule_____NoDeny = api.NewRule(). 333 WithLabels(lbls_____NoDeny). 334 WithIngressRules([]api.IngressRule{{}}) 335 336 lblsL3_____Deny = labels.ParseLabelArray("l3-deny") 337 ruleL3_____Deny = api.NewRule(). 338 WithLabels(lblsL3_____Deny). 339 WithIngressDenyRules([]api.IngressDenyRule{{ 340 IngressCommonRule: api.IngressCommonRule{ 341 FromEndpoints: []api.EndpointSelector{denyFooL3__}, 342 }, 343 ToPorts: denyAllL4_, 344 }}) 345 346 lbls__L4___Deny = labels.ParseLabelArray("l4-deny") 347 rule__L4___Deny = api.NewRule(). 348 WithLabels(lbls__L4___Deny). 349 WithIngressDenyRules([]api.IngressDenyRule{{ 350 ToPorts: denyPort80, 351 }}) 352 353 lblsL3L4___Deny = labels.ParseLabelArray("l3l4-deny") 354 ruleL3L4___Deny = api.NewRule(). 355 WithLabels(lblsL3L4___Deny). 356 WithIngressDenyRules([]api.IngressDenyRule{{ 357 IngressCommonRule: api.IngressCommonRule{ 358 FromEndpoints: []api.EndpointSelector{denyFooL3__}, 359 }, 360 ToPorts: denyPort80, 361 }}) 362 363 // Misc other bpf key fields for convenience / readability. 364 dirIngress = trafficdirection.Ingress.Uint8() 365 dirEgress = trafficdirection.Egress.Uint8() 366 // Desired map keys for L3, L3-dependent L4, L4 367 mapKeyAllowFoo__ = key(identityFoo, 0, 0, dirIngress) 368 mapKeyAllowBar__ = key(identityBar, 0, 0, dirIngress) 369 mapKeyAllowBarL4 = key(identityBar, 80, 6, dirIngress) 370 mapKeyAllowFooL4 = key(identityFoo, 80, 6, dirIngress) 371 mapKeyDeny_Foo__ = mapKeyAllowFoo__ 372 mapKeyDeny_FooL4 = mapKeyAllowFooL4 373 mapKeyAllow___L4 = key(0, 80, 6, dirIngress) 374 mapKeyDeny____L4 = mapKeyAllow___L4 375 mapKeyAllowAll__ = key(0, 0, 0, dirIngress) 376 mapKeyAllowAllE_ = key(0, 0, 0, dirEgress) 377 // Desired map entries for no L7 redirect / redirect to Proxy 378 mapEntryL7None_ = func(lbls ...labels.LabelArray) MapStateEntry { 379 return NewMapStateEntry(nil, labels.LabelArrayList(lbls).Sort(), 0, "", 0, false, DefaultAuthType, AuthTypeDisabled).WithOwners() 380 } 381 mapEntryL7Auth_ = func(at AuthType, lbls ...labels.LabelArray) MapStateEntry { 382 return NewMapStateEntry(nil, labels.LabelArrayList(lbls).Sort(), 0, "", 0, false, ExplicitAuthType, at).WithOwners() 383 } 384 mapEntryL7Deny_ = func(lbls ...labels.LabelArray) MapStateEntry { 385 return NewMapStateEntry(nil, labels.LabelArrayList(lbls).Sort(), 0, "", 0, true, DefaultAuthType, AuthTypeDisabled).WithOwners() 386 } 387 mapEntryL7Proxy = func(lbls ...labels.LabelArray) MapStateEntry { 388 entry := NewMapStateEntry(nil, labels.LabelArrayList(lbls).Sort(), 1, "", 0, false, DefaultAuthType, AuthTypeDisabled).WithOwners() 389 entry.ProxyPort = 1 390 return entry 391 } 392 ) 393 394 // combineL4L7 returns a new PortRule that refers to the specified l4 ports and 395 // l7 rules. 396 func combineL4L7(l4 []api.PortRule, l7 *api.L7Rules) []api.PortRule { 397 result := make([]api.PortRule, 0, len(l4)) 398 for _, pr := range l4 { 399 result = append(result, api.PortRule{ 400 Ports: pr.Ports, 401 Rules: l7, 402 }) 403 } 404 return result 405 } 406 407 // policyDistillery is a convenience wrapper around the existing policy engine, 408 // allowing simple direct evaluation of L3 and L4 state into "MapState". 409 type policyDistillery struct { 410 *Repository 411 log io.Writer 412 } 413 414 func newPolicyDistillery(selectorCache *SelectorCache) *policyDistillery { 415 ret := &policyDistillery{ 416 Repository: NewPolicyRepository(nil, nil, nil), 417 } 418 ret.selectorCache = selectorCache 419 return ret 420 } 421 422 func (d *policyDistillery) WithLogBuffer(w io.Writer) *policyDistillery { 423 return &policyDistillery{ 424 Repository: d.Repository, 425 log: w, 426 } 427 } 428 429 // distillPolicy distills the policy repository into a set of bpf map state 430 // entries for an endpoint with the specified labels. 431 func (d *policyDistillery) distillPolicy(owner PolicyOwner, epLabels labels.LabelArray, identity *identity.Identity) (MapState, error) { 432 sp := d.Repository.GetPolicyCache().insert(identity) 433 d.Repository.GetPolicyCache().UpdatePolicy(identity) 434 epp := sp.Consume(DummyOwner{}) 435 if epp == nil { 436 return nil, errors.New("policy distillation failure") 437 } 438 439 // Remove the allow-all egress entry that's generated by default. This is 440 // because this test suite doesn't have a notion of traffic direction, so 441 // the extra egress allow-all is technically correct, but omitted from the 442 // expected output that's asserted against for the sake of brevity. 443 epp.policyMapState.Delete(mapKeyAllowAllE_) 444 445 return epp.policyMapState, nil 446 } 447 448 // Perm calls f with each permutation of a. 449 func Perm[X any](a []X, f func([]X)) { 450 perm(a, f, 0) 451 } 452 453 // Permute the values at index i to len(a)-1. 454 func perm[X any](a []X, f func([]X), i int) { 455 if i > len(a) { 456 f(a) 457 return 458 } 459 perm(a, f, i+1) 460 for j := i + 1; j < len(a); j++ { 461 a[i], a[j] = a[j], a[i] 462 perm(a, f, i+1) 463 a[i], a[j] = a[j], a[i] 464 } 465 } 466 467 func Test_Perm(t *testing.T) { 468 var res []string 469 expected := []string{ 470 "abc", 471 "acb", 472 "bac", 473 "bca", 474 "cba", 475 "cab", 476 } 477 Perm([]rune("abc"), func(x []rune) { res = append(res, string(x)) }) 478 assert.Equal(t, res, expected, "invalid permutations") 479 } 480 481 func Test_MergeL3(t *testing.T) { 482 // Cache policy enforcement value from when test was ran to avoid pollution 483 // across tests. 484 oldPolicyEnable := GetPolicyEnabled() 485 defer SetPolicyEnabled(oldPolicyEnable) 486 487 SetPolicyEnabled(option.DefaultEnforcement) 488 489 identityCache := identity.IdentityMap{ 490 identity.NumericIdentity(identityFoo): labelsFoo, 491 identity.NumericIdentity(identityBar): labelsBar, 492 } 493 selectorCache := testNewSelectorCache(identityCache) 494 495 type authResult map[identity.NumericIdentity]AuthTypes 496 tests := []struct { 497 test int 498 rules api.Rules 499 result MapState 500 auths authResult 501 }{ 502 { 503 0, 504 api.Rules{ruleL3__AllowFoo, ruleL3__AllowBar}, 505 NewMapState(map[Key]MapStateEntry{ 506 mapKeyAllowFoo__: mapEntryL7None_(lblsL3__AllowFoo), 507 mapKeyAllowBar__: mapEntryL7None_(lblsL3__AllowBar), 508 }), 509 authResult{ 510 identity.NumericIdentity(identityBar): AuthTypes{}, 511 identity.NumericIdentity(identityFoo): AuthTypes{}, 512 }, 513 }, 514 { 515 1, 516 api.Rules{ruleL3__AllowFoo, ruleL3L4__Allow}, 517 NewMapState(map[Key]MapStateEntry{ 518 mapKeyAllowFoo__: mapEntryL7None_(lblsL3__AllowFoo), 519 mapKeyAllowFooL4: mapEntryL7None_(lblsL3L4__Allow), 520 }), 521 authResult{ 522 identity.NumericIdentity(identityBar): AuthTypes{}, 523 identity.NumericIdentity(identityFoo): AuthTypes{}, 524 }, 525 }, 526 { 527 2, 528 api.Rules{ruleL3__AllowFoo, ruleL3__AllowBarAuth}, 529 NewMapState(map[Key]MapStateEntry{ 530 mapKeyAllowFoo__: mapEntryL7None_(lblsL3__AllowFoo), 531 mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeAlwaysFail, lblsL3__AllowBar), 532 }), 533 authResult{ 534 identity.NumericIdentity(identityBar): AuthTypes{AuthTypeAlwaysFail: struct{}{}}, 535 identity.NumericIdentity(identityFoo): AuthTypes{}, 536 }, 537 }, 538 { 539 3, 540 api.Rules{ruleL3__AllowFoo, ruleL3__AllowBarAuth, rule__L4__AllowAuth}, 541 NewMapState(map[Key]MapStateEntry{ 542 mapKeyAllow___L4: mapEntryL7Auth_(AuthTypeSpire, lbls__L4__Allow), 543 mapKeyAllowFoo__: mapEntryL7None_(lblsL3__AllowFoo), 544 mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeAlwaysFail, lblsL3__AllowBar), 545 }), 546 authResult{ 547 identity.NumericIdentity(identityBar): AuthTypes{AuthTypeAlwaysFail: struct{}{}, AuthTypeSpire: struct{}{}}, 548 identity.NumericIdentity(identityFoo): AuthTypes{AuthTypeSpire: struct{}{}}, 549 }, 550 }, 551 { 552 4, 553 api.Rules{rule____AllowAll, ruleL3__AllowBarAuth}, 554 NewMapState(map[Key]MapStateEntry{ 555 mapKeyAllowAll__: mapEntryL7None_(lbls____AllowAll), 556 mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeAlwaysFail, lblsL3__AllowBar), 557 }), 558 authResult{ 559 identity.NumericIdentity(identityBar): AuthTypes{AuthTypeAlwaysFail: struct{}{}}, 560 identity.NumericIdentity(identityFoo): AuthTypes{}, 561 }, 562 }, 563 { 564 5, 565 api.Rules{rule____AllowAllAuth, ruleL3__AllowBar}, 566 NewMapState(map[Key]MapStateEntry{ 567 mapKeyAllowAll__: mapEntryL7Auth_(AuthTypeSpire, lbls____AllowAll), 568 mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeSpire, lblsL3__AllowBar), 569 }), 570 authResult{ 571 identity.NumericIdentity(identityBar): AuthTypes{AuthTypeSpire: struct{}{}}, 572 identity.NumericIdentity(identityFoo): AuthTypes{AuthTypeSpire: struct{}{}}, 573 }, 574 }, 575 { 576 6, 577 api.Rules{rule____AllowAllAuth, rule__L4__Allow}, 578 NewMapState(map[Key]MapStateEntry{ 579 mapKeyAllowAll__: mapEntryL7Auth_(AuthTypeSpire, lbls____AllowAll), 580 mapKeyAllow___L4: mapEntryL7Auth_(AuthTypeSpire, lbls__L4__Allow), 581 }), 582 authResult{ 583 identity.NumericIdentity(identityBar): AuthTypes{AuthTypeSpire: struct{}{}}, 584 identity.NumericIdentity(identityFoo): AuthTypes{AuthTypeSpire: struct{}{}}, 585 }, 586 }, 587 { 588 7, 589 api.Rules{rule____AllowAllAuth, ruleL3__AllowBar, rule__L4__Allow}, 590 NewMapState(map[Key]MapStateEntry{ 591 mapKeyAllowAll__: mapEntryL7Auth_(AuthTypeSpire, lbls____AllowAll), 592 mapKeyAllow___L4: mapEntryL7Auth_(AuthTypeSpire, lbls__L4__Allow), 593 mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeSpire, lblsL3__AllowBar), 594 }), 595 authResult{ 596 identity.NumericIdentity(identityBar): AuthTypes{AuthTypeSpire: struct{}{}}, 597 identity.NumericIdentity(identityFoo): AuthTypes{AuthTypeSpire: struct{}{}}, 598 }, 599 }, 600 { 601 8, 602 api.Rules{rule____AllowAll, ruleL3__AllowBar, rule__L4__Allow}, 603 NewMapState(map[Key]MapStateEntry{ 604 mapKeyAllowAll__: mapEntryL7Auth_(AuthTypeDisabled, lbls____AllowAll), 605 mapKeyAllow___L4: mapEntryL7Auth_(AuthTypeDisabled, lbls__L4__Allow), 606 mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeDisabled, lblsL3__AllowBar), 607 }), 608 authResult{ 609 identity.NumericIdentity(identityBar): AuthTypes{}, 610 identity.NumericIdentity(identityFoo): AuthTypes{}, 611 }, 612 }, 613 { 614 9, 615 api.Rules{rule____AllowAll, rule__L4__Allow, ruleL3__AllowBarAuth}, 616 NewMapState(map[Key]MapStateEntry{ 617 mapKeyAllowAll__: mapEntryL7Auth_(AuthTypeDisabled, lbls____AllowAll), 618 mapKeyAllow___L4: mapEntryL7Auth_(AuthTypeDisabled, lbls__L4__Allow), 619 mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeAlwaysFail, lblsL3__AllowBar), 620 mapKeyAllowBarL4: mapEntryL7Auth_(AuthTypeAlwaysFail, lbls__L4__Allow, lblsL3__AllowBar), 621 }), 622 authResult{ 623 identity.NumericIdentity(identityBar): AuthTypes{AuthTypeAlwaysFail: struct{}{}}, 624 identity.NumericIdentity(identityFoo): AuthTypes{}, 625 }, 626 }, 627 { 628 10, // Same as 9, but the L3L4 entry is created by an explicit rule. 629 api.Rules{rule____AllowAll, rule__L4__Allow, ruleL3__AllowBarAuth, ruleL3L4AllowBarAuth}, 630 NewMapState(map[Key]MapStateEntry{ 631 mapKeyAllowAll__: mapEntryL7Auth_(AuthTypeDisabled, lbls____AllowAll), 632 mapKeyAllow___L4: mapEntryL7Auth_(AuthTypeDisabled, lbls__L4__Allow), 633 mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeAlwaysFail, lblsL3__AllowBar), 634 mapKeyAllowBarL4: mapEntryL7Auth_(AuthTypeAlwaysFail, lblsL3L4AllowBar, lbls__L4__Allow, lblsL3__AllowBar), 635 }), 636 authResult{ 637 identity.NumericIdentity(identityBar): AuthTypes{AuthTypeAlwaysFail: struct{}{}}, 638 identity.NumericIdentity(identityFoo): AuthTypes{}, 639 }, 640 }, 641 } 642 643 identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(identityFoo), labelsFoo) 644 for _, tt := range tests { 645 for i, r := range tt.rules { 646 tt.rules[i] = r.WithEndpointSelector(selectFoo_) 647 } 648 649 round := 0 650 Perm(tt.rules, func(rules []*api.Rule) { 651 round++ 652 653 repo := newPolicyDistillery(selectorCache) 654 _, _ = repo.MustAddList(rules) 655 656 t.Run(fmt.Sprintf("permutation_%d-%d", tt.test, round), func(t *testing.T) { 657 logBuffer := new(bytes.Buffer) 658 repo = repo.WithLogBuffer(logBuffer) 659 mapstate, err := repo.distillPolicy(DummyOwner{}, labelsFoo, identity) 660 if err != nil { 661 t.Errorf("Policy resolution failure: %s", err) 662 } 663 if equal := assert.True(t, mapstate.Equals(tt.result), mapstate.Diff(tt.result)); !equal { 664 t.Logf("Rules:\n%s\n\n", api.Rules(rules).String()) 665 t.Logf("Policy Trace: \n%s\n", logBuffer.String()) 666 t.Errorf("Policy obtained didn't match expected for endpoint %s:\nObtained: %v\nExpected: %v", labelsFoo, mapstate, tt.result) 667 } 668 for remoteID, expectedAuthTypes := range tt.auths { 669 authTypes := repo.GetAuthTypes(identity.ID, remoteID) 670 if !maps.Equal(authTypes, expectedAuthTypes) { 671 t.Errorf("Incorrect AuthTypes result for remote ID %d: obtained %v, expected %v", remoteID, authTypes, expectedAuthTypes) 672 } 673 } 674 }) 675 }) 676 } 677 } 678 679 // The following variables names are derived from the following google sheet 680 // https://docs.google.com/spreadsheets/d/1WANIoZGB48nryylQjjOw6lKjI80eVgPShrdMTMalLEw/edit?usp=sharing 681 682 const ( 683 L3L4KeyL3 = iota 684 L3L4KeyL4 685 L3L4KeyL7 686 L3L4KeyDeny 687 L4KeyL3 688 L4KeyL4 689 L4KeyL7 690 L4KeyDeny 691 L3KeyL3 692 L3KeyL4 693 L3KeyL7 694 L3KeyDeny 695 Total 696 ) 697 698 // fieldsSet is the representation of the values set in the cells M8-P8, Q8-T8 699 // and U8-X8. 700 type fieldsSet struct { 701 L3 *bool 702 L4 *bool 703 L7 *bool 704 Deny *bool 705 } 706 707 // generatedBPFKey is the representation of the values set in the cells [M:P]6, 708 // [Q:T]6 and [U:X]6. 709 type generatedBPFKey struct { 710 L3L4Key fieldsSet 711 L4Key fieldsSet 712 L3Key fieldsSet 713 } 714 715 func parseFieldBool(s string) *bool { 716 switch s { 717 case "X": 718 return nil 719 case "0": 720 return func() *bool { a := false; return &a }() 721 case "1": 722 return func() *bool { a := true; return &a }() 723 default: 724 panic("Unknown value") 725 } 726 } 727 728 func parseTable(test string) generatedBPFKey { 729 // Remove all consecutive white space characters and return the charts that 730 // need want to parse. 731 fields := strings.Fields(test) 732 if len(fields) != Total { 733 panic("Wrong number of expected results") 734 } 735 return generatedBPFKey{ 736 L3L4Key: fieldsSet{ 737 L3: parseFieldBool(fields[L3L4KeyL3]), 738 L4: parseFieldBool(fields[L3L4KeyL4]), 739 L7: parseFieldBool(fields[L3L4KeyL7]), 740 Deny: parseFieldBool(fields[L3L4KeyDeny]), 741 }, 742 L4Key: fieldsSet{ 743 L3: parseFieldBool(fields[L4KeyL3]), 744 L4: parseFieldBool(fields[L4KeyL4]), 745 L7: parseFieldBool(fields[L4KeyL7]), 746 Deny: parseFieldBool(fields[L4KeyDeny]), 747 }, 748 L3Key: fieldsSet{ 749 L3: parseFieldBool(fields[L3KeyL3]), 750 L4: parseFieldBool(fields[L3KeyL4]), 751 L7: parseFieldBool(fields[L3KeyL7]), 752 Deny: parseFieldBool(fields[L3KeyDeny]), 753 }, 754 } 755 } 756 757 // testCaseToMapState generates the expected MapState logic. This function is 758 // an implementation of the expected behavior. Any relation between this 759 // function and non unit-test code should be seen as coincidental. 760 // The algorithm represented in this function should be the source of truth 761 // of our expectations when enforcing multiple types of policies. 762 func testCaseToMapState(t generatedBPFKey) MapState { 763 m := newMapState(nil) 764 765 if t.L3Key.L3 != nil { 766 if t.L3Key.Deny != nil && *t.L3Key.Deny { 767 m.denies.Upsert(mapKeyDeny_Foo__, mapEntryL7Deny_()) 768 } else { 769 // If L7 is not set or if it explicitly set but it's false 770 if t.L3Key.L7 == nil || !*t.L3Key.L7 { 771 m.allows.Upsert(mapKeyAllowFoo__, mapEntryL7None_()) 772 } 773 // there's no "else" because we don't support L3L7 policies, i.e., 774 // a L4 port needs to be specified. 775 } 776 } 777 if t.L4Key.L3 != nil { 778 if t.L4Key.Deny != nil && *t.L4Key.Deny { 779 m.denies.Upsert(mapKeyDeny____L4, mapEntryL7Deny_()) 780 } else { 781 // If L7 is not set or if it explicitly set but it's false 782 if t.L4Key.L7 == nil || !*t.L4Key.L7 { 783 m.allows.Upsert(mapKeyAllow___L4, mapEntryL7None_()) 784 } else { 785 // L7 is set and it's true then we should expected a mapEntry 786 // with L7 redirection. 787 m.allows.Upsert(mapKeyAllow___L4, mapEntryL7Proxy()) 788 } 789 } 790 } 791 if t.L3L4Key.L3 != nil { 792 if t.L3L4Key.Deny != nil && *t.L3L4Key.Deny { 793 m.denies.Upsert(mapKeyDeny_FooL4, mapEntryL7Deny_()) 794 } else { 795 // If L7 is not set or if it explicitly set but it's false 796 if t.L3L4Key.L7 == nil || !*t.L3L4Key.L7 { 797 m.allows.Upsert(mapKeyAllowFooL4, mapEntryL7None_()) 798 } else { 799 // L7 is set and it's true then we should expected a mapEntry 800 // with L7 redirection only if we haven't set it already 801 // for an existing L4-only. 802 if t.L4Key.L7 == nil || !*t.L4Key.L7 { 803 m.allows.Upsert(mapKeyAllowFooL4, mapEntryL7Proxy()) 804 } 805 } 806 } 807 } 808 809 // Add dependency deny-L3->deny-L3L4 if allow-L4 exists 810 denyL3, denyL3exists := m.denies.Lookup(mapKeyDeny_Foo__) 811 denyL3L4, denyL3L4exists := m.denies.Lookup(mapKeyDeny_FooL4) 812 allowL4, allowL4exists := m.allows.Lookup(mapKeyAllow___L4) 813 if allowL4exists && !allowL4.IsDeny && denyL3exists && denyL3.IsDeny && denyL3L4exists && denyL3L4.IsDeny { 814 m.AddDependent(mapKeyDeny_Foo__, mapKeyDeny_FooL4, ChangeState{}) 815 } 816 return m 817 } 818 819 func generateMapStates() []MapState { 820 rawTestTable := []string{ 821 "X X X X X X X X X X X X", // 0 822 "X X X X X X X X 1 0 0 0", 823 "X X X X 0 1 0 0 X X X X", 824 "X X X X 0 1 0 0 1 0 0 0", 825 "1 1 0 0 X X X X X X X X", 826 "1 1 0 0 X X X X 1 0 0 0", // 5 827 "X X X X 0 1 0 0 X X X X", 828 "X X X X 0 1 0 0 1 0 0 0", 829 "X X X X 0 1 1 0 X X X X", 830 "X X X X 0 1 1 0 1 0 0 0", 831 "X X X X 0 1 1 0 X X X X", // 10 832 "X X X X 0 1 1 0 1 0 0 0", 833 "1 1 1 0 0 1 1 0 X X X X", 834 "1 1 1 0 0 1 1 0 1 0 0 0", 835 "1 1 1 0 0 1 1 0 X X X X", 836 "1 1 1 0 0 1 1 0 1 0 0 0", // 15 837 "1 1 1 0 X X X X X X X X", 838 "1 1 1 0 X X X X 1 0 0 0", 839 "1 1 1 0 0 1 0 0 X X X X", 840 "1 1 1 0 0 1 0 0 1 0 0 0", 841 "1 1 1 0 X X X X X X X X", // 20 842 "1 1 1 0 X X X X 1 0 0 0", 843 "1 1 1 0 0 1 0 0 X X X X", 844 "1 1 1 0 0 1 0 0 1 0 0 0", 845 "1 1 1 0 0 1 1 0 X X X X", 846 "1 1 1 0 0 1 1 0 1 0 0 0", // 25 847 "1 1 1 0 0 1 1 0 X X X X", 848 "1 1 1 0 0 1 1 0 1 0 0 0", 849 "1 1 1 0 0 1 1 0 X X X X", 850 "1 1 1 0 0 1 1 0 1 0 0 0", 851 "1 1 1 0 0 1 1 0 X X X X", // 30 852 "1 1 1 0 0 1 1 0 1 0 0 0", 853 854 "X X X X X X X X 1 0 0 1", // 32 855 "X X X X X X X X 1 0 0 1", 856 "1 1 0 1 0 1 0 0 1 0 0 1", 857 "1 1 0 1 0 1 0 0 1 0 0 1", 858 "X X X X X X X X 1 0 0 1", 859 "X X X X X X X X 1 0 0 1", 860 "1 1 0 1 0 1 0 0 1 0 0 1", 861 "1 1 0 1 0 1 0 0 1 0 0 1", 862 "1 1 0 1 0 1 1 0 1 0 0 1", 863 "1 1 0 1 0 1 1 0 1 0 0 1", 864 "1 1 0 1 0 1 1 0 1 0 0 1", 865 "1 1 0 1 0 1 1 0 1 0 0 1", 866 "1 1 0 1 0 1 1 0 1 0 0 1", 867 "1 1 0 1 0 1 1 0 1 0 0 1", 868 "1 1 0 1 0 1 1 0 1 0 0 1", 869 "1 1 0 1 0 1 1 0 1 0 0 1", 870 "X X X X X X X X 1 0 0 1", 871 "X X X X X X X X 1 0 0 1", 872 "1 1 0 1 0 1 0 0 1 0 0 1", 873 "1 1 0 1 0 1 0 0 1 0 0 1", 874 "X X X X X X X X 1 0 0 1", 875 "X X X X X X X X 1 0 0 1", 876 "1 1 0 1 0 1 0 0 1 0 0 1", 877 "1 1 0 1 0 1 0 0 1 0 0 1", 878 "1 1 0 1 0 1 1 0 1 0 0 1", 879 "1 1 0 1 0 1 1 0 1 0 0 1", 880 "1 1 0 1 0 1 1 0 1 0 0 1", 881 "1 1 0 1 0 1 1 0 1 0 0 1", 882 "1 1 0 1 0 1 1 0 1 0 0 1", 883 "1 1 0 1 0 1 1 0 1 0 0 1", 884 "1 1 0 1 0 1 1 0 1 0 0 1", 885 "1 1 0 1 0 1 1 0 1 0 0 1", 886 887 "X X X X 0 1 0 1 X X X X", // 64 888 "X X X X 0 1 0 1 1 0 0 0", 889 "X X X X 0 1 0 1 X X X X", 890 "X X X X 0 1 0 1 1 0 0 0", 891 "X X X X 0 1 0 1 X X X X", 892 "X X X X 0 1 0 1 1 0 0 0", 893 "X X X X 0 1 0 1 X X X X", 894 "X X X X 0 1 0 1 1 0 0 0", 895 "X X X X 0 1 0 1 X X X X", 896 "X X X X 0 1 0 1 1 0 0 0", 897 "X X X X 0 1 0 1 X X X X", 898 "X X X X 0 1 0 1 1 0 0 0", 899 "X X X X 0 1 0 1 X X X X", 900 "X X X X 0 1 0 1 1 0 0 0", 901 "X X X X 0 1 0 1 X X X X", 902 "X X X X 0 1 0 1 1 0 0 0", 903 "X X X X 0 1 0 1 X X X X", 904 "X X X X 0 1 0 1 1 0 0 0", 905 "X X X X 0 1 0 1 X X X X", 906 "X X X X 0 1 0 1 1 0 0 0", 907 "X X X X 0 1 0 1 X X X X", 908 "X X X X 0 1 0 1 1 0 0 0", 909 "X X X X 0 1 0 1 X X X X", 910 "X X X X 0 1 0 1 1 0 0 0", 911 "X X X X 0 1 0 1 X X X X", 912 "X X X X 0 1 0 1 1 0 0 0", 913 "X X X X 0 1 0 1 X X X X", 914 "X X X X 0 1 0 1 1 0 0 0", 915 "X X X X 0 1 0 1 X X X X", 916 "X X X X 0 1 0 1 1 0 0 0", 917 "X X X X 0 1 0 1 X X X X", 918 "X X X X 0 1 0 1 1 0 0 0", 919 920 "X X X X 0 1 0 1 1 0 0 1", // 96 921 "X X X X 0 1 0 1 1 0 0 1", 922 "X X X X 0 1 0 1 1 0 0 1", 923 "X X X X 0 1 0 1 1 0 0 1", 924 "X X X X 0 1 0 1 1 0 0 1", 925 "X X X X 0 1 0 1 1 0 0 1", 926 "X X X X 0 1 0 1 1 0 0 1", 927 "X X X X 0 1 0 1 1 0 0 1", 928 "X X X X 0 1 0 1 1 0 0 1", 929 "X X X X 0 1 0 1 1 0 0 1", 930 "X X X X 0 1 0 1 1 0 0 1", 931 "X X X X 0 1 0 1 1 0 0 1", 932 "X X X X 0 1 0 1 1 0 0 1", 933 "X X X X 0 1 0 1 1 0 0 1", 934 "X X X X 0 1 0 1 1 0 0 1", 935 "X X X X 0 1 0 1 1 0 0 1", 936 "X X X X 0 1 0 1 1 0 0 1", 937 "X X X X 0 1 0 1 1 0 0 1", 938 "X X X X 0 1 0 1 1 0 0 1", 939 "X X X X 0 1 0 1 1 0 0 1", 940 "X X X X 0 1 0 1 1 0 0 1", 941 "X X X X 0 1 0 1 1 0 0 1", 942 "X X X X 0 1 0 1 1 0 0 1", 943 "X X X X 0 1 0 1 1 0 0 1", 944 "X X X X 0 1 0 1 1 0 0 1", 945 "X X X X 0 1 0 1 1 0 0 1", 946 "X X X X 0 1 0 1 1 0 0 1", 947 "X X X X 0 1 0 1 1 0 0 1", 948 "X X X X 0 1 0 1 1 0 0 1", 949 "X X X X 0 1 0 1 1 0 0 1", 950 "X X X X 0 1 0 1 1 0 0 1", 951 "X X X X 0 1 0 1 1 0 0 1", 952 953 "1 1 0 1 X X X X X X X X", // 128 954 "1 1 0 1 X X X X 1 0 0 0", 955 "1 1 0 1 0 1 0 0 X X X X", 956 "1 1 0 1 0 1 0 0 1 0 0 0", 957 "1 1 0 1 X X X X X X X X", 958 "1 1 0 1 X X X X 1 0 0 0", 959 "1 1 0 1 0 1 0 0 X X X X", 960 "1 1 0 1 0 1 0 0 1 0 0 0", 961 "1 1 0 1 0 1 1 0 X X X X", 962 "1 1 0 1 0 1 1 0 1 0 0 0", 963 "1 1 0 1 0 1 1 0 X X X X", 964 "1 1 0 1 0 1 1 0 1 0 0 0", 965 "1 1 0 1 0 1 1 0 X X X X", 966 "1 1 0 1 0 1 1 0 1 0 0 0", 967 "1 1 0 1 0 1 1 0 X X X X", 968 "1 1 0 1 0 1 1 0 1 0 0 0", 969 "1 1 0 1 X X X X X X X X", 970 "1 1 0 1 X X X X 1 0 0 0", 971 "1 1 0 1 0 1 0 0 X X X X", 972 "1 1 0 1 0 1 0 0 1 0 0 0", 973 "1 1 0 1 X X X X X X X X", 974 "1 1 0 1 X X X X 1 0 0 0", 975 "1 1 0 1 0 1 0 0 X X X X", 976 "1 1 0 1 0 1 0 0 1 0 0 0", 977 "1 1 0 1 0 1 1 0 X X X X", 978 "1 1 0 1 0 1 1 0 1 0 0 0", 979 "1 1 0 1 0 1 1 0 X X X X", 980 "1 1 0 1 0 1 1 0 1 0 0 0", 981 "1 1 0 1 0 1 1 0 X X X X", 982 "1 1 0 1 0 1 1 0 1 0 0 0", 983 "1 1 0 1 0 1 1 0 X X X X", 984 "1 1 0 1 0 1 1 0 1 0 0 0", 985 986 "X X X X X X X X 1 0 0 1", // 160 987 "X X X X X X X X 1 0 0 1", 988 "1 1 0 1 0 1 0 0 1 0 0 1", 989 "1 1 0 1 0 1 0 0 1 0 0 1", 990 "X X X X X X X X 1 0 0 1", 991 "X X X X X X X X 1 0 0 1", 992 "1 1 0 1 0 1 0 0 1 0 0 1", 993 "1 1 0 1 0 1 0 0 1 0 0 1", 994 "1 1 0 1 0 1 1 0 1 0 0 1", 995 "1 1 0 1 0 1 1 0 1 0 0 1", 996 "1 1 0 1 0 1 1 0 1 0 0 1", 997 "1 1 0 1 0 1 1 0 1 0 0 1", 998 "1 1 0 1 0 1 1 0 1 0 0 1", 999 "1 1 0 1 0 1 1 0 1 0 0 1", 1000 "1 1 0 1 0 1 1 0 1 0 0 1", 1001 "1 1 0 1 0 1 1 0 1 0 0 1", 1002 "X X X X X X X X 1 0 0 1", 1003 "X X X X X X X X 1 0 0 1", 1004 "1 1 0 1 0 1 0 0 1 0 0 1", 1005 "1 1 0 1 0 1 0 0 1 0 0 1", 1006 "X X X X X X X X 1 0 0 1", 1007 "X X X X X X X X 1 0 0 1", 1008 "1 1 0 1 0 1 0 0 1 0 0 1", 1009 "1 1 0 1 0 1 0 0 1 0 0 1", 1010 "1 1 0 1 0 1 1 0 1 0 0 1", 1011 "1 1 0 1 0 1 1 0 1 0 0 1", 1012 "1 1 0 1 0 1 1 0 1 0 0 1", 1013 "1 1 0 1 0 1 1 0 1 0 0 1", 1014 "1 1 0 1 0 1 1 0 1 0 0 1", 1015 "1 1 0 1 0 1 1 0 1 0 0 1", 1016 "1 1 0 1 0 1 1 0 1 0 0 1", 1017 "1 1 0 1 0 1 1 0 1 0 0 1", 1018 1019 "X X X X 0 1 0 1 X X X X", // 192 1020 "X X X X 0 1 0 1 1 0 0 0", 1021 "X X X X 0 1 0 1 X X X X", 1022 "X X X X 0 1 0 1 1 0 0 0", 1023 "X X X X 0 1 0 1 X X X X", 1024 "X X X X 0 1 0 1 1 0 0 0", 1025 "X X X X 0 1 0 1 X X X X", 1026 "X X X X 0 1 0 1 1 0 0 0", 1027 "X X X X 0 1 0 1 X X X X", 1028 "X X X X 0 1 0 1 1 0 0 0", 1029 "X X X X 0 1 0 1 X X X X", 1030 "X X X X 0 1 0 1 1 0 0 0", 1031 "X X X X 0 1 0 1 X X X X", 1032 "X X X X 0 1 0 1 1 0 0 0", 1033 "X X X X 0 1 0 1 X X X X", 1034 "X X X X 0 1 0 1 1 0 0 0", 1035 "X X X X 0 1 0 1 X X X X", 1036 "X X X X 0 1 0 1 1 0 0 0", 1037 "X X X X 0 1 0 1 X X X X", 1038 "X X X X 0 1 0 1 1 0 0 0", 1039 "X X X X 0 1 0 1 X X X X", 1040 "X X X X 0 1 0 1 1 0 0 0", 1041 "X X X X 0 1 0 1 X X X X", 1042 "X X X X 0 1 0 1 1 0 0 0", 1043 "X X X X 0 1 0 1 X X X X", 1044 "X X X X 0 1 0 1 1 0 0 0", 1045 "X X X X 0 1 0 1 X X X X", 1046 "X X X X 0 1 0 1 1 0 0 0", 1047 "X X X X 0 1 0 1 X X X X", 1048 "X X X X 0 1 0 1 1 0 0 0", 1049 "X X X X 0 1 0 1 X X X X", 1050 "X X X X 0 1 0 1 1 0 0 0", 1051 1052 "X X X X 1 1 0 1 1 0 0 1", // 224 1053 "X X X X 1 1 0 1 1 0 0 1", 1054 "X X X X 1 1 0 1 1 0 0 1", 1055 "X X X X 1 1 0 1 1 0 0 1", 1056 "X X X X 1 1 0 1 1 0 0 1", 1057 "X X X X 1 1 0 1 1 0 0 1", 1058 "X X X X 1 1 0 1 1 0 0 1", 1059 "X X X X 1 1 0 1 1 0 0 1", 1060 "X X X X 1 1 0 1 1 0 0 1", 1061 "X X X X 1 1 0 1 1 0 0 1", 1062 "X X X X 1 1 0 1 1 0 0 1", 1063 "X X X X 1 1 0 1 1 0 0 1", 1064 "X X X X 1 1 0 1 1 0 0 1", 1065 "X X X X 1 1 0 1 1 0 0 1", 1066 "X X X X 1 1 0 1 1 0 0 1", 1067 "X X X X 1 1 0 1 1 0 0 1", 1068 "X X X X 1 1 0 1 1 0 0 1", 1069 "X X X X 1 1 0 1 1 0 0 1", 1070 "X X X X 1 1 0 1 1 0 0 1", 1071 "X X X X 1 1 0 1 1 0 0 1", 1072 "X X X X 1 1 0 1 1 0 0 1", 1073 "X X X X 1 1 0 1 1 0 0 1", 1074 "X X X X 1 1 0 1 1 0 0 1", 1075 "X X X X 1 1 0 1 1 0 0 1", 1076 "X X X X 1 1 0 1 1 0 0 1", 1077 "X X X X 1 1 0 1 1 0 0 1", 1078 "X X X X 1 1 0 1 1 0 0 1", 1079 "X X X X 1 1 0 1 1 0 0 1", 1080 "X X X X 1 1 0 1 1 0 0 1", 1081 "X X X X 1 1 0 1 1 0 0 1", 1082 "X X X X 1 1 0 1 1 0 0 1", 1083 "X X X X 1 1 0 1 1 0 0 1", 1084 } 1085 mapStates := make([]MapState, 0, len(rawTestTable)) 1086 for _, rawTest := range rawTestTable { 1087 testCase := parseTable(rawTest) 1088 mapState := testCaseToMapState(testCase) 1089 mapStates = append(mapStates, mapState) 1090 } 1091 1092 return mapStates 1093 } 1094 1095 func generateRule(testCase int) api.Rules { 1096 rulesIdx := api.Rules{ 1097 ruleL3____Allow, 1098 rule__L4__Allow, 1099 ruleL3L4__Allow, 1100 rule__L4L7Allow, 1101 ruleL3L4L7Allow, 1102 // denyIdx 1103 ruleL3_____Deny, 1104 rule__L4___Deny, 1105 ruleL3L4___Deny, 1106 } 1107 rules := make(api.Rules, 0, len(rulesIdx)) 1108 for i := len(rulesIdx) - 1; i >= 0; i-- { 1109 if ((testCase >> i) & 0x1) != 0 { 1110 rules = append(rules, rulesIdx[i]) 1111 } else { 1112 if i >= 5 { // denyIdx 1113 rules = append(rules, rule_____NoDeny) 1114 } else { 1115 rules = append(rules, rule____NoAllow) 1116 } 1117 } 1118 } 1119 return rules 1120 } 1121 1122 func Test_MergeRules(t *testing.T) { 1123 // Cache policy enforcement value from when test was ran to avoid pollution 1124 // across tests. 1125 oldPolicyEnable := GetPolicyEnabled() 1126 defer SetPolicyEnabled(oldPolicyEnable) 1127 1128 SetPolicyEnabled(option.DefaultEnforcement) 1129 1130 identityCache := identity.IdentityMap{ 1131 identity.NumericIdentity(identityFoo): labelsFoo, 1132 } 1133 selectorCache := testNewSelectorCache(identityCache) 1134 identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(identityFoo), labelsFoo) 1135 1136 tests := []struct { 1137 test int 1138 rules api.Rules 1139 expected MapState 1140 }{ 1141 // The following table is derived from the Google Doc here: 1142 // https://docs.google.com/spreadsheets/d/1WANIoZGB48nryylQjjOw6lKjI80eVgPShrdMTMalLEw/edit?usp=sharing 1143 // 1144 // Rule 0 | Rule 1 | Rule 2 | Rule 3 | Rule 4 | Rule 5 | Rule 6 | Rule 7 | Desired BPF map state 1145 {0, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(nil)}, 1146 {1, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1147 {2, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})}, 1148 {3, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1149 {4, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3L4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7None_(lblsL3L4__Allow)})}, 1150 {5, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3L4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7None_(lblsL3L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1151 {6, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3L4__Allow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})}, // identical L3L4 entry suppressed 1152 {7, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3L4__Allow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed 1153 {8, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})}, 1154 {9, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1155 {10, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, rule____NoAllow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})}, 1156 {11, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, rule____NoAllow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1157 {12, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, ruleL3L4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})}, // L3L4 entry suppressed to allow L4-only entry to redirect 1158 {13, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, ruleL3L4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // L3L4 entry suppressed to allow L4-only entry to redirect 1159 {14, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, ruleL3L4__Allow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})}, // L3L4 entry suppressed to allow L4-only entry to redirect 1160 {15, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, ruleL3L4__Allow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // L3L4 entry suppressed to allow L4-only entry to redirect 1161 {16, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow)})}, 1162 {17, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1163 {18, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, rule____NoAllow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})}, 1164 {19, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, rule____NoAllow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1165 {20, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, ruleL3L4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow)})}, 1166 {21, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, ruleL3L4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1167 {22, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, ruleL3L4__Allow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})}, 1168 {23, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, ruleL3L4__Allow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1169 {24, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})}, // identical L3L4 entry suppressed 1170 {25, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed 1171 {26, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, rule____NoAllow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})}, // identical L3L4 entry suppressed 1172 {27, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, rule____NoAllow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed 1173 {28, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, ruleL3L4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})}, // identical L3L4 entry suppressed 1174 {29, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, ruleL3L4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed 1175 {30, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, ruleL3L4__Allow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})}, // identical L3L4 entry suppressed 1176 {31, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, ruleL3L4__Allow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed 1177 } 1178 1179 expectedMapState := generateMapStates() 1180 // Add the auto generated test cases for the deny policies 1181 generatedIdx := 32 1182 for i := generatedIdx; i < 256; i++ { 1183 tests = append(tests, 1184 struct { 1185 test int 1186 rules api.Rules 1187 expected MapState 1188 }{ 1189 test: i, 1190 rules: generateRule(i), 1191 expected: expectedMapState[i], 1192 }) 1193 } 1194 1195 for i, tt := range tests { 1196 repo := newPolicyDistillery(selectorCache) 1197 generatedRule := generateRule(tt.test) 1198 for _, r := range tt.rules { 1199 if r != nil { 1200 rule := r.WithEndpointSelector(selectFoo_) 1201 _, _ = repo.MustAddList(api.Rules{rule}) 1202 } 1203 } 1204 t.Run(fmt.Sprintf("permutation_%d", tt.test), func(t *testing.T) { 1205 logBuffer := new(bytes.Buffer) 1206 repo = repo.WithLogBuffer(logBuffer) 1207 mapstate, err := repo.distillPolicy(DummyOwner{}, labelsFoo, identity) 1208 if err != nil { 1209 t.Errorf("Policy resolution failure: %s", err) 1210 } 1211 // Ignore generated rules as they lap LabelArrayList which would 1212 // make the tests fail. 1213 if i < generatedIdx { 1214 if equal := assert.True(t, mapstate.Equals(tt.expected), mapstate.Diff(tt.expected)); !equal { 1215 require.EqualExportedValuesf(t, tt.expected, mapstate, "Policy obtained didn't match expected for endpoint %s", labelsFoo) 1216 t.Logf("Rules:\n%s\n\n", tt.rules.String()) 1217 t.Logf("Policy Trace: \n%s\n", logBuffer.String()) 1218 t.Errorf("Policy obtained didn't match expected for endpoint %s", labelsFoo) 1219 } 1220 } 1221 // It is extremely difficult to derive the "DerivedFromRules" field. 1222 // Since this field is only used for debuggability purposes we can 1223 // ignore it and test only for the MapState that we are expecting 1224 // to be plumbed into the datapath. 1225 mapstate.ForEach(func(k Key, v MapStateEntry) bool { 1226 if v.DerivedFromRules == nil || len(v.DerivedFromRules) == 0 { 1227 return true 1228 } 1229 v.DerivedFromRules = labels.LabelArrayList(nil).Sort() 1230 mapstate.Insert(k, v) 1231 return true 1232 }) 1233 if equal := assert.EqualExportedValues(t, expectedMapState[tt.test], mapstate); !equal { 1234 t.Logf("Rules:\n%s\n\n", tt.rules.String()) 1235 t.Logf("Policy Trace: \n%s\n", logBuffer.String()) 1236 t.Error("Policy obtained didn't match expected for endpoint") 1237 } 1238 if equal := assert.ElementsMatch(t, tt.rules, generatedRule); !equal { 1239 t.Logf("Rules:\n%s\n\n", tt.rules.String()) 1240 t.Logf("Policy Trace: \n%s\n", logBuffer.String()) 1241 t.Error("Generated rules didn't match manual rules") 1242 } 1243 }) 1244 } 1245 } 1246 1247 func Test_MergeRulesWithNamedPorts(t *testing.T) { 1248 // Cache policy enforcement value from when test was ran to avoid pollution 1249 // across tests. 1250 oldPolicyEnable := GetPolicyEnabled() 1251 defer SetPolicyEnabled(oldPolicyEnable) 1252 1253 SetPolicyEnabled(option.DefaultEnforcement) 1254 1255 identityCache := identity.IdentityMap{ 1256 identity.NumericIdentity(identityFoo): labelsFoo, 1257 } 1258 selectorCache := testNewSelectorCache(identityCache) 1259 identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(identityFoo), labelsFoo) 1260 1261 tests := []struct { 1262 test int 1263 rules api.Rules 1264 expected MapState 1265 }{ 1266 // The following table is derived from the Google Doc here: 1267 // https://docs.google.com/spreadsheets/d/1WANIoZGB48nryylQjjOw6lKjI80eVgPShrdMTMalLEw/edit?usp=sharing 1268 // 1269 // Rule 0 | Rule 1 | Rule 2 | Rule 3 | Rule 4 | Rule 5 | Rule 6 | Rule 7 | Desired BPF map state 1270 {0, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(nil)}, 1271 {1, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1272 {2, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})}, 1273 {3, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1274 {4, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3npL4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7None_(lblsL3L4__Allow)})}, 1275 {5, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3npL4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7None_(lblsL3L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1276 {6, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3npL4__Allow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})}, // identical L3L4 entry suppressed 1277 {7, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3npL4__Allow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed 1278 {8, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})}, 1279 {9, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1280 {10, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, rule____NoAllow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})}, 1281 {11, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, rule____NoAllow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1282 {12, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, ruleL3npL4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})}, // L3L4 entry suppressed to allow L4-only entry to redirect 1283 {13, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, ruleL3npL4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // L3L4 entry suppressed to allow L4-only entry to redirect 1284 {14, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, ruleL3npL4__Allow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})}, // L3L4 entry suppressed to allow L4-only entry to redirect 1285 {15, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, ruleL3npL4__Allow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // L3L4 entry suppressed to allow L4-only entry to redirect 1286 {16, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow)})}, 1287 {17, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1288 {18, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, rule____NoAllow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})}, 1289 {19, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, rule____NoAllow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1290 {20, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, ruleL3npL4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow)})}, 1291 {21, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, ruleL3npL4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1292 {22, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, ruleL3npL4__Allow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})}, 1293 {23, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, ruleL3npL4__Allow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, 1294 {24, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})}, // identical L3L4 entry suppressed 1295 {25, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed 1296 {26, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, rule____NoAllow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})}, // identical L3L4 entry suppressed 1297 {27, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, rule____NoAllow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed 1298 {28, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, ruleL3npL4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})}, // identical L3L4 entry suppressed 1299 {29, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, ruleL3npL4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed 1300 {30, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, ruleL3npL4__Allow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})}, // identical L3L4 entry suppressed 1301 {31, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, ruleL3npL4__Allow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed 1302 } 1303 for _, tt := range tests { 1304 repo := newPolicyDistillery(selectorCache) 1305 for _, r := range tt.rules { 1306 if r != nil { 1307 rule := r.WithEndpointSelector(selectFoo_) 1308 _, _ = repo.MustAddList(api.Rules{rule}) 1309 } 1310 } 1311 t.Run(fmt.Sprintf("permutation_%d", tt.test), func(t *testing.T) { 1312 logBuffer := new(bytes.Buffer) 1313 repo = repo.WithLogBuffer(logBuffer) 1314 mapstate, err := repo.distillPolicy(DummyOwner{}, labelsFoo, identity) 1315 if err != nil { 1316 t.Errorf("Policy resolution failure: %s", err) 1317 } 1318 require.Truef(t, mapstate.Equals(tt.expected), 1319 "Policy obtained didn't match expected for endpoint %s:\n%s", labelsFoo, mapstate.Diff(tt.expected)) 1320 }) 1321 } 1322 } 1323 1324 func Test_AllowAll(t *testing.T) { 1325 // Cache policy enforcement value from when test was ran to avoid pollution 1326 // across tests. 1327 oldPolicyEnable := GetPolicyEnabled() 1328 defer SetPolicyEnabled(oldPolicyEnable) 1329 1330 SetPolicyEnabled(option.DefaultEnforcement) 1331 1332 identityCache := identity.IdentityMap{ 1333 identity.NumericIdentity(identityFoo): labelsFoo, 1334 identity.NumericIdentity(identityBar): labelsBar, 1335 } 1336 selectorCache := testNewSelectorCache(identityCache) 1337 identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(identityFoo), labelsFoo) 1338 1339 tests := []struct { 1340 test int 1341 selector api.EndpointSelector 1342 rules api.Rules 1343 expected MapState 1344 }{ 1345 {0, api.EndpointSelectorNone, api.Rules{rule____AllowAll}, NewMapState(map[Key]MapStateEntry{mapKeyAllowAll__: mapEntryL7None_(lblsAllowAllIngress)})}, 1346 {1, api.WildcardEndpointSelector, api.Rules{rule____AllowAll}, NewMapState(map[Key]MapStateEntry{mapKeyAllowAll__: mapEntryL7None_(lbls____AllowAll)})}, 1347 } 1348 1349 for _, tt := range tests { 1350 repo := newPolicyDistillery(selectorCache) 1351 for _, r := range tt.rules { 1352 if r != nil { 1353 rule := r.WithEndpointSelector(tt.selector) 1354 _, _ = repo.MustAddList(api.Rules{rule}) 1355 } 1356 } 1357 t.Run(fmt.Sprintf("permutation_%d", tt.test), func(t *testing.T) { 1358 logBuffer := new(bytes.Buffer) 1359 repo = repo.WithLogBuffer(logBuffer) 1360 mapstate, err := repo.distillPolicy(DummyOwner{}, labelsFoo, identity) 1361 if err != nil { 1362 t.Errorf("Policy resolution failure: %s", err) 1363 } 1364 if equal := assert.True(t, mapstate.Equals(tt.expected), mapstate.Diff(tt.expected)); !equal { 1365 t.Logf("Rules:\n%s\n\n", tt.rules.String()) 1366 t.Logf("Policy Trace: \n%s\n", logBuffer.String()) 1367 t.Errorf("Policy obtained didn't match expected for endpoint %s", labelsFoo) 1368 } 1369 }) 1370 } 1371 } 1372 1373 var ( 1374 ruleAllowAllIngress = api.NewRule().WithIngressRules([]api.IngressRule{{ 1375 IngressCommonRule: api.IngressCommonRule{ 1376 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 1377 }}}).WithEndpointSelector(api.WildcardEndpointSelector) 1378 ruleL3DenyWorld = api.NewRule().WithIngressDenyRules([]api.IngressDenyRule{{ 1379 IngressCommonRule: api.IngressCommonRule{ 1380 FromEntities: api.EntitySlice{api.EntityWorld}, 1381 }, 1382 }}).WithEgressDenyRules([]api.EgressDenyRule{{ 1383 EgressCommonRule: api.EgressCommonRule{ 1384 ToEntities: api.EntitySlice{api.EntityWorld}, 1385 }, 1386 }}).WithEndpointSelector(api.WildcardEndpointSelector) 1387 1388 cpyRule = *ruleL3DenyWorld 1389 ruleL3DenyWorldWithLabels = (&cpyRule).WithLabels(labels.LabelWorld.LabelArray()) 1390 worldReservedID = identity.ReservedIdentityWorld.Uint32() 1391 mapKeyL3WorldIngress = key(worldReservedID, 0, 0, trafficdirection.Ingress.Uint8()) 1392 mapKeyL3WorldEgress = key(worldReservedID, 0, 0, trafficdirection.Egress.Uint8()) 1393 mapEntryDeny = MapStateEntry{ 1394 ProxyPort: 0, 1395 DerivedFromRules: labels.LabelArrayList{nil}, 1396 IsDeny: true, 1397 owners: map[MapStateOwner]struct{}{}, 1398 } 1399 mapEntryAllow = MapStateEntry{ 1400 ProxyPort: 0, 1401 DerivedFromRules: labels.LabelArrayList{nil}, 1402 owners: map[MapStateOwner]struct{}{}, 1403 } 1404 worldLabelArrayList = labels.LabelArrayList{labels.LabelWorld.LabelArray()} 1405 mapEntryWorldDenyWithLabels = MapStateEntry{ 1406 ProxyPort: 0, 1407 DerivedFromRules: worldLabelArrayList, 1408 IsDeny: true, 1409 owners: map[MapStateOwner]struct{}{}, 1410 } 1411 1412 worldIPIdentity = localIdentity(16324) 1413 worldIPCIDR = api.CIDR("192.0.2.3/32") 1414 lblWorldIP = labels.ParseSelectLabelArray(fmt.Sprintf("%s:%s", labels.LabelSourceCIDR, worldIPCIDR)) 1415 hostIPv4 = api.CIDR("172.19.0.1/32") 1416 hostIPv6 = api.CIDR("fc00:c111::3/64") 1417 lblHostIPv4CIDR = labels.GetCIDRLabels(netip.MustParsePrefix(string(hostIPv4))) 1418 lblHostIPv6CIDR = labels.GetCIDRLabels(netip.MustParsePrefix(string(hostIPv6))) 1419 1420 ruleL3AllowWorldIP = api.NewRule().WithIngressRules([]api.IngressRule{{ 1421 IngressCommonRule: api.IngressCommonRule{ 1422 FromCIDR: api.CIDRSlice{worldIPCIDR}, 1423 }, 1424 }}).WithEgressRules([]api.EgressRule{{ 1425 EgressCommonRule: api.EgressCommonRule{ 1426 ToCIDR: api.CIDRSlice{worldIPCIDR}, 1427 }, 1428 }}).WithEndpointSelector(api.WildcardEndpointSelector) 1429 1430 worldSubnetIdentity = localIdentity(16325) 1431 worldSubnet = api.CIDR("192.0.2.0/24") 1432 worldSubnetRule = api.CIDRRule{ 1433 Cidr: worldSubnet, 1434 } 1435 lblWorldSubnet = labels.GetCIDRLabels(netip.MustParsePrefix(string(worldSubnet))) 1436 ruleL3DenySubnet = api.NewRule().WithIngressDenyRules([]api.IngressDenyRule{{ 1437 IngressCommonRule: api.IngressCommonRule{ 1438 FromCIDRSet: api.CIDRRuleSlice{worldSubnetRule}, 1439 }, 1440 }}).WithEgressDenyRules([]api.EgressDenyRule{{ 1441 EgressCommonRule: api.EgressCommonRule{ 1442 ToCIDRSet: api.CIDRRuleSlice{worldSubnetRule}, 1443 }, 1444 }}).WithEndpointSelector(api.WildcardEndpointSelector) 1445 mapKeyL3SubnetIngress = key(worldSubnetIdentity.Uint32(), 0, 0, trafficdirection.Ingress.Uint8()) 1446 mapKeyL3SubnetEgress = key(worldSubnetIdentity.Uint32(), 0, 0, trafficdirection.Egress.Uint8()) 1447 1448 ruleL3DenySmallerSubnet = api.NewRule().WithIngressDenyRules([]api.IngressDenyRule{{ 1449 IngressCommonRule: api.IngressCommonRule{ 1450 FromCIDRSet: api.CIDRRuleSlice{api.CIDRRule{Cidr: worldIPCIDR}}, 1451 }, 1452 }}).WithEgressDenyRules([]api.EgressDenyRule{{ 1453 EgressCommonRule: api.EgressCommonRule{ 1454 ToCIDRSet: api.CIDRRuleSlice{api.CIDRRule{Cidr: worldIPCIDR}}, 1455 }, 1456 }}).WithEndpointSelector(api.WildcardEndpointSelector) 1457 1458 ruleL3AllowLargerSubnet = api.NewRule().WithIngressRules([]api.IngressRule{{ 1459 IngressCommonRule: api.IngressCommonRule{ 1460 FromCIDRSet: api.CIDRRuleSlice{api.CIDRRule{Cidr: worldSubnet}}, 1461 }, 1462 }}).WithEgressRules([]api.EgressRule{{ 1463 EgressCommonRule: api.EgressCommonRule{ 1464 ToCIDRSet: api.CIDRRuleSlice{api.CIDRRule{Cidr: worldSubnet}}, 1465 }, 1466 }}).WithEndpointSelector(api.WildcardEndpointSelector) 1467 1468 mapKeyL3WorldIPIngress = key(worldIPIdentity.Uint32(), 0, 0, trafficdirection.Ingress.Uint8()) 1469 mapKeyL3WorldIPEgress = key(worldIPIdentity.Uint32(), 0, 0, trafficdirection.Egress.Uint8()) 1470 1471 ruleL3AllowHostEgress = api.NewRule().WithEgressRules([]api.EgressRule{{ 1472 EgressCommonRule: api.EgressCommonRule{ 1473 ToCIDRSet: api.CIDRRuleSlice{api.CIDRRule{Cidr: hostIPv4}, api.CIDRRule{Cidr: hostIPv6}}, 1474 }, 1475 }}).WithEndpointSelector(api.WildcardEndpointSelector) 1476 1477 mapKeyL3UnknownIngress = key(identity.IdentityUnknown.Uint32(), 0, 0, trafficdirection.Ingress.Uint8()) 1478 derivedFrom = labels.LabelArrayList{ 1479 labels.LabelArray{ 1480 labels.NewLabel(LabelKeyPolicyDerivedFrom, LabelAllowAnyIngress, labels.LabelSourceReserved), 1481 }, 1482 } 1483 mapEntryL3UnknownIngress = NewMapStateEntry(nil, derivedFrom, 0, "", 0, false, ExplicitAuthType, AuthTypeDisabled) 1484 mapKeyL3HostEgress = key(identity.ReservedIdentityHost.Uint32(), 0, 0, trafficdirection.Egress.Uint8()) 1485 ruleL3L4Port8080ProtoAnyDenyWorld = api.NewRule().WithIngressDenyRules([]api.IngressDenyRule{ 1486 { 1487 ToPorts: api.PortDenyRules{ 1488 api.PortDenyRule{ 1489 Ports: []api.PortProtocol{ 1490 { 1491 Port: "8080", 1492 Protocol: api.ProtoAny, 1493 }, 1494 }, 1495 }, 1496 }, 1497 IngressCommonRule: api.IngressCommonRule{ 1498 FromEntities: api.EntitySlice{api.EntityWorld}, 1499 }, 1500 }, 1501 }).WithEgressDenyRules([]api.EgressDenyRule{ 1502 { 1503 ToPorts: api.PortDenyRules{ 1504 api.PortDenyRule{ 1505 Ports: []api.PortProtocol{ 1506 { 1507 Port: "8080", 1508 Protocol: api.ProtoAny, 1509 }, 1510 }, 1511 }, 1512 }, 1513 EgressCommonRule: api.EgressCommonRule{ 1514 ToEntities: api.EntitySlice{api.EntityWorld}, 1515 }, 1516 }, 1517 }).WithEndpointSelector(api.WildcardEndpointSelector) 1518 mapKeyL3L4Port8080ProtoTCPWorldIngress = key(worldReservedID, 8080, 6, trafficdirection.Ingress.Uint8()) 1519 mapKeyL3L4Port8080ProtoTCPWorldEgress = key(worldReservedID, 8080, 6, trafficdirection.Egress.Uint8()) 1520 mapKeyL3L4Port8080ProtoUDPWorldIngress = key(worldReservedID, 8080, 17, trafficdirection.Ingress.Uint8()) 1521 mapKeyL3L4Port8080ProtoUDPWorldEgress = key(worldReservedID, 8080, 17, trafficdirection.Egress.Uint8()) 1522 mapKeyL3L4Port8080ProtoSCTPWorldIngress = key(worldReservedID, 8080, 132, trafficdirection.Ingress.Uint8()) 1523 mapKeyL3L4Port8080ProtoSCTPWorldEgress = key(worldReservedID, 8080, 132, trafficdirection.Egress.Uint8()) 1524 1525 mapKeyL3L4Port8080ProtoTCPWorldSNIngress = key(worldSubnetIdentity.Uint32(), 8080, 6, trafficdirection.Ingress.Uint8()) 1526 mapKeyL3L4Port8080ProtoTCPWorldSNEgress = key(worldSubnetIdentity.Uint32(), 8080, 6, trafficdirection.Egress.Uint8()) 1527 mapKeyL3L4Port8080ProtoUDPWorldSNIngress = key(worldSubnetIdentity.Uint32(), 8080, 17, trafficdirection.Ingress.Uint8()) 1528 mapKeyL3L4Port8080ProtoUDPWorldSNEgress = key(worldSubnetIdentity.Uint32(), 8080, 17, trafficdirection.Egress.Uint8()) 1529 mapKeyL3L4Port8080ProtoSCTPWorldSNIngress = key(worldSubnetIdentity.Uint32(), 8080, 132, trafficdirection.Ingress.Uint8()) 1530 mapKeyL3L4Port8080ProtoSCTPWorldSNEgress = key(worldSubnetIdentity.Uint32(), 8080, 132, trafficdirection.Egress.Uint8()) 1531 1532 mapKeyL3L4Port8080ProtoTCPWorldIPIngress = key(worldIPIdentity.Uint32(), 8080, 6, trafficdirection.Ingress.Uint8()) 1533 mapKeyL3L4Port8080ProtoTCPWorldIPEgress = key(worldIPIdentity.Uint32(), 8080, 6, trafficdirection.Egress.Uint8()) 1534 mapKeyL3L4Port8080ProtoUDPWorldIPIngress = key(worldIPIdentity.Uint32(), 8080, 17, trafficdirection.Ingress.Uint8()) 1535 mapKeyL3L4Port8080ProtoUDPWorldIPEgress = key(worldIPIdentity.Uint32(), 8080, 17, trafficdirection.Egress.Uint8()) 1536 mapKeyL3L4Port8080ProtoSCTPWorldIPIngress = key(worldIPIdentity.Uint32(), 8080, 132, trafficdirection.Ingress.Uint8()) 1537 mapKeyL3L4Port8080ProtoSCTPWorldIPEgress = key(worldIPIdentity.Uint32(), 8080, 132, trafficdirection.Egress.Uint8()) 1538 1539 ruleL3AllowWorldSubnet = api.NewRule().WithIngressRules([]api.IngressRule{{ 1540 ToPorts: api.PortRules{ 1541 api.PortRule{ 1542 Ports: []api.PortProtocol{ 1543 { 1544 Port: "8080", 1545 Protocol: api.ProtoAny, 1546 }, 1547 }, 1548 }, 1549 }, 1550 IngressCommonRule: api.IngressCommonRule{ 1551 FromCIDR: api.CIDRSlice{worldSubnet}, 1552 }, 1553 }}).WithEgressRules([]api.EgressRule{{ 1554 ToPorts: api.PortRules{ 1555 api.PortRule{ 1556 Ports: []api.PortProtocol{ 1557 { 1558 Port: "8080", 1559 Protocol: api.ProtoAny, 1560 }, 1561 }, 1562 }, 1563 }, 1564 EgressCommonRule: api.EgressCommonRule{ 1565 ToCIDR: api.CIDRSlice{worldSubnet}, 1566 }, 1567 }}).WithEndpointSelector(api.WildcardEndpointSelector) 1568 1569 ruleL3DenyWorldIP = api.NewRule().WithIngressDenyRules([]api.IngressDenyRule{{ 1570 IngressCommonRule: api.IngressCommonRule{ 1571 FromCIDR: api.CIDRSlice{worldIPCIDR}, 1572 }, 1573 }}).WithEgressDenyRules([]api.EgressDenyRule{{ 1574 EgressCommonRule: api.EgressCommonRule{ 1575 ToCIDR: api.CIDRSlice{worldIPCIDR}, 1576 }, 1577 }}).WithEndpointSelector(api.WildcardEndpointSelector) 1578 mapKeyAnyIngress = key(0, 0, 0, trafficdirection.Ingress.Uint8()) 1579 mapKeyL4AnyPortProtoWorldIPIngress = key(worldIPIdentity.Uint32(), 0, 0, trafficdirection.Ingress.Uint8()) 1580 mapKeyL4AnyPortProtoWorldIPEgress = key(worldIPIdentity.Uint32(), 0, 0, trafficdirection.Egress.Uint8()) 1581 mapKeyL4Port8080ProtoTCPWorldIPIngress = key(worldIPIdentity.Uint32(), 8080, 6, trafficdirection.Ingress.Uint8()) 1582 mapKeyL4Port8080ProtoTCPWorldIPEgress = key(worldIPIdentity.Uint32(), 8080, 6, trafficdirection.Egress.Uint8()) 1583 mapKeyL4Port8080ProtoUDPWorldIPIngress = key(worldIPIdentity.Uint32(), 8080, 17, trafficdirection.Ingress.Uint8()) 1584 mapKeyL4Port8080ProtoUDPWorldIPEgress = key(worldIPIdentity.Uint32(), 8080, 17, trafficdirection.Egress.Uint8()) 1585 mapKeyL4Port8080ProtoSCTPWorldIPIngress = key(worldIPIdentity.Uint32(), 8080, 132, trafficdirection.Ingress.Uint8()) 1586 mapKeyL4Port8080ProtoSCTPWorldIPEgress = key(worldIPIdentity.Uint32(), 8080, 132, trafficdirection.Egress.Uint8()) 1587 mapEntryL4WorldIPDependentsIngressDeny = MapStateEntry{ 1588 ProxyPort: 0, 1589 IsDeny: true, 1590 DerivedFromRules: labels.LabelArrayList{nil}, 1591 owners: map[MapStateOwner]struct{}{}, 1592 dependents: Keys{ 1593 mapKeyL4Port8080ProtoTCPWorldIPIngress: struct{}{}, 1594 mapKeyL4Port8080ProtoUDPWorldIPIngress: struct{}{}, 1595 mapKeyL4Port8080ProtoSCTPWorldIPIngress: struct{}{}, 1596 }, 1597 } 1598 mapEntryL4WorldIPDependentsEgressDeny = MapStateEntry{ 1599 ProxyPort: 0, 1600 IsDeny: true, 1601 DerivedFromRules: labels.LabelArrayList{nil}, 1602 owners: map[MapStateOwner]struct{}{}, 1603 dependents: Keys{ 1604 mapKeyL4Port8080ProtoTCPWorldIPEgress: struct{}{}, 1605 mapKeyL4Port8080ProtoUDPWorldIPEgress: struct{}{}, 1606 mapKeyL4Port8080ProtoSCTPWorldIPEgress: struct{}{}, 1607 }, 1608 } 1609 1610 ruleL3AllowWorldSubnetNamedPort = api.NewRule().WithIngressRules([]api.IngressRule{{ 1611 ToPorts: api.PortRules{ 1612 api.PortRule{ 1613 Ports: []api.PortProtocol{ 1614 { 1615 Port: "http", 1616 Protocol: api.ProtoTCP, 1617 }, 1618 }, 1619 }, 1620 }, 1621 IngressCommonRule: api.IngressCommonRule{ 1622 FromCIDR: api.CIDRSlice{worldSubnet}, 1623 }, 1624 }}).WithEndpointSelector(api.WildcardEndpointSelector) 1625 mapKeyL3L4NamedPortHTTPProtoTCPWorldSubNetIngress = key(worldSubnetIdentity.Uint32(), 80, 6, trafficdirection.Ingress.Uint8()) 1626 mapKeyL3L4NamedPortHTTPProtoTCPWorldIPIngress = key(worldIPIdentity.Uint32(), 80, 6, trafficdirection.Ingress.Uint8()) 1627 1628 ruleL3AllowWorldSubnetPortRange = api.NewRule().WithIngressRules([]api.IngressRule{{ 1629 ToPorts: api.PortRules{ 1630 api.PortRule{ 1631 Ports: []api.PortProtocol{ 1632 { 1633 Port: "64", 1634 EndPort: 127, 1635 Protocol: api.ProtoTCP, 1636 }, 1637 { 1638 Port: "5", 1639 EndPort: 10, 1640 Protocol: api.ProtoTCP, 1641 }, 1642 }, 1643 }, 1644 }, 1645 IngressCommonRule: api.IngressCommonRule{ 1646 FromCIDR: api.CIDRSlice{worldSubnet}, 1647 }, 1648 }}).WithEndpointSelector(api.WildcardEndpointSelector) 1649 mapKeyL3L4Port64To127ProtoTCPWorldSubNetIngress = keyWithPortMask(worldSubnetIdentity.Uint32(), 64, 0xffc0, 6, trafficdirection.Ingress.Uint8()) 1650 mapKeyL3L4Port5ProtoTCPWorldSubNetIngress = key(worldSubnetIdentity.Uint32(), 5, 6, trafficdirection.Ingress.Uint8()) 1651 mapKeyL3L4Port6To7ProtoTCPWorldSubNetIngress = keyWithPortMask(worldSubnetIdentity.Uint32(), 6, 0xfffe, 6, trafficdirection.Ingress.Uint8()) 1652 mapKeyL3L4Port8To9ProtoTCPWorldSubNetIngress = keyWithPortMask(worldSubnetIdentity.Uint32(), 8, 0xfffe, 6, trafficdirection.Ingress.Uint8()) 1653 mapKeyL3L4Port10ProtoTCPWorldSubNetIngress = key(worldSubnetIdentity.Uint32(), 10, 6, trafficdirection.Ingress.Uint8()) 1654 mapKeyL3L4Port64To127ProtoTCPWorldIPIngress = keyWithPortMask(worldIPIdentity.Uint32(), 64, 0xffc0, 6, trafficdirection.Ingress.Uint8()) 1655 mapKeyL3L4Port5ProtoTCPWorldIPIngress = key(worldIPIdentity.Uint32(), 5, 6, trafficdirection.Ingress.Uint8()) 1656 mapKeyL3L4Port6To7ProtoTCPWorldIPIngress = keyWithPortMask(worldIPIdentity.Uint32(), 6, 0xfffe, 6, trafficdirection.Ingress.Uint8()) 1657 mapKeyL3L4Port8To9ProtoTCPWorldIPIngress = keyWithPortMask(worldIPIdentity.Uint32(), 8, 0xfffe, 6, trafficdirection.Ingress.Uint8()) 1658 mapKeyL3L4Port10ProtoTCPWorldIPIngress = key(worldIPIdentity.Uint32(), 10, 6, trafficdirection.Ingress.Uint8()) 1659 ) 1660 1661 func Test_EnsureDeniesPrecedeAllows(t *testing.T) { 1662 // Cache policy enforcement value from when test was ran to avoid pollution 1663 // across tests. 1664 oldPolicyEnable := GetPolicyEnabled() 1665 defer SetPolicyEnabled(oldPolicyEnable) 1666 1667 SetPolicyEnabled(option.DefaultEnforcement) 1668 1669 identityCache := identity.IdentityMap{ 1670 identity.NumericIdentity(identityFoo): labelsFoo, 1671 identity.ReservedIdentityWorld: labels.LabelWorld.LabelArray(), 1672 worldIPIdentity: lblWorldIP, // "192.0.2.3/32" 1673 worldSubnetIdentity: lblWorldSubnet.LabelArray(), // "192.0.2.0/24" 1674 } 1675 selectorCache := testNewSelectorCache(identityCache) 1676 identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(identityFoo), labelsFoo) 1677 1678 tests := []struct { 1679 test string 1680 rules api.Rules 1681 expected MapState 1682 }{ 1683 {"deny_world_no_labels", api.Rules{ruleAllowAllIngress, ruleL3DenyWorld, ruleL3AllowWorldIP}, newMapState(map[Key]MapStateEntry{ 1684 mapKeyAnyIngress: mapEntryAllow, 1685 mapKeyL3WorldIngress: mapEntryDeny, 1686 mapKeyL3WorldEgress: mapEntryDeny, 1687 mapKeyL3SubnetIngress: mapEntryDeny, 1688 mapKeyL3SubnetEgress: mapEntryDeny, 1689 mapKeyL3WorldIPIngress: mapEntryDeny, 1690 mapKeyL3WorldIPEgress: mapEntryDeny, 1691 })}, {"deny_world_with_labels", api.Rules{ruleAllowAllIngress, ruleL3DenyWorldWithLabels, ruleL3AllowWorldIP}, newMapState(map[Key]MapStateEntry{ 1692 mapKeyAnyIngress: mapEntryAllow, 1693 mapKeyL3WorldIngress: mapEntryWorldDenyWithLabels, 1694 mapKeyL3WorldEgress: mapEntryWorldDenyWithLabels, 1695 mapKeyL3SubnetIngress: mapEntryDeny, 1696 mapKeyL3SubnetEgress: mapEntryDeny, 1697 mapKeyL3WorldIPIngress: mapEntryDeny, 1698 mapKeyL3WorldIPEgress: mapEntryDeny, 1699 })}, {"deny_one_ip_with_a_larger_subnet", api.Rules{ruleAllowAllIngress, ruleL3DenySubnet, ruleL3AllowWorldIP}, newMapState(map[Key]MapStateEntry{ 1700 mapKeyAnyIngress: mapEntryAllow, 1701 mapKeyL3SubnetIngress: mapEntryDeny, 1702 mapKeyL3SubnetEgress: mapEntryDeny, 1703 mapKeyL3WorldIPIngress: mapEntryDeny, 1704 mapKeyL3WorldIPEgress: mapEntryDeny, 1705 })}, {"deny_part_of_a_subnet_with_an_ip", api.Rules{ruleAllowAllIngress, ruleL3DenySmallerSubnet, ruleL3AllowLargerSubnet}, newMapState(map[Key]MapStateEntry{ 1706 mapKeyAnyIngress: mapEntryAllow, 1707 mapKeyL3WorldIPIngress: mapEntryDeny, 1708 mapKeyL3WorldIPEgress: mapEntryDeny, 1709 mapKeyL3SubnetIngress: mapEntryAllow, 1710 mapKeyL3SubnetEgress: mapEntryAllow, 1711 })}, {"broad_cidr_deny_is_a_portproto_subset_of_a_specific_cidr_allow", api.Rules{ruleAllowAllIngress, ruleL3L4Port8080ProtoAnyDenyWorld, ruleL3AllowWorldIP}, newMapState(map[Key]MapStateEntry{ 1712 mapKeyAnyIngress: mapEntryAllow, 1713 mapKeyL3L4Port8080ProtoTCPWorldIngress: mapEntryDeny, 1714 mapKeyL3L4Port8080ProtoTCPWorldEgress: mapEntryDeny, 1715 mapKeyL3L4Port8080ProtoUDPWorldIngress: mapEntryDeny, 1716 mapKeyL3L4Port8080ProtoUDPWorldEgress: mapEntryDeny, 1717 mapKeyL3L4Port8080ProtoSCTPWorldIngress: mapEntryDeny, 1718 mapKeyL3L4Port8080ProtoSCTPWorldEgress: mapEntryDeny, 1719 mapKeyL3L4Port8080ProtoTCPWorldSNIngress: mapEntryDeny, 1720 mapKeyL3L4Port8080ProtoTCPWorldSNEgress: mapEntryDeny, 1721 mapKeyL3L4Port8080ProtoUDPWorldSNIngress: mapEntryDeny, 1722 mapKeyL3L4Port8080ProtoUDPWorldSNEgress: mapEntryDeny, 1723 mapKeyL3L4Port8080ProtoSCTPWorldSNIngress: mapEntryDeny, 1724 mapKeyL3L4Port8080ProtoSCTPWorldSNEgress: mapEntryDeny, 1725 mapKeyL3L4Port8080ProtoTCPWorldIPIngress: mapEntryDeny, 1726 mapKeyL3L4Port8080ProtoTCPWorldIPEgress: mapEntryDeny, 1727 mapKeyL3L4Port8080ProtoUDPWorldIPIngress: mapEntryDeny, 1728 mapKeyL3L4Port8080ProtoUDPWorldIPEgress: mapEntryDeny, 1729 mapKeyL3L4Port8080ProtoSCTPWorldIPIngress: mapEntryDeny, 1730 mapKeyL3L4Port8080ProtoSCTPWorldIPEgress: mapEntryDeny, 1731 mapKeyL3WorldIPIngress: mapEntryAllow, 1732 mapKeyL3WorldIPEgress: mapEntryAllow, 1733 })}, {"broad_cidr_allow_is_a_portproto_subset_of_a_specific_cidr_deny", api.Rules{ruleAllowAllIngress, ruleL3AllowWorldSubnet, ruleL3DenyWorldIP}, newMapState(map[Key]MapStateEntry{ 1734 mapKeyAnyIngress: mapEntryAllow, 1735 mapKeyL3L4Port8080ProtoTCPWorldSNIngress: mapEntryAllow, 1736 mapKeyL3L4Port8080ProtoTCPWorldSNEgress: mapEntryAllow, 1737 mapKeyL3L4Port8080ProtoUDPWorldSNIngress: mapEntryAllow, 1738 mapKeyL3L4Port8080ProtoUDPWorldSNEgress: mapEntryAllow, 1739 mapKeyL3L4Port8080ProtoSCTPWorldSNIngress: mapEntryAllow, 1740 mapKeyL3L4Port8080ProtoSCTPWorldSNEgress: mapEntryAllow, 1741 mapKeyL4AnyPortProtoWorldIPIngress: mapEntryL4WorldIPDependentsIngressDeny, 1742 mapKeyL4AnyPortProtoWorldIPEgress: mapEntryL4WorldIPDependentsEgressDeny, 1743 mapKeyL4Port8080ProtoTCPWorldIPIngress: mapEntryDeny, 1744 mapKeyL4Port8080ProtoTCPWorldIPEgress: mapEntryDeny, 1745 mapKeyL4Port8080ProtoUDPWorldIPIngress: mapEntryDeny, 1746 mapKeyL4Port8080ProtoUDPWorldIPEgress: mapEntryDeny, 1747 mapKeyL4Port8080ProtoSCTPWorldIPIngress: mapEntryDeny, 1748 mapKeyL4Port8080ProtoSCTPWorldIPEgress: mapEntryDeny, 1749 })}, {"named_port_world_subnet", api.Rules{ruleAllowAllIngress, ruleL3AllowWorldSubnetNamedPort}, newMapState(map[Key]MapStateEntry{ 1750 mapKeyAnyIngress: mapEntryAllow, 1751 mapKeyL3L4NamedPortHTTPProtoTCPWorldSubNetIngress: mapEntryAllow, 1752 mapKeyL3L4NamedPortHTTPProtoTCPWorldIPIngress: mapEntryAllow, 1753 })}, {"port_range_world_subnet", api.Rules{ruleAllowAllIngress, ruleL3AllowWorldSubnetPortRange}, newMapState(map[Key]MapStateEntry{ 1754 mapKeyAnyIngress: mapEntryAllow, 1755 mapKeyL3L4Port64To127ProtoTCPWorldSubNetIngress: mapEntryAllow, 1756 mapKeyL3L4Port5ProtoTCPWorldSubNetIngress: mapEntryAllow, 1757 mapKeyL3L4Port6To7ProtoTCPWorldSubNetIngress: mapEntryAllow, 1758 mapKeyL3L4Port8To9ProtoTCPWorldSubNetIngress: mapEntryAllow, 1759 mapKeyL3L4Port10ProtoTCPWorldSubNetIngress: mapEntryAllow, 1760 mapKeyL3L4Port64To127ProtoTCPWorldIPIngress: mapEntryAllow, 1761 mapKeyL3L4Port5ProtoTCPWorldIPIngress: mapEntryAllow, 1762 mapKeyL3L4Port6To7ProtoTCPWorldIPIngress: mapEntryAllow, 1763 mapKeyL3L4Port8To9ProtoTCPWorldIPIngress: mapEntryAllow, 1764 mapKeyL3L4Port10ProtoTCPWorldIPIngress: mapEntryAllow, 1765 })}, 1766 } 1767 // Do not test in dualstack mode 1768 defer func(ipv4, ipv6 bool) { 1769 option.Config.EnableIPv4 = ipv4 1770 option.Config.EnableIPv6 = ipv6 1771 }(option.Config.EnableIPv4, option.Config.EnableIPv6) 1772 option.Config.EnableIPv4 = true 1773 option.Config.EnableIPv6 = false 1774 for _, tt := range tests { 1775 repo := newPolicyDistillery(selectorCache) 1776 for _, rule := range tt.rules { 1777 if rule != nil { 1778 _, _ = repo.MustAddList(api.Rules{rule}) 1779 } 1780 } 1781 t.Run(tt.test, func(t *testing.T) { 1782 logBuffer := new(bytes.Buffer) 1783 repo = repo.WithLogBuffer(logBuffer) 1784 mapstate, err := repo.distillPolicy(DummyOwner{}, labelsFoo, identity) 1785 if err != nil { 1786 t.Errorf("Policy resolution failure: %s", err) 1787 } 1788 if equal := assert.True(t, mapstate.Equals(tt.expected), mapstate.Diff(tt.expected)); !equal { 1789 t.Logf("Policy Trace: \n%s\n", logBuffer.String()) 1790 t.Errorf("Policy test, %q, obtained didn't match expected for endpoint %s", tt.test, labelsFoo) 1791 } 1792 }) 1793 } 1794 } 1795 1796 func Test_EnsureEntitiesSelectableByCIDR(t *testing.T) { 1797 // Cache policy enforcement value from when test was ran to avoid pollution 1798 // across tests. 1799 oldPolicyEnable := GetPolicyEnabled() 1800 defer SetPolicyEnabled(oldPolicyEnable) 1801 1802 SetPolicyEnabled(option.DefaultEnforcement) 1803 hostLabel := labels.NewFrom(labels.LabelHost) 1804 hostLabel.MergeLabels(lblHostIPv4CIDR) 1805 hostLabel.MergeLabels(lblHostIPv6CIDR) 1806 identityCache := identity.IdentityMap{ 1807 identity.NumericIdentity(identityFoo): labelsFoo, 1808 identity.ReservedIdentityHost: hostLabel.LabelArray(), 1809 } 1810 selectorCache := testNewSelectorCache(identityCache) 1811 identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(identityFoo), labelsFoo) 1812 1813 tests := []struct { 1814 test string 1815 rules api.Rules 1816 expected MapState 1817 }{ 1818 {"host_cidr_select", api.Rules{ruleL3AllowHostEgress}, newMapState(map[Key]MapStateEntry{ 1819 mapKeyL3UnknownIngress: mapEntryL3UnknownIngress, 1820 mapKeyL3HostEgress: mapEntryAllow, 1821 })}, 1822 } 1823 1824 for _, tt := range tests { 1825 repo := newPolicyDistillery(selectorCache) 1826 for _, rule := range tt.rules { 1827 if rule != nil { 1828 _, _ = repo.MustAddList(api.Rules{rule}) 1829 } 1830 } 1831 t.Run(tt.test, func(t *testing.T) { 1832 logBuffer := new(bytes.Buffer) 1833 repo = repo.WithLogBuffer(logBuffer) 1834 mapstate, err := repo.distillPolicy(DummyOwner{}, labelsFoo, identity) 1835 if err != nil { 1836 t.Errorf("Policy resolution failure: %s", err) 1837 } 1838 if equal := assert.True(t, mapstate.Equals(tt.expected), mapstate.Diff(tt.expected)); !equal { 1839 t.Logf("Policy Trace: \n%s\n", logBuffer.String()) 1840 t.Errorf("Policy test, %q, obtained didn't match expected for endpoint %s", tt.test, labelsFoo) 1841 } 1842 }) 1843 } 1844 } 1845 1846 func mapStateAllowsKey(ms *mapState, key Key) bool { 1847 var ok bool 1848 ms.denies.trie.Ancestors(key.PrefixLength(), key, 1849 func(_ uint, _ bitlpm.Key[types.Key], idMap map[identity.NumericIdentity]MapStateEntry) bool { 1850 if _, exists := idMap[identity.NumericIdentity(key.Identity)]; exists { 1851 ok = true 1852 } 1853 return true 1854 }) 1855 if ok { 1856 return false 1857 } 1858 ms.allows.trie.Ancestors(key.PrefixLength(), key, 1859 func(_ uint, _ bitlpm.Key[types.Key], idMap map[identity.NumericIdentity]MapStateEntry) bool { 1860 1861 if _, exists := idMap[identity.NumericIdentity(key.Identity)]; exists { 1862 ok = true 1863 } 1864 return true 1865 }) 1866 return ok 1867 } 1868 1869 func TestEgressPortRangePrecedence(t *testing.T) { 1870 td := newTestData() 1871 identityCache := identity.IdentityMap{ 1872 identity.NumericIdentity(100): labelsA, 1873 } 1874 td.sc.UpdateIdentities(identityCache, nil, &sync.WaitGroup{}) 1875 identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(100), labelsA) 1876 1877 type portRange struct { 1878 startPort, endPort uint16 1879 isAllow bool 1880 } 1881 tests := []struct { 1882 name string 1883 rules []portRange 1884 rangeTests []portRange 1885 }{ 1886 { 1887 name: "deny range (1-1024) covers port allow (80)", 1888 rules: []portRange{ 1889 {80, 0, true}, 1890 {1, 1024, false}, 1891 }, 1892 rangeTests: []portRange{ 1893 {79, 81, false}, 1894 {1023, 1025, false}, 1895 }, 1896 }, 1897 { 1898 name: "deny port (80) in broader allow range (1-1024)", 1899 rules: []portRange{ 1900 {80, 0, false}, 1901 {1, 1024, true}, 1902 }, 1903 rangeTests: []portRange{ 1904 {1, 2, true}, 1905 {79, 0, true}, 1906 {80, 0, false}, 1907 {81, 0, true}, 1908 {1023, 1024, true}, 1909 {1025, 1026, false}, 1910 }, 1911 }, 1912 { 1913 name: "wildcard deny (*) covers broad allow range (1-1024)", 1914 rules: []portRange{ 1915 {0, 0, false}, 1916 {1, 1024, true}, 1917 }, 1918 rangeTests: []portRange{ 1919 {1, 2, false}, 1920 {1023, 1025, false}, 1921 }, 1922 }, 1923 { 1924 name: "wildcard allow (*) has an deny range hole (1-1024)", 1925 rules: []portRange{ 1926 {0, 0, true}, 1927 {1, 1024, false}, 1928 }, 1929 rangeTests: []portRange{ 1930 {1, 2, false}, 1931 {1023, 1024, false}, 1932 {1025, 1026, true}, 1933 {65534, 0, true}, 1934 }, 1935 }, 1936 { 1937 name: "two allow ranges (80-90, 90-100) with overlapping deny (85-95)", 1938 rules: []portRange{ 1939 {80, 90, true}, 1940 {85, 95, false}, 1941 {90, 100, true}, 1942 }, 1943 rangeTests: []portRange{ 1944 {79, 0, false}, 1945 {80, 84, true}, 1946 {85, 95, false}, 1947 {96, 100, true}, 1948 {101, 0, true}, 1949 }, 1950 }, 1951 } 1952 1953 for _, tt := range tests { 1954 t.Run(tt.name, func(t *testing.T) { 1955 tr := &rule{ 1956 Rule: api.Rule{ 1957 EndpointSelector: endpointSelectorA, 1958 }, 1959 } 1960 for _, rul := range tt.rules { 1961 pp := api.PortProtocol{ 1962 Port: fmt.Sprintf("%d", rul.startPort), 1963 EndPort: int32(rul.endPort), 1964 Protocol: api.ProtoTCP, 1965 } 1966 if rul.isAllow { 1967 tr.Rule.Egress = append(tr.Rule.Egress, api.EgressRule{ 1968 EgressCommonRule: api.EgressCommonRule{ 1969 ToEndpoints: []api.EndpointSelector{endpointSelectorA}, 1970 }, 1971 ToPorts: []api.PortRule{{ 1972 Ports: []api.PortProtocol{pp}, 1973 }}, 1974 }) 1975 } else { 1976 tr.Rule.EgressDeny = append(tr.Rule.EgressDeny, api.EgressDenyRule{ 1977 EgressCommonRule: api.EgressCommonRule{ 1978 ToEndpoints: []api.EndpointSelector{endpointSelectorA}, 1979 }, 1980 ToPorts: []api.PortDenyRule{{ 1981 Ports: []api.PortProtocol{pp}, 1982 }}, 1983 }) 1984 } 1985 } 1986 buffer := new(bytes.Buffer) 1987 ctxFromA := SearchContext{From: labelsA, Trace: TRACE_VERBOSE} 1988 ctxFromA.Logging = stdlog.New(buffer, "", 0) 1989 defer t.Log(buffer) 1990 1991 require.NoError(t, tr.Sanitize()) 1992 state := traceState{} 1993 res, err := tr.resolveEgressPolicy(td.testPolicyContext, &ctxFromA, &state, NewL4PolicyMap(), nil, nil) 1994 require.NoError(t, err) 1995 require.NotNil(t, res) 1996 1997 repo := newPolicyDistillery(td.sc) 1998 repo.MustAddList(api.Rules{&tr.Rule}) 1999 repo = repo.WithLogBuffer(buffer) 2000 ms, err := repo.distillPolicy(DummyOwner{}, labelsA, identity) 2001 2002 require.NoError(t, err) 2003 require.NotNil(t, ms) 2004 mapStateP, ok := ms.(*mapState) 2005 require.True(t, ok, "failed type coercion") 2006 2007 for _, rt := range tt.rangeTests { 2008 for i := rt.startPort; i <= rt.endPort; i++ { 2009 ctxFromA.DPorts = []*models.Port{{Port: i, Protocol: models.PortProtocolTCP}} 2010 key := Key{ 2011 Identity: identity.ID.Uint32(), 2012 DestPort: i, 2013 Nexthdr: uint8(u8proto.TCP), 2014 TrafficDirection: trafficdirection.Egress.Uint8(), 2015 } 2016 if rt.isAllow { 2017 // IngressCoversContext just checks the "From" labels of the search context. 2018 require.Equalf(t, api.Allowed.String(), res.IngressCoversContext(&ctxFromA).String(), "Requesting port %d", i) 2019 2020 require.Truef(t, mapStateAllowsKey(mapStateP, key), "key (%v) not allowed", key) 2021 } else { 2022 // IngressCoversContext just checks the "From" labels of the search context. 2023 require.Equalf(t, api.Denied.String(), res.IngressCoversContext(&ctxFromA).String(), "Requesting port %d", i) 2024 require.Falsef(t, mapStateAllowsKey(mapStateP, key), "key (%v) allowed", key) 2025 2026 } 2027 } 2028 } 2029 2030 }) 2031 } 2032 }