github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/repository_test.go (about) 1 // Copyright 2016-2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build !privileged_tests 16 17 package policy 18 19 import ( 20 "bytes" 21 "fmt" 22 "testing" 23 24 "github.com/cilium/cilium/api/v1/models" 25 "github.com/cilium/cilium/pkg/checker" 26 "github.com/cilium/cilium/pkg/identity" 27 k8sConst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io" 28 "github.com/cilium/cilium/pkg/labels" 29 "github.com/cilium/cilium/pkg/option" 30 "github.com/cilium/cilium/pkg/policy/api" 31 32 logging "github.com/op/go-logging" 33 . "gopkg.in/check.v1" 34 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 35 ) 36 37 func (ds *PolicyTestSuite) TestComputePolicyEnforcementAndRules(c *C) { 38 39 // Cache policy enforcement value from when test was ran to avoid pollution 40 // across tests. 41 oldPolicyEnable := GetPolicyEnabled() 42 defer SetPolicyEnabled(oldPolicyEnable) 43 44 SetPolicyEnabled(option.DefaultEnforcement) 45 46 repo := NewPolicyRepository() 47 repo.selectorCache = testSelectorCache 48 49 fooSelectLabel := labels.ParseSelectLabel("foo") 50 fooNumericIdentity := 9001 51 fooIdentity := identity.NewIdentity(identity.NumericIdentity(fooNumericIdentity), lbls) 52 fooIngressRule1Label := labels.NewLabel(k8sConst.PolicyLabelName, "fooIngressRule1", labels.LabelSourceAny) 53 fooIngressRule2Label := labels.NewLabel(k8sConst.PolicyLabelName, "fooIngressRule2", labels.LabelSourceAny) 54 fooEgressRule1Label := labels.NewLabel(k8sConst.PolicyLabelName, "fooEgressRule1", labels.LabelSourceAny) 55 fooEgressRule2Label := labels.NewLabel(k8sConst.PolicyLabelName, "fooEgressRule2", labels.LabelSourceAny) 56 combinedLabel := labels.NewLabel(k8sConst.PolicyLabelName, "combined", labels.LabelSourceAny) 57 initIdentity := identity.ReservedIdentityCache[identity.ReservedIdentityInit] 58 59 fooIngressRule1 := api.Rule{ 60 EndpointSelector: api.NewESFromLabels(fooSelectLabel), 61 Ingress: []api.IngressRule{ 62 { 63 FromEndpoints: []api.EndpointSelector{ 64 api.NewESFromLabels(fooSelectLabel), 65 }, 66 }, 67 }, 68 Labels: labels.LabelArray{ 69 fooIngressRule1Label, 70 }, 71 } 72 73 fooIngressRule2 := api.Rule{ 74 EndpointSelector: api.NewESFromLabels(fooSelectLabel), 75 Ingress: []api.IngressRule{ 76 { 77 FromEndpoints: []api.EndpointSelector{ 78 api.NewESFromLabels(fooSelectLabel), 79 }, 80 }, 81 }, 82 Labels: labels.LabelArray{ 83 fooIngressRule2Label, 84 }, 85 } 86 87 fooEgressRule1 := api.Rule{ 88 EndpointSelector: api.NewESFromLabels(fooSelectLabel), 89 Egress: []api.EgressRule{ 90 { 91 ToEndpoints: []api.EndpointSelector{ 92 api.NewESFromLabels(fooSelectLabel), 93 }, 94 }, 95 }, 96 Labels: labels.LabelArray{ 97 fooEgressRule1Label, 98 }, 99 } 100 101 fooEgressRule2 := api.Rule{ 102 EndpointSelector: api.NewESFromLabels(fooSelectLabel), 103 Egress: []api.EgressRule{ 104 { 105 ToEndpoints: []api.EndpointSelector{ 106 api.NewESFromLabels(fooSelectLabel), 107 }, 108 }, 109 }, 110 Labels: labels.LabelArray{ 111 fooEgressRule2Label, 112 }, 113 } 114 115 combinedRule := api.Rule{ 116 EndpointSelector: api.NewESFromLabels(fooSelectLabel), 117 Ingress: []api.IngressRule{ 118 { 119 FromEndpoints: []api.EndpointSelector{ 120 api.NewESFromLabels(fooSelectLabel), 121 }, 122 }, 123 }, 124 Egress: []api.EgressRule{ 125 { 126 ToEndpoints: []api.EndpointSelector{ 127 api.NewESFromLabels(fooSelectLabel), 128 }, 129 }, 130 }, 131 Labels: labels.LabelArray{ 132 combinedLabel, 133 }, 134 } 135 136 ing, egr, matchingRules := repo.computePolicyEnforcementAndRules(fooIdentity) 137 c.Assert(ing, Equals, false, Commentf("ingress policy enforcement should not apply since no rules are in repository")) 138 c.Assert(egr, Equals, false, Commentf("egress policy enforcement should not apply since no rules are in repository")) 139 c.Assert(matchingRules, checker.DeepEquals, ruleSlice{}, Commentf("returned matching rules did not match")) 140 141 _, _, err := repo.Add(fooIngressRule1, []Endpoint{}) 142 c.Assert(err, IsNil, Commentf("unable to add rule to policy repository")) 143 ing, egr, matchingRules = repo.computePolicyEnforcementAndRules(fooIdentity) 144 c.Assert(ing, Equals, true, Commentf("ingress policy enforcement should apply since ingress rule selects")) 145 c.Assert(egr, Equals, false, Commentf("egress policy enforcement should not apply since no egress rules select")) 146 c.Assert(matchingRules[0].Rule, checker.DeepEquals, fooIngressRule1, Commentf("returned matching rules did not match")) 147 148 _, _, err = repo.Add(fooIngressRule2, []Endpoint{}) 149 c.Assert(err, IsNil, Commentf("unable to add rule to policy repository")) 150 ing, egr, matchingRules = repo.computePolicyEnforcementAndRules(fooIdentity) 151 c.Assert(ing, Equals, true, Commentf("ingress policy enforcement should apply since ingress rule selects")) 152 c.Assert(egr, Equals, false, Commentf("egress policy enforcement should not apply since no egress rules select")) 153 c.Assert(matchingRules[0].Rule, checker.DeepEquals, fooIngressRule1, Commentf("returned matching rules did not match")) 154 c.Assert(matchingRules[1].Rule, checker.DeepEquals, fooIngressRule2, Commentf("returned matching rules did not match")) 155 156 _, _, numDeleted := repo.DeleteByLabelsLocked(labels.LabelArray{fooIngressRule1Label}) 157 c.Assert(numDeleted, Equals, 1) 158 c.Assert(err, IsNil, Commentf("unable to add rule to policy repository")) 159 ing, egr, matchingRules = repo.computePolicyEnforcementAndRules(fooIdentity) 160 c.Assert(ing, Equals, true, Commentf("ingress policy enforcement should apply since ingress rule selects")) 161 c.Assert(egr, Equals, false, Commentf("egress policy enforcement should not apply since no egress rules select")) 162 c.Assert(matchingRules[0].Rule, checker.DeepEquals, fooIngressRule2, Commentf("returned matching rules did not match")) 163 164 _, _, numDeleted = repo.DeleteByLabelsLocked(labels.LabelArray{fooIngressRule2Label}) 165 c.Assert(numDeleted, Equals, 1) 166 167 ing, egr, matchingRules = repo.computePolicyEnforcementAndRules(fooIdentity) 168 c.Assert(ing, Equals, false, Commentf("ingress policy enforcement should not apply since no rules are in repository")) 169 c.Assert(egr, Equals, false, Commentf("egress policy enforcement should not apply since no rules are in repository")) 170 c.Assert(matchingRules, checker.DeepEquals, ruleSlice{}, Commentf("returned matching rules did not match")) 171 172 _, _, err = repo.Add(fooEgressRule1, []Endpoint{}) 173 c.Assert(err, IsNil, Commentf("unable to add rule to policy repository")) 174 ing, egr, matchingRules = repo.computePolicyEnforcementAndRules(fooIdentity) 175 c.Assert(ing, Equals, false, Commentf("ingress policy enforcement should not apply since no ingress rules select")) 176 c.Assert(egr, Equals, true, Commentf("egress policy enforcement should apply since egress rules select")) 177 c.Assert(matchingRules[0].Rule, checker.DeepEquals, fooEgressRule1, Commentf("returned matching rules did not match")) 178 _, _, numDeleted = repo.DeleteByLabelsLocked(labels.LabelArray{fooEgressRule1Label}) 179 c.Assert(numDeleted, Equals, 1) 180 181 _, _, err = repo.Add(fooEgressRule2, []Endpoint{}) 182 c.Assert(err, IsNil, Commentf("unable to add rule to policy repository")) 183 ing, egr, matchingRules = repo.computePolicyEnforcementAndRules(fooIdentity) 184 c.Assert(ing, Equals, false, Commentf("ingress policy enforcement should not apply since no ingress rules select")) 185 c.Assert(egr, Equals, true, Commentf("egress policy enforcement should apply since egress rules select")) 186 c.Assert(matchingRules[0].Rule, checker.DeepEquals, fooEgressRule2, Commentf("returned matching rules did not match")) 187 188 _, _, numDeleted = repo.DeleteByLabelsLocked(labels.LabelArray{fooEgressRule2Label}) 189 c.Assert(numDeleted, Equals, 1) 190 191 _, _, err = repo.Add(combinedRule, []Endpoint{}) 192 c.Assert(err, IsNil, Commentf("unable to add rule to policy repository")) 193 ing, egr, matchingRules = repo.computePolicyEnforcementAndRules(fooIdentity) 194 c.Assert(ing, Equals, true, Commentf("ingress policy enforcement should apply since ingress rule selects")) 195 c.Assert(egr, Equals, true, Commentf("egress policy enforcement should apply since egress rules selects")) 196 c.Assert(matchingRules[0].Rule, checker.DeepEquals, combinedRule, Commentf("returned matching rules did not match")) 197 _, _, numDeleted = repo.DeleteByLabelsLocked(labels.LabelArray{combinedLabel}) 198 c.Assert(numDeleted, Equals, 1) 199 200 SetPolicyEnabled(option.AlwaysEnforce) 201 c.Assert(err, IsNil, Commentf("unable to add rule to policy repository")) 202 ing, egr, matchingRules = repo.computePolicyEnforcementAndRules(fooIdentity) 203 c.Assert(ing, Equals, true, Commentf("ingress policy enforcement should apply since ingress rule selects")) 204 c.Assert(egr, Equals, true, Commentf("egress policy enforcement should apply since egress rules selects")) 205 c.Assert(matchingRules, checker.DeepEquals, ruleSlice{}, Commentf("returned matching rules did not match")) 206 207 SetPolicyEnabled(option.NeverEnforce) 208 _, _, err = repo.Add(combinedRule, []Endpoint{}) 209 c.Assert(err, IsNil, Commentf("unable to add rule to policy repository")) 210 ing, egr, matchingRules = repo.computePolicyEnforcementAndRules(fooIdentity) 211 c.Assert(ing, Equals, false, Commentf("ingress policy enforcement should not apply since policy enforcement is disabled ")) 212 c.Assert(egr, Equals, false, Commentf("egress policy enforcement should not apply since policy enforcement is disabled")) 213 c.Assert(matchingRules, IsNil, Commentf("no rules should be returned since policy enforcement is disabled")) 214 215 // Test init identity. 216 217 SetPolicyEnabled(option.DefaultEnforcement) 218 // If the mode is "default", check that the policy is always enforced for 219 // endpoints with the reserved:init label. If no policy rules match 220 // reserved:init, this drops all ingress and egress traffic. 221 ingress, egress, matchingRules := repo.computePolicyEnforcementAndRules(initIdentity) 222 c.Assert(ingress, Equals, true) 223 c.Assert(egress, Equals, true) 224 c.Assert(matchingRules, checker.DeepEquals, ruleSlice{}, Commentf("no rules should be returned since policy enforcement is disabled")) 225 226 // Check that the "always" and "never" modes are not affected. 227 SetPolicyEnabled(option.AlwaysEnforce) 228 ingress, egress, _ = repo.computePolicyEnforcementAndRules(initIdentity) 229 c.Assert(ingress, Equals, true) 230 c.Assert(egress, Equals, true) 231 232 SetPolicyEnabled(option.NeverEnforce) 233 ingress, egress, _ = repo.computePolicyEnforcementAndRules(initIdentity) 234 c.Assert(ingress, Equals, false) 235 c.Assert(egress, Equals, false) 236 237 } 238 239 func (ds *PolicyTestSuite) TestAddSearchDelete(c *C) { 240 repo := NewPolicyRepository() 241 repo.selectorCache = testSelectorCache 242 243 // cannot add empty rule 244 rev, _, err := repo.Add(api.Rule{}, []Endpoint{}) 245 c.Assert(err, Not(IsNil)) 246 c.Assert(rev, Equals, uint64(1)) 247 248 lbls1 := labels.LabelArray{ 249 labels.ParseLabel("tag1"), 250 labels.ParseLabel("tag2"), 251 } 252 rule1 := api.Rule{ 253 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("foo")), 254 Labels: lbls1, 255 } 256 rule2 := api.Rule{ 257 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 258 Labels: lbls1, 259 } 260 lbls2 := labels.LabelArray{labels.ParseSelectLabel("tag3")} 261 rule3 := api.Rule{ 262 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 263 Labels: lbls2, 264 } 265 266 nextRevision := uint64(1) 267 268 c.Assert(repo.GetRevision(), Equals, nextRevision) 269 nextRevision++ 270 271 // add rule1,rule2 272 rev, _, err = repo.Add(rule1, []Endpoint{}) 273 c.Assert(err, IsNil) 274 c.Assert(rev, Equals, nextRevision) 275 nextRevision++ 276 rev, _, err = repo.Add(rule2, []Endpoint{}) 277 c.Assert(err, IsNil) 278 c.Assert(rev, Equals, nextRevision) 279 nextRevision++ 280 281 // rule3 should not be in there yet 282 repo.Mutex.RLock() 283 c.Assert(repo.SearchRLocked(lbls2), checker.DeepEquals, api.Rules{}) 284 repo.Mutex.RUnlock() 285 286 // add rule3 287 rev, _, err = repo.Add(rule3, []Endpoint{}) 288 c.Assert(err, IsNil) 289 c.Assert(rev, Equals, nextRevision) 290 nextRevision++ 291 292 // search rule1,rule2 293 repo.Mutex.RLock() 294 c.Assert(repo.SearchRLocked(lbls1), checker.DeepEquals, api.Rules{&rule1, &rule2}) 295 c.Assert(repo.SearchRLocked(lbls2), checker.DeepEquals, api.Rules{&rule3}) 296 repo.Mutex.RUnlock() 297 298 // delete rule1, rule2 299 rev, n := repo.DeleteByLabels(lbls1) 300 c.Assert(n, Equals, 2) 301 c.Assert(rev, Equals, nextRevision) 302 nextRevision++ 303 304 // delete rule1, rule2 again has no effect 305 rev, n = repo.DeleteByLabels(lbls1) 306 c.Assert(n, Equals, 0) 307 c.Assert(rev, Equals, nextRevision-1) 308 309 // rule3 can still be found 310 repo.Mutex.RLock() 311 c.Assert(repo.SearchRLocked(lbls2), checker.DeepEquals, api.Rules{&rule3}) 312 repo.Mutex.RUnlock() 313 314 // delete rule3 315 rev, n = repo.DeleteByLabels(lbls2) 316 c.Assert(n, Equals, 1) 317 c.Assert(rev, Equals, nextRevision) 318 319 // rule1 is gone 320 repo.Mutex.RLock() 321 c.Assert(repo.SearchRLocked(lbls2), checker.DeepEquals, api.Rules{}) 322 repo.Mutex.RUnlock() 323 } 324 325 func BenchmarkParseLabel(b *testing.B) { 326 repo := NewPolicyRepository() 327 repo.selectorCache = testSelectorCache 328 329 b.ResetTimer() 330 var err error 331 var cntAdd, cntFound int 332 333 lbls := make([]labels.LabelArray, 100) 334 for i := 0; i < 100; i++ { 335 I := fmt.Sprintf("%d", i) 336 lbls[i] = labels.LabelArray{labels.NewLabel("tag3", I, labels.LabelSourceK8s), labels.NewLabel("namespace", "default", labels.LabelSourceK8s)} 337 } 338 for i := 0; i < b.N; i++ { 339 for j := 0; j < 100; j++ { 340 J := fmt.Sprintf("%d", j) 341 _, _, err = repo.Add(api.Rule{ 342 EndpointSelector: api.NewESFromLabels(labels.NewLabel("foo", J, labels.LabelSourceK8s), labels.NewLabel("namespace", "default", labels.LabelSourceK8s)), 343 Labels: labels.LabelArray{ 344 labels.ParseLabel("k8s:tag1"), 345 labels.NewLabel("namespace", "default", labels.LabelSourceK8s), 346 labels.NewLabel("tag3", J, labels.LabelSourceK8s), 347 }, 348 }, []Endpoint{}) 349 if err == nil { 350 cntAdd++ 351 } 352 } 353 354 repo.Mutex.RLock() 355 for j := 0; j < 100; j++ { 356 cntFound += len(repo.SearchRLocked(lbls[j])) 357 } 358 repo.Mutex.RUnlock() 359 } 360 b.Log("Added: ", cntAdd) 361 b.Log("found: ", cntFound) 362 } 363 364 func (ds *PolicyTestSuite) TestAllowsIngress(c *C) { 365 repo := NewPolicyRepository() 366 repo.selectorCache = testSelectorCache 367 368 fooToBar := &SearchContext{ 369 From: labels.ParseSelectLabelArray("foo"), 370 To: labels.ParseSelectLabelArray("bar"), 371 } 372 373 repo.Mutex.RLock() 374 // no rules loaded: Allows() => denied 375 c.Assert(repo.AllowsIngressRLocked(fooToBar), Equals, api.Denied) 376 repo.Mutex.RUnlock() 377 378 tag1 := labels.LabelArray{labels.ParseLabel("tag1")} 379 rule1 := api.Rule{ 380 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 381 Ingress: []api.IngressRule{ 382 { 383 FromEndpoints: []api.EndpointSelector{ 384 api.NewESFromLabels(labels.ParseSelectLabel("foo")), 385 }, 386 }, 387 }, 388 Labels: tag1, 389 } 390 391 // selector: groupA 392 // require: groupA 393 rule2 := api.Rule{ 394 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("groupA")), 395 Ingress: []api.IngressRule{ 396 { 397 FromRequires: []api.EndpointSelector{ 398 api.NewESFromLabels(labels.ParseSelectLabel("groupA")), 399 }, 400 }, 401 }, 402 Labels: tag1, 403 } 404 rule3 := api.Rule{ 405 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar2")), 406 Ingress: []api.IngressRule{ 407 { 408 FromEndpoints: []api.EndpointSelector{ 409 api.NewESFromLabels(labels.ParseSelectLabel("foo")), 410 }, 411 }, 412 }, 413 Labels: tag1, 414 } 415 416 _, _, err := repo.Add(rule1, []Endpoint{}) 417 c.Assert(err, IsNil) 418 _, _, err = repo.Add(rule2, []Endpoint{}) 419 c.Assert(err, IsNil) 420 _, _, err = repo.Add(rule3, []Endpoint{}) 421 c.Assert(err, IsNil) 422 423 // foo=>bar is OK 424 c.Assert(repo.AllowsIngressRLocked(fooToBar), Equals, api.Allowed) 425 426 // foo=>bar2 is OK 427 c.Assert(repo.AllowsIngressRLocked(&SearchContext{ 428 From: labels.ParseSelectLabelArray("foo"), 429 To: labels.ParseSelectLabelArray("bar2"), 430 }), Equals, api.Allowed) 431 432 // foo=>bar inside groupA is OK 433 c.Assert(repo.AllowsIngressRLocked(&SearchContext{ 434 From: labels.ParseSelectLabelArray("foo", "groupA"), 435 To: labels.ParseSelectLabelArray("bar", "groupA"), 436 }), Equals, api.Allowed) 437 438 // groupB can't talk to groupA => Denied 439 c.Assert(repo.AllowsIngressRLocked(&SearchContext{ 440 From: labels.ParseSelectLabelArray("foo", "groupB"), 441 To: labels.ParseSelectLabelArray("bar", "groupA"), 442 }), Equals, api.Denied) 443 444 // no restriction on groupB, unused label => OK 445 c.Assert(repo.AllowsIngressRLocked(&SearchContext{ 446 From: labels.ParseSelectLabelArray("foo", "groupB"), 447 To: labels.ParseSelectLabelArray("bar", "groupB"), 448 }), Equals, api.Allowed) 449 450 // foo=>bar3, no rule => Denied 451 c.Assert(repo.AllowsIngressRLocked(&SearchContext{ 452 From: labels.ParseSelectLabelArray("foo"), 453 To: labels.ParseSelectLabelArray("bar3"), 454 }), Equals, api.Denied) 455 } 456 457 func (ds *PolicyTestSuite) TestAllowsEgress(c *C) { 458 repo := NewPolicyRepository() 459 repo.selectorCache = testSelectorCache 460 461 fooToBar := &SearchContext{ 462 From: labels.ParseSelectLabelArray("foo"), 463 To: labels.ParseSelectLabelArray("bar"), 464 } 465 466 repo.Mutex.RLock() 467 // no rules loaded: Allows() => denied 468 c.Assert(repo.AllowsEgressRLocked(fooToBar), Equals, api.Denied) 469 repo.Mutex.RUnlock() 470 471 tag1 := labels.LabelArray{labels.ParseLabel("tag1")} 472 rule1 := api.Rule{ 473 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("foo")), 474 Egress: []api.EgressRule{ 475 { 476 ToEndpoints: []api.EndpointSelector{ 477 api.NewESFromLabels(labels.ParseSelectLabel("bar")), 478 }, 479 }, 480 }, 481 Labels: tag1, 482 } 483 484 // selector: groupA 485 // require: groupA 486 rule2 := api.Rule{ 487 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("groupA")), 488 Egress: []api.EgressRule{ 489 { 490 ToRequires: []api.EndpointSelector{ 491 api.NewESFromLabels(labels.ParseSelectLabel("groupA")), 492 }, 493 }, 494 }, 495 Labels: tag1, 496 } 497 rule3 := api.Rule{ 498 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("foo")), 499 Egress: []api.EgressRule{ 500 { 501 ToEndpoints: []api.EndpointSelector{ 502 api.NewESFromLabels(labels.ParseSelectLabel("bar2")), 503 }, 504 }, 505 }, 506 Labels: tag1, 507 } 508 _, _, err := repo.Add(rule1, []Endpoint{}) 509 c.Assert(err, IsNil) 510 _, _, err = repo.Add(rule2, []Endpoint{}) 511 c.Assert(err, IsNil) 512 _, _, err = repo.Add(rule3, []Endpoint{}) 513 c.Assert(err, IsNil) 514 515 // foo=>bar is OK 516 logBuffer := new(bytes.Buffer) 517 result := repo.AllowsEgressRLocked(fooToBar.WithLogger(logBuffer)) 518 if equal, err := checker.DeepEqual(result, api.Allowed); !equal { 519 c.Logf("%s", logBuffer.String()) 520 c.Errorf("Resolved policy did not match expected: \n%s", err) 521 } 522 523 // foo=>bar2 is OK 524 c.Assert(repo.AllowsEgressRLocked(&SearchContext{ 525 From: labels.ParseSelectLabelArray("foo"), 526 To: labels.ParseSelectLabelArray("bar2"), 527 }), Equals, api.Allowed) 528 529 // foo=>bar inside groupA is OK 530 c.Assert(repo.AllowsEgressRLocked(&SearchContext{ 531 From: labels.ParseSelectLabelArray("foo", "groupA"), 532 To: labels.ParseSelectLabelArray("bar", "groupA"), 533 }), Equals, api.Allowed) 534 535 buffer := new(bytes.Buffer) 536 // groupB can't talk to groupA => Denied 537 ctx := &SearchContext{ 538 To: labels.ParseSelectLabelArray("foo", "groupB"), 539 From: labels.ParseSelectLabelArray("bar", "groupA"), 540 Logging: logging.NewLogBackend(buffer, "", 0), 541 Trace: TRACE_VERBOSE, 542 } 543 verdict := repo.AllowsEgressRLocked(ctx) 544 c.Assert(verdict, Equals, api.Denied) 545 546 // no restriction on groupB, unused label => OK 547 c.Assert(repo.AllowsEgressRLocked(&SearchContext{ 548 From: labels.ParseSelectLabelArray("foo", "groupB"), 549 To: labels.ParseSelectLabelArray("bar", "groupB"), 550 }), Equals, api.Allowed) 551 552 // foo=>bar3, no rule => Denied 553 c.Assert(repo.AllowsEgressRLocked(&SearchContext{ 554 From: labels.ParseSelectLabelArray("foo"), 555 To: labels.ParseSelectLabelArray("bar3"), 556 }), Equals, api.Denied) 557 } 558 559 func (ds *PolicyTestSuite) TestWildcardL3RulesIngress(c *C) { 560 repo := NewPolicyRepository() 561 repo.selectorCache = testSelectorCache 562 563 labelsL3 := labels.LabelArray{labels.ParseLabel("L3")} 564 labelsKafka := labels.LabelArray{labels.ParseLabel("kafka")} 565 labelsHTTP := labels.LabelArray{labels.ParseLabel("http")} 566 labelsL7 := labels.LabelArray{labels.ParseLabel("l7")} 567 568 l3Rule := api.Rule{ 569 EndpointSelector: selFoo, 570 Ingress: []api.IngressRule{ 571 { 572 FromEndpoints: []api.EndpointSelector{selBar1}, 573 }, 574 }, 575 Labels: labelsL3, 576 } 577 l3Rule.Sanitize() 578 _, _, err := repo.Add(l3Rule, []Endpoint{}) 579 c.Assert(err, IsNil) 580 581 kafkaRule := api.Rule{ 582 EndpointSelector: selFoo, 583 Ingress: []api.IngressRule{ 584 { 585 FromEndpoints: []api.EndpointSelector{selBar2}, 586 ToPorts: []api.PortRule{{ 587 Ports: []api.PortProtocol{ 588 {Port: "9092", Protocol: api.ProtoTCP}, 589 }, 590 Rules: &api.L7Rules{ 591 Kafka: []api.PortRuleKafka{ 592 {APIKey: "produce"}, 593 }, 594 }, 595 }}, 596 }, 597 }, 598 Labels: labelsKafka, 599 } 600 kafkaRule.Sanitize() 601 _, _, err = repo.Add(kafkaRule, []Endpoint{}) 602 c.Assert(err, IsNil) 603 604 httpRule := api.Rule{ 605 EndpointSelector: selFoo, 606 Ingress: []api.IngressRule{ 607 { 608 FromEndpoints: []api.EndpointSelector{selBar2}, 609 ToPorts: []api.PortRule{{ 610 Ports: []api.PortProtocol{ 611 {Port: "80", Protocol: api.ProtoTCP}, 612 }, 613 Rules: &api.L7Rules{ 614 HTTP: []api.PortRuleHTTP{ 615 {Method: "GET", Path: "/"}, 616 }, 617 }, 618 }}, 619 }, 620 }, 621 Labels: labelsHTTP, 622 } 623 _, _, err = repo.Add(httpRule, []Endpoint{}) 624 c.Assert(err, IsNil) 625 626 l7Rule := api.Rule{ 627 EndpointSelector: selFoo, 628 Ingress: []api.IngressRule{ 629 { 630 FromEndpoints: []api.EndpointSelector{selBar2}, 631 ToPorts: []api.PortRule{{ 632 Ports: []api.PortProtocol{ 633 {Port: "9090", Protocol: api.ProtoTCP}, 634 }, 635 Rules: &api.L7Rules{ 636 L7Proto: "tester", 637 L7: []api.PortRuleL7{map[string]string{"method": "GET", "path": "/"}}, 638 }, 639 }}, 640 }, 641 }, 642 Labels: labelsL7, 643 } 644 _, _, err = repo.Add(l7Rule, []Endpoint{}) 645 c.Assert(err, IsNil) 646 647 ctx := &SearchContext{ 648 To: labels.ParseSelectLabelArray("id=foo"), 649 } 650 651 repo.Mutex.RLock() 652 defer repo.Mutex.RUnlock() 653 654 policy, err := repo.ResolveL4IngressPolicy(ctx) 655 c.Assert(err, IsNil) 656 657 expectedPolicy := L4PolicyMap{ 658 "0/ANY": { 659 Port: 0, 660 Protocol: api.ProtoAny, 661 U8Proto: 0x0, 662 CachedSelectors: CachedSelectorSlice{cachedSelectorBar1}, 663 L7RulesPerEp: L7DataMap{}, 664 Ingress: true, 665 DerivedFromRules: labels.LabelArrayList{labelsL3}, 666 }, 667 "9092/TCP": { 668 Port: 9092, 669 Protocol: api.ProtoTCP, 670 U8Proto: 0x6, 671 CachedSelectors: CachedSelectorSlice{cachedSelectorBar2, cachedSelectorBar1}, 672 L7Parser: ParserTypeKafka, 673 Ingress: true, 674 L7RulesPerEp: L7DataMap{ 675 cachedSelectorBar2: api.L7Rules{ 676 Kafka: []api.PortRuleKafka{kafkaRule.Ingress[0].ToPorts[0].Rules.Kafka[0]}, 677 }, 678 cachedSelectorBar1: api.L7Rules{ 679 Kafka: []api.PortRuleKafka{{}}, 680 }, 681 }, 682 DerivedFromRules: labels.LabelArrayList{labelsKafka, labelsL3}, 683 }, 684 "80/TCP": { 685 Port: 80, 686 Protocol: api.ProtoTCP, 687 U8Proto: 0x6, 688 CachedSelectors: CachedSelectorSlice{cachedSelectorBar2, cachedSelectorBar1}, 689 L7Parser: ParserTypeHTTP, 690 Ingress: true, 691 L7RulesPerEp: L7DataMap{ 692 cachedSelectorBar2: api.L7Rules{ 693 HTTP: []api.PortRuleHTTP{httpRule.Ingress[0].ToPorts[0].Rules.HTTP[0]}, 694 }, 695 cachedSelectorBar1: api.L7Rules{ 696 HTTP: []api.PortRuleHTTP{{}}, 697 }, 698 }, 699 DerivedFromRules: labels.LabelArrayList{labelsHTTP, labelsL3}, 700 }, 701 "9090/TCP": { 702 Port: 9090, 703 Protocol: api.ProtoTCP, 704 U8Proto: 0x6, 705 CachedSelectors: CachedSelectorSlice{cachedSelectorBar2, cachedSelectorBar1}, 706 L7Parser: L7ParserType("tester"), 707 Ingress: true, 708 L7RulesPerEp: L7DataMap{ 709 cachedSelectorBar2: api.L7Rules{ 710 L7Proto: "tester", 711 L7: []api.PortRuleL7{l7Rule.Ingress[0].ToPorts[0].Rules.L7[0]}, 712 }, 713 cachedSelectorBar1: api.L7Rules{ 714 L7Proto: "tester", 715 L7: []api.PortRuleL7{}, 716 }, 717 }, 718 DerivedFromRules: labels.LabelArrayList{labelsL7, labelsL3}, 719 }, 720 } 721 c.Assert(policy, checker.Equals, expectedPolicy) 722 policy.Detach(repo.GetSelectorCache()) 723 } 724 725 func (ds *PolicyTestSuite) TestWildcardL4RulesIngress(c *C) { 726 repo := NewPolicyRepository() 727 repo.selectorCache = testSelectorCache 728 729 selFoo := api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 730 selBar1 := api.NewESFromLabels(labels.ParseSelectLabel("id=bar1")) 731 selBar2 := api.NewESFromLabels(labels.ParseSelectLabel("id=bar2")) 732 733 labelsL4 := labels.LabelArray{labels.ParseLabel("L4")} 734 labelsKafka := labels.LabelArray{labels.ParseLabel("kafka")} 735 labelsHTTP := labels.LabelArray{labels.ParseLabel("http")} 736 737 l49092Rule := api.Rule{ 738 EndpointSelector: selFoo, 739 Ingress: []api.IngressRule{ 740 { 741 FromEndpoints: []api.EndpointSelector{selBar1}, 742 ToPorts: []api.PortRule{{ 743 Ports: []api.PortProtocol{ 744 {Port: "9092", Protocol: api.ProtoTCP}, 745 }, 746 }}, 747 }, 748 }, 749 Labels: labelsL4, 750 } 751 l49092Rule.Sanitize() 752 _, _, err := repo.Add(l49092Rule, []Endpoint{}) 753 c.Assert(err, IsNil) 754 755 kafkaRule := api.Rule{ 756 EndpointSelector: selFoo, 757 Ingress: []api.IngressRule{ 758 { 759 FromEndpoints: []api.EndpointSelector{selBar2}, 760 ToPorts: []api.PortRule{{ 761 Ports: []api.PortProtocol{ 762 {Port: "9092", Protocol: api.ProtoTCP}, 763 }, 764 Rules: &api.L7Rules{ 765 Kafka: []api.PortRuleKafka{ 766 {APIKey: "produce"}, 767 }, 768 }, 769 }}, 770 }, 771 }, 772 Labels: labelsKafka, 773 } 774 kafkaRule.Sanitize() 775 _, _, err = repo.Add(kafkaRule, []Endpoint{}) 776 c.Assert(err, IsNil) 777 778 l480Rule := api.Rule{ 779 EndpointSelector: selFoo, 780 Ingress: []api.IngressRule{ 781 { 782 FromEndpoints: []api.EndpointSelector{selBar1}, 783 ToPorts: []api.PortRule{{ 784 Ports: []api.PortProtocol{ 785 {Port: "80", Protocol: api.ProtoTCP}, 786 }, 787 }}, 788 }, 789 }, 790 Labels: labelsL4, 791 } 792 l480Rule.Sanitize() 793 _, _, err = repo.Add(l480Rule, []Endpoint{}) 794 c.Assert(err, IsNil) 795 796 httpRule := api.Rule{ 797 EndpointSelector: selFoo, 798 Ingress: []api.IngressRule{ 799 { 800 FromEndpoints: []api.EndpointSelector{selBar2}, 801 ToPorts: []api.PortRule{{ 802 Ports: []api.PortProtocol{ 803 {Port: "80", Protocol: api.ProtoTCP}, 804 }, 805 Rules: &api.L7Rules{ 806 HTTP: []api.PortRuleHTTP{ 807 {Method: "GET", Path: "/"}, 808 }, 809 }, 810 }}, 811 }, 812 }, 813 Labels: labelsHTTP, 814 } 815 _, _, err = repo.Add(httpRule, []Endpoint{}) 816 c.Assert(err, IsNil) 817 818 ctx := &SearchContext{ 819 To: labels.ParseSelectLabelArray("id=foo"), 820 } 821 822 repo.Mutex.RLock() 823 defer repo.Mutex.RUnlock() 824 825 policy, err := repo.ResolveL4IngressPolicy(ctx) 826 c.Assert(err, IsNil) 827 828 expectedPolicy := L4PolicyMap{ 829 "80/TCP": { 830 Port: 80, 831 Protocol: api.ProtoTCP, 832 U8Proto: 0x6, 833 CachedSelectors: CachedSelectorSlice{cachedSelectorBar1, cachedSelectorBar2}, 834 L7Parser: ParserTypeHTTP, 835 Ingress: true, 836 L7RulesPerEp: L7DataMap{ 837 cachedSelectorBar1: api.L7Rules{ 838 HTTP: []api.PortRuleHTTP{{}}, 839 }, 840 cachedSelectorBar2: api.L7Rules{ 841 HTTP: []api.PortRuleHTTP{httpRule.Ingress[0].ToPorts[0].Rules.HTTP[0]}, 842 }, 843 }, 844 DerivedFromRules: labels.LabelArrayList{labelsL4, labelsHTTP, labelsL4}, 845 }, 846 "9092/TCP": { 847 Port: 9092, 848 Protocol: api.ProtoTCP, 849 U8Proto: 0x6, 850 CachedSelectors: CachedSelectorSlice{cachedSelectorBar1, cachedSelectorBar2}, 851 L7Parser: ParserTypeKafka, 852 Ingress: true, 853 L7RulesPerEp: L7DataMap{ 854 cachedSelectorBar1: api.L7Rules{ 855 Kafka: []api.PortRuleKafka{{}}, 856 }, 857 cachedSelectorBar2: api.L7Rules{ 858 Kafka: []api.PortRuleKafka{kafkaRule.Ingress[0].ToPorts[0].Rules.Kafka[0]}, 859 }, 860 }, 861 DerivedFromRules: labels.LabelArrayList{labelsL4, labelsKafka, labelsL4}, 862 }, 863 } 864 c.Assert(policy, checker.Equals, expectedPolicy) 865 policy.Detach(repo.GetSelectorCache()) 866 } 867 868 func (ds *PolicyTestSuite) TestL3DependentL4IngressFromRequires(c *C) { 869 repo := NewPolicyRepository() 870 repo.selectorCache = testSelectorCache 871 872 selFoo := api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 873 selBar1 := api.NewESFromLabels(labels.ParseSelectLabel("id=bar1")) 874 selBar2 := api.NewESFromLabels(labels.ParseSelectLabel("id=bar2")) 875 876 l480Rule := api.Rule{ 877 EndpointSelector: selFoo, 878 Ingress: []api.IngressRule{ 879 { 880 FromEndpoints: []api.EndpointSelector{ 881 selBar1, 882 }, 883 ToPorts: []api.PortRule{{ 884 Ports: []api.PortProtocol{ 885 {Port: "80", Protocol: api.ProtoTCP}, 886 }, 887 }}, 888 }, 889 { 890 FromRequires: []api.EndpointSelector{selBar2}, 891 }, 892 }, 893 } 894 l480Rule.Sanitize() 895 _, _, err := repo.Add(l480Rule, []Endpoint{}) 896 c.Assert(err, IsNil) 897 898 ctx := &SearchContext{ 899 To: labels.ParseSelectLabelArray("id=foo"), 900 } 901 902 repo.Mutex.RLock() 903 defer repo.Mutex.RUnlock() 904 905 policy, err := repo.ResolveL4IngressPolicy(ctx) 906 c.Assert(err, IsNil) 907 908 expectedSelector := api.NewESFromMatchRequirements(map[string]string{"any.id": "bar1"}, []v1.LabelSelectorRequirement{ 909 { 910 Key: "any.id", 911 Operator: v1.LabelSelectorOpIn, 912 Values: []string{"bar2"}, 913 }, 914 }) 915 expectedCachedSelector, _ := testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, expectedSelector) 916 917 expectedPolicy := L4PolicyMap{ 918 "80/TCP": &L4Filter{ 919 Port: 80, 920 Protocol: api.ProtoTCP, 921 U8Proto: 0x6, 922 CachedSelectors: CachedSelectorSlice{ 923 expectedCachedSelector, 924 }, 925 L7RulesPerEp: L7DataMap{}, 926 Ingress: true, 927 DerivedFromRules: labels.LabelArrayList{nil}, 928 }, 929 } 930 c.Assert(policy, checker.Equals, expectedPolicy) 931 policy.Detach(repo.GetSelectorCache()) 932 } 933 934 func (ds *PolicyTestSuite) TestL3DependentL4EgressFromRequires(c *C) { 935 repo := NewPolicyRepository() 936 repo.selectorCache = testSelectorCache 937 938 selFoo := api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 939 selBar1 := api.NewESFromLabels(labels.ParseSelectLabel("id=bar1")) 940 selBar2 := api.NewESFromLabels(labels.ParseSelectLabel("id=bar2")) 941 942 l480Rule := api.Rule{ 943 EndpointSelector: selFoo, 944 Egress: []api.EgressRule{ 945 { 946 ToEndpoints: []api.EndpointSelector{ 947 selBar1, 948 }, 949 ToPorts: []api.PortRule{{ 950 Ports: []api.PortProtocol{ 951 {Port: "80", Protocol: api.ProtoTCP}, 952 }, 953 }}, 954 }, 955 { 956 ToEndpoints: []api.EndpointSelector{ 957 api.WildcardEndpointSelector, 958 }, 959 ToRequires: []api.EndpointSelector{selBar2}, 960 }, 961 }, 962 } 963 l480Rule.Sanitize() 964 _, _, err := repo.Add(l480Rule, []Endpoint{}) 965 c.Assert(err, IsNil) 966 967 ctx := &SearchContext{ 968 From: labels.ParseSelectLabelArray("id=foo"), 969 } 970 971 repo.Mutex.RLock() 972 defer repo.Mutex.RUnlock() 973 974 logBuffer := new(bytes.Buffer) 975 policy, err := repo.ResolveL4EgressPolicy(ctx.WithLogger(logBuffer)) 976 c.Assert(err, IsNil) 977 978 expectedSelector := api.NewESFromMatchRequirements(map[string]string{"any.id": "bar1"}, []v1.LabelSelectorRequirement{ 979 { 980 Key: "any.id", 981 Operator: v1.LabelSelectorOpIn, 982 Values: []string{"bar2"}, 983 }, 984 }) 985 expectedSelector2 := api.NewESFromMatchRequirements(map[string]string{}, []v1.LabelSelectorRequirement{ 986 { 987 Key: "any.id", 988 Operator: v1.LabelSelectorOpIn, 989 Values: []string{"bar2"}, 990 }, 991 }) 992 expectedCachedSelector, _ := testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, expectedSelector) 993 expectedCachedSelector2, _ := testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, expectedSelector2) 994 995 expectedPolicy := L4PolicyMap{ 996 "0/ANY": &L4Filter{ 997 Port: 0, 998 Protocol: "ANY", 999 U8Proto: 0x0, 1000 allowsAllAtL3: false, 1001 CachedSelectors: CachedSelectorSlice{ 1002 expectedCachedSelector2, 1003 }, 1004 L7RulesPerEp: L7DataMap{}, 1005 DerivedFromRules: labels.LabelArrayList{nil}, 1006 }, 1007 "80/TCP": &L4Filter{ 1008 Port: 80, 1009 Protocol: api.ProtoTCP, 1010 U8Proto: 0x6, 1011 CachedSelectors: CachedSelectorSlice{ 1012 expectedCachedSelector, 1013 }, 1014 L7RulesPerEp: L7DataMap{}, 1015 DerivedFromRules: labels.LabelArrayList{nil}, 1016 }, 1017 } 1018 if !c.Check(policy, checker.Equals, expectedPolicy) { 1019 c.Errorf("Policy doesn't match expected:\n%s", logBuffer.String()) 1020 } 1021 policy.Detach(repo.GetSelectorCache()) 1022 } 1023 1024 func (ds *PolicyTestSuite) TestWildcardL3RulesEgress(c *C) { 1025 repo := NewPolicyRepository() 1026 repo.selectorCache = testSelectorCache 1027 1028 selFoo := api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 1029 selBar1 := api.NewESFromLabels(labels.ParseSelectLabel("id=bar1")) 1030 selBar2 := api.NewESFromLabels(labels.ParseSelectLabel("id=bar2")) 1031 1032 labelsL4 := labels.LabelArray{labels.ParseLabel("L4")} 1033 labelsDNS := labels.LabelArray{labels.ParseLabel("dns")} 1034 labelsHTTP := labels.LabelArray{labels.ParseLabel("http")} 1035 1036 l3Rule := api.Rule{ 1037 EndpointSelector: selFoo, 1038 Egress: []api.EgressRule{ 1039 { 1040 ToEndpoints: []api.EndpointSelector{selBar1}, 1041 }, 1042 }, 1043 Labels: labelsL4, 1044 } 1045 l3Rule.Sanitize() 1046 _, _, err := repo.Add(l3Rule, []Endpoint{}) 1047 c.Assert(err, IsNil) 1048 1049 dnsRule := api.Rule{ 1050 EndpointSelector: selFoo, 1051 Egress: []api.EgressRule{ 1052 { 1053 ToEndpoints: []api.EndpointSelector{selBar2}, 1054 ToPorts: []api.PortRule{{ 1055 Ports: []api.PortProtocol{ 1056 {Port: "53", Protocol: api.ProtoUDP}, 1057 }, 1058 Rules: &api.L7Rules{ 1059 DNS: []api.PortRuleDNS{ 1060 {MatchName: "empire.gov"}, 1061 }, 1062 }, 1063 }}, 1064 }, 1065 }, 1066 Labels: labelsDNS, 1067 } 1068 dnsRule.Sanitize() 1069 _, _, err = repo.Add(dnsRule, []Endpoint{}) 1070 c.Assert(err, IsNil) 1071 1072 httpRule := api.Rule{ 1073 EndpointSelector: selFoo, 1074 Egress: []api.EgressRule{ 1075 { 1076 ToEndpoints: []api.EndpointSelector{selBar2}, 1077 ToPorts: []api.PortRule{{ 1078 Ports: []api.PortProtocol{ 1079 {Port: "80", Protocol: api.ProtoTCP}, 1080 }, 1081 Rules: &api.L7Rules{ 1082 HTTP: []api.PortRuleHTTP{ 1083 {Method: "GET", Path: "/"}, 1084 }, 1085 }, 1086 }}, 1087 }, 1088 }, 1089 Labels: labelsHTTP, 1090 } 1091 _, _, err = repo.Add(httpRule, []Endpoint{}) 1092 c.Assert(err, IsNil) 1093 1094 ctx := &SearchContext{ 1095 From: labels.ParseSelectLabelArray("id=foo"), 1096 } 1097 1098 repo.Mutex.RLock() 1099 defer repo.Mutex.RUnlock() 1100 1101 policy, err := repo.ResolveL4EgressPolicy(ctx) 1102 c.Assert(err, IsNil) 1103 1104 expectedPolicy := L4PolicyMap{ 1105 "53/UDP": { 1106 Port: 53, 1107 Protocol: api.ProtoUDP, 1108 U8Proto: 0x11, 1109 CachedSelectors: CachedSelectorSlice{cachedSelectorBar2, cachedSelectorBar1}, 1110 L7Parser: ParserTypeDNS, 1111 Ingress: false, 1112 L7RulesPerEp: L7DataMap{ 1113 cachedSelectorBar1: api.L7Rules{ 1114 DNS: []api.PortRuleDNS{{MatchPattern: "*"}}, 1115 }, 1116 cachedSelectorBar2: api.L7Rules{ 1117 DNS: []api.PortRuleDNS{dnsRule.Egress[0].ToPorts[0].Rules.DNS[0]}, 1118 }, 1119 }, 1120 DerivedFromRules: labels.LabelArrayList{labelsDNS, labelsL4}, 1121 }, 1122 "80/TCP": { 1123 Port: 80, 1124 Protocol: api.ProtoTCP, 1125 U8Proto: 0x6, 1126 CachedSelectors: CachedSelectorSlice{cachedSelectorBar2, cachedSelectorBar1}, 1127 L7Parser: ParserTypeHTTP, 1128 Ingress: false, 1129 L7RulesPerEp: L7DataMap{ 1130 cachedSelectorBar1: api.L7Rules{ 1131 HTTP: []api.PortRuleHTTP{{}}, 1132 }, 1133 cachedSelectorBar2: api.L7Rules{ 1134 HTTP: []api.PortRuleHTTP{httpRule.Egress[0].ToPorts[0].Rules.HTTP[0]}, 1135 }, 1136 }, 1137 DerivedFromRules: labels.LabelArrayList{labelsHTTP, labelsL4}, 1138 }, 1139 "0/ANY": { 1140 Port: 0, 1141 Protocol: "ANY", 1142 U8Proto: 0x0, 1143 allowsAllAtL3: false, 1144 CachedSelectors: CachedSelectorSlice{cachedSelectorBar1}, 1145 L7Parser: "", 1146 L7RulesPerEp: L7DataMap{}, 1147 Ingress: false, 1148 DerivedFromRules: labels.LabelArrayList{labelsL4}, 1149 }, 1150 } 1151 c.Assert(policy, checker.Equals, expectedPolicy) 1152 policy.Detach(repo.GetSelectorCache()) 1153 } 1154 1155 func (ds *PolicyTestSuite) TestWildcardL4RulesEgress(c *C) { 1156 repo := NewPolicyRepository() 1157 repo.selectorCache = testSelectorCache 1158 1159 selFoo := api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 1160 selBar1 := api.NewESFromLabels(labels.ParseSelectLabel("id=bar1")) 1161 selBar2 := api.NewESFromLabels(labels.ParseSelectLabel("id=bar2")) 1162 1163 labelsL3 := labels.LabelArray{labels.ParseLabel("L3")} 1164 labelsDNS := labels.LabelArray{labels.ParseLabel("dns")} 1165 labelsHTTP := labels.LabelArray{labels.ParseLabel("http")} 1166 1167 l453Rule := api.Rule{ 1168 EndpointSelector: selFoo, 1169 Egress: []api.EgressRule{ 1170 { 1171 ToEndpoints: []api.EndpointSelector{selBar1}, 1172 ToPorts: []api.PortRule{{ 1173 Ports: []api.PortProtocol{ 1174 {Port: "53", Protocol: api.ProtoUDP}, 1175 }, 1176 }}, 1177 }, 1178 }, 1179 Labels: labelsL3, 1180 } 1181 l453Rule.Sanitize() 1182 _, _, err := repo.Add(l453Rule, []Endpoint{}) 1183 c.Assert(err, IsNil) 1184 1185 dnsRule := api.Rule{ 1186 EndpointSelector: selFoo, 1187 Egress: []api.EgressRule{ 1188 { 1189 ToEndpoints: []api.EndpointSelector{selBar2}, 1190 ToPorts: []api.PortRule{{ 1191 Ports: []api.PortProtocol{ 1192 {Port: "53", Protocol: api.ProtoUDP}, 1193 }, 1194 Rules: &api.L7Rules{ 1195 DNS: []api.PortRuleDNS{ 1196 {MatchName: "empire.gov"}, 1197 }, 1198 }, 1199 }}, 1200 }, 1201 }, 1202 Labels: labelsDNS, 1203 } 1204 dnsRule.Sanitize() 1205 _, _, err = repo.Add(dnsRule, []Endpoint{}) 1206 c.Assert(err, IsNil) 1207 1208 l480Rule := api.Rule{ 1209 EndpointSelector: selFoo, 1210 Egress: []api.EgressRule{ 1211 { 1212 ToEndpoints: []api.EndpointSelector{selBar1}, 1213 ToPorts: []api.PortRule{{ 1214 Ports: []api.PortProtocol{ 1215 {Port: "80", Protocol: api.ProtoTCP}, 1216 }, 1217 }}, 1218 }, 1219 }, 1220 Labels: labelsL3, 1221 } 1222 l480Rule.Sanitize() 1223 _, _, err = repo.Add(l480Rule, []Endpoint{}) 1224 c.Assert(err, IsNil) 1225 1226 httpRule := api.Rule{ 1227 EndpointSelector: selFoo, 1228 Egress: []api.EgressRule{ 1229 { 1230 ToEndpoints: []api.EndpointSelector{selBar2}, 1231 ToPorts: []api.PortRule{{ 1232 Ports: []api.PortProtocol{ 1233 {Port: "80", Protocol: api.ProtoTCP}, 1234 }, 1235 Rules: &api.L7Rules{ 1236 HTTP: []api.PortRuleHTTP{ 1237 {Method: "GET", Path: "/"}, 1238 }, 1239 }, 1240 }}, 1241 }, 1242 }, 1243 Labels: labelsHTTP, 1244 } 1245 _, _, err = repo.Add(httpRule, []Endpoint{}) 1246 c.Assert(err, IsNil) 1247 1248 ctx := &SearchContext{ 1249 From: labels.ParseSelectLabelArray("id=foo"), 1250 } 1251 1252 repo.Mutex.RLock() 1253 defer repo.Mutex.RUnlock() 1254 1255 policy, err := repo.ResolveL4EgressPolicy(ctx) 1256 c.Assert(err, IsNil) 1257 1258 expectedPolicy := L4PolicyMap{ 1259 "80/TCP": { 1260 Port: 80, 1261 Protocol: api.ProtoTCP, 1262 U8Proto: 0x6, 1263 CachedSelectors: CachedSelectorSlice{cachedSelectorBar1, cachedSelectorBar2}, 1264 L7Parser: ParserTypeHTTP, 1265 Ingress: false, 1266 L7RulesPerEp: L7DataMap{ 1267 cachedSelectorBar1: api.L7Rules{ 1268 HTTP: []api.PortRuleHTTP{{}}, 1269 }, 1270 cachedSelectorBar2: api.L7Rules{ 1271 HTTP: []api.PortRuleHTTP{httpRule.Egress[0].ToPorts[0].Rules.HTTP[0]}, 1272 }, 1273 }, 1274 DerivedFromRules: labels.LabelArrayList{labelsL3, labelsHTTP, labelsL3}, 1275 }, 1276 "53/UDP": { 1277 Port: 53, 1278 Protocol: api.ProtoUDP, 1279 U8Proto: 0x11, 1280 CachedSelectors: CachedSelectorSlice{cachedSelectorBar1, cachedSelectorBar2}, 1281 L7Parser: ParserTypeDNS, 1282 Ingress: false, 1283 L7RulesPerEp: L7DataMap{ 1284 cachedSelectorBar1: api.L7Rules{ 1285 DNS: []api.PortRuleDNS{{MatchPattern: "*"}}, 1286 }, 1287 cachedSelectorBar2: api.L7Rules{ 1288 DNS: []api.PortRuleDNS{dnsRule.Egress[0].ToPorts[0].Rules.DNS[0]}, 1289 }, 1290 }, 1291 DerivedFromRules: labels.LabelArrayList{labelsL3, labelsDNS, labelsL3}, 1292 }, 1293 } 1294 c.Assert(policy, checker.Equals, expectedPolicy) 1295 policy.Detach(repo.GetSelectorCache()) 1296 } 1297 1298 func (ds *PolicyTestSuite) TestWildcardCIDRRulesEgress(c *C) { 1299 repo := NewPolicyRepository() 1300 repo.selectorCache = testSelectorCache 1301 1302 labelsL3 := labels.LabelArray{labels.ParseLabel("L3")} 1303 labelsHTTP := labels.LabelArray{labels.ParseLabel("http")} 1304 1305 cidrSlice := api.CIDRSlice{"192.0.0.0/3"} 1306 cidrSelectors := cidrSlice.GetAsEndpointSelectors() 1307 var cachedSelectors CachedSelectorSlice 1308 for i := range cidrSelectors { 1309 c, _ := testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, cidrSelectors[i]) 1310 cachedSelectors = append(cachedSelectors, c) 1311 defer testSelectorCache.RemoveSelector(c, dummySelectorCacheUser) 1312 } 1313 selFoo := api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 1314 1315 l480Get := api.Rule{ 1316 EndpointSelector: selFoo, 1317 Egress: []api.EgressRule{ 1318 { 1319 ToCIDR: api.CIDRSlice{"192.0.0.0/3"}, 1320 ToPorts: []api.PortRule{{ 1321 Ports: []api.PortProtocol{ 1322 { 1323 Port: "80", 1324 Protocol: api.ProtoTCP, 1325 }, 1326 }, 1327 Rules: &api.L7Rules{ 1328 HTTP: []api.PortRuleHTTP{ 1329 { 1330 Headers: []string{"X-My-Header: true"}, 1331 Method: "GET", 1332 Path: "/", 1333 }, 1334 }, 1335 }, 1336 }}, 1337 }, 1338 }, 1339 Labels: labelsHTTP, 1340 } 1341 l480Get.Sanitize() 1342 _, _, err := repo.Add(l480Get, []Endpoint{}) 1343 c.Assert(err, IsNil) 1344 1345 l3Rule := api.Rule{ 1346 EndpointSelector: selFoo, 1347 Egress: []api.EgressRule{ 1348 { 1349 ToCIDR: api.CIDRSlice{"192.0.0.0/3"}, 1350 }, 1351 }, 1352 Labels: labelsL3, 1353 } 1354 l3Rule.Sanitize() 1355 _, _, err = repo.Add(l3Rule, []Endpoint{}) 1356 c.Assert(err, IsNil) 1357 1358 ctx := &SearchContext{ 1359 From: labels.ParseSelectLabelArray("id=foo"), 1360 } 1361 1362 repo.Mutex.RLock() 1363 defer repo.Mutex.RUnlock() 1364 1365 policy, err := repo.ResolveL4EgressPolicy(ctx) 1366 c.Assert(err, IsNil) 1367 1368 expectedPolicy := L4PolicyMap{ 1369 "80/TCP": { 1370 Port: 80, 1371 Protocol: api.ProtoTCP, 1372 U8Proto: 0x6, 1373 CachedSelectors: cachedSelectors, 1374 L7Parser: ParserTypeHTTP, 1375 Ingress: false, 1376 L7RulesPerEp: L7DataMap{ 1377 cachedSelectors[0]: api.L7Rules{ 1378 HTTP: []api.PortRuleHTTP{{}}, 1379 }, 1380 }, 1381 DerivedFromRules: labels.LabelArrayList{labelsHTTP, labelsL3}, 1382 }, 1383 "0/ANY": { 1384 Port: 0, 1385 Protocol: api.ProtoAny, 1386 U8Proto: 0x0, 1387 CachedSelectors: cachedSelectors, 1388 L7Parser: ParserTypeNone, 1389 Ingress: false, 1390 DerivedFromRules: labels.LabelArrayList{labelsL3}, 1391 L7RulesPerEp: L7DataMap{}, 1392 }, 1393 } 1394 c.Assert(policy, checker.Equals, expectedPolicy) 1395 policy.Detach(repo.GetSelectorCache()) 1396 } 1397 1398 func (ds *PolicyTestSuite) TestWildcardL3RulesIngressFromEntities(c *C) { 1399 repo := NewPolicyRepository() 1400 repo.selectorCache = testSelectorCache 1401 1402 selFoo := api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 1403 selBar2 := api.NewESFromLabels(labels.ParseSelectLabel("id=bar2")) 1404 1405 labelsL3 := labels.LabelArray{labels.ParseLabel("L3")} 1406 labelsKafka := labels.LabelArray{labels.ParseLabel("kafka")} 1407 labelsHTTP := labels.LabelArray{labels.ParseLabel("http")} 1408 1409 l3Rule := api.Rule{ 1410 EndpointSelector: selFoo, 1411 Ingress: []api.IngressRule{ 1412 { 1413 FromEntities: api.EntitySlice{api.EntityWorld}, 1414 }, 1415 }, 1416 Labels: labelsL3, 1417 } 1418 l3Rule.Sanitize() 1419 _, _, err := repo.Add(l3Rule, []Endpoint{}) 1420 c.Assert(err, IsNil) 1421 1422 kafkaRule := api.Rule{ 1423 EndpointSelector: selFoo, 1424 Ingress: []api.IngressRule{ 1425 { 1426 FromEndpoints: []api.EndpointSelector{selBar2}, 1427 ToPorts: []api.PortRule{{ 1428 Ports: []api.PortProtocol{ 1429 {Port: "9092", Protocol: api.ProtoTCP}, 1430 }, 1431 Rules: &api.L7Rules{ 1432 Kafka: []api.PortRuleKafka{ 1433 {APIKey: "produce"}, 1434 }, 1435 }, 1436 }}, 1437 }, 1438 }, 1439 Labels: labelsKafka, 1440 } 1441 kafkaRule.Sanitize() 1442 _, _, err = repo.Add(kafkaRule, []Endpoint{}) 1443 c.Assert(err, IsNil) 1444 1445 httpRule := api.Rule{ 1446 EndpointSelector: selFoo, 1447 Ingress: []api.IngressRule{ 1448 { 1449 FromEndpoints: []api.EndpointSelector{selBar2}, 1450 ToPorts: []api.PortRule{{ 1451 Ports: []api.PortProtocol{ 1452 {Port: "80", Protocol: api.ProtoTCP}, 1453 }, 1454 Rules: &api.L7Rules{ 1455 HTTP: []api.PortRuleHTTP{ 1456 {Method: "GET", Path: "/"}, 1457 }, 1458 }, 1459 }}, 1460 }, 1461 }, 1462 Labels: labelsHTTP, 1463 } 1464 _, _, err = repo.Add(httpRule, []Endpoint{}) 1465 c.Assert(err, IsNil) 1466 1467 ctx := &SearchContext{ 1468 To: labels.ParseSelectLabelArray("id=foo"), 1469 } 1470 1471 repo.Mutex.RLock() 1472 defer repo.Mutex.RUnlock() 1473 1474 policy, err := repo.ResolveL4IngressPolicy(ctx) 1475 c.Assert(err, IsNil) 1476 c.Assert(len(policy), Equals, 3) 1477 selWorld := api.EntitySelectorMapping[api.EntityWorld][0] 1478 c.Assert(len(policy["80/TCP"].CachedSelectors), Equals, 2) 1479 cachedSelectorWorld := testSelectorCache.FindCachedIdentitySelector(selWorld) 1480 c.Assert(cachedSelectorWorld, Not(IsNil)) 1481 1482 expectedPolicy := L4PolicyMap{ 1483 "0/ANY": { 1484 Port: 0, 1485 Protocol: "ANY", 1486 U8Proto: 0x0, 1487 allowsAllAtL3: false, 1488 CachedSelectors: CachedSelectorSlice{cachedSelectorWorld}, 1489 L7Parser: "", 1490 L7RulesPerEp: L7DataMap{}, 1491 Ingress: true, 1492 DerivedFromRules: labels.LabelArrayList{labelsL3}, 1493 }, 1494 "9092/TCP": { 1495 Port: 9092, 1496 Protocol: api.ProtoTCP, 1497 U8Proto: 0x6, 1498 CachedSelectors: CachedSelectorSlice{cachedSelectorBar2, cachedSelectorWorld}, 1499 L7Parser: ParserTypeKafka, 1500 Ingress: true, 1501 L7RulesPerEp: L7DataMap{ 1502 cachedSelectorWorld: api.L7Rules{ 1503 Kafka: []api.PortRuleKafka{{}}, 1504 }, 1505 cachedSelectorBar2: api.L7Rules{ 1506 Kafka: []api.PortRuleKafka{kafkaRule.Ingress[0].ToPorts[0].Rules.Kafka[0]}, 1507 }, 1508 }, 1509 DerivedFromRules: labels.LabelArrayList{labelsKafka, labelsL3}, 1510 }, 1511 "80/TCP": { 1512 Port: 80, 1513 Protocol: api.ProtoTCP, 1514 U8Proto: 0x6, 1515 CachedSelectors: CachedSelectorSlice{cachedSelectorBar2, cachedSelectorWorld}, 1516 L7Parser: ParserTypeHTTP, 1517 Ingress: true, 1518 L7RulesPerEp: L7DataMap{ 1519 cachedSelectorWorld: api.L7Rules{ 1520 HTTP: []api.PortRuleHTTP{{}}, 1521 }, 1522 cachedSelectorBar2: api.L7Rules{ 1523 HTTP: []api.PortRuleHTTP{httpRule.Ingress[0].ToPorts[0].Rules.HTTP[0]}, 1524 }, 1525 }, 1526 DerivedFromRules: labels.LabelArrayList{labelsHTTP, labelsL3}, 1527 }, 1528 } 1529 1530 c.Assert(policy, checker.Equals, expectedPolicy) 1531 policy.Detach(repo.GetSelectorCache()) 1532 } 1533 1534 func (ds *PolicyTestSuite) TestWildcardL3RulesEgressToEntities(c *C) { 1535 repo := NewPolicyRepository() 1536 repo.selectorCache = testSelectorCache 1537 1538 selFoo := api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 1539 selBar2 := api.NewESFromLabels(labels.ParseSelectLabel("id=bar2")) 1540 1541 labelsL3 := labels.LabelArray{labels.ParseLabel("L3")} 1542 labelsDNS := labels.LabelArray{labels.ParseLabel("dns")} 1543 labelsHTTP := labels.LabelArray{labels.ParseLabel("http")} 1544 1545 l3Rule := api.Rule{ 1546 EndpointSelector: selFoo, 1547 Egress: []api.EgressRule{ 1548 { 1549 ToEntities: api.EntitySlice{api.EntityWorld}, 1550 }, 1551 }, 1552 Labels: labelsL3, 1553 } 1554 l3Rule.Sanitize() 1555 _, _, err := repo.Add(l3Rule, []Endpoint{}) 1556 c.Assert(err, IsNil) 1557 1558 dnsRule := api.Rule{ 1559 EndpointSelector: selFoo, 1560 Egress: []api.EgressRule{ 1561 { 1562 ToEndpoints: []api.EndpointSelector{selBar2}, 1563 ToPorts: []api.PortRule{{ 1564 Ports: []api.PortProtocol{ 1565 {Port: "53", Protocol: api.ProtoUDP}, 1566 }, 1567 Rules: &api.L7Rules{ 1568 DNS: []api.PortRuleDNS{ 1569 {MatchName: "empire.gov"}, 1570 }, 1571 }, 1572 }}, 1573 }, 1574 }, 1575 Labels: labelsDNS, 1576 } 1577 dnsRule.Sanitize() 1578 _, _, err = repo.Add(dnsRule, []Endpoint{}) 1579 c.Assert(err, IsNil) 1580 1581 httpRule := api.Rule{ 1582 EndpointSelector: selFoo, 1583 Egress: []api.EgressRule{ 1584 { 1585 ToEndpoints: []api.EndpointSelector{selBar2}, 1586 ToPorts: []api.PortRule{{ 1587 Ports: []api.PortProtocol{ 1588 {Port: "80", Protocol: api.ProtoTCP}, 1589 }, 1590 Rules: &api.L7Rules{ 1591 HTTP: []api.PortRuleHTTP{ 1592 {Method: "GET", Path: "/"}, 1593 }, 1594 }, 1595 }}, 1596 }, 1597 }, 1598 Labels: labelsHTTP, 1599 } 1600 _, _, err = repo.Add(httpRule, []Endpoint{}) 1601 c.Assert(err, IsNil) 1602 1603 ctx := &SearchContext{ 1604 From: labels.ParseSelectLabelArray("id=foo"), 1605 } 1606 1607 repo.Mutex.RLock() 1608 defer repo.Mutex.RUnlock() 1609 1610 policy, err := repo.ResolveL4EgressPolicy(ctx) 1611 c.Assert(err, IsNil) 1612 c.Assert(len(policy), Equals, 3) 1613 selWorld := api.EntitySelectorMapping[api.EntityWorld][0] 1614 c.Assert(len(policy["80/TCP"].CachedSelectors), Equals, 2) 1615 cachedSelectorWorld := testSelectorCache.FindCachedIdentitySelector(selWorld) 1616 c.Assert(cachedSelectorWorld, Not(IsNil)) 1617 1618 expectedPolicy := L4PolicyMap{ 1619 "0/ANY": { 1620 Port: 0, 1621 Protocol: "ANY", 1622 U8Proto: 0x0, 1623 allowsAllAtL3: false, 1624 CachedSelectors: CachedSelectorSlice{cachedSelectorWorld}, 1625 L7Parser: "", 1626 L7RulesPerEp: L7DataMap{}, 1627 Ingress: false, 1628 DerivedFromRules: labels.LabelArrayList{labelsL3}, 1629 }, 1630 "53/UDP": { 1631 Port: 53, 1632 Protocol: api.ProtoUDP, 1633 U8Proto: 0x11, 1634 CachedSelectors: CachedSelectorSlice{cachedSelectorBar2, cachedSelectorWorld}, 1635 L7Parser: ParserTypeDNS, 1636 Ingress: false, 1637 L7RulesPerEp: L7DataMap{ 1638 cachedSelectorWorld: api.L7Rules{ 1639 DNS: []api.PortRuleDNS{{MatchPattern: "*"}}, 1640 }, 1641 cachedSelectorBar2: api.L7Rules{ 1642 DNS: []api.PortRuleDNS{dnsRule.Egress[0].ToPorts[0].Rules.DNS[0]}, 1643 }, 1644 }, 1645 DerivedFromRules: labels.LabelArrayList{labelsDNS, labelsL3}, 1646 }, 1647 "80/TCP": { 1648 Port: 80, 1649 Protocol: api.ProtoTCP, 1650 U8Proto: 0x6, 1651 CachedSelectors: CachedSelectorSlice{cachedSelectorBar2, cachedSelectorWorld}, 1652 L7Parser: ParserTypeHTTP, 1653 Ingress: false, 1654 L7RulesPerEp: L7DataMap{ 1655 cachedSelectorWorld: api.L7Rules{ 1656 HTTP: []api.PortRuleHTTP{{}}, 1657 }, 1658 cachedSelectorBar2: api.L7Rules{ 1659 HTTP: []api.PortRuleHTTP{httpRule.Egress[0].ToPorts[0].Rules.HTTP[0]}, 1660 }, 1661 }, 1662 DerivedFromRules: labels.LabelArrayList{labelsHTTP, labelsL3}, 1663 }, 1664 } 1665 1666 c.Assert(policy, checker.Equals, expectedPolicy) 1667 policy.Detach(repo.GetSelectorCache()) 1668 } 1669 1670 func (ds *PolicyTestSuite) TestMinikubeGettingStarted(c *C) { 1671 repo := NewPolicyRepository() 1672 repo.selectorCache = testSelectorCache 1673 1674 app2Selector := labels.ParseSelectLabelArray("id=app2") 1675 1676 fromApp2 := &SearchContext{ 1677 From: app2Selector, 1678 To: labels.ParseSelectLabelArray("id=app1"), 1679 Trace: TRACE_VERBOSE, 1680 } 1681 1682 fromApp3 := &SearchContext{ 1683 From: labels.ParseSelectLabelArray("id=app3"), 1684 To: labels.ParseSelectLabelArray("id=app1"), 1685 } 1686 1687 repo.Mutex.RLock() 1688 // no rules loaded: Allows() => denied 1689 c.Assert(repo.AllowsIngressRLocked(fromApp2), Equals, api.Denied) 1690 c.Assert(repo.AllowsIngressRLocked(fromApp3), Equals, api.Denied) 1691 repo.Mutex.RUnlock() 1692 1693 selFromApp2 := api.NewESFromLabels( 1694 labels.ParseSelectLabel("id=app2"), 1695 ) 1696 1697 selectorFromApp2 := []api.EndpointSelector{ 1698 selFromApp2, 1699 } 1700 1701 _, _, err := repo.Add(api.Rule{ 1702 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("id=app1")), 1703 Ingress: []api.IngressRule{ 1704 { 1705 FromEndpoints: selectorFromApp2, 1706 ToPorts: []api.PortRule{{ 1707 Ports: []api.PortProtocol{ 1708 {Port: "80", Protocol: api.ProtoTCP}, 1709 }, 1710 }}, 1711 }, 1712 }, 1713 }, []Endpoint{}) 1714 c.Assert(err, IsNil) 1715 1716 _, _, err = repo.Add(api.Rule{ 1717 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("id=app1")), 1718 Ingress: []api.IngressRule{ 1719 { 1720 FromEndpoints: selectorFromApp2, 1721 ToPorts: []api.PortRule{{ 1722 Ports: []api.PortProtocol{ 1723 {Port: "80", Protocol: api.ProtoTCP}, 1724 }, 1725 Rules: &api.L7Rules{ 1726 HTTP: []api.PortRuleHTTP{ 1727 {Method: "GET", Path: "/"}, 1728 }, 1729 }, 1730 }}, 1731 }, 1732 }, 1733 }, []Endpoint{}) 1734 c.Assert(err, IsNil) 1735 1736 _, _, err = repo.Add(api.Rule{ 1737 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("id=app1")), 1738 Ingress: []api.IngressRule{ 1739 { 1740 FromEndpoints: selectorFromApp2, 1741 ToPorts: []api.PortRule{{ 1742 Ports: []api.PortProtocol{ 1743 {Port: "80", Protocol: api.ProtoTCP}, 1744 }, 1745 Rules: &api.L7Rules{ 1746 HTTP: []api.PortRuleHTTP{ 1747 {Method: "GET", Path: "/"}, 1748 }, 1749 }, 1750 }}, 1751 }, 1752 }, 1753 }, []Endpoint{}) 1754 c.Assert(err, IsNil) 1755 1756 repo.Mutex.RLock() 1757 defer repo.Mutex.RUnlock() 1758 1759 // L4 from app2 is restricted 1760 logBuffer := new(bytes.Buffer) 1761 l4IngressPolicy, err := repo.ResolveL4IngressPolicy(fromApp2.WithLogger(logBuffer)) 1762 c.Assert(err, IsNil) 1763 1764 cachedSelectorApp2 := testSelectorCache.FindCachedIdentitySelector(selFromApp2) 1765 c.Assert(cachedSelectorApp2, Not(IsNil)) 1766 1767 expected := NewL4Policy(repo.GetRevision()) 1768 expected.Ingress["80/TCP"] = &L4Filter{ 1769 Port: 80, Protocol: api.ProtoTCP, U8Proto: 6, 1770 CachedSelectors: CachedSelectorSlice{cachedSelectorApp2}, 1771 L7Parser: ParserTypeHTTP, 1772 L7RulesPerEp: L7DataMap{ 1773 cachedSelectorApp2: api.L7Rules{ 1774 HTTP: []api.PortRuleHTTP{{}}, 1775 }, 1776 }, 1777 Ingress: true, 1778 DerivedFromRules: []labels.LabelArray{nil, nil, nil, nil}, 1779 } 1780 1781 if equal, err := checker.Equal(l4IngressPolicy, expected.Ingress); !equal { 1782 c.Logf("%s", logBuffer.String()) 1783 c.Errorf("Resolved policy did not match expected: \n%s", err) 1784 } 1785 l4IngressPolicy.Detach(testSelectorCache) 1786 expected.Detach(testSelectorCache) 1787 1788 // L4 from app3 has no rules 1789 expected = NewL4Policy(repo.GetRevision()) 1790 l4IngressPolicy, err = repo.ResolveL4IngressPolicy(fromApp3) 1791 c.Assert(err, IsNil) 1792 c.Assert(len(l4IngressPolicy), Equals, 0) 1793 c.Assert(l4IngressPolicy, checker.Equals, expected.Ingress) 1794 l4IngressPolicy.Detach(testSelectorCache) 1795 expected.Detach(testSelectorCache) 1796 } 1797 1798 func buildSearchCtx(from, to string, port uint16) *SearchContext { 1799 ports := []*models.Port{{Port: port, Protocol: string(api.ProtoAny)}} 1800 return &SearchContext{ 1801 From: labels.ParseSelectLabelArray(from), 1802 To: labels.ParseSelectLabelArray(to), 1803 DPorts: ports, 1804 Trace: TRACE_ENABLED, 1805 } 1806 } 1807 1808 func buildRule(from, to, port string) api.Rule { 1809 reservedES := api.NewESFromLabels(labels.ParseSelectLabel("reserved:host")) 1810 fromES := api.NewESFromLabels(labels.ParseSelectLabel(from)) 1811 toES := api.NewESFromLabels(labels.ParseSelectLabel(to)) 1812 1813 ports := []api.PortRule{} 1814 if port != "" { 1815 ports = []api.PortRule{ 1816 {Ports: []api.PortProtocol{{Port: port}}}, 1817 } 1818 } 1819 return api.Rule{ 1820 EndpointSelector: toES, 1821 Ingress: []api.IngressRule{ 1822 { 1823 FromEndpoints: []api.EndpointSelector{ 1824 reservedES, 1825 fromES, 1826 }, 1827 ToPorts: ports, 1828 }, 1829 }, 1830 } 1831 } 1832 1833 func (repo *Repository) checkTrace(c *C, ctx *SearchContext, trace string, 1834 expectedVerdict api.Decision) { 1835 1836 buffer := new(bytes.Buffer) 1837 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1838 1839 repo.Mutex.RLock() 1840 verdict := repo.AllowsIngressRLocked(ctx) 1841 repo.Mutex.RUnlock() 1842 1843 expectedOut := "Tracing " + ctx.String() + "\n" + trace 1844 c.Assert(buffer.String(), checker.DeepEquals, expectedOut) 1845 c.Assert(verdict, Equals, expectedVerdict) 1846 } 1847 1848 func (ds *PolicyTestSuite) TestPolicyTrace(c *C) { 1849 repo := NewPolicyRepository() 1850 repo.selectorCache = testSelectorCache 1851 1852 // Add rules to allow foo=>bar 1853 l3rule := buildRule("foo", "bar", "") 1854 rules := api.Rules{&l3rule} 1855 _, _ = repo.AddList(rules) 1856 1857 // foo=>bar is OK 1858 expectedOut := ` 1859 Resolving ingress policy for [any:bar] 1860 * Rule {"matchLabels":{"any:bar":""}}: selected 1861 Allows from labels {"matchLabels":{"reserved:host":""}} 1862 Allows from labels {"matchLabels":{"any:foo":""}} 1863 Found all required labels 1864 1/1 rules selected 1865 Found allow rule 1866 Ingress verdict: allowed 1867 ` 1868 ctx := buildSearchCtx("foo", "bar", 0) 1869 repo.checkTrace(c, ctx, expectedOut, api.Allowed) 1870 1871 // foo=>bar:80 is OK 1872 ctx = buildSearchCtx("foo", "bar", 80) 1873 repo.checkTrace(c, ctx, expectedOut, api.Allowed) 1874 1875 // bar=>foo is Denied 1876 ctx = buildSearchCtx("bar", "foo", 0) 1877 expectedOut = ` 1878 Resolving ingress policy for [any:foo] 1879 0/1 rules selected 1880 Found no allow rule 1881 Ingress verdict: denied 1882 ` 1883 repo.checkTrace(c, ctx, expectedOut, api.Denied) 1884 1885 // bar=>foo:80 is also Denied by the same logic 1886 ctx = buildSearchCtx("bar", "foo", 80) 1887 repo.checkTrace(c, ctx, expectedOut, api.Denied) 1888 1889 // Now, add extra rules to allow specifically baz=>bar on port 80 1890 l4rule := buildRule("baz", "bar", "80") 1891 _, _, err := repo.Add(l4rule, []Endpoint{}) 1892 c.Assert(err, IsNil) 1893 1894 // baz=>bar:80 is OK 1895 ctx = buildSearchCtx("baz", "bar", 80) 1896 expectedOut = ` 1897 Resolving ingress policy for [any:bar] 1898 * Rule {"matchLabels":{"any:bar":""}}: selected 1899 Allows from labels {"matchLabels":{"reserved:host":""}} 1900 Allows from labels {"matchLabels":{"any:foo":""}} 1901 No label match for [any:baz] 1902 * Rule {"matchLabels":{"any:bar":""}}: selected 1903 Allows from labels {"matchLabels":{"reserved:host":""}} 1904 Allows from labels {"matchLabels":{"any:baz":""}} 1905 Found all required labels 1906 Allows port [{80 ANY}] 1907 2/2 rules selected 1908 Found allow rule 1909 Ingress verdict: allowed 1910 ` 1911 repo.checkTrace(c, ctx, expectedOut, api.Allowed) 1912 1913 // bar=>bar:80 is Denied 1914 ctx = buildSearchCtx("bar", "bar", 80) 1915 expectedOut = ` 1916 Resolving ingress policy for [any:bar] 1917 * Rule {"matchLabels":{"any:bar":""}}: selected 1918 Allows from labels {"matchLabels":{"reserved:host":""}} 1919 Allows from labels {"matchLabels":{"any:foo":""}} 1920 No label match for [any:bar] 1921 * Rule {"matchLabels":{"any:bar":""}}: selected 1922 Allows from labels {"matchLabels":{"reserved:host":""}} 1923 Allows from labels {"matchLabels":{"any:baz":""}} 1924 No label match for [any:bar] 1925 2/2 rules selected 1926 Found no allow rule 1927 Ingress verdict: denied 1928 ` 1929 repo.checkTrace(c, ctx, expectedOut, api.Denied) 1930 1931 // Test that FromRequires "baz" drops "foo" traffic 1932 l3rule = api.Rule{ 1933 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 1934 Ingress: []api.IngressRule{{ 1935 FromRequires: []api.EndpointSelector{ 1936 api.NewESFromLabels(labels.ParseSelectLabel("baz")), 1937 }, 1938 }}, 1939 } 1940 _, _, err = repo.Add(l3rule, []Endpoint{}) 1941 c.Assert(err, IsNil) 1942 1943 // foo=>bar is now denied due to the FromRequires 1944 ctx = buildSearchCtx("foo", "bar", 0) 1945 expectedOut = ` 1946 Resolving ingress policy for [any:bar] 1947 * Rule {"matchLabels":{"any:bar":""}}: selected 1948 Enforcing requirements [{Key:any.baz Operator:In Values:[]}] 1949 Allows from labels {"matchLabels":{"reserved:host":""},"matchExpressions":[{"key":"any:baz","operator":"In","values":[""]}]} 1950 Allows from labels {"matchLabels":{"any:foo":""},"matchExpressions":[{"key":"any:baz","operator":"In","values":[""]}]} 1951 No label match for [any:foo] 1952 * Rule {"matchLabels":{"any:bar":""}}: selected 1953 Enforcing requirements [{Key:any.baz Operator:In Values:[]}] 1954 Allows from labels {"matchLabels":{"reserved:host":""},"matchExpressions":[{"key":"any:baz","operator":"In","values":[""]}]} 1955 Allows from labels {"matchLabels":{"any:baz":""},"matchExpressions":[{"key":"any:baz","operator":"In","values":[""]}]} 1956 No label match for [any:foo] 1957 * Rule {"matchLabels":{"any:bar":""}}: selected 1958 3/3 rules selected 1959 Found no allow rule 1960 Ingress verdict: denied 1961 ` 1962 repo.checkTrace(c, ctx, expectedOut, api.Denied) 1963 1964 // baz=>bar is only denied because of the L4 policy 1965 ctx = buildSearchCtx("baz", "bar", 0) 1966 expectedOut = ` 1967 Resolving ingress policy for [any:bar] 1968 * Rule {"matchLabels":{"any:bar":""}}: selected 1969 Enforcing requirements [{Key:any.baz Operator:In Values:[]}] 1970 Allows from labels {"matchLabels":{"reserved:host":""},"matchExpressions":[{"key":"any:baz","operator":"In","values":[""]}]} 1971 Allows from labels {"matchLabels":{"any:foo":""},"matchExpressions":[{"key":"any:baz","operator":"In","values":[""]}]} 1972 No label match for [any:baz] 1973 * Rule {"matchLabels":{"any:bar":""}}: selected 1974 Enforcing requirements [{Key:any.baz Operator:In Values:[]}] 1975 Allows from labels {"matchLabels":{"reserved:host":""},"matchExpressions":[{"key":"any:baz","operator":"In","values":[""]}]} 1976 Allows from labels {"matchLabels":{"any:baz":""},"matchExpressions":[{"key":"any:baz","operator":"In","values":[""]}]} 1977 Found all required labels 1978 Allows port [{80 ANY}] 1979 No port match found 1980 * Rule {"matchLabels":{"any:bar":""}}: selected 1981 3/3 rules selected 1982 Found no allow rule 1983 Ingress verdict: denied 1984 ` 1985 repo.checkTrace(c, ctx, expectedOut, api.Denied) 1986 1987 // Should still be allowed with the new FromRequires constraint 1988 ctx = buildSearchCtx("baz", "bar", 80) 1989 repo.Mutex.RLock() 1990 verdict := repo.AllowsIngressRLocked(ctx) 1991 repo.Mutex.RUnlock() 1992 c.Assert(verdict, Equals, api.Allowed) 1993 } 1994 1995 func (ds *PolicyTestSuite) TestremoveIdentityFromRuleCaches(c *C) { 1996 1997 testRepo := parseAndAddRules(c, api.Rules{&api.Rule{ 1998 EndpointSelector: endpointSelectorA, 1999 Ingress: []api.IngressRule{ 2000 { 2001 FromEndpoints: []api.EndpointSelector{endpointSelectorC}, 2002 }, 2003 }, 2004 }}) 2005 2006 addedRule := testRepo.rules[0] 2007 2008 selectedEpLabels := labels.ParseSelectLabel("id=a") 2009 selectedIdentity := identity.NewIdentity(54321, labels.Labels{selectedEpLabels.Key: selectedEpLabels}) 2010 2011 notSelectedEpLabels := labels.ParseSelectLabel("id=b") 2012 notSelectedIdentity := identity.NewIdentity(9876, labels.Labels{notSelectedEpLabels.Key: notSelectedEpLabels}) 2013 2014 // selectedEndpoint is selected by rule, so we it should be added to 2015 // EndpointsSelected. 2016 c.Assert(addedRule.matches(selectedIdentity), Equals, true) 2017 c.Assert(addedRule.metadata.IdentitySelected, checker.DeepEquals, map[identity.NumericIdentity]bool{selectedIdentity.ID: true}) 2018 2019 wg := testRepo.removeIdentityFromRuleCaches(selectedIdentity) 2020 wg.Wait() 2021 2022 c.Assert(addedRule.metadata.IdentitySelected, checker.DeepEquals, map[identity.NumericIdentity]bool{}) 2023 2024 c.Assert(addedRule.matches(notSelectedIdentity), Equals, false) 2025 c.Assert(addedRule.metadata.IdentitySelected, checker.DeepEquals, map[identity.NumericIdentity]bool{notSelectedIdentity.ID: false}) 2026 2027 wg = testRepo.removeIdentityFromRuleCaches(notSelectedIdentity) 2028 wg.Wait() 2029 2030 c.Assert(addedRule.metadata.IdentitySelected, checker.DeepEquals, map[identity.NumericIdentity]bool{}) 2031 }