github.com/zhyoulun/cilium@v1.6.12/pkg/policy/l4_filter_test.go (about) 1 // Copyright 2018 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 22 "github.com/cilium/cilium/pkg/checker" 23 "github.com/cilium/cilium/pkg/identity/cache" 24 "github.com/cilium/cilium/pkg/labels" 25 "github.com/cilium/cilium/pkg/option" 26 "github.com/cilium/cilium/pkg/policy/api" 27 28 logging "github.com/op/go-logging" 29 . "gopkg.in/check.v1" 30 ) 31 32 var ( 33 hostSelector = api.ReservedEndpointSelectors[labels.IDNameHost] 34 toFoo = &SearchContext{To: labels.ParseSelectLabelArray("foo")} 35 36 dummySelectorCacheUser = &DummySelectorCacheUser{} 37 testSelectorCache = testNewSelectorCache(cache.GetIdentityCache()) 38 39 wildcardCachedSelector, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, api.WildcardEndpointSelector) 40 41 cachedSelectorA, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, endpointSelectorA) 42 cachedSelectorC, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, endpointSelectorC) 43 cachedSelectorHost, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, hostSelector) 44 45 fooSelector = api.NewESFromLabels(labels.ParseSelectLabel("foo")) 46 barSelector = api.NewESFromLabels(labels.ParseSelectLabel("bar")) 47 bazSelector = api.NewESFromLabels(labels.ParseSelectLabel("baz")) 48 49 cachedFooSelector, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, fooSelector) 50 cachedBazSelector, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, bazSelector) 51 52 selFoo = api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 53 selBar1 = api.NewESFromLabels(labels.ParseSelectLabel("id=bar1")) 54 selBar2 = api.NewESFromLabels(labels.ParseSelectLabel("id=bar2")) 55 56 cachedSelectorBar1, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, selBar1) 57 cachedSelectorBar2, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, selBar2) 58 ) 59 60 // Tests in this file: 61 // 62 // How to read this table: 63 // Case: The test / subtest number. 64 // L3: Matches at L3 for rule 1, followed by rule 2. 65 // L4: Matches at L4. 66 // L7: Rules at L7 for rule 1, followed by rule 2. 67 // Notes: Extra information about the test. 68 // 69 // +-----+-----------------+----------+-----------------+------------------------------------------------------+ 70 // |Case | L3 (1, 2) match | L4 match | L7 match (1, 2) | Notes | 71 // +=====+=================+==========+=================+======================================================+ 72 // | 1A | *, * | 80/TCP | *, * | Allow all communication on the specified port | 73 // | 1B | *, * | 80/TCP | *, * | Same as 1A, with implicit L3 wildcards | 74 // | 2A | *, * | 80/TCP | *, "GET /" | Rule 1 shadows rule 2 | 75 // | 2B | *, * | 80/TCP | "GET /", * | Same as 2A, but import in reverse order | 76 // | 3 | *, * | 80/TCP | "GET /","GET /" | Exactly duplicate rules (HTTP) | 77 // | 4 | *, * | 9092/TCP | "foo","foo" | Exactly duplicate rules (Kafka) | 78 // | 5A | *, * | 80/TCP | "foo","GET /" | Rules with conflicting L7 parser | 79 // | 5B | *, * | 80/TCP | "GET /","foo" | Same as 5A, but import in reverse order | 80 // | 6A | "id=a", * | 80/TCP | *, * | Rule 2 is a superset of rule 1 | 81 // | 6B | *, "id=a" | 80/TCP | *, * | Same as 6A, but import in reverse order | 82 // | 7A | "id=a", * | 80/TCP | "GET /", * | All traffic is allowed; traffic to A goes via proxy | 83 // | 7B | *, "id=a" | 80/TCP | *, "GET /" | Same as 7A, but import in reverse order | 84 // | 8A | "id=a", * | 80/TCP | "GET /","GET /" | Rule 2 is the same as rule 1, except matching all L3 | 85 // | 8B | *, "id=a" | 80/TCP | "GET /","GET /" | Same as 8A, but import in reverse order | 86 // | 9A | "id=a", * | 80/TCP | "foo","GET /" | Rules with conflicting L7 parser (+L3 match) | 87 // | 9B | *, "id=a" | 80/TCP | "GET /","foo" | Same as 9A, but import in reverse order | 88 // | 10 | "id=a", "id=c" | 80/TCP | "GET /","GET /" | Allow at L7 for two distinct labels (disjoint set) | 89 // | 11 | "id=a", "id=c" | 80/TCP | *, * | Allow at L4 for two distinct labels (disjoint set) | 90 // | 12 | "id=a", | 80/TCP | "GET /" | Configure to allow localhost traffic always | 91 // +-----+-----------------+----------+-----------------+------------------------------------------------------+ 92 93 // Case 1: allow all at L3 in both rules, and all at L7 (duplicate rule). 94 func (ds *PolicyTestSuite) TestMergeAllowAllL3AndAllowAllL7(c *C) { 95 // Case 1A: Specify WildcardEndpointSelector explicitly. 96 repo := parseAndAddRules(c, api.Rules{&api.Rule{ 97 EndpointSelector: endpointSelectorA, 98 Ingress: []api.IngressRule{ 99 { 100 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 101 ToPorts: []api.PortRule{{ 102 Ports: []api.PortProtocol{ 103 {Port: "80", Protocol: api.ProtoTCP}, 104 }, 105 }}, 106 }, 107 { 108 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 109 ToPorts: []api.PortRule{{ 110 Ports: []api.PortProtocol{ 111 {Port: "80", Protocol: api.ProtoTCP}, 112 }, 113 }}, 114 }, 115 }, 116 }}) 117 118 buffer := new(bytes.Buffer) 119 ctx := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 120 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 121 122 l4IngressPolicy, err := repo.ResolveL4IngressPolicy(&ctx) 123 c.Assert(err, IsNil) 124 125 c.Log(buffer) 126 127 filter, ok := l4IngressPolicy["80/TCP"] 128 c.Assert(ok, Equals, true) 129 c.Assert(filter.Port, Equals, 80) 130 c.Assert(filter.Ingress, Equals, true) 131 132 c.Assert(filter.CachedSelectors.SelectsAllEndpoints(), Equals, true) 133 134 c.Assert(filter.L7Parser, Equals, ParserTypeNone) 135 c.Assert(len(filter.L7RulesPerEp), Equals, 0) 136 l4IngressPolicy.Detach(repo.GetSelectorCache()) 137 138 // Case1B: implicitly wildcard all endpoints. 139 repo = parseAndAddRules(c, api.Rules{&api.Rule{ 140 EndpointSelector: endpointSelectorA, 141 Ingress: []api.IngressRule{ 142 { 143 FromEndpoints: []api.EndpointSelector{}, 144 ToPorts: []api.PortRule{{ 145 Ports: []api.PortProtocol{ 146 {Port: "80", Protocol: api.ProtoTCP}, 147 }, 148 }}, 149 }, 150 { 151 FromEndpoints: []api.EndpointSelector{}, 152 ToPorts: []api.PortRule{{ 153 Ports: []api.PortProtocol{ 154 {Port: "80", Protocol: api.ProtoTCP}, 155 }, 156 }}, 157 }, 158 }, 159 }}) 160 161 buffer = new(bytes.Buffer) 162 ctx = SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 163 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 164 165 l4IngressPolicy, err = repo.ResolveL4IngressPolicy(&ctx) 166 c.Assert(err, IsNil) 167 168 c.Log(buffer) 169 170 filter, ok = l4IngressPolicy["80/TCP"] 171 c.Assert(ok, Equals, true) 172 c.Assert(filter.Port, Equals, 80) 173 c.Assert(filter.Ingress, Equals, true) 174 175 c.Assert(filter.CachedSelectors.SelectsAllEndpoints(), Equals, true) 176 177 c.Assert(filter.L7Parser, Equals, ParserTypeNone) 178 c.Assert(len(filter.L7RulesPerEp), Equals, 0) 179 l4IngressPolicy.Detach(repo.GetSelectorCache()) 180 } 181 182 // Case 2: allow all at L3 in both rules. Allow all in one L7 rule, but second 183 // rule restricts at L7. Because one L7 rule allows at L7, all traffic is allowed 184 // at L7, but still redirected at the proxy. 185 // Should resolve to one rule. 186 func (ds *PolicyTestSuite) TestMergeAllowAllL3AndShadowedL7(c *C) { 187 rule1 := &rule{ 188 Rule: api.Rule{ 189 EndpointSelector: endpointSelectorA, 190 Ingress: []api.IngressRule{ 191 { 192 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 193 ToPorts: []api.PortRule{{ 194 Ports: []api.PortProtocol{ 195 {Port: "80", Protocol: api.ProtoTCP}, 196 }, 197 }}, 198 }, 199 { 200 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 201 ToPorts: []api.PortRule{{ 202 Ports: []api.PortProtocol{ 203 {Port: "80", Protocol: api.ProtoTCP}, 204 }, 205 Rules: &api.L7Rules{ 206 HTTP: []api.PortRuleHTTP{ 207 {Method: "GET", Path: "/"}, 208 }, 209 }, 210 }}, 211 }, 212 }, 213 }} 214 215 buffer := new(bytes.Buffer) 216 ctx := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 217 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 218 219 ingressState := traceState{} 220 res, err := rule1.resolveIngressPolicy(&ctx, &ingressState, L4PolicyMap{}, nil, testSelectorCache) 221 c.Assert(err, IsNil) 222 c.Assert(res, Not(IsNil)) 223 224 c.Log(buffer) 225 226 // The expected policy contains the L7 Rules below, but in practice 227 // when the policy is being resolved and sent to the proxy, it actually 228 // allows all at L7, based on the first API rule imported above. We 229 // just set the expected set of L7 rules below to include this to match 230 // the current implementation. 231 expected := L4PolicyMap{"80/TCP": &L4Filter{ 232 Port: 80, 233 Protocol: api.ProtoTCP, 234 U8Proto: 6, 235 allowsAllAtL3: true, 236 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 237 L7Parser: "http", 238 L7RulesPerEp: L7DataMap{ 239 wildcardCachedSelector: api.L7Rules{ 240 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 241 }, 242 }, 243 Ingress: true, 244 DerivedFromRules: labels.LabelArrayList{nil, nil}, 245 }} 246 247 c.Assert(res, checker.Equals, expected) 248 c.Assert(ingressState.selectedRules, Equals, 1) 249 c.Assert(ingressState.matchedRules, Equals, 0) 250 res.Detach(testSelectorCache) 251 expected.Detach(testSelectorCache) 252 253 // Case 2B: Flip order of case 2A so that rule being merged with is different 254 // than rule being consumed. 255 repo := parseAndAddRules(c, api.Rules{&api.Rule{ 256 EndpointSelector: endpointSelectorA, 257 Ingress: []api.IngressRule{ 258 { 259 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 260 ToPorts: []api.PortRule{{ 261 Ports: []api.PortProtocol{ 262 {Port: "80", Protocol: api.ProtoTCP}, 263 }, 264 Rules: &api.L7Rules{ 265 HTTP: []api.PortRuleHTTP{ 266 {Method: "GET", Path: "/"}, 267 }, 268 }, 269 }}, 270 }, 271 { 272 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 273 ToPorts: []api.PortRule{{ 274 Ports: []api.PortProtocol{ 275 {Port: "80", Protocol: api.ProtoTCP}, 276 }, 277 }}, 278 }, 279 }, 280 }}) 281 282 buffer = new(bytes.Buffer) 283 ctx = SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 284 ctx.Logging = logging.NewLogBackend(buffer, "", 0) 285 286 l4IngressPolicy, err := repo.ResolveL4IngressPolicy(&ctx) 287 c.Assert(err, IsNil) 288 289 c.Log(buffer) 290 291 filter, ok := l4IngressPolicy["80/TCP"] 292 c.Assert(ok, Equals, true) 293 c.Assert(filter.Port, Equals, 80) 294 c.Assert(filter.Ingress, Equals, true) 295 296 c.Assert(filter.CachedSelectors.SelectsAllEndpoints(), Equals, true) 297 298 c.Assert(filter.L7Parser, Equals, ParserTypeHTTP) 299 c.Assert(len(filter.L7RulesPerEp), Equals, 1) 300 l4IngressPolicy.Detach(repo.GetSelectorCache()) 301 } 302 303 // Case 3: allow all at L3 in both rules. Both rules have same parser type and 304 // same API resource specified at L7 for HTTP. 305 func (ds *PolicyTestSuite) TestMergeIdenticalAllowAllL3AndRestrictedL7HTTP(c *C) { 306 identicalHTTPRule := &rule{ 307 Rule: api.Rule{ 308 EndpointSelector: endpointSelectorA, 309 Ingress: []api.IngressRule{ 310 { 311 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 312 ToPorts: []api.PortRule{{ 313 Ports: []api.PortProtocol{ 314 {Port: "80", Protocol: api.ProtoTCP}, 315 }, 316 Rules: &api.L7Rules{ 317 HTTP: []api.PortRuleHTTP{ 318 {Method: "GET", Path: "/"}, 319 }, 320 }, 321 }}, 322 }, 323 { 324 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 325 ToPorts: []api.PortRule{{ 326 Ports: []api.PortProtocol{ 327 {Port: "80", Protocol: api.ProtoTCP}, 328 }, 329 Rules: &api.L7Rules{ 330 HTTP: []api.PortRuleHTTP{ 331 {Method: "GET", Path: "/"}, 332 }, 333 }, 334 }}, 335 }, 336 }, 337 }} 338 339 expected := L4PolicyMap{"80/TCP": &L4Filter{ 340 Port: 80, 341 Protocol: api.ProtoTCP, 342 U8Proto: 6, 343 allowsAllAtL3: true, 344 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 345 L7Parser: ParserTypeHTTP, 346 L7RulesPerEp: L7DataMap{ 347 wildcardCachedSelector: api.L7Rules{ 348 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 349 }, 350 }, 351 Ingress: true, 352 DerivedFromRules: labels.LabelArrayList{nil, nil}, 353 }} 354 355 buffer := new(bytes.Buffer) 356 ctxToA := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 357 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 358 c.Log(buffer) 359 360 state := traceState{} 361 res, err := identicalHTTPRule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 362 c.Assert(err, IsNil) 363 c.Assert(res, Not(IsNil)) 364 c.Assert(res, checker.Equals, expected) 365 c.Assert(state.selectedRules, Equals, 1) 366 c.Assert(state.matchedRules, Equals, 0) 367 res.Detach(testSelectorCache) 368 expected.Detach(testSelectorCache) 369 370 state = traceState{} 371 res, err = identicalHTTPRule.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 372 c.Assert(err, IsNil) 373 c.Assert(res, IsNil) 374 c.Assert(state.selectedRules, Equals, 0) 375 c.Assert(state.matchedRules, Equals, 0) 376 } 377 378 // Case 4: identical allow all at L3 with identical restrictions on Kafka. 379 func (ds *PolicyTestSuite) TestMergeIdenticalAllowAllL3AndRestrictedL7Kafka(c *C) { 380 381 identicalKafkaRule := &rule{ 382 Rule: api.Rule{ 383 EndpointSelector: endpointSelectorA, 384 Ingress: []api.IngressRule{ 385 { 386 FromEndpoints: api.EndpointSelectorSlice{api.WildcardEndpointSelector}, 387 ToPorts: []api.PortRule{{ 388 Ports: []api.PortProtocol{ 389 {Port: "9092", Protocol: api.ProtoTCP}, 390 }, 391 Rules: &api.L7Rules{ 392 Kafka: []api.PortRuleKafka{ 393 {Topic: "foo"}, 394 }, 395 }, 396 }}, 397 }, 398 { 399 FromEndpoints: api.EndpointSelectorSlice{api.WildcardEndpointSelector}, 400 ToPorts: []api.PortRule{{ 401 Ports: []api.PortProtocol{ 402 {Port: "9092", Protocol: api.ProtoTCP}, 403 }, 404 Rules: &api.L7Rules{ 405 Kafka: []api.PortRuleKafka{ 406 {Topic: "foo"}, 407 }, 408 }, 409 }}, 410 }, 411 }, 412 }} 413 414 buffer := new(bytes.Buffer) 415 ctxToA := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 416 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 417 c.Log(buffer) 418 419 expected := L4PolicyMap{"9092/TCP": &L4Filter{ 420 Port: 9092, 421 Protocol: api.ProtoTCP, 422 U8Proto: 6, 423 allowsAllAtL3: true, 424 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 425 L7Parser: ParserTypeKafka, 426 L7RulesPerEp: L7DataMap{ 427 wildcardCachedSelector: api.L7Rules{ 428 Kafka: []api.PortRuleKafka{{Topic: "foo"}}, 429 }, 430 }, 431 Ingress: true, 432 DerivedFromRules: labels.LabelArrayList{nil, nil}, 433 }} 434 435 state := traceState{} 436 res, err := identicalKafkaRule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 437 c.Assert(err, IsNil) 438 c.Assert(res, Not(IsNil)) 439 c.Assert(res, checker.Equals, expected) 440 c.Assert(state.selectedRules, Equals, 1) 441 c.Assert(state.matchedRules, Equals, 0) 442 res.Detach(testSelectorCache) 443 expected.Detach(testSelectorCache) 444 445 state = traceState{} 446 res, err = identicalKafkaRule.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 447 c.Assert(err, IsNil) 448 c.Assert(res, IsNil) 449 c.Assert(state.selectedRules, Equals, 0) 450 c.Assert(state.matchedRules, Equals, 0) 451 } 452 453 // Case 5: use conflicting protocols on the same port in different rules. This 454 // is not supported, so return an error. 455 func (ds *PolicyTestSuite) TestMergeIdenticalAllowAllL3AndMismatchingParsers(c *C) { 456 457 // Case 5A: Kafka first, HTTP second. 458 conflictingParsersRule := &rule{ 459 Rule: api.Rule{ 460 EndpointSelector: endpointSelectorA, 461 Ingress: []api.IngressRule{ 462 { 463 FromEndpoints: api.EndpointSelectorSlice{api.WildcardEndpointSelector}, 464 ToPorts: []api.PortRule{{ 465 Ports: []api.PortProtocol{ 466 {Port: "80", Protocol: api.ProtoTCP}, 467 }, 468 Rules: &api.L7Rules{ 469 Kafka: []api.PortRuleKafka{ 470 {Topic: "foo"}, 471 }, 472 }, 473 }}, 474 }, 475 { 476 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 477 ToPorts: []api.PortRule{{ 478 Ports: []api.PortProtocol{ 479 {Port: "80", Protocol: api.ProtoTCP}, 480 }, 481 Rules: &api.L7Rules{ 482 HTTP: []api.PortRuleHTTP{ 483 {Method: "GET", Path: "/"}, 484 }, 485 }, 486 }}, 487 }, 488 }, 489 }} 490 491 buffer := new(bytes.Buffer) 492 ctxToA := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 493 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 494 c.Log(buffer) 495 496 state := traceState{} 497 res, err := conflictingParsersRule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 498 c.Assert(err, Not(IsNil)) 499 c.Assert(res, IsNil) 500 501 // Case 5B: HTTP first, Kafka second. 502 conflictingParsersRule = &rule{ 503 Rule: api.Rule{ 504 EndpointSelector: endpointSelectorA, 505 Ingress: []api.IngressRule{ 506 { 507 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 508 ToPorts: []api.PortRule{{ 509 Ports: []api.PortProtocol{ 510 {Port: "80", Protocol: api.ProtoTCP}, 511 }, 512 Rules: &api.L7Rules{ 513 HTTP: []api.PortRuleHTTP{ 514 {Method: "GET", Path: "/"}, 515 }, 516 }, 517 }}, 518 }, 519 { 520 FromEndpoints: api.EndpointSelectorSlice{api.WildcardEndpointSelector}, 521 ToPorts: []api.PortRule{{ 522 Ports: []api.PortProtocol{ 523 {Port: "80", Protocol: api.ProtoTCP}, 524 }, 525 Rules: &api.L7Rules{ 526 Kafka: []api.PortRuleKafka{ 527 {Topic: "foo"}, 528 }, 529 }, 530 }}, 531 }, 532 }, 533 }} 534 535 buffer = new(bytes.Buffer) 536 ctxToA = SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 537 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 538 c.Log(buffer) 539 540 state = traceState{} 541 res, err = conflictingParsersRule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 542 c.Assert(err, Not(IsNil)) 543 c.Assert(res, IsNil) 544 545 // Case 5B+: HTTP first, generic L7 second. 546 conflictingParsersIngressRule := &rule{ 547 Rule: api.Rule{ 548 EndpointSelector: endpointSelectorA, 549 Ingress: []api.IngressRule{ 550 { 551 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 552 ToPorts: []api.PortRule{{ 553 Ports: []api.PortProtocol{ 554 {Port: "80", Protocol: api.ProtoTCP}, 555 }, 556 Rules: &api.L7Rules{ 557 HTTP: []api.PortRuleHTTP{ 558 {Method: "GET", Path: "/"}, 559 }, 560 }, 561 }}, 562 }, 563 { 564 FromEndpoints: api.EndpointSelectorSlice{api.WildcardEndpointSelector}, 565 ToPorts: []api.PortRule{{ 566 Ports: []api.PortProtocol{ 567 {Port: "80", Protocol: api.ProtoTCP}, 568 }, 569 Rules: &api.L7Rules{ 570 L7Proto: "testing", 571 L7: []api.PortRuleL7{ 572 {"method": "PUT", "path": "/Foo"}, 573 }, 574 }, 575 }}, 576 }, 577 }, 578 }} 579 580 buffer = new(bytes.Buffer) 581 ctxToA = SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 582 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 583 c.Log(buffer) 584 585 err = conflictingParsersIngressRule.Sanitize() 586 c.Assert(err, IsNil) 587 588 state = traceState{} 589 res, err = conflictingParsersIngressRule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 590 c.Assert(err, Not(IsNil)) 591 c.Assert(res, IsNil) 592 593 // Case 5B++: generic L7 without rules first, HTTP second. 594 conflictingParsersEgressRule := &rule{ 595 Rule: api.Rule{ 596 EndpointSelector: endpointSelectorA, 597 Egress: []api.EgressRule{ 598 { 599 ToEndpoints: []api.EndpointSelector{endpointSelectorC}, 600 ToPorts: []api.PortRule{{ 601 Ports: []api.PortProtocol{ 602 {Port: "80", Protocol: api.ProtoTCP}, 603 }, 604 Rules: &api.L7Rules{ 605 L7Proto: "testing", 606 }, 607 }}, 608 }, 609 { 610 ToEndpoints: []api.EndpointSelector{endpointSelectorC}, 611 ToPorts: []api.PortRule{{ 612 Ports: []api.PortProtocol{ 613 {Port: "80", Protocol: api.ProtoTCP}, 614 }, 615 Rules: &api.L7Rules{ 616 HTTP: []api.PortRuleHTTP{ 617 {Method: "GET", Path: "/"}, 618 }, 619 }, 620 }}, 621 }, 622 }, 623 }} 624 625 buffer = new(bytes.Buffer) 626 ctxAToC := SearchContext{From: labelsA, To: labelsC, Trace: TRACE_VERBOSE} 627 ctxAToC.Logging = logging.NewLogBackend(buffer, "", 0) 628 c.Log(buffer) 629 630 err = conflictingParsersEgressRule.Sanitize() 631 c.Assert(err, IsNil) 632 633 state = traceState{} 634 res, err = conflictingParsersEgressRule.resolveEgressPolicy(&ctxAToC, &state, L4PolicyMap{}, nil, testSelectorCache) 635 c.Log(buffer) 636 c.Assert(err, Not(IsNil)) 637 c.Assert(res, IsNil) 638 } 639 640 // Case 6: allow all at L3/L7 in one rule, and select an endpoint and allow all on L7 641 // in another rule. Should resolve to just allowing all on L3/L7 (first rule 642 // shadows the second). 643 func (ds *PolicyTestSuite) TestL3RuleShadowedByL3AllowAll(c *C) { 644 // Case 6A: Specify WildcardEndpointSelector explicitly. 645 shadowRule := &rule{ 646 Rule: api.Rule{ 647 EndpointSelector: endpointSelectorA, 648 Ingress: []api.IngressRule{ 649 { 650 FromEndpoints: []api.EndpointSelector{endpointSelectorA}, 651 ToPorts: []api.PortRule{{ 652 Ports: []api.PortProtocol{ 653 {Port: "80", Protocol: api.ProtoTCP}, 654 }, 655 }}, 656 }, 657 { 658 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 659 ToPorts: []api.PortRule{{ 660 Ports: []api.PortProtocol{ 661 {Port: "80", Protocol: api.ProtoTCP}, 662 }, 663 }}, 664 }, 665 }, 666 }} 667 668 buffer := new(bytes.Buffer) 669 ctxToA := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 670 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 671 c.Log(buffer) 672 673 expected := L4PolicyMap{"80/TCP": &L4Filter{ 674 Port: 80, 675 Protocol: api.ProtoTCP, 676 U8Proto: 6, 677 allowsAllAtL3: true, 678 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 679 L7Parser: ParserTypeNone, 680 L7RulesPerEp: L7DataMap{}, 681 Ingress: true, 682 DerivedFromRules: labels.LabelArrayList{nil, nil}, 683 }} 684 685 state := traceState{} 686 res, err := shadowRule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 687 c.Assert(err, IsNil) 688 c.Assert(res, Not(IsNil)) 689 c.Assert(res, checker.Equals, expected) 690 c.Assert(state.selectedRules, Equals, 1) 691 c.Assert(state.matchedRules, Equals, 0) 692 res.Detach(testSelectorCache) 693 expected.Detach(testSelectorCache) 694 695 state = traceState{} 696 res, err = shadowRule.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 697 c.Assert(err, IsNil) 698 c.Assert(res, IsNil) 699 c.Assert(state.selectedRules, Equals, 0) 700 c.Assert(state.matchedRules, Equals, 0) 701 702 // Case 6B: Reverse the ordering of the rules. Result should be the same. 703 shadowRule = &rule{ 704 Rule: api.Rule{ 705 EndpointSelector: endpointSelectorA, 706 Ingress: []api.IngressRule{ 707 { 708 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 709 ToPorts: []api.PortRule{{ 710 Ports: []api.PortProtocol{ 711 {Port: "80", Protocol: api.ProtoTCP}, 712 }, 713 }}, 714 }, 715 { 716 FromEndpoints: []api.EndpointSelector{endpointSelectorA}, 717 ToPorts: []api.PortRule{{ 718 Ports: []api.PortProtocol{ 719 {Port: "80", Protocol: api.ProtoTCP}, 720 }, 721 }}, 722 }, 723 }, 724 }} 725 726 buffer = new(bytes.Buffer) 727 ctxToA = SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 728 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 729 c.Log(buffer) 730 731 expected = L4PolicyMap{"80/TCP": &L4Filter{ 732 Port: 80, 733 Protocol: api.ProtoTCP, 734 U8Proto: 6, 735 allowsAllAtL3: true, 736 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 737 L7Parser: ParserTypeNone, 738 L7RulesPerEp: L7DataMap{}, 739 Ingress: true, 740 DerivedFromRules: labels.LabelArrayList{nil, nil}, 741 }} 742 743 state = traceState{} 744 res, err = shadowRule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 745 c.Assert(err, IsNil) 746 c.Assert(res, Not(IsNil)) 747 c.Assert(res, checker.Equals, expected) 748 c.Assert(state.selectedRules, Equals, 1) 749 c.Assert(state.matchedRules, Equals, 0) 750 res.Detach(testSelectorCache) 751 expected.Detach(testSelectorCache) 752 753 state = traceState{} 754 res, err = shadowRule.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 755 c.Assert(err, IsNil) 756 c.Assert(res, IsNil) 757 c.Assert(state.selectedRules, Equals, 0) 758 c.Assert(state.matchedRules, Equals, 0) 759 } 760 761 // Case 7: allow all at L3/L7 in one rule, and in another rule, select an endpoint 762 // which restricts on L7. Should resolve to just allowing all on L3/L7 (first rule 763 // shadows the second), but setting traffic to the HTTP proxy. 764 func (ds *PolicyTestSuite) TestL3RuleWithL7RulePartiallyShadowedByL3AllowAll(c *C) { 765 // Case 7A: selects specific endpoint with L7 restrictions rule first, then 766 // rule which selects all endpoints and allows all on L7. Net result sets 767 // parser type to whatever is in first rule, but without the restriction 768 // on L7. 769 shadowRule := &rule{ 770 Rule: api.Rule{ 771 EndpointSelector: endpointSelectorA, 772 Ingress: []api.IngressRule{ 773 { 774 FromEndpoints: []api.EndpointSelector{endpointSelectorA}, 775 ToPorts: []api.PortRule{{ 776 Ports: []api.PortProtocol{ 777 {Port: "80", Protocol: api.ProtoTCP}, 778 }, 779 Rules: &api.L7Rules{ 780 HTTP: []api.PortRuleHTTP{ 781 {Method: "GET", Path: "/"}, 782 }, 783 }, 784 }}, 785 }, 786 { 787 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 788 ToPorts: []api.PortRule{{ 789 Ports: []api.PortProtocol{ 790 {Port: "80", Protocol: api.ProtoTCP}, 791 }, 792 }}, 793 }, 794 }, 795 }} 796 797 buffer := new(bytes.Buffer) 798 ctxToA := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 799 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 800 c.Log(buffer) 801 802 expected := L4PolicyMap{"80/TCP": &L4Filter{ 803 Port: 80, 804 Protocol: api.ProtoTCP, 805 U8Proto: 6, 806 allowsAllAtL3: true, 807 CachedSelectors: CachedSelectorSlice{cachedSelectorA, wildcardCachedSelector}, 808 L7Parser: ParserTypeHTTP, 809 L7RulesPerEp: L7DataMap{ 810 cachedSelectorA: api.L7Rules{ 811 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 812 }, 813 }, 814 Ingress: true, 815 DerivedFromRules: labels.LabelArrayList{nil, nil}, 816 }} 817 818 state := traceState{} 819 res, err := shadowRule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 820 c.Assert(err, IsNil) 821 c.Assert(res, Not(IsNil)) 822 c.Assert(res, checker.Equals, expected) 823 c.Assert(state.selectedRules, Equals, 1) 824 c.Assert(state.matchedRules, Equals, 0) 825 res.Detach(testSelectorCache) 826 expected.Detach(testSelectorCache) 827 828 state = traceState{} 829 res, err = shadowRule.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 830 c.Assert(err, IsNil) 831 c.Assert(res, IsNil) 832 c.Assert(state.selectedRules, Equals, 0) 833 c.Assert(state.matchedRules, Equals, 0) 834 835 // Case 7B: selects all endpoints and allows all on L7, then selects specific 836 // endpoint with L7 restrictions rule. Net result sets parser type to whatever 837 // is in first rule, but without the restriction on L7. 838 shadowRule = &rule{ 839 Rule: api.Rule{ 840 EndpointSelector: endpointSelectorA, 841 Ingress: []api.IngressRule{ 842 { 843 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 844 ToPorts: []api.PortRule{{ 845 Ports: []api.PortProtocol{ 846 {Port: "80", Protocol: api.ProtoTCP}, 847 }, 848 }}, 849 }, 850 { 851 FromEndpoints: []api.EndpointSelector{endpointSelectorA}, 852 ToPorts: []api.PortRule{{ 853 Ports: []api.PortProtocol{ 854 {Port: "80", Protocol: api.ProtoTCP}, 855 }, 856 Rules: &api.L7Rules{ 857 HTTP: []api.PortRuleHTTP{ 858 {Method: "GET", Path: "/"}, 859 }, 860 }, 861 }}, 862 }, 863 }, 864 }} 865 866 buffer = new(bytes.Buffer) 867 ctxToA = SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 868 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 869 c.Log(buffer) 870 871 expected = L4PolicyMap{"80/TCP": &L4Filter{ 872 Port: 80, 873 Protocol: api.ProtoTCP, 874 U8Proto: 6, 875 allowsAllAtL3: true, 876 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector, cachedSelectorA}, 877 L7Parser: ParserTypeHTTP, 878 L7RulesPerEp: L7DataMap{ 879 cachedSelectorA: api.L7Rules{ 880 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 881 }, 882 }, 883 Ingress: true, 884 DerivedFromRules: labels.LabelArrayList{nil, nil}, 885 }} 886 887 state = traceState{} 888 res, err = shadowRule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 889 c.Assert(err, IsNil) 890 c.Assert(res, Not(IsNil)) 891 c.Assert(res, checker.Equals, expected) 892 c.Assert(state.selectedRules, Equals, 1) 893 c.Assert(state.matchedRules, Equals, 0) 894 res.Detach(testSelectorCache) 895 expected.Detach(testSelectorCache) 896 897 state = traceState{} 898 res, err = shadowRule.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 899 c.Assert(err, IsNil) 900 c.Assert(res, IsNil) 901 c.Assert(state.selectedRules, Equals, 0) 902 c.Assert(state.matchedRules, Equals, 0) 903 } 904 905 // Case 8: allow all at L3 and restricts on L7 in one rule, and in another rule, 906 // select an endpoint which restricts the same as the first rule on L7. 907 // Should resolve to just allowing all on L3, but restricting on L7 for both 908 // wildcard and the specified endpoint. 909 func (ds *PolicyTestSuite) TestL3RuleWithL7RuleShadowedByL3AllowAll(c *C) { 910 911 // Case 8A: selects specific endpoint with L7 restrictions rule first, then 912 // rule which selects all endpoints and restricts on the same resource on L7. 913 // L7RulesPerEp contains entries for both endpoints selected in each rule 914 // on L7 restriction. 915 case8Rule := &rule{ 916 Rule: api.Rule{ 917 EndpointSelector: endpointSelectorA, 918 Ingress: []api.IngressRule{ 919 { 920 FromEndpoints: []api.EndpointSelector{endpointSelectorA}, 921 ToPorts: []api.PortRule{{ 922 Ports: []api.PortProtocol{ 923 {Port: "80", Protocol: api.ProtoTCP}, 924 }, 925 Rules: &api.L7Rules{ 926 HTTP: []api.PortRuleHTTP{ 927 {Method: "GET", Path: "/"}, 928 }, 929 }, 930 }}, 931 }, 932 { 933 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 934 ToPorts: []api.PortRule{{ 935 Ports: []api.PortProtocol{ 936 {Port: "80", Protocol: api.ProtoTCP}, 937 }, 938 Rules: &api.L7Rules{ 939 HTTP: []api.PortRuleHTTP{ 940 {Method: "GET", Path: "/"}, 941 }, 942 }, 943 }}, 944 }, 945 }, 946 }} 947 948 buffer := new(bytes.Buffer) 949 ctxToA := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 950 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 951 c.Log(buffer) 952 953 expected := L4PolicyMap{"80/TCP": &L4Filter{ 954 Port: 80, 955 Protocol: api.ProtoTCP, 956 U8Proto: 6, 957 allowsAllAtL3: true, 958 CachedSelectors: CachedSelectorSlice{cachedSelectorA, wildcardCachedSelector}, 959 L7Parser: ParserTypeHTTP, 960 L7RulesPerEp: L7DataMap{ 961 wildcardCachedSelector: api.L7Rules{ 962 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 963 }, 964 cachedSelectorA: api.L7Rules{ 965 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 966 }, 967 }, 968 Ingress: true, 969 DerivedFromRules: labels.LabelArrayList{nil, nil}, 970 }} 971 972 state := traceState{} 973 res, err := case8Rule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 974 c.Assert(err, IsNil) 975 c.Assert(res, Not(IsNil)) 976 c.Assert(res, checker.Equals, expected) 977 c.Assert(state.selectedRules, Equals, 1) 978 c.Assert(state.matchedRules, Equals, 0) 979 res.Detach(testSelectorCache) 980 expected.Detach(testSelectorCache) 981 982 state = traceState{} 983 res, err = case8Rule.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 984 c.Assert(err, IsNil) 985 c.Assert(res, IsNil) 986 c.Assert(state.selectedRules, Equals, 0) 987 c.Assert(state.matchedRules, Equals, 0) 988 989 // Case 8B: first insert rule which selects all endpoints and restricts on 990 // the same resource on L7. Then, insert rule which selects specific endpoint 991 // with L7 restrictions rule. L7RulesPerEp contains entries for both 992 // endpoints selected in each rule on L7 restriction. 993 case8Rule = &rule{ 994 Rule: api.Rule{ 995 EndpointSelector: endpointSelectorA, 996 Ingress: []api.IngressRule{ 997 { 998 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 999 ToPorts: []api.PortRule{{ 1000 Ports: []api.PortProtocol{ 1001 {Port: "80", Protocol: api.ProtoTCP}, 1002 }, 1003 Rules: &api.L7Rules{ 1004 HTTP: []api.PortRuleHTTP{ 1005 {Method: "GET", Path: "/"}, 1006 }, 1007 }, 1008 }}, 1009 }, 1010 { 1011 FromEndpoints: []api.EndpointSelector{endpointSelectorA}, 1012 ToPorts: []api.PortRule{{ 1013 Ports: []api.PortProtocol{ 1014 {Port: "80", Protocol: api.ProtoTCP}, 1015 }, 1016 Rules: &api.L7Rules{ 1017 HTTP: []api.PortRuleHTTP{ 1018 {Method: "GET", Path: "/"}, 1019 }, 1020 }, 1021 }}, 1022 }, 1023 }, 1024 }} 1025 1026 buffer = new(bytes.Buffer) 1027 ctxToA = SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 1028 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 1029 c.Log(buffer) 1030 1031 expected = L4PolicyMap{"80/TCP": &L4Filter{ 1032 Port: 80, 1033 Protocol: api.ProtoTCP, 1034 U8Proto: 6, 1035 allowsAllAtL3: true, 1036 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector, cachedSelectorA}, 1037 L7Parser: ParserTypeHTTP, 1038 L7RulesPerEp: L7DataMap{ 1039 wildcardCachedSelector: api.L7Rules{ 1040 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 1041 }, 1042 cachedSelectorA: api.L7Rules{ 1043 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 1044 }, 1045 }, 1046 Ingress: true, 1047 DerivedFromRules: labels.LabelArrayList{nil, nil}, 1048 }} 1049 1050 state = traceState{} 1051 res, err = case8Rule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 1052 c.Assert(err, IsNil) 1053 c.Assert(res, Not(IsNil)) 1054 c.Assert(res, checker.Equals, expected) 1055 c.Assert(state.selectedRules, Equals, 1) 1056 c.Assert(state.matchedRules, Equals, 0) 1057 res.Detach(testSelectorCache) 1058 expected.Detach(testSelectorCache) 1059 1060 state = traceState{} 1061 res, err = case8Rule.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 1062 c.Assert(err, IsNil) 1063 c.Assert(res, IsNil) 1064 c.Assert(state.selectedRules, Equals, 0) 1065 c.Assert(state.matchedRules, Equals, 0) 1066 } 1067 1068 // Case 9: allow all at L3 and restricts on L7 in one rule, and in another rule, 1069 // select an endpoint which restricts on different L7 protocol. 1070 // Should fail as cannot have conflicting parsers on same port. 1071 func (ds *PolicyTestSuite) TestL3SelectingEndpointAndL3AllowAllMergeConflictingL7(c *C) { 1072 1073 // Case 9A: Kafka first, then HTTP. 1074 conflictingL7Rule := &rule{ 1075 Rule: api.Rule{ 1076 EndpointSelector: endpointSelectorA, 1077 Ingress: []api.IngressRule{ 1078 { 1079 FromEndpoints: []api.EndpointSelector{endpointSelectorA}, 1080 ToPorts: []api.PortRule{{ 1081 Ports: []api.PortProtocol{ 1082 {Port: "80", Protocol: api.ProtoTCP}, 1083 }, 1084 Rules: &api.L7Rules{ 1085 Kafka: []api.PortRuleKafka{ 1086 {Topic: "foo"}, 1087 }, 1088 }, 1089 }}, 1090 }, 1091 { 1092 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 1093 ToPorts: []api.PortRule{{ 1094 Ports: []api.PortProtocol{ 1095 {Port: "80", Protocol: api.ProtoTCP}, 1096 }, 1097 Rules: &api.L7Rules{ 1098 HTTP: []api.PortRuleHTTP{ 1099 {Method: "GET", Path: "/"}, 1100 }, 1101 }, 1102 }}, 1103 }, 1104 }, 1105 }} 1106 1107 buffer := new(bytes.Buffer) 1108 ctxToA := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 1109 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 1110 c.Log(buffer) 1111 1112 state := traceState{} 1113 res, err := conflictingL7Rule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 1114 c.Assert(err, Not(IsNil)) 1115 c.Assert(res, IsNil) 1116 1117 state = traceState{} 1118 res, err = conflictingL7Rule.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 1119 c.Assert(err, IsNil) 1120 c.Assert(res, IsNil) 1121 c.Assert(state.selectedRules, Equals, 0) 1122 c.Assert(state.matchedRules, Equals, 0) 1123 1124 // Case 9B: HTTP first, then Kafka. 1125 conflictingL7Rule = &rule{ 1126 Rule: api.Rule{ 1127 EndpointSelector: endpointSelectorA, 1128 Ingress: []api.IngressRule{ 1129 { 1130 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 1131 ToPorts: []api.PortRule{{ 1132 Ports: []api.PortProtocol{ 1133 {Port: "80", Protocol: api.ProtoTCP}, 1134 }, 1135 Rules: &api.L7Rules{ 1136 HTTP: []api.PortRuleHTTP{ 1137 {Method: "GET", Path: "/"}, 1138 }, 1139 }, 1140 }}, 1141 }, 1142 { 1143 FromEndpoints: []api.EndpointSelector{endpointSelectorA}, 1144 ToPorts: []api.PortRule{{ 1145 Ports: []api.PortProtocol{ 1146 {Port: "80", Protocol: api.ProtoTCP}, 1147 }, 1148 Rules: &api.L7Rules{ 1149 Kafka: []api.PortRuleKafka{ 1150 {Topic: "foo"}, 1151 }, 1152 }, 1153 }}, 1154 }, 1155 }, 1156 }} 1157 1158 buffer = new(bytes.Buffer) 1159 ctxToA = SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 1160 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 1161 c.Log(buffer) 1162 1163 state = traceState{} 1164 res, err = conflictingL7Rule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 1165 c.Assert(err, Not(IsNil)) 1166 c.Assert(res, IsNil) 1167 1168 state = traceState{} 1169 res, err = conflictingL7Rule.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 1170 c.Assert(err, IsNil) 1171 c.Assert(res, IsNil) 1172 c.Assert(state.selectedRules, Equals, 0) 1173 c.Assert(state.matchedRules, Equals, 0) 1174 } 1175 1176 // Case 10: restrict same path / method on L7 in both rules, 1177 // but select different endpoints in each rule. 1178 func (ds *PolicyTestSuite) TestMergingWithDifferentEndpointsSelectedAllowSameL7(c *C) { 1179 1180 selectDifferentEndpointsRestrictL7 := &rule{ 1181 Rule: api.Rule{ 1182 EndpointSelector: endpointSelectorA, 1183 Ingress: []api.IngressRule{ 1184 { 1185 FromEndpoints: []api.EndpointSelector{endpointSelectorA}, 1186 ToPorts: []api.PortRule{{ 1187 Ports: []api.PortProtocol{ 1188 {Port: "80", Protocol: api.ProtoTCP}, 1189 }, 1190 Rules: &api.L7Rules{ 1191 HTTP: []api.PortRuleHTTP{ 1192 {Method: "GET", Path: "/"}, 1193 }, 1194 }, 1195 }}, 1196 }, 1197 { 1198 FromEndpoints: []api.EndpointSelector{endpointSelectorC}, 1199 ToPorts: []api.PortRule{{ 1200 Ports: []api.PortProtocol{ 1201 {Port: "80", Protocol: api.ProtoTCP}, 1202 }, 1203 Rules: &api.L7Rules{ 1204 HTTP: []api.PortRuleHTTP{ 1205 {Method: "GET", Path: "/"}, 1206 }, 1207 }, 1208 }}, 1209 }, 1210 }, 1211 }} 1212 1213 buffer := new(bytes.Buffer) 1214 ctxToA := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 1215 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 1216 c.Log(buffer) 1217 1218 expected := L4PolicyMap{"80/TCP": &L4Filter{ 1219 Port: 80, 1220 Protocol: api.ProtoTCP, 1221 U8Proto: 6, 1222 CachedSelectors: CachedSelectorSlice{cachedSelectorA, cachedSelectorC}, 1223 L7Parser: ParserTypeHTTP, 1224 L7RulesPerEp: L7DataMap{ 1225 cachedSelectorC: api.L7Rules{ 1226 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 1227 }, 1228 cachedSelectorA: api.L7Rules{ 1229 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 1230 }, 1231 }, 1232 Ingress: true, 1233 DerivedFromRules: labels.LabelArrayList{nil, nil}, 1234 }} 1235 1236 state := traceState{} 1237 res, err := selectDifferentEndpointsRestrictL7.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 1238 c.Assert(err, IsNil) 1239 c.Assert(res, Not(IsNil)) 1240 c.Assert(res, checker.Equals, expected) 1241 c.Assert(state.selectedRules, Equals, 1) 1242 c.Assert(state.matchedRules, Equals, 0) 1243 res.Detach(testSelectorCache) 1244 expected.Detach(testSelectorCache) 1245 1246 buffer = new(bytes.Buffer) 1247 ctxToC := SearchContext{To: labelsC, Trace: TRACE_VERBOSE} 1248 ctxToC.Logging = logging.NewLogBackend(buffer, "", 0) 1249 c.Log(buffer) 1250 1251 state = traceState{} 1252 res, err = selectDifferentEndpointsRestrictL7.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 1253 c.Assert(err, IsNil) 1254 c.Assert(res, IsNil) 1255 c.Assert(state.selectedRules, Equals, 0) 1256 c.Assert(state.matchedRules, Equals, 0) 1257 } 1258 1259 // Case 11: allow all on L7 in both rules, but select different endpoints in each rule. 1260 func (ds *PolicyTestSuite) TestMergingWithDifferentEndpointSelectedAllowAllL7(c *C) { 1261 1262 selectDifferentEndpointsAllowAllL7 := &rule{ 1263 Rule: api.Rule{ 1264 EndpointSelector: endpointSelectorA, 1265 Ingress: []api.IngressRule{ 1266 { 1267 FromEndpoints: []api.EndpointSelector{endpointSelectorA}, 1268 ToPorts: []api.PortRule{{ 1269 Ports: []api.PortProtocol{ 1270 {Port: "80", Protocol: api.ProtoTCP}, 1271 }, 1272 }}, 1273 }, 1274 { 1275 FromEndpoints: []api.EndpointSelector{endpointSelectorC}, 1276 ToPorts: []api.PortRule{{ 1277 Ports: []api.PortProtocol{ 1278 {Port: "80", Protocol: api.ProtoTCP}, 1279 }, 1280 }}, 1281 }, 1282 }, 1283 }} 1284 1285 buffer := new(bytes.Buffer) 1286 ctxToA := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 1287 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 1288 c.Log(buffer) 1289 1290 expected := L4PolicyMap{"80/TCP": &L4Filter{ 1291 Port: 80, 1292 Protocol: api.ProtoTCP, 1293 U8Proto: 6, 1294 CachedSelectors: CachedSelectorSlice{cachedSelectorA, cachedSelectorC}, 1295 L7Parser: ParserTypeNone, 1296 L7RulesPerEp: L7DataMap{}, 1297 Ingress: true, 1298 DerivedFromRules: labels.LabelArrayList{nil, nil}, 1299 }} 1300 1301 state := traceState{} 1302 res, err := selectDifferentEndpointsAllowAllL7.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 1303 c.Assert(err, IsNil) 1304 c.Assert(res, Not(IsNil)) 1305 c.Assert(res, checker.Equals, expected) 1306 c.Assert(state.selectedRules, Equals, 1) 1307 c.Assert(state.matchedRules, Equals, 0) 1308 res.Detach(testSelectorCache) 1309 expected.Detach(testSelectorCache) 1310 1311 buffer = new(bytes.Buffer) 1312 ctxToC := SearchContext{To: labelsC, Trace: TRACE_VERBOSE} 1313 ctxToC.Logging = logging.NewLogBackend(buffer, "", 0) 1314 c.Log(buffer) 1315 1316 state = traceState{} 1317 res, err = selectDifferentEndpointsAllowAllL7.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 1318 c.Assert(err, IsNil) 1319 c.Assert(res, IsNil) 1320 c.Assert(state.selectedRules, Equals, 0) 1321 c.Assert(state.matchedRules, Equals, 0) 1322 } 1323 1324 // Case 12: allow all at L3 in one rule with restrictions at L7. Determine that 1325 // the host should always be allowed. From Host should go to proxy 1326 // allow all; other L3 should restrict at L7 in a separate filter. 1327 func (ds *PolicyTestSuite) TestAllowingLocalhostShadowsL7(c *C) { 1328 1329 // This test checks that when the AllowLocalhost=always option is 1330 // enabled, we always wildcard the host at L7. That means we need to 1331 // set the option in the config, and of course clean up afterwards so 1332 // that this test doesn't affect subsequent tests. 1333 // XXX: Does this affect other tests being run concurrently? 1334 oldLocalhostOpt := option.Config.AllowLocalhost 1335 option.Config.AllowLocalhost = option.AllowLocalhostAlways 1336 defer func() { option.Config.AllowLocalhost = oldLocalhostOpt }() 1337 1338 rule := &rule{ 1339 Rule: api.Rule{ 1340 EndpointSelector: endpointSelectorA, 1341 Ingress: []api.IngressRule{ 1342 { 1343 FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector}, 1344 ToPorts: []api.PortRule{{ 1345 Ports: []api.PortProtocol{ 1346 {Port: "80", Protocol: api.ProtoTCP}, 1347 }, 1348 Rules: &api.L7Rules{ 1349 HTTP: []api.PortRuleHTTP{ 1350 {Method: "GET", Path: "/"}, 1351 }, 1352 }, 1353 }}, 1354 }, 1355 }, 1356 }} 1357 1358 buffer := new(bytes.Buffer) 1359 ctxToA := SearchContext{To: labelsA, Trace: TRACE_VERBOSE} 1360 ctxToA.Logging = logging.NewLogBackend(buffer, "", 0) 1361 1362 expected := L4PolicyMap{"80/TCP": &L4Filter{ 1363 Port: 80, 1364 Protocol: api.ProtoTCP, 1365 U8Proto: 6, 1366 allowsAllAtL3: true, 1367 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector, cachedSelectorHost}, 1368 L7Parser: ParserTypeHTTP, 1369 L7RulesPerEp: L7DataMap{ 1370 wildcardCachedSelector: api.L7Rules{ 1371 HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}}, 1372 }, 1373 cachedSelectorHost: api.L7Rules{}, // Empty => Allow all 1374 }, 1375 Ingress: true, 1376 DerivedFromRules: labels.LabelArrayList{nil}, 1377 }} 1378 1379 state := traceState{} 1380 res, err := rule.resolveIngressPolicy(&ctxToA, &state, L4PolicyMap{}, nil, testSelectorCache) 1381 c.Log(buffer) 1382 c.Assert(err, IsNil) 1383 c.Assert(res, Not(IsNil)) 1384 c.Assert(res, checker.Equals, expected) 1385 c.Assert(state.selectedRules, Equals, 1) 1386 c.Assert(state.matchedRules, Equals, 0) 1387 res.Detach(testSelectorCache) 1388 expected.Detach(testSelectorCache) 1389 1390 // Endpoints not selected by the rule should not match the rule. 1391 buffer = new(bytes.Buffer) 1392 ctxToC := SearchContext{To: labelsC, Trace: TRACE_VERBOSE} 1393 ctxToC.Logging = logging.NewLogBackend(buffer, "", 0) 1394 1395 state = traceState{} 1396 res, err = rule.resolveIngressPolicy(toFoo, &state, L4PolicyMap{}, nil, testSelectorCache) 1397 c.Log(buffer) 1398 c.Assert(err, IsNil) 1399 c.Assert(res, IsNil) 1400 c.Assert(state.selectedRules, Equals, 0) 1401 c.Assert(state.matchedRules, Equals, 0) 1402 } 1403 1404 func (ds *PolicyTestSuite) TestEntitiesL3(c *C) { 1405 1406 allowWorldRule := &rule{ 1407 Rule: api.Rule{ 1408 EndpointSelector: endpointSelectorA, 1409 Egress: []api.EgressRule{ 1410 { 1411 ToEntities: api.EntitySlice{api.EntityAll}, 1412 }, 1413 }, 1414 }} 1415 1416 buffer := new(bytes.Buffer) 1417 ctxFromA := SearchContext{From: labelsA, Trace: TRACE_VERBOSE} 1418 ctxFromA.Logging = logging.NewLogBackend(buffer, "", 0) 1419 c.Log(buffer) 1420 1421 expected := L4PolicyMap{"0/ANY": &L4Filter{ 1422 Port: 0, 1423 Protocol: api.ProtoAny, 1424 U8Proto: 0, 1425 CachedSelectors: CachedSelectorSlice{wildcardCachedSelector}, 1426 L7Parser: ParserTypeNone, 1427 L7RulesPerEp: L7DataMap{}, 1428 Ingress: false, 1429 allowsAllAtL3: true, 1430 DerivedFromRules: labels.LabelArrayList{nil}, 1431 }} 1432 1433 state := traceState{} 1434 res, err := allowWorldRule.resolveEgressPolicy(&ctxFromA, &state, L4PolicyMap{}, nil, testSelectorCache) 1435 1436 c.Assert(err, IsNil) 1437 c.Assert(res, Not(IsNil)) 1438 c.Assert(res, checker.Equals, expected) 1439 c.Assert(state.selectedRules, Equals, 1) 1440 c.Assert(state.matchedRules, Equals, 0) 1441 res.Detach(testSelectorCache) 1442 expected.Detach(testSelectorCache) 1443 }