github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/rule_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 "net" 23 24 "github.com/cilium/cilium/api/v1/models" 25 "github.com/cilium/cilium/pkg/checker" 26 "github.com/cilium/cilium/pkg/identity" 27 identity2 "github.com/cilium/cilium/pkg/identity" 28 "github.com/cilium/cilium/pkg/labels" 29 "github.com/cilium/cilium/pkg/policy/api" 30 31 logging "github.com/op/go-logging" 32 . "gopkg.in/check.v1" 33 ) 34 35 func (ds *PolicyTestSuite) TestL4Policy(c *C) { 36 toBar := &SearchContext{To: labels.ParseSelectLabelArray("bar")} 37 fromBar := &SearchContext{From: labels.ParseSelectLabelArray("bar")} 38 toFoo := &SearchContext{To: labels.ParseSelectLabelArray("foo")} 39 fromFoo := &SearchContext{From: labels.ParseSelectLabelArray("foo")} 40 41 rule1 := &rule{ 42 Rule: api.Rule{ 43 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 44 Ingress: []api.IngressRule{ 45 { 46 ToPorts: []api.PortRule{{ 47 Ports: []api.PortProtocol{ 48 {Port: "80", Protocol: api.ProtoTCP}, 49 {Port: "8080", Protocol: api.ProtoTCP}, 50 }, 51 Rules: &api.L7Rules{ 52 HTTP: []api.PortRuleHTTP{ 53 {Method: "GET", Path: "/"}, 54 }, 55 }, 56 }}, 57 }, 58 }, 59 Egress: []api.EgressRule{ 60 { 61 ToPorts: []api.PortRule{{ 62 Ports: []api.PortProtocol{ 63 {Port: "3000", Protocol: api.ProtoAny}, 64 }, 65 }}, 66 }, 67 }, 68 }, 69 } 70 71 l7rules := api.L7Rules{ 72 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 73 } 74 l7map := L7DataMap{ 75 wildcardCachedSelector: l7rules, 76 } 77 78 expected := NewL4Policy(0) 79 expected.Ingress["80/TCP"] = &L4Filter{ 80 Port: 80, Protocol: api.ProtoTCP, U8Proto: 6, 81 allowsAllAtL3: true, 82 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 83 L7Parser: "http", L7RulesPerEp: l7map, Ingress: true, 84 DerivedFromRules: labels.LabelArrayList{nil}, 85 } 86 expected.Ingress["8080/TCP"] = &L4Filter{ 87 Port: 8080, Protocol: api.ProtoTCP, U8Proto: 6, 88 allowsAllAtL3: true, 89 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 90 L7Parser: "http", L7RulesPerEp: l7map, Ingress: true, 91 DerivedFromRules: labels.LabelArrayList{nil}, 92 } 93 94 expected.Egress["3000/TCP"] = &L4Filter{ 95 Port: 3000, Protocol: api.ProtoTCP, U8Proto: 6, Ingress: false, 96 allowsAllAtL3: true, 97 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 98 L7RulesPerEp: L7DataMap{}, 99 DerivedFromRules: labels.LabelArrayList{nil}, 100 } 101 expected.Egress["3000/UDP"] = &L4Filter{ 102 Port: 3000, Protocol: api.ProtoUDP, U8Proto: 17, Ingress: false, 103 allowsAllAtL3: true, 104 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 105 L7RulesPerEp: L7DataMap{}, 106 DerivedFromRules: labels.LabelArrayList{nil}, 107 } 108 109 ingressState := traceState{} 110 egressState := traceState{} 111 res := NewL4Policy(0) 112 var err error 113 res.Ingress, err = rule1.resolveIngressPolicy(toBar, &ingressState, L4PolicyMap{}, nil, testSelectorCache) 114 c.Assert(err, IsNil) 115 c.Assert(res.Ingress, Not(IsNil)) 116 117 res.Egress, err = rule1.resolveEgressPolicy(fromBar, &egressState, L4PolicyMap{}, nil, testSelectorCache) 118 c.Assert(err, IsNil) 119 c.Assert(res.Egress, Not(IsNil)) 120 121 c.Assert(res, checker.Equals, expected) 122 c.Assert(ingressState.selectedRules, Equals, 1) 123 c.Assert(ingressState.matchedRules, Equals, 0) 124 125 c.Assert(egressState.selectedRules, Equals, 1) 126 c.Assert(egressState.matchedRules, Equals, 0) 127 res.Detach(testSelectorCache) 128 expected.Detach(testSelectorCache) 129 130 // Foo isn't selected in the rule1's policy. 131 ingressState = traceState{} 132 egressState = traceState{} 133 134 res1, err := rule1.resolveIngressPolicy(toFoo, &ingressState, L4PolicyMap{}, nil, testSelectorCache) 135 c.Assert(err, IsNil) 136 res2, err := rule1.resolveEgressPolicy(fromFoo, &ingressState, L4PolicyMap{}, nil, testSelectorCache) 137 c.Assert(err, IsNil) 138 139 c.Assert(res1, IsNil) 140 c.Assert(res2, IsNil) 141 c.Assert(ingressState.selectedRules, Equals, 0) 142 c.Assert(ingressState.matchedRules, Equals, 0) 143 c.Assert(egressState.selectedRules, Equals, 0) 144 c.Assert(egressState.matchedRules, Equals, 0) 145 146 // This rule actually overlaps with the existing ingress "http" rule, 147 // so we'd expect it to merge. 148 rule2 := &rule{ 149 Rule: api.Rule{ 150 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 151 Ingress: []api.IngressRule{ 152 { 153 ToPorts: []api.PortRule{{ 154 Ports: []api.PortProtocol{ 155 {Port: "80", Protocol: api.ProtoTCP}, 156 }, 157 }}, 158 }, 159 { 160 ToPorts: []api.PortRule{{ 161 Ports: []api.PortProtocol{ 162 {Port: "80", Protocol: api.ProtoTCP}, 163 }, 164 Rules: &api.L7Rules{ 165 HTTP: []api.PortRuleHTTP{ 166 {Method: "GET", Path: "/"}, 167 }, 168 }, 169 }}, 170 }, 171 }, 172 Egress: []api.EgressRule{ 173 { 174 ToPorts: []api.PortRule{{ 175 Ports: []api.PortProtocol{ 176 {Port: "3000", Protocol: api.ProtoAny}, 177 }, 178 }}, 179 }, 180 }, 181 }, 182 } 183 184 expected = NewL4Policy(0) 185 expected.Ingress["80/TCP"] = &L4Filter{ 186 Port: 80, 187 Protocol: api.ProtoTCP, 188 U8Proto: 6, 189 allowsAllAtL3: true, 190 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 191 L7Parser: ParserTypeHTTP, 192 L7RulesPerEp: L7DataMap{ 193 wildcardCachedSelector: api.L7Rules{ 194 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 195 }, 196 }, 197 Ingress: true, 198 DerivedFromRules: labels.LabelArrayList{nil, nil}, 199 } 200 expected.Egress["3000/TCP"] = &L4Filter{ 201 Port: 3000, Protocol: api.ProtoTCP, U8Proto: 6, Ingress: false, 202 allowsAllAtL3: true, 203 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 204 L7RulesPerEp: L7DataMap{}, 205 DerivedFromRules: labels.LabelArrayList{nil}, 206 } 207 expected.Egress["3000/UDP"] = &L4Filter{ 208 Port: 3000, Protocol: api.ProtoUDP, U8Proto: 17, Ingress: false, 209 allowsAllAtL3: true, 210 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 211 L7RulesPerEp: L7DataMap{}, 212 DerivedFromRules: labels.LabelArrayList{nil}, 213 } 214 215 ingressState = traceState{} 216 egressState = traceState{} 217 res = NewL4Policy(0) 218 res.Ingress, err = rule2.resolveIngressPolicy(toBar, &ingressState, L4PolicyMap{}, nil, testSelectorCache) 219 c.Assert(err, IsNil) 220 c.Assert(res.Ingress, Not(IsNil)) 221 222 res.Egress, err = rule2.resolveEgressPolicy(fromBar, &egressState, L4PolicyMap{}, nil, testSelectorCache) 223 c.Assert(err, IsNil) 224 c.Assert(res.Egress, Not(IsNil)) 225 226 c.Assert(len(res.Ingress), Equals, 1) 227 c.Assert(res, checker.Equals, expected) 228 c.Assert(ingressState.selectedRules, Equals, 1) 229 c.Assert(ingressState.matchedRules, Equals, 0) 230 231 c.Assert(egressState.selectedRules, Equals, 1) 232 c.Assert(egressState.matchedRules, Equals, 0) 233 res.Detach(testSelectorCache) 234 expected.Detach(testSelectorCache) 235 236 ingressState = traceState{} 237 egressState = traceState{} 238 239 res1, err = rule2.resolveIngressPolicy(toFoo, &ingressState, L4PolicyMap{}, nil, testSelectorCache) 240 c.Assert(err, IsNil) 241 c.Assert(res1, IsNil) 242 243 res2, err = rule2.resolveEgressPolicy(fromFoo, &egressState, L4PolicyMap{}, nil, testSelectorCache) 244 c.Assert(err, IsNil) 245 c.Assert(res2, IsNil) 246 247 c.Assert(ingressState.selectedRules, Equals, 0) 248 c.Assert(ingressState.matchedRules, Equals, 0) 249 250 c.Assert(egressState.selectedRules, Equals, 0) 251 c.Assert(egressState.matchedRules, Equals, 0) 252 } 253 254 func (ds *PolicyTestSuite) TestMergeL4PolicyIngress(c *C) { 255 toBar := &SearchContext{To: labels.ParseSelectLabelArray("bar")} 256 //toFoo := &SearchContext{To: labels.ParseSelectLabelArray("foo")} 257 258 rule1 := &rule{ 259 Rule: api.Rule{ 260 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 261 Ingress: []api.IngressRule{ 262 { 263 FromEndpoints: []api.EndpointSelector{fooSelector}, 264 ToPorts: []api.PortRule{{ 265 Ports: []api.PortProtocol{ 266 {Port: "80", Protocol: api.ProtoTCP}, 267 }, 268 }}, 269 }, 270 { 271 FromEndpoints: []api.EndpointSelector{bazSelector}, 272 ToPorts: []api.PortRule{{ 273 Ports: []api.PortProtocol{ 274 {Port: "80", Protocol: api.ProtoTCP}, 275 }, 276 }}, 277 }, 278 }, 279 }, 280 } 281 282 mergedES := CachedSelectorSlice{cachedFooSelector, cachedBazSelector} 283 expected := L4PolicyMap{"80/TCP": &L4Filter{ 284 Port: 80, Protocol: api.ProtoTCP, U8Proto: 6, CachedSelectors: mergedES, 285 L7Parser: ParserTypeNone, L7RulesPerEp: L7DataMap{}, Ingress: true, 286 DerivedFromRules: labels.LabelArrayList{nil, nil}, 287 }} 288 289 state := traceState{} 290 res, err := rule1.resolveIngressPolicy(toBar, &state, L4PolicyMap{}, nil, testSelectorCache) 291 c.Assert(err, IsNil) 292 c.Assert(res, Not(IsNil)) 293 c.Assert(res, checker.Equals, expected) 294 c.Assert(state.selectedRules, Equals, 1) 295 c.Assert(state.matchedRules, Equals, 0) 296 res.Detach(testSelectorCache) 297 expected.Detach(testSelectorCache) 298 } 299 300 func (ds *PolicyTestSuite) TestMergeL4PolicyEgress(c *C) { 301 302 buffer := new(bytes.Buffer) 303 fromBar := &SearchContext{ 304 From: labels.ParseSelectLabelArray("bar"), 305 Logging: logging.NewLogBackend(buffer, "", 0), 306 Trace: TRACE_VERBOSE, 307 } 308 309 // bar can access foo with TCP on port 80, and baz with TCP on port 80. 310 rule1 := &rule{ 311 Rule: api.Rule{ 312 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 313 Egress: []api.EgressRule{ 314 { 315 ToEndpoints: []api.EndpointSelector{fooSelector}, 316 ToPorts: []api.PortRule{{ 317 Ports: []api.PortProtocol{ 318 {Port: "80", Protocol: api.ProtoTCP}, 319 }, 320 }}, 321 }, 322 { 323 ToEndpoints: []api.EndpointSelector{bazSelector}, 324 ToPorts: []api.PortRule{{ 325 Ports: []api.PortProtocol{ 326 {Port: "80", Protocol: api.ProtoTCP}, 327 }, 328 }}, 329 }, 330 }, 331 }, 332 } 333 334 mergedES := CachedSelectorSlice{cachedFooSelector, cachedBazSelector} 335 expected := L4PolicyMap{"80/TCP": &L4Filter{ 336 Port: 80, Protocol: api.ProtoTCP, U8Proto: 6, CachedSelectors: mergedES, 337 L7Parser: ParserTypeNone, L7RulesPerEp: L7DataMap{}, Ingress: false, 338 DerivedFromRules: labels.LabelArrayList{nil, nil}, 339 }} 340 341 state := traceState{} 342 res, err := rule1.resolveEgressPolicy(fromBar, &state, L4PolicyMap{}, nil, testSelectorCache) 343 344 c.Log(buffer) 345 346 c.Assert(err, IsNil) 347 c.Assert(res, Not(IsNil)) 348 c.Assert(res, checker.Equals, expected) 349 c.Assert(state.selectedRules, Equals, 1) 350 c.Assert(state.matchedRules, Equals, 0) 351 res.Detach(testSelectorCache) 352 expected.Detach(testSelectorCache) 353 } 354 355 func (ds *PolicyTestSuite) TestMergeL7PolicyIngress(c *C) { 356 toBar := &SearchContext{To: labels.ParseSelectLabelArray("bar")} 357 toFoo := &SearchContext{To: labels.ParseSelectLabelArray("foo")} 358 359 fooSelectorSlice := []api.EndpointSelector{ 360 fooSelector, 361 } 362 rule1 := &rule{ 363 Rule: api.Rule{ 364 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 365 Ingress: []api.IngressRule{ 366 { 367 ToPorts: []api.PortRule{{ 368 Ports: []api.PortProtocol{ 369 {Port: "80", Protocol: api.ProtoTCP}, 370 }, 371 }}, 372 }, 373 { 374 ToPorts: []api.PortRule{{ 375 Ports: []api.PortProtocol{ 376 {Port: "80", Protocol: api.ProtoTCP}, 377 }, 378 Rules: &api.L7Rules{ 379 HTTP: []api.PortRuleHTTP{ 380 {Method: "GET", Path: "/"}, 381 }, 382 }, 383 }}, 384 }, 385 { 386 FromEndpoints: fooSelectorSlice, 387 ToPorts: []api.PortRule{{ 388 Ports: []api.PortProtocol{ 389 {Port: "80", Protocol: api.ProtoTCP}, 390 }, 391 Rules: &api.L7Rules{ 392 HTTP: []api.PortRuleHTTP{ 393 {Method: "GET", Path: "/"}, 394 }, 395 }, 396 }}, 397 }, 398 }, 399 }, 400 } 401 402 expected := L4PolicyMap{"80/TCP": &L4Filter{ 403 Port: 80, 404 Protocol: api.ProtoTCP, 405 U8Proto: 6, 406 allowsAllAtL3: true, 407 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector, cachedFooSelector}, 408 L7Parser: ParserTypeHTTP, 409 L7RulesPerEp: L7DataMap{ 410 wildcardCachedSelector: api.L7Rules{ 411 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 412 }, 413 cachedFooSelector: api.L7Rules{ 414 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 415 }, 416 }, 417 Ingress: true, 418 DerivedFromRules: labels.LabelArrayList{nil, nil, nil}, 419 }} 420 421 state := traceState{} 422 res, err := rule1.resolveIngressPolicy(toBar, &state, L4PolicyMap{}, nil, testSelectorCache) 423 c.Assert(err, IsNil) 424 c.Assert(res, Not(IsNil)) 425 c.Assert(res, checker.Equals, expected) 426 c.Assert(state.selectedRules, Equals, 1) 427 c.Assert(state.matchedRules, Equals, 0) 428 res.Detach(testSelectorCache) 429 expected.Detach(testSelectorCache) 430 431 state = traceState{} 432 res, err = rule1.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 433 c.Assert(err, IsNil) 434 c.Assert(res, IsNil) 435 c.Assert(state.selectedRules, Equals, 0) 436 c.Assert(state.matchedRules, Equals, 0) 437 438 rule2 := &rule{ 439 Rule: api.Rule{ 440 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 441 Ingress: []api.IngressRule{ 442 { 443 ToPorts: []api.PortRule{{ 444 Ports: []api.PortProtocol{ 445 {Port: "80", Protocol: api.ProtoTCP}, 446 }, 447 Rules: &api.L7Rules{ 448 Kafka: []api.PortRuleKafka{ 449 {Topic: "foo"}, 450 }, 451 }, 452 }}, 453 }, 454 { 455 FromEndpoints: fooSelectorSlice, 456 ToPorts: []api.PortRule{{ 457 Ports: []api.PortProtocol{ 458 {Port: "80", Protocol: api.ProtoTCP}, 459 }, 460 Rules: &api.L7Rules{ 461 Kafka: []api.PortRuleKafka{ 462 {Topic: "foo"}, 463 }, 464 }, 465 }}, 466 }, 467 }, 468 }, 469 } 470 471 l7rules := api.L7Rules{ 472 Kafka: []api.PortRuleKafka{{Topic: "foo"}}, 473 } 474 l7map := L7DataMap{ 475 wildcardCachedSelector: l7rules, 476 cachedFooSelector: l7rules, 477 } 478 479 expected = L4PolicyMap{"80/TCP": &L4Filter{ 480 Port: 80, Protocol: api.ProtoTCP, U8Proto: 6, 481 allowsAllAtL3: true, 482 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector, cachedFooSelector}, 483 L7Parser: "kafka", L7RulesPerEp: l7map, Ingress: true, 484 DerivedFromRules: labels.LabelArrayList{nil, nil}, 485 }} 486 487 state = traceState{} 488 res, err = rule2.resolveIngressPolicy(toBar, &state, L4PolicyMap{}, nil, testSelectorCache) 489 c.Assert(err, IsNil) 490 c.Assert(res, Not(IsNil)) 491 c.Assert(res, checker.Equals, expected) 492 c.Assert(state.selectedRules, Equals, 1) 493 c.Assert(state.matchedRules, Equals, 0) 494 res.Detach(testSelectorCache) 495 expected.Detach(testSelectorCache) 496 497 state = traceState{} 498 res, err = rule2.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 499 c.Assert(err, IsNil) 500 c.Assert(res, IsNil) 501 c.Assert(state.selectedRules, Equals, 0) 502 c.Assert(state.matchedRules, Equals, 0) 503 504 // Resolve rule1's policy, then try to add rule2. 505 res, err = rule1.resolveIngressPolicy(toBar, &state, L4PolicyMap{}, nil, testSelectorCache) 506 c.Assert(err, IsNil) 507 c.Assert(res, Not(IsNil)) 508 509 state = traceState{} 510 _, err = rule2.resolveIngressPolicy(toBar, &state, res, nil, testSelectorCache) 511 512 c.Assert(err, Not(IsNil)) 513 res.Detach(testSelectorCache) 514 515 // Similar to 'rule2', but with different topics for the l3-dependent 516 // rule and the l4-only rule. 517 rule3 := &rule{ 518 Rule: api.Rule{ 519 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 520 Ingress: []api.IngressRule{ 521 { 522 FromEndpoints: fooSelectorSlice, 523 ToPorts: []api.PortRule{{ 524 Ports: []api.PortProtocol{ 525 {Port: "80", Protocol: api.ProtoTCP}, 526 }, 527 Rules: &api.L7Rules{ 528 Kafka: []api.PortRuleKafka{ 529 {Topic: "foo"}, 530 }, 531 }, 532 }}, 533 }, 534 { 535 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 536 ToPorts: []api.PortRule{{ 537 Ports: []api.PortProtocol{ 538 {Port: "80", Protocol: api.ProtoTCP}, 539 }, 540 Rules: &api.L7Rules{ 541 Kafka: []api.PortRuleKafka{ 542 {Topic: "bar"}, 543 }, 544 }, 545 }}, 546 }, 547 }, 548 }, 549 } 550 551 fooRules := api.L7Rules{ 552 Kafka: []api.PortRuleKafka{{Topic: "foo"}}, 553 } 554 555 barRules := api.L7Rules{ 556 Kafka: []api.PortRuleKafka{{Topic: "bar"}}, 557 } 558 559 // The L3-dependent L7 rules are not merged together. 560 l7map = L7DataMap{ 561 cachedFooSelector: fooRules, 562 wildcardCachedSelector: barRules, 563 } 564 expected = L4PolicyMap{"80/TCP": &L4Filter{ 565 Port: 80, Protocol: api.ProtoTCP, U8Proto: 6, 566 allowsAllAtL3: true, 567 CachedSelectors: CachedSelectorSlice{cachedFooSelector, wildcardCachedSelector}, 568 L7Parser: "kafka", L7RulesPerEp: l7map, Ingress: true, 569 DerivedFromRules: labels.LabelArrayList{nil, nil}, 570 }} 571 572 state = traceState{} 573 res, err = rule3.resolveIngressPolicy(toBar, &state, L4PolicyMap{}, nil, testSelectorCache) 574 c.Assert(err, IsNil) 575 c.Assert(res, Not(IsNil)) 576 c.Assert(res, checker.Equals, expected) 577 c.Assert(state.selectedRules, Equals, 1) 578 c.Assert(state.matchedRules, Equals, 0) 579 res.Detach(testSelectorCache) 580 expected.Detach(testSelectorCache) 581 } 582 583 func (ds *PolicyTestSuite) TestMergeL7PolicyEgress(c *C) { 584 fromBar := &SearchContext{From: labels.ParseSelectLabelArray("bar")} 585 fromFoo := &SearchContext{From: labels.ParseSelectLabelArray("foo")} 586 587 fooSelector := []api.EndpointSelector{ 588 api.NewESFromLabels(labels.ParseSelectLabel("foo")), 589 } 590 591 rule1 := &rule{ 592 Rule: api.Rule{ 593 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 594 Egress: []api.EgressRule{ 595 { 596 ToPorts: []api.PortRule{{ 597 Ports: []api.PortProtocol{ 598 {Port: "80", Protocol: api.ProtoTCP}, 599 }, 600 }}, 601 }, 602 { 603 ToPorts: []api.PortRule{{ 604 Ports: []api.PortProtocol{ 605 {Port: "80", Protocol: api.ProtoTCP}, 606 }, 607 Rules: &api.L7Rules{ 608 HTTP: []api.PortRuleHTTP{ 609 {Method: "GET", Path: "/public"}, 610 }, 611 }, 612 }}, 613 }, 614 { 615 ToEndpoints: fooSelector, 616 ToPorts: []api.PortRule{{ 617 Ports: []api.PortProtocol{ 618 {Port: "80", Protocol: api.ProtoTCP}, 619 }, 620 Rules: &api.L7Rules{ 621 HTTP: []api.PortRuleHTTP{ 622 {Method: "GET", Path: "/private"}, 623 }, 624 }, 625 }}, 626 }, 627 }, 628 }, 629 } 630 631 expected := L4PolicyMap{"80/TCP": &L4Filter{ 632 Port: 80, Protocol: api.ProtoTCP, U8Proto: 6, 633 allowsAllAtL3: true, 634 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector, cachedFooSelector}, 635 L7Parser: ParserTypeHTTP, 636 L7RulesPerEp: L7DataMap{ 637 wildcardCachedSelector: api.L7Rules{ 638 HTTP: []api.PortRuleHTTP{{Path: "/public", Method: "GET"}}, 639 }, 640 cachedFooSelector: api.L7Rules{ 641 HTTP: []api.PortRuleHTTP{{Path: "/private", Method: "GET"}}, 642 }, 643 }, 644 Ingress: false, 645 DerivedFromRules: labels.LabelArrayList{nil, nil, nil}, 646 }} 647 648 state := traceState{} 649 res, err := rule1.resolveEgressPolicy(fromBar, &state, L4PolicyMap{}, nil, testSelectorCache) 650 c.Assert(err, IsNil) 651 c.Assert(res, Not(IsNil)) 652 c.Assert(res, checker.Equals, expected) 653 c.Assert(state.selectedRules, Equals, 1) 654 c.Assert(state.matchedRules, Equals, 0) 655 res.Detach(testSelectorCache) 656 expected.Detach(testSelectorCache) 657 658 state = traceState{} 659 res, err = rule1.resolveEgressPolicy(fromFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 660 c.Assert(err, IsNil) 661 c.Assert(res, IsNil) 662 c.Assert(state.selectedRules, Equals, 0) 663 c.Assert(state.matchedRules, Equals, 0) 664 665 rule2 := &rule{ 666 Rule: api.Rule{ 667 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 668 Egress: []api.EgressRule{ 669 { 670 ToPorts: []api.PortRule{{ 671 Ports: []api.PortProtocol{ 672 {Port: "80", Protocol: api.ProtoTCP}, 673 }, 674 }}, 675 }, 676 { 677 ToPorts: []api.PortRule{{ 678 Ports: []api.PortProtocol{ 679 {Port: "80", Protocol: api.ProtoTCP}, 680 }, 681 Rules: &api.L7Rules{ 682 Kafka: []api.PortRuleKafka{ 683 {Topic: "foo"}, 684 }, 685 }, 686 }}, 687 }, 688 { 689 ToEndpoints: fooSelector, 690 ToPorts: []api.PortRule{{ 691 Ports: []api.PortProtocol{ 692 {Port: "80", Protocol: api.ProtoTCP}, 693 }, 694 Rules: &api.L7Rules{ 695 Kafka: []api.PortRuleKafka{ 696 {Topic: "foo"}, 697 }, 698 }, 699 }}, 700 }, 701 }, 702 }, 703 } 704 705 expected = L4PolicyMap{"80/TCP": &L4Filter{ 706 Port: 80, Protocol: api.ProtoTCP, U8Proto: 6, 707 allowsAllAtL3: true, 708 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector, cachedFooSelector}, 709 L7Parser: ParserTypeKafka, 710 L7RulesPerEp: L7DataMap{ 711 wildcardCachedSelector: api.L7Rules{ 712 Kafka: []api.PortRuleKafka{{Topic: "foo"}}, 713 }, 714 cachedFooSelector: api.L7Rules{ 715 Kafka: []api.PortRuleKafka{{Topic: "foo"}}, 716 }, 717 }, 718 Ingress: false, 719 DerivedFromRules: labels.LabelArrayList{nil, nil, nil}, 720 }} 721 722 state = traceState{} 723 res, err = rule2.resolveEgressPolicy(fromBar, &state, L4PolicyMap{}, nil, testSelectorCache) 724 c.Assert(err, IsNil) 725 c.Assert(res, Not(IsNil)) 726 c.Assert(res, checker.Equals, expected) 727 c.Assert(state.selectedRules, Equals, 1) 728 c.Assert(state.matchedRules, Equals, 0) 729 res.Detach(testSelectorCache) 730 expected.Detach(testSelectorCache) 731 732 state = traceState{} 733 res, err = rule2.resolveEgressPolicy(fromFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 734 c.Assert(err, IsNil) 735 c.Assert(res, IsNil) 736 c.Assert(state.selectedRules, Equals, 0) 737 c.Assert(state.matchedRules, Equals, 0) 738 739 // Resolve rule1's policy, then try to add rule2. 740 res, err = rule1.resolveEgressPolicy(fromBar, &state, L4PolicyMap{}, nil, testSelectorCache) 741 c.Assert(err, IsNil) 742 c.Assert(res, Not(IsNil)) 743 res.Detach(testSelectorCache) 744 745 // Similar to 'rule2', but with different topics for the l3-dependent 746 // rule and the l4-only rule. 747 rule3 := &rule{ 748 Rule: api.Rule{ 749 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 750 Egress: []api.EgressRule{ 751 { 752 ToEndpoints: fooSelector, 753 ToPorts: []api.PortRule{{ 754 Ports: []api.PortProtocol{ 755 {Port: "80", Protocol: api.ProtoTCP}, 756 }, 757 Rules: &api.L7Rules{ 758 Kafka: []api.PortRuleKafka{ 759 {Topic: "foo"}, 760 }, 761 }, 762 }}, 763 }, 764 { 765 ToPorts: []api.PortRule{{ 766 Ports: []api.PortProtocol{ 767 {Port: "80", Protocol: api.ProtoTCP}, 768 }, 769 Rules: &api.L7Rules{ 770 Kafka: []api.PortRuleKafka{ 771 {Topic: "bar"}, 772 }, 773 }, 774 }}, 775 }, 776 }, 777 }, 778 } 779 780 fooRules := api.L7Rules{ 781 Kafka: []api.PortRuleKafka{{Topic: "foo"}}, 782 } 783 barRules := api.L7Rules{ 784 Kafka: []api.PortRuleKafka{{Topic: "bar"}}, 785 } 786 787 // The l3-dependent l7 rules are not merged together. 788 l7map := L7DataMap{ 789 cachedFooSelector: fooRules, 790 wildcardCachedSelector: barRules, 791 } 792 expected = L4PolicyMap{"80/TCP": &L4Filter{ 793 Port: 80, Protocol: api.ProtoTCP, U8Proto: 6, 794 allowsAllAtL3: true, 795 CachedSelectors: CachedSelectorSlice{cachedFooSelector, wildcardCachedSelector}, 796 L7Parser: "kafka", L7RulesPerEp: l7map, Ingress: false, 797 DerivedFromRules: labels.LabelArrayList{nil, nil}, 798 }} 799 800 state = traceState{} 801 res, err = rule3.resolveEgressPolicy(fromBar, &state, L4PolicyMap{}, nil, testSelectorCache) 802 c.Assert(err, IsNil) 803 c.Assert(res, Not(IsNil)) 804 c.Assert(res, checker.Equals, expected) 805 c.Assert(state.selectedRules, Equals, 1) 806 c.Assert(state.matchedRules, Equals, 0) 807 res.Detach(testSelectorCache) 808 expected.Detach(testSelectorCache) 809 } 810 811 func (ds *PolicyTestSuite) TestRuleWithNoEndpointSelector(c *C) { 812 apiRule1 := api.Rule{ 813 Ingress: []api.IngressRule{ 814 { 815 FromCIDR: []api.CIDR{ 816 "10.0.1.0/24", 817 "192.168.2.0", 818 "10.0.3.1", 819 "2001:db8::1/48", 820 "2001:db9::", 821 }, 822 }, 823 }, 824 Egress: []api.EgressRule{ 825 { 826 ToCIDR: []api.CIDR{ 827 "10.1.0.0/16", 828 "2001:dbf::/64", 829 }, 830 }, { 831 ToCIDRSet: []api.CIDRRule{{Cidr: api.CIDR("10.0.0.0/8"), ExceptCIDRs: []api.CIDR{"10.96.0.0/12"}}}, 832 }, 833 }, 834 } 835 836 err := apiRule1.Sanitize() 837 c.Assert(err, Not(IsNil)) 838 } 839 840 func (ds *PolicyTestSuite) TestL3Policy(c *C) { 841 apiRule1 := api.Rule{ 842 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 843 844 Ingress: []api.IngressRule{ 845 { 846 FromCIDR: []api.CIDR{ 847 "10.0.1.0/24", 848 "192.168.2.0", 849 "10.0.3.1", 850 "2001:db8::1/48", 851 "2001:db9::", 852 }, 853 }, 854 }, 855 Egress: []api.EgressRule{ 856 { 857 ToCIDR: []api.CIDR{ 858 "10.1.0.0/16", 859 "2001:dbf::/64", 860 }, 861 }, { 862 ToCIDRSet: []api.CIDRRule{{Cidr: api.CIDR("10.0.0.0/8"), ExceptCIDRs: []api.CIDR{"10.96.0.0/12"}}}, 863 }, 864 }, 865 } 866 867 err := apiRule1.Sanitize() 868 c.Assert(err, IsNil) 869 870 rule1 := &rule{Rule: apiRule1} 871 err = rule1.Sanitize() 872 c.Assert(err, IsNil) 873 874 expected := NewCIDRPolicy() 875 expected.Ingress.Map["10.0.1.0/24"] = &CIDRPolicyMapRule{Prefix: net.IPNet{IP: []byte{10, 0, 1, 0}, Mask: []byte{255, 255, 255, 0}}, DerivedFromRules: labels.LabelArrayList{nil}} 876 expected.Ingress.Map["192.168.2.0/24"] = &CIDRPolicyMapRule{Prefix: net.IPNet{IP: []byte{192, 168, 2, 0}, Mask: []byte{255, 255, 255, 0}}, DerivedFromRules: labels.LabelArrayList{nil}} 877 expected.Ingress.Map["10.0.3.1/32"] = &CIDRPolicyMapRule{Prefix: net.IPNet{IP: []byte{10, 0, 3, 1}, Mask: []byte{255, 255, 255, 255}}, DerivedFromRules: labels.LabelArrayList{nil}} 878 expected.Ingress.IPv4PrefixCount[32] = 1 879 expected.Ingress.IPv4PrefixCount[24] = 2 880 expected.Ingress.Map["2001:db8::/48"] = &CIDRPolicyMapRule{Prefix: net.IPNet{IP: []byte{0x20, 1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Mask: []byte{255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, DerivedFromRules: labels.LabelArrayList{nil}} 881 expected.Ingress.Map["2001:db9::/128"] = &CIDRPolicyMapRule{Prefix: net.IPNet{IP: []byte{0x20, 1, 0xd, 0xb9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}, DerivedFromRules: labels.LabelArrayList{nil}} 882 expected.Ingress.IPv6PrefixCount[128] = 1 883 expected.Ingress.IPv6PrefixCount[48] = 1 884 expected.Egress.Map["10.1.0.0/16"] = &CIDRPolicyMapRule{Prefix: net.IPNet{IP: []byte{10, 1, 0, 0}, Mask: []byte{255, 255, 0, 0}}, DerivedFromRules: labels.LabelArrayList{nil}} 885 expected.Egress.Map["10.128.0.0/9"] = &CIDRPolicyMapRule{Prefix: net.IPNet{IP: []byte{10, 128, 0, 0}, Mask: []byte{255, 128, 0, 0}}, DerivedFromRules: labels.LabelArrayList{nil}} 886 expected.Egress.Map["10.0.0.0/10"] = &CIDRPolicyMapRule{Prefix: net.IPNet{IP: []byte{10, 0, 0, 0}, Mask: []byte{255, 192, 0, 0}}, DerivedFromRules: labels.LabelArrayList{nil}} 887 expected.Egress.Map["10.64.0.0/11"] = &CIDRPolicyMapRule{Prefix: net.IPNet{IP: []byte{10, 64, 0, 0}, Mask: []byte{255, 224, 0, 0}}, DerivedFromRules: labels.LabelArrayList{nil}} 888 expected.Egress.Map["10.112.0.0/12"] = &CIDRPolicyMapRule{Prefix: net.IPNet{IP: []byte{10, 112, 0, 0}, Mask: []byte{255, 240, 0, 0}}, DerivedFromRules: labels.LabelArrayList{nil}} 889 expected.Egress.IPv4PrefixCount[16] = 1 890 expected.Egress.IPv4PrefixCount[12] = 1 891 expected.Egress.IPv4PrefixCount[11] = 1 892 expected.Egress.IPv4PrefixCount[10] = 1 893 expected.Egress.IPv4PrefixCount[9] = 1 894 expected.Egress.Map["2001:dbf::/64"] = &CIDRPolicyMapRule{Prefix: net.IPNet{IP: []byte{0x20, 1, 0xd, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}}, DerivedFromRules: labels.LabelArrayList{nil}} 895 expected.Egress.IPv6PrefixCount[64] = 1 896 897 toBar := &SearchContext{To: labels.ParseSelectLabelArray("bar")} 898 state := traceState{} 899 res := rule1.resolveCIDRPolicy(toBar, &state, NewCIDRPolicy()) 900 c.Assert(res, Not(IsNil)) 901 c.Assert(*res, checker.DeepEquals, *expected) 902 c.Assert(state.selectedRules, Equals, 1) 903 c.Assert(state.matchedRules, Equals, 0) 904 905 // Must be parsable, make sure Validate fails when not. 906 err = api.Rule{ 907 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 908 Ingress: []api.IngressRule{{ 909 FromCIDR: []api.CIDR{"10.0.1..0/24"}, 910 }}, 911 }.Sanitize() 912 c.Assert(err, Not(IsNil)) 913 914 // Test CIDRRule with no provided CIDR or ExceptionCIDR. 915 // Should fail as CIDR is required. 916 err = api.Rule{ 917 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 918 Ingress: []api.IngressRule{{ 919 FromCIDRSet: []api.CIDRRule{{Cidr: "", ExceptCIDRs: nil}}, 920 }}, 921 }.Sanitize() 922 c.Assert(err, Not(IsNil)) 923 924 // Test CIDRRule with only CIDR provided; should not fail, as ExceptionCIDR 925 // is optional. 926 err = api.Rule{ 927 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 928 Ingress: []api.IngressRule{{ 929 FromCIDRSet: []api.CIDRRule{{Cidr: "10.0.1.0/24", ExceptCIDRs: nil}}, 930 }}, 931 }.Sanitize() 932 c.Assert(err, IsNil) 933 934 // Cannot provide just an IP to a CIDRRule; Cidr must be of format 935 // <IP>/<prefix>. 936 err = api.Rule{ 937 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 938 Ingress: []api.IngressRule{{ 939 FromCIDRSet: []api.CIDRRule{{Cidr: "10.0.1.32", ExceptCIDRs: nil}}, 940 }}, 941 }.Sanitize() 942 c.Assert(err, Not(IsNil)) 943 944 // Cannot exclude a range that is not part of the CIDR. 945 err = api.Rule{ 946 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 947 Ingress: []api.IngressRule{{ 948 FromCIDRSet: []api.CIDRRule{{Cidr: "10.0.0.0/10", ExceptCIDRs: []api.CIDR{"10.64.0.0/11"}}}, 949 }}, 950 }.Sanitize() 951 c.Assert(err, Not(IsNil)) 952 953 // Must have a contiguous mask, make sure Validate fails when not. 954 err = api.Rule{ 955 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 956 Ingress: []api.IngressRule{{ 957 FromCIDR: []api.CIDR{"10.0.1.0/128.0.0.128"}, 958 }}, 959 }.Sanitize() 960 c.Assert(err, Not(IsNil)) 961 962 // Prefix length must be in range for the address, make sure 963 // Validate fails if given prefix length is out of range. 964 err = api.Rule{ 965 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 966 Ingress: []api.IngressRule{{ 967 FromCIDR: []api.CIDR{"10.0.1.0/34"}, 968 }}, 969 }.Sanitize() 970 c.Assert(err, Not(IsNil)) 971 } 972 973 func (ds *PolicyTestSuite) TestL3PolicyRestrictions(c *C) { 974 // Check rejection of too many prefix lengths 975 cidrs := []api.CIDR{} 976 for i := 1; i < 42; i++ { 977 cidrs = append(cidrs, api.CIDR(fmt.Sprintf("%d::/%d", i, i))) 978 } 979 apiRule2 := api.Rule{ 980 EndpointSelector: barSelector, 981 Ingress: []api.IngressRule{{FromCIDR: cidrs}}, 982 } 983 err := apiRule2.Sanitize() 984 c.Assert(err, Not(IsNil)) 985 apiRule3 := api.Rule{ 986 EndpointSelector: barSelector, 987 Egress: []api.EgressRule{{ToCIDR: cidrs}}, 988 } 989 err = apiRule3.Sanitize() 990 c.Assert(err, Not(IsNil)) 991 } 992 993 // Tests the restrictions of combining certain label-based L3 and L4 policies. 994 // This ensures that the user is informed of policy combinations that are not 995 // implemented in the datapath. 996 func (ds *PolicyTestSuite) TestEgressRuleRestrictions(c *C) { 997 998 fooSelector := []api.EndpointSelector{ 999 api.NewESFromLabels(labels.ParseSelectLabel("foo")), 1000 } 1001 1002 // Cannot combine ToEndpoints and ToCIDR 1003 apiRule1 := api.Rule{ 1004 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 1005 Egress: []api.EgressRule{ 1006 { 1007 ToCIDR: []api.CIDR{ 1008 "10.1.0.0/16", 1009 "2001:dbf::/64", 1010 }, 1011 ToEndpoints: fooSelector, 1012 }, 1013 }, 1014 } 1015 1016 err := apiRule1.Sanitize() 1017 c.Assert(err, Not(IsNil)) 1018 } 1019 1020 func (ds *PolicyTestSuite) TestPolicyEntityValidationEgress(c *C) { 1021 r := api.Rule{ 1022 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 1023 Egress: []api.EgressRule{ 1024 { 1025 ToEntities: []api.Entity{api.EntityWorld}, 1026 }, 1027 }, 1028 } 1029 c.Assert(r.Sanitize(), IsNil) 1030 c.Assert(len(r.Egress[0].ToEntities), Equals, 1) 1031 1032 r.Egress[0].ToEntities = []api.Entity{api.EntityHost} 1033 c.Assert(r.Sanitize(), IsNil) 1034 c.Assert(len(r.Egress[0].ToEntities), Equals, 1) 1035 1036 r.Egress[0].ToEntities = []api.Entity{"trololo"} 1037 c.Assert(r.Sanitize(), NotNil) 1038 } 1039 1040 func (ds *PolicyTestSuite) TestPolicyEntityValidationIngress(c *C) { 1041 r := api.Rule{ 1042 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 1043 Ingress: []api.IngressRule{ 1044 { 1045 FromEntities: []api.Entity{api.EntityWorld}, 1046 }, 1047 }, 1048 } 1049 c.Assert(r.Sanitize(), IsNil) 1050 c.Assert(len(r.Ingress[0].FromEntities), Equals, 1) 1051 1052 r.Ingress[0].FromEntities = []api.Entity{api.EntityHost} 1053 c.Assert(r.Sanitize(), IsNil) 1054 c.Assert(len(r.Ingress[0].FromEntities), Equals, 1) 1055 1056 r.Ingress[0].FromEntities = []api.Entity{"trololo"} 1057 c.Assert(r.Sanitize(), NotNil) 1058 } 1059 1060 func (ds *PolicyTestSuite) TestPolicyEntityValidationEntitySelectorsFill(c *C) { 1061 r := api.Rule{ 1062 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 1063 Ingress: []api.IngressRule{ 1064 { 1065 FromEntities: []api.Entity{api.EntityWorld, api.EntityHost}, 1066 }, 1067 }, 1068 Egress: []api.EgressRule{ 1069 { 1070 ToEntities: []api.Entity{api.EntityWorld, api.EntityHost}, 1071 }, 1072 }, 1073 } 1074 c.Assert(r.Sanitize(), IsNil) 1075 c.Assert(len(r.Ingress[0].FromEntities), Equals, 2) 1076 c.Assert(len(r.Egress[0].ToEntities), Equals, 2) 1077 } 1078 1079 func (ds *PolicyTestSuite) TestL3RuleLabels(c *C) { 1080 ruleLabels := map[string]labels.LabelArray{ 1081 "rule0": labels.ParseLabelArray("name=apiRule0"), 1082 "rule1": labels.ParseLabelArray("name=apiRule1"), 1083 "rule2": labels.ParseLabelArray("name=apiRule2"), 1084 } 1085 1086 rules := map[string]api.Rule{ 1087 "rule0": { 1088 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 1089 Labels: ruleLabels["rule0"], 1090 Ingress: []api.IngressRule{}, 1091 Egress: []api.EgressRule{}, 1092 }, 1093 "rule1": { 1094 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 1095 Labels: ruleLabels["rule1"], 1096 Ingress: []api.IngressRule{ 1097 { 1098 FromCIDR: []api.CIDR{"10.0.1.0/32"}, 1099 }, 1100 }, 1101 Egress: []api.EgressRule{ 1102 { 1103 ToCIDR: []api.CIDR{"10.1.0.0/32"}, 1104 }, 1105 }, 1106 }, 1107 "rule2": { 1108 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 1109 Labels: ruleLabels["rule2"], 1110 Ingress: []api.IngressRule{ 1111 { 1112 FromCIDR: []api.CIDR{"10.0.2.0/32"}, 1113 }, 1114 }, 1115 Egress: []api.EgressRule{ 1116 { 1117 ToCIDR: []api.CIDR{"10.2.0.0/32"}, 1118 }, 1119 }, 1120 }, 1121 } 1122 1123 testCases := []struct { 1124 description string // the description to print in asserts 1125 rulesToApply []string // the rules from the rules map to resolve, in order 1126 expectedIngressLabels map[string]labels.LabelArrayList // the slice of LabelArray we should see, per CIDR prefix 1127 expectedEgressLabels map[string]labels.LabelArrayList // the slice of LabelArray we should see, per CIDR prefix 1128 1129 }{ 1130 { 1131 description: "Empty rule that matches. Should not apply labels", 1132 rulesToApply: []string{"rule0"}, 1133 expectedIngressLabels: nil, 1134 expectedEgressLabels: nil, 1135 }, 1136 { 1137 description: "A rule that matches. Should apply labels", 1138 rulesToApply: []string{"rule1"}, 1139 expectedIngressLabels: map[string]labels.LabelArrayList{"10.0.1.0/32": {ruleLabels["rule1"]}}, 1140 expectedEgressLabels: map[string]labels.LabelArrayList{"10.1.0.0/32": {ruleLabels["rule1"]}}, 1141 }, { 1142 description: "Multiple matching rules. Should apply labels from all that have rule entries", 1143 rulesToApply: []string{"rule0", "rule1", "rule2"}, 1144 expectedIngressLabels: map[string]labels.LabelArrayList{ 1145 "10.0.1.0/32": {ruleLabels["rule1"]}, 1146 "10.0.2.0/32": {ruleLabels["rule2"]}}, 1147 expectedEgressLabels: map[string]labels.LabelArrayList{ 1148 "10.1.0.0/32": {ruleLabels["rule1"]}, 1149 "10.2.0.0/32": {ruleLabels["rule2"]}}, 1150 }} 1151 1152 // endpoint selector for all tests 1153 toBar := &SearchContext{To: labels.ParseSelectLabelArray("bar")} 1154 1155 for _, test := range testCases { 1156 finalPolicy := NewCIDRPolicy() 1157 for _, r := range test.rulesToApply { 1158 apiRule := rules[r] 1159 err := apiRule.Sanitize() 1160 c.Assert(err, IsNil, Commentf("Cannot sanitize Rule: %+v", apiRule)) 1161 1162 rule := &rule{Rule: apiRule} 1163 1164 rule.resolveCIDRPolicy(toBar, &traceState{}, finalPolicy) 1165 } 1166 1167 c.Assert(len(finalPolicy.Ingress.Map), Equals, len(test.expectedIngressLabels), Commentf(test.description)) 1168 for cidrKey := range test.expectedIngressLabels { 1169 out := finalPolicy.Ingress.Map[cidrKey] 1170 c.Assert(out, Not(IsNil), Commentf(test.description)) 1171 c.Assert(out.DerivedFromRules, checker.DeepEquals, test.expectedIngressLabels[cidrKey], Commentf(test.description)) 1172 } 1173 1174 c.Assert(len(finalPolicy.Egress.Map), Equals, len(test.expectedEgressLabels), Commentf(test.description)) 1175 for cidrKey := range test.expectedEgressLabels { 1176 out := finalPolicy.Egress.Map[cidrKey] 1177 c.Assert(out, Not(IsNil), Commentf(test.description)) 1178 c.Assert(out.DerivedFromRules, checker.DeepEquals, test.expectedEgressLabels[cidrKey], Commentf(test.description)) 1179 } 1180 } 1181 } 1182 1183 func (ds *PolicyTestSuite) TestL4RuleLabels(c *C) { 1184 ruleLabels := map[string]labels.LabelArray{ 1185 "rule0": labels.ParseLabelArray("name=apiRule0"), 1186 "rule1": labels.ParseLabelArray("name=apiRule1"), 1187 "rule2": labels.ParseLabelArray("name=apiRule2"), 1188 } 1189 1190 rules := map[string]api.Rule{ 1191 "rule0": { 1192 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 1193 Labels: ruleLabels["rule0"], 1194 Ingress: []api.IngressRule{}, 1195 Egress: []api.EgressRule{}, 1196 }, 1197 1198 "rule1": { 1199 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 1200 Labels: ruleLabels["rule1"], 1201 Ingress: []api.IngressRule{ 1202 { 1203 ToPorts: []api.PortRule{{ 1204 Ports: []api.PortProtocol{{Port: "1010", Protocol: api.ProtoTCP}}, 1205 }}, 1206 }, 1207 }, 1208 Egress: []api.EgressRule{ 1209 { 1210 ToPorts: []api.PortRule{{ 1211 Ports: []api.PortProtocol{{Port: "1100", Protocol: api.ProtoTCP}}, 1212 }}, 1213 }, 1214 }, 1215 }, 1216 "rule2": { 1217 EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")), 1218 Labels: ruleLabels["rule2"], 1219 Ingress: []api.IngressRule{ 1220 { 1221 ToPorts: []api.PortRule{{ 1222 Ports: []api.PortProtocol{{Port: "1020", Protocol: api.ProtoTCP}}, 1223 }}, 1224 }, 1225 }, 1226 Egress: []api.EgressRule{ 1227 { 1228 ToPorts: []api.PortRule{{ 1229 Ports: []api.PortProtocol{{Port: "1200", Protocol: api.ProtoTCP}}, 1230 }}, 1231 }, 1232 }, 1233 }, 1234 } 1235 1236 testCases := []struct { 1237 description string // the description to print in asserts 1238 rulesToApply []string // the rules from the rules map to resolve, in order 1239 expectedIngressLabels map[string]labels.LabelArrayList // the slice of LabelArray we should see, in order 1240 expectedEgressLabels map[string]labels.LabelArrayList // the slice of LabelArray we should see, in order 1241 1242 }{ 1243 { 1244 description: "Empty rule that matches. Should not apply labels", 1245 rulesToApply: []string{"rule0"}, 1246 expectedIngressLabels: map[string]labels.LabelArrayList{}, 1247 expectedEgressLabels: map[string]labels.LabelArrayList{}, 1248 }, 1249 { 1250 description: "A rule that matches. Should apply labels", 1251 rulesToApply: []string{"rule1"}, 1252 expectedIngressLabels: map[string]labels.LabelArrayList{"1010/TCP": {ruleLabels["rule1"]}}, 1253 expectedEgressLabels: map[string]labels.LabelArrayList{"1100/TCP": {ruleLabels["rule1"]}}, 1254 }, { 1255 description: "Multiple matching rules. Should apply labels from all that have rule entries", 1256 rulesToApply: []string{"rule0", "rule1", "rule2"}, 1257 expectedIngressLabels: map[string]labels.LabelArrayList{ 1258 "1010/TCP": {ruleLabels["rule1"]}, 1259 "1020/TCP": {ruleLabels["rule2"]}}, 1260 expectedEgressLabels: map[string]labels.LabelArrayList{ 1261 "1100/TCP": {ruleLabels["rule1"]}, 1262 "1200/TCP": {ruleLabels["rule2"]}}, 1263 }} 1264 1265 // endpoint selector for all tests 1266 toBar := &SearchContext{To: labels.ParseSelectLabelArray("bar")} 1267 fromBar := &SearchContext{From: labels.ParseSelectLabelArray("bar")} 1268 1269 for _, test := range testCases { 1270 finalPolicy := NewL4Policy(0) 1271 for _, r := range test.rulesToApply { 1272 apiRule := rules[r] 1273 err := apiRule.Sanitize() 1274 c.Assert(err, IsNil, Commentf("Cannot sanitize api.Rule: %+v", apiRule)) 1275 1276 rule := &rule{Rule: apiRule} 1277 1278 rule.resolveIngressPolicy(toBar, &traceState{}, finalPolicy.Ingress, nil, testSelectorCache) 1279 rule.resolveEgressPolicy(fromBar, &traceState{}, finalPolicy.Egress, nil, testSelectorCache) 1280 } 1281 1282 c.Assert(len(finalPolicy.Ingress), Equals, len(test.expectedIngressLabels), Commentf(test.description)) 1283 for portProto := range test.expectedIngressLabels { 1284 out, found := finalPolicy.Ingress[portProto] 1285 c.Assert(found, Equals, true, Commentf(test.description)) 1286 c.Assert(out, NotNil, Commentf(test.description)) 1287 c.Assert(out.DerivedFromRules, checker.DeepEquals, test.expectedIngressLabels[portProto], Commentf(test.description)) 1288 } 1289 1290 c.Assert(len(finalPolicy.Egress), Equals, len(test.expectedEgressLabels), Commentf(test.description)) 1291 for portProto := range test.expectedEgressLabels { 1292 out, found := finalPolicy.Egress[portProto] 1293 c.Assert(found, Equals, true, Commentf(test.description)) 1294 c.Assert(out, Not(IsNil), Commentf(test.description)) 1295 c.Assert(out.DerivedFromRules, checker.DeepEquals, test.expectedEgressLabels[portProto], Commentf(test.description)) 1296 } 1297 finalPolicy.Detach(testSelectorCache) 1298 } 1299 } 1300 1301 var ( 1302 labelsA = labels.LabelArray{ 1303 labels.NewLabel("id", "a", labels.LabelSourceK8s), 1304 } 1305 1306 endpointSelectorA = api.NewESFromLabels(labels.ParseSelectLabel("id=a")) 1307 1308 labelsB = labels.LabelArray{ 1309 labels.NewLabel("id1", "b", labels.LabelSourceK8s), 1310 labels.NewLabel("id2", "c", labels.LabelSourceK8s), 1311 } 1312 1313 labelsC = labels.LabelArray{ 1314 labels.NewLabel("id", "c", labels.LabelSourceK8s), 1315 } 1316 1317 endpointSelectorC = api.NewESFromLabels(labels.ParseSelectLabel("id=c")) 1318 1319 ctxAToB = SearchContext{From: labelsA, To: labelsB, Trace: TRACE_VERBOSE} 1320 ctxAToC = SearchContext{From: labelsA, To: labelsC, Trace: TRACE_VERBOSE} 1321 ) 1322 1323 func expectResult(c *C, expected, obtained api.Decision, buffer *bytes.Buffer) { 1324 if obtained != expected { 1325 c.Errorf("Unexpected result: obtained=%v, expected=%v", obtained, expected) 1326 c.Log(buffer) 1327 } 1328 } 1329 1330 func checkIngress(c *C, repo *Repository, ctx *SearchContext, verdict api.Decision) { 1331 repo.Mutex.RLock() 1332 defer repo.Mutex.RUnlock() 1333 1334 buffer := new(bytes.Buffer) 1335 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1336 expectResult(c, verdict, repo.AllowsIngressRLocked(ctx), buffer) 1337 } 1338 1339 func checkEgress(c *C, repo *Repository, ctx *SearchContext, verdict api.Decision) { 1340 repo.Mutex.RLock() 1341 defer repo.Mutex.RUnlock() 1342 1343 buffer := new(bytes.Buffer) 1344 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1345 expectResult(c, verdict, repo.AllowsEgressRLocked(ctx), buffer) 1346 } 1347 1348 func parseAndAddRules(c *C, rules api.Rules) *Repository { 1349 repo := NewPolicyRepository() 1350 repo.selectorCache = testSelectorCache 1351 1352 _, _ = repo.AddList(rules) 1353 return repo 1354 } 1355 1356 func (ds *PolicyTestSuite) TestIngressAllowAll(c *C) { 1357 repo := parseAndAddRules(c, api.Rules{ 1358 &api.Rule{ 1359 EndpointSelector: endpointSelectorC, 1360 Ingress: []api.IngressRule{ 1361 { 1362 // Allow all L3&L4 ingress rule 1363 FromEndpoints: []api.EndpointSelector{ 1364 api.WildcardEndpointSelector, 1365 }, 1366 }, 1367 }, 1368 }, 1369 }) 1370 1371 checkIngress(c, repo, &ctxAToB, api.Denied) 1372 checkIngress(c, repo, &ctxAToC, api.Allowed) 1373 1374 ctxAToC80 := ctxAToC 1375 ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}} 1376 checkIngress(c, repo, &ctxAToC80, api.Allowed) 1377 1378 ctxAToC90 := ctxAToC 1379 ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1380 checkIngress(c, repo, &ctxAToC90, api.Allowed) 1381 } 1382 1383 func (ds *PolicyTestSuite) TestIngressAllowAllL4Overlap(c *C) { 1384 repo := parseAndAddRules(c, api.Rules{ 1385 &api.Rule{ 1386 EndpointSelector: endpointSelectorC, 1387 Ingress: []api.IngressRule{ 1388 { 1389 // Allow all L3&L4 ingress rule 1390 FromEndpoints: []api.EndpointSelector{ 1391 api.WildcardEndpointSelector, 1392 }, 1393 }, 1394 { 1395 // This rule is a subset of the above 1396 // rule and should *NOT* restrict to 1397 // port 80 only 1398 ToPorts: []api.PortRule{{ 1399 Ports: []api.PortProtocol{ 1400 {Port: "80", Protocol: api.ProtoTCP}, 1401 }, 1402 }}, 1403 }, 1404 }, 1405 }, 1406 }) 1407 1408 ctxAToC80 := ctxAToC 1409 ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}} 1410 checkIngress(c, repo, &ctxAToC80, api.Allowed) 1411 1412 ctxAToC90 := ctxAToC 1413 ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1414 checkIngress(c, repo, &ctxAToC90, api.Allowed) 1415 } 1416 1417 func (ds *PolicyTestSuite) TestIngressL4AllowAll(c *C) { 1418 repo := parseAndAddRules(c, api.Rules{ 1419 &api.Rule{ 1420 EndpointSelector: endpointSelectorC, 1421 Ingress: []api.IngressRule{ 1422 { 1423 ToPorts: []api.PortRule{{ 1424 Ports: []api.PortProtocol{ 1425 {Port: "80", Protocol: api.ProtoTCP}, 1426 }, 1427 }}, 1428 }, 1429 }, 1430 }, 1431 }) 1432 1433 ctxAToC80 := ctxAToC 1434 ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}} 1435 checkIngress(c, repo, &ctxAToC80, api.Allowed) 1436 1437 ctxAToC90 := ctxAToC 1438 ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1439 checkIngress(c, repo, &ctxAToC90, api.Denied) 1440 1441 l4IngressPolicy, err := repo.ResolveL4IngressPolicy(&ctxAToC80) 1442 c.Assert(err, IsNil) 1443 1444 filter, ok := l4IngressPolicy["80/TCP"] 1445 c.Assert(ok, Equals, true) 1446 c.Assert(filter.Port, Equals, 80) 1447 c.Assert(filter.Ingress, Equals, true) 1448 1449 c.Assert(len(filter.CachedSelectors), Equals, 1) 1450 c.Assert(filter.CachedSelectors[0], checker.Equals, wildcardCachedSelector) 1451 l4IngressPolicy.Detach(repo.GetSelectorCache()) 1452 } 1453 1454 func (ds *PolicyTestSuite) TestEgressAllowAll(c *C) { 1455 repo := parseAndAddRules(c, api.Rules{ 1456 &api.Rule{ 1457 EndpointSelector: endpointSelectorA, 1458 Egress: []api.EgressRule{ 1459 { 1460 ToEndpoints: []api.EndpointSelector{ 1461 api.WildcardEndpointSelector, 1462 }, 1463 }, 1464 }, 1465 }, 1466 }) 1467 1468 checkEgress(c, repo, &ctxAToB, api.Allowed) 1469 checkEgress(c, repo, &ctxAToC, api.Allowed) 1470 1471 ctxAToC80 := ctxAToC 1472 ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}} 1473 checkEgress(c, repo, &ctxAToC80, api.Allowed) 1474 1475 ctxAToC90 := ctxAToC 1476 ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1477 checkEgress(c, repo, &ctxAToC90, api.Allowed) 1478 } 1479 1480 func (ds *PolicyTestSuite) TestEgressL4AllowAll(c *C) { 1481 repo := parseAndAddRules(c, api.Rules{ 1482 &api.Rule{ 1483 EndpointSelector: endpointSelectorA, 1484 Egress: []api.EgressRule{ 1485 { 1486 ToPorts: []api.PortRule{{ 1487 Ports: []api.PortProtocol{ 1488 {Port: "80", Protocol: api.ProtoTCP}, 1489 }, 1490 }}, 1491 }, 1492 }, 1493 }, 1494 }) 1495 1496 ctxAToC80 := ctxAToC 1497 ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}} 1498 checkEgress(c, repo, &ctxAToC80, api.Allowed) 1499 1500 ctxAToC90 := ctxAToC 1501 ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1502 checkEgress(c, repo, &ctxAToC90, api.Denied) 1503 1504 buffer := new(bytes.Buffer) 1505 ctx := SearchContext{From: labelsA, Trace: TRACE_VERBOSE} 1506 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1507 1508 l4EgressPolicy, err := repo.ResolveL4EgressPolicy(&ctx) 1509 c.Assert(err, IsNil) 1510 1511 c.Log(buffer) 1512 1513 filter, ok := l4EgressPolicy["80/TCP"] 1514 c.Assert(ok, Equals, true) 1515 c.Assert(filter.Port, Equals, 80) 1516 c.Assert(filter.Ingress, Equals, false) 1517 1518 c.Assert(len(filter.CachedSelectors), Equals, 1) 1519 c.Assert(filter.CachedSelectors[0], checker.Equals, wildcardCachedSelector) 1520 l4EgressPolicy.Detach(repo.GetSelectorCache()) 1521 } 1522 1523 func (ds *PolicyTestSuite) TestEgressL4AllowWorld(c *C) { 1524 repo := parseAndAddRules(c, api.Rules{ 1525 &api.Rule{ 1526 EndpointSelector: endpointSelectorA, 1527 Egress: []api.EgressRule{ 1528 { 1529 ToEntities: []api.Entity{api.EntityWorld}, 1530 ToPorts: []api.PortRule{{ 1531 Ports: []api.PortProtocol{ 1532 {Port: "80", Protocol: api.ProtoTCP}, 1533 }, 1534 }}, 1535 }, 1536 }, 1537 }, 1538 }) 1539 1540 worldLabel := labels.ParseSelectLabelArray("reserved:world") 1541 ctxAToWorld80 := SearchContext{From: labelsA, To: worldLabel, Trace: TRACE_VERBOSE} 1542 ctxAToWorld80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}} 1543 checkEgress(c, repo, &ctxAToWorld80, api.Allowed) 1544 1545 ctxAToWorld90 := ctxAToWorld80 1546 ctxAToWorld90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1547 checkEgress(c, repo, &ctxAToWorld90, api.Denied) 1548 1549 // Pod to pod must be denied on port 80 and 90, only world was whitelisted 1550 fooLabel := labels.ParseSelectLabelArray("k8s:app=foo") 1551 ctxAToFoo := SearchContext{From: labelsA, To: fooLabel, Trace: TRACE_VERBOSE, 1552 DPorts: []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}} 1553 checkEgress(c, repo, &ctxAToFoo, api.Denied) 1554 ctxAToFoo90 := ctxAToFoo 1555 ctxAToFoo90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1556 checkEgress(c, repo, &ctxAToFoo90, api.Denied) 1557 1558 buffer := new(bytes.Buffer) 1559 ctx := SearchContext{From: labelsA, Trace: TRACE_VERBOSE} 1560 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1561 1562 l4EgressPolicy, err := repo.ResolveL4EgressPolicy(&ctx) 1563 c.Assert(err, IsNil) 1564 1565 c.Log(buffer) 1566 1567 filter, ok := l4EgressPolicy["80/TCP"] 1568 c.Assert(ok, Equals, true) 1569 c.Assert(filter.Port, Equals, 80) 1570 c.Assert(filter.Ingress, Equals, false) 1571 1572 c.Assert(len(filter.CachedSelectors), Equals, 1) 1573 l4EgressPolicy.Detach(repo.GetSelectorCache()) 1574 } 1575 1576 func (ds *PolicyTestSuite) TestEgressL4AllowAllEntity(c *C) { 1577 repo := parseAndAddRules(c, api.Rules{ 1578 &api.Rule{ 1579 EndpointSelector: endpointSelectorA, 1580 Egress: []api.EgressRule{ 1581 { 1582 ToEntities: []api.Entity{api.EntityAll}, 1583 ToPorts: []api.PortRule{{ 1584 Ports: []api.PortProtocol{ 1585 {Port: "80", Protocol: api.ProtoTCP}, 1586 }, 1587 }}, 1588 }, 1589 }, 1590 }, 1591 }) 1592 1593 worldLabel := labels.ParseSelectLabelArray("reserved:world") 1594 ctxAToWorld80 := SearchContext{From: labelsA, To: worldLabel, Trace: TRACE_VERBOSE} 1595 ctxAToWorld80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}} 1596 checkEgress(c, repo, &ctxAToWorld80, api.Allowed) 1597 1598 ctxAToWorld90 := ctxAToWorld80 1599 ctxAToWorld90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1600 checkEgress(c, repo, &ctxAToWorld90, api.Denied) 1601 1602 // Pod to pod must be allowed on port 80, denied on port 90 (all identity) 1603 fooLabel := labels.ParseSelectLabelArray("k8s:app=foo") 1604 ctxAToFoo := SearchContext{From: labelsA, To: fooLabel, Trace: TRACE_VERBOSE, 1605 DPorts: []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}} 1606 checkEgress(c, repo, &ctxAToFoo, api.Allowed) 1607 ctxAToFoo90 := ctxAToFoo 1608 ctxAToFoo90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1609 checkEgress(c, repo, &ctxAToFoo90, api.Denied) 1610 1611 buffer := new(bytes.Buffer) 1612 ctx := SearchContext{From: labelsA, Trace: TRACE_VERBOSE} 1613 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1614 1615 l4EgressPolicy, err := repo.ResolveL4EgressPolicy(&ctx) 1616 c.Assert(err, IsNil) 1617 1618 c.Log(buffer) 1619 1620 filter, ok := l4EgressPolicy["80/TCP"] 1621 c.Assert(ok, Equals, true) 1622 c.Assert(filter.Port, Equals, 80) 1623 c.Assert(filter.Ingress, Equals, false) 1624 1625 c.Assert(len(filter.CachedSelectors), Equals, 1) 1626 l4EgressPolicy.Detach(repo.GetSelectorCache()) 1627 } 1628 1629 func (ds *PolicyTestSuite) TestEgressL3AllowWorld(c *C) { 1630 repo := parseAndAddRules(c, api.Rules{ 1631 &api.Rule{ 1632 EndpointSelector: endpointSelectorA, 1633 Egress: []api.EgressRule{ 1634 { 1635 ToEntities: []api.Entity{api.EntityWorld}, 1636 }, 1637 }, 1638 }, 1639 }) 1640 1641 worldLabel := labels.ParseSelectLabelArray("reserved:world") 1642 ctxAToWorld80 := SearchContext{From: labelsA, To: worldLabel, Trace: TRACE_VERBOSE} 1643 ctxAToWorld80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}} 1644 checkEgress(c, repo, &ctxAToWorld80, api.Allowed) 1645 1646 ctxAToWorld90 := ctxAToWorld80 1647 ctxAToWorld90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1648 checkEgress(c, repo, &ctxAToWorld90, api.Allowed) 1649 1650 // Pod to pod must be denied on port 80 and 90, only world was whitelisted 1651 fooLabel := labels.ParseSelectLabelArray("k8s:app=foo") 1652 ctxAToFoo := SearchContext{From: labelsA, To: fooLabel, Trace: TRACE_VERBOSE, 1653 DPorts: []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}} 1654 checkEgress(c, repo, &ctxAToFoo, api.Denied) 1655 ctxAToFoo90 := ctxAToFoo 1656 ctxAToFoo90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1657 checkEgress(c, repo, &ctxAToFoo90, api.Denied) 1658 1659 buffer := new(bytes.Buffer) 1660 ctx := SearchContext{From: labelsA, Trace: TRACE_VERBOSE} 1661 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1662 } 1663 1664 func (ds *PolicyTestSuite) TestEgressL3AllowAllEntity(c *C) { 1665 repo := parseAndAddRules(c, api.Rules{ 1666 &api.Rule{ 1667 EndpointSelector: endpointSelectorA, 1668 Egress: []api.EgressRule{ 1669 { 1670 ToEntities: []api.Entity{api.EntityAll}, 1671 }, 1672 }, 1673 }, 1674 }) 1675 1676 worldLabel := labels.ParseSelectLabelArray("reserved:world") 1677 ctxAToWorld80 := SearchContext{From: labelsA, To: worldLabel, Trace: TRACE_VERBOSE} 1678 ctxAToWorld80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}} 1679 checkEgress(c, repo, &ctxAToWorld80, api.Allowed) 1680 1681 ctxAToWorld90 := ctxAToWorld80 1682 ctxAToWorld90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1683 checkEgress(c, repo, &ctxAToWorld90, api.Allowed) 1684 1685 // Pod to pod must be allowed on both port 80 and 90 (L3 only rule) 1686 fooLabel := labels.ParseSelectLabelArray("k8s:app=foo") 1687 ctxAToFoo := SearchContext{From: labelsA, To: fooLabel, Trace: TRACE_VERBOSE, 1688 DPorts: []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}} 1689 checkEgress(c, repo, &ctxAToFoo, api.Allowed) 1690 ctxAToFoo90 := ctxAToFoo 1691 ctxAToFoo90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}} 1692 checkEgress(c, repo, &ctxAToFoo90, api.Allowed) 1693 1694 buffer := new(bytes.Buffer) 1695 ctx := SearchContext{From: labelsA, Trace: TRACE_VERBOSE} 1696 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1697 } 1698 1699 func (ds *PolicyTestSuite) TestL4WildcardMerge(c *C) { 1700 1701 // First, test implicit case. 1702 // 1703 // Test the case where if we have rules that select the same endpoint on the 1704 // same port-protocol tuple with one that is L4-only, and the other applying 1705 // at L4 and L7, that the L4-only rule shadows the L4-L7 rule. This is because 1706 // L4-only rule implicitly allows all traffic at L7, so the L7-related 1707 // parts of the L4-L7 rule are useless. 1708 repo := parseAndAddRules(c, api.Rules{&api.Rule{ 1709 EndpointSelector: endpointSelectorA, 1710 Ingress: []api.IngressRule{ 1711 { 1712 FromEndpoints: []api.EndpointSelector{endpointSelectorC}, 1713 ToPorts: []api.PortRule{{ 1714 Ports: []api.PortProtocol{ 1715 {Port: "80", Protocol: api.ProtoTCP}, 1716 }, 1717 Rules: &api.L7Rules{ 1718 HTTP: []api.PortRuleHTTP{ 1719 {Method: "GET", Path: "/"}, 1720 }, 1721 }, 1722 }}, 1723 }, 1724 { 1725 ToPorts: []api.PortRule{{ 1726 Ports: []api.PortProtocol{ 1727 {Port: "80", Protocol: api.ProtoTCP}, 1728 }, 1729 }}, 1730 }, 1731 }, 1732 }}) 1733 1734 buffer := new(bytes.Buffer) 1735 ctx := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 1736 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1737 1738 l4IngressPolicy, err := repo.ResolveL4IngressPolicy(&ctx) 1739 c.Assert(err, IsNil) 1740 1741 c.Log(buffer) 1742 1743 filter, ok := l4IngressPolicy["80/TCP"] 1744 c.Assert(ok, Equals, true) 1745 c.Assert(filter.Port, Equals, 80) 1746 c.Assert(filter.Ingress, Equals, true) 1747 1748 c.Assert(len(filter.CachedSelectors), Equals, 2) 1749 c.Assert(filter.CachedSelectors[0], checker.Equals, cachedSelectorC) 1750 c.Assert(filter.CachedSelectors[1], checker.Equals, wildcardCachedSelector) 1751 1752 c.Assert(filter.L7Parser, Equals, ParserTypeHTTP) 1753 c.Assert(len(filter.L7RulesPerEp), Equals, 2) 1754 l4IngressPolicy.Detach(repo.GetSelectorCache()) 1755 1756 // Test the reverse order as well; ensure that we check both conditions 1757 // for if L4-only policy is in the L4Filter for the same port-protocol tuple, 1758 // and L7 metadata exists in the L4Filter we are adding; expect to resolve 1759 // to L4-only policy without any L7-metadata. 1760 repo = parseAndAddRules(c, api.Rules{&api.Rule{ 1761 EndpointSelector: endpointSelectorA, 1762 Ingress: []api.IngressRule{ 1763 { 1764 ToPorts: []api.PortRule{{ 1765 Ports: []api.PortProtocol{ 1766 {Port: "80", Protocol: api.ProtoTCP}, 1767 }, 1768 }}, 1769 }, 1770 { 1771 FromEndpoints: []api.EndpointSelector{endpointSelectorC}, 1772 ToPorts: []api.PortRule{{ 1773 Ports: []api.PortProtocol{ 1774 {Port: "80", Protocol: api.ProtoTCP}, 1775 }, 1776 Rules: &api.L7Rules{ 1777 HTTP: []api.PortRuleHTTP{ 1778 {Method: "GET", Path: "/"}, 1779 }, 1780 }, 1781 }}, 1782 }, 1783 }, 1784 }}) 1785 1786 buffer = new(bytes.Buffer) 1787 ctx = SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 1788 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1789 1790 l4IngressPolicy, err = repo.ResolveL4IngressPolicy(&ctx) 1791 c.Assert(err, IsNil) 1792 1793 c.Log(buffer) 1794 1795 filter, ok = l4IngressPolicy["80/TCP"] 1796 c.Assert(ok, Equals, true) 1797 c.Assert(filter.Port, Equals, 80) 1798 c.Assert(filter.Ingress, Equals, true) 1799 1800 c.Assert(len(filter.CachedSelectors), Equals, 2) 1801 c.Assert(filter.CachedSelectors[0], checker.Equals, wildcardCachedSelector) 1802 c.Assert(filter.CachedSelectors[1], checker.Equals, cachedSelectorC) 1803 1804 c.Assert(filter.L7Parser, Equals, ParserTypeHTTP) 1805 c.Assert(len(filter.L7RulesPerEp), Equals, 2) 1806 l4IngressPolicy.Detach(repo.GetSelectorCache()) 1807 1808 // Second, test the explicit allow at L3. 1809 repo = parseAndAddRules(c, api.Rules{&api.Rule{ 1810 EndpointSelector: endpointSelectorA, 1811 Ingress: []api.IngressRule{ 1812 { 1813 FromEndpoints: []api.EndpointSelector{endpointSelectorC}, 1814 ToPorts: []api.PortRule{{ 1815 Ports: []api.PortProtocol{ 1816 {Port: "80", Protocol: api.ProtoTCP}, 1817 }, 1818 Rules: &api.L7Rules{ 1819 HTTP: []api.PortRuleHTTP{ 1820 {Method: "GET", Path: "/"}, 1821 }, 1822 }, 1823 }}, 1824 }, 1825 { 1826 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 1827 ToPorts: []api.PortRule{{ 1828 Ports: []api.PortProtocol{ 1829 {Port: "80", Protocol: api.ProtoTCP}, 1830 }, 1831 }}, 1832 }, 1833 }, 1834 }}) 1835 1836 buffer = new(bytes.Buffer) 1837 ctx = SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 1838 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1839 1840 l4IngressPolicy, err = repo.ResolveL4IngressPolicy(&ctx) 1841 c.Assert(err, IsNil) 1842 1843 c.Log(buffer) 1844 1845 filter, ok = l4IngressPolicy["80/TCP"] 1846 c.Assert(ok, Equals, true) 1847 c.Assert(filter.Port, Equals, 80) 1848 c.Assert(filter.Ingress, Equals, true) 1849 1850 c.Assert(len(filter.CachedSelectors), Equals, 2) 1851 c.Assert(filter.L7Parser, Equals, ParserTypeHTTP) 1852 c.Assert(len(filter.L7RulesPerEp), Equals, 2) 1853 l4IngressPolicy.Detach(repo.GetSelectorCache()) 1854 1855 // Test the reverse order as well; ensure that we check both conditions 1856 // for if L4-only policy is in the L4Filter for the same port-protocol tuple, 1857 // and L7 metadata exists in the L4Filter we are adding; expect to resolve 1858 // to L4-only policy without any L7-metadata. 1859 repo = parseAndAddRules(c, api.Rules{&api.Rule{ 1860 EndpointSelector: endpointSelectorA, 1861 Ingress: []api.IngressRule{ 1862 { 1863 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 1864 ToPorts: []api.PortRule{{ 1865 Ports: []api.PortProtocol{ 1866 {Port: "80", Protocol: api.ProtoTCP}, 1867 }, 1868 }}, 1869 }, 1870 { 1871 FromEndpoints: []api.EndpointSelector{endpointSelectorC}, 1872 ToPorts: []api.PortRule{{ 1873 Ports: []api.PortProtocol{ 1874 {Port: "80", Protocol: api.ProtoTCP}, 1875 }, 1876 Rules: &api.L7Rules{ 1877 HTTP: []api.PortRuleHTTP{ 1878 {Method: "GET", Path: "/"}, 1879 }, 1880 }, 1881 }}, 1882 }, 1883 }, 1884 }}) 1885 1886 buffer = new(bytes.Buffer) 1887 ctx = SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 1888 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1889 1890 l4IngressPolicy, err = repo.ResolveL4IngressPolicy(&ctx) 1891 c.Assert(err, IsNil) 1892 1893 c.Log(buffer) 1894 1895 filter, ok = l4IngressPolicy["80/TCP"] 1896 c.Assert(ok, Equals, true) 1897 c.Assert(filter.Port, Equals, 80) 1898 c.Assert(filter.Ingress, Equals, true) 1899 1900 c.Assert(len(filter.CachedSelectors), Equals, 2) 1901 1902 c.Assert(filter.L7Parser, Equals, ParserTypeHTTP) 1903 c.Assert(len(filter.L7RulesPerEp), Equals, 2) 1904 l4IngressPolicy.Detach(repo.GetSelectorCache()) 1905 } 1906 1907 func (ds *PolicyTestSuite) TestL3L4L7Merge(c *C) { 1908 1909 // First rule allows ingress from all endpoints to port 80 only on 1910 // GET to "/". However, second rule allows all traffic on port 80 only to a 1911 // specific endpoint. When these rules are merged, it equates to allowing 1912 // all traffic from port 80 from any endpoint. 1913 // 1914 // TODO: This comment can't be correct, the resulting policy 1915 // should allow all on port 80 only from endpoint C, traffic 1916 // from all other endpoints should still only allow only GET 1917 // on "/". 1918 repo := parseAndAddRules(c, api.Rules{&api.Rule{ 1919 EndpointSelector: endpointSelectorA, 1920 Ingress: []api.IngressRule{ 1921 { 1922 ToPorts: []api.PortRule{{ 1923 Ports: []api.PortProtocol{ 1924 {Port: "80", Protocol: api.ProtoTCP}, 1925 }, 1926 Rules: &api.L7Rules{ 1927 HTTP: []api.PortRuleHTTP{ 1928 {Method: "GET", Path: "/"}, 1929 }, 1930 }, 1931 }}, 1932 }, 1933 { 1934 FromEndpoints: []api.EndpointSelector{endpointSelectorC}, 1935 ToPorts: []api.PortRule{{ 1936 Ports: []api.PortProtocol{ 1937 {Port: "80", Protocol: api.ProtoTCP}, 1938 }, 1939 }}, 1940 }, 1941 }, 1942 }}) 1943 1944 buffer := new(bytes.Buffer) 1945 ctx := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 1946 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1947 1948 l4IngressPolicy, err := repo.ResolveL4IngressPolicy(&ctx) 1949 c.Assert(err, IsNil) 1950 1951 c.Log(buffer) 1952 1953 filter, ok := l4IngressPolicy["80/TCP"] 1954 c.Assert(ok, Equals, true) 1955 c.Assert(filter.Port, Equals, 80) 1956 c.Assert(filter.Ingress, Equals, true) 1957 1958 c.Assert(len(filter.CachedSelectors), Equals, 2) 1959 c.Assert(filter.CachedSelectors[0], checker.Equals, wildcardCachedSelector) 1960 c.Assert(filter.CachedSelectors[1], checker.Equals, cachedSelectorC) 1961 1962 c.Assert(filter.L7Parser, Equals, ParserTypeHTTP) 1963 c.Assert(len(filter.L7RulesPerEp), Equals, 2) 1964 l4IngressPolicy.Detach(repo.GetSelectorCache()) 1965 1966 repo = parseAndAddRules(c, api.Rules{&api.Rule{ 1967 EndpointSelector: endpointSelectorA, 1968 Ingress: []api.IngressRule{ 1969 { 1970 FromEndpoints: []api.EndpointSelector{endpointSelectorC}, 1971 ToPorts: []api.PortRule{{ 1972 Ports: []api.PortProtocol{ 1973 {Port: "80", Protocol: api.ProtoTCP}, 1974 }, 1975 }}, 1976 }, 1977 { 1978 ToPorts: []api.PortRule{{ 1979 Ports: []api.PortProtocol{ 1980 {Port: "80", Protocol: api.ProtoTCP}, 1981 }, 1982 Rules: &api.L7Rules{ 1983 HTTP: []api.PortRuleHTTP{ 1984 {Method: "GET", Path: "/"}, 1985 }, 1986 }, 1987 }}, 1988 }, 1989 }, 1990 }}) 1991 1992 buffer = new(bytes.Buffer) 1993 ctx = SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 1994 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 1995 1996 l4IngressPolicy, err = repo.ResolveL4IngressPolicy(&ctx) 1997 c.Assert(err, IsNil) 1998 1999 c.Log(buffer) 2000 2001 filter, ok = l4IngressPolicy["80/TCP"] 2002 c.Assert(ok, Equals, true) 2003 c.Assert(filter.Port, Equals, 80) 2004 c.Assert(filter.Ingress, Equals, true) 2005 2006 c.Assert(len(filter.CachedSelectors), Equals, 2) 2007 c.Assert(filter.CachedSelectors[0], checker.Equals, wildcardCachedSelector) 2008 c.Assert(filter.CachedSelectors[1], checker.Equals, cachedSelectorC) 2009 2010 c.Assert(filter.L7Parser, Equals, ParserTypeHTTP) 2011 c.Assert(len(filter.L7RulesPerEp), Equals, 2) 2012 l4IngressPolicy.Detach(repo.GetSelectorCache()) 2013 } 2014 2015 func (ds *PolicyTestSuite) TestMatches(c *C) { 2016 repo := parseAndAddRules(c, api.Rules{&api.Rule{ 2017 EndpointSelector: endpointSelectorA, 2018 Ingress: []api.IngressRule{ 2019 { 2020 FromEndpoints: []api.EndpointSelector{endpointSelectorC}, 2021 }, 2022 }, 2023 }}) 2024 2025 addedRule := repo.rules[0] 2026 2027 selectedEpLabels := labels.ParseSelectLabel("id=a") 2028 selectedIdentity := identity2.NewIdentity(54321, labels.Labels{selectedEpLabels.Key: selectedEpLabels}) 2029 2030 notSelectedEpLabels := labels.ParseSelectLabel("id=b") 2031 notSelectedIdentity := identity2.NewIdentity(9876, labels.Labels{notSelectedEpLabels.Key: notSelectedEpLabels}) 2032 2033 // notSelectedEndpoint is not selected by rule, so we it shouldn't be added 2034 // to EndpointsSelected. 2035 c.Assert(addedRule.matches(notSelectedIdentity), Equals, false) 2036 c.Assert(addedRule.metadata.IdentitySelected, checker.DeepEquals, map[identity.NumericIdentity]bool{notSelectedIdentity.ID: false}) 2037 2038 // selectedEndpoint is selected by rule, so we it should be added to 2039 // EndpointsSelected. 2040 c.Assert(addedRule.matches(selectedIdentity), Equals, true) 2041 c.Assert(addedRule.metadata.IdentitySelected, checker.DeepEquals, map[identity.NumericIdentity]bool{selectedIdentity.ID: true, notSelectedIdentity.ID: false}) 2042 2043 // Test again to check for caching working correctly. 2044 c.Assert(addedRule.matches(selectedIdentity), Equals, true) 2045 c.Assert(addedRule.metadata.IdentitySelected, checker.DeepEquals, map[identity.NumericIdentity]bool{selectedIdentity.ID: true, notSelectedIdentity.ID: false}) 2046 2047 // Possible scenario where an endpoint is deleted, and soon after another 2048 // endpoint is added with the same ID, but with a different identity. Matching 2049 // needs to handle this case correctly. 2050 c.Assert(addedRule.matches(notSelectedIdentity), Equals, false) 2051 c.Assert(addedRule.metadata.IdentitySelected, checker.DeepEquals, map[identity.NumericIdentity]bool{selectedIdentity.ID: true, notSelectedIdentity.ID: false}) 2052 }