github.phpd.cn/cilium/cilium@v1.6.12/pkg/envoy/server_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 envoy 18 19 import ( 20 "github.com/cilium/cilium/pkg/checker" 21 "github.com/cilium/cilium/pkg/identity" 22 "github.com/cilium/cilium/pkg/identity/cache" 23 "github.com/cilium/cilium/pkg/labels" 24 "github.com/cilium/cilium/pkg/policy" 25 "github.com/cilium/cilium/pkg/policy/api" 26 27 "github.com/cilium/proxy/go/cilium/api" 28 envoy_api_v2_core "github.com/cilium/proxy/go/envoy/api/v2/core" 29 envoy_api_v2_route "github.com/cilium/proxy/go/envoy/api/v2/route" 30 envoy_type_matcher "github.com/cilium/proxy/go/envoy/type/matcher" 31 32 "github.com/golang/protobuf/ptypes/wrappers" 33 34 . "gopkg.in/check.v1" 35 ) 36 37 type ServerSuite struct{} 38 39 type DummySelectorCacheUser struct{} 40 41 func (d *DummySelectorCacheUser) IdentitySelectionUpdated(selector policy.CachedSelector, selections, added, deleted []identity.NumericIdentity) { 42 } 43 44 var ( 45 _ = Suite(&ServerSuite{}) 46 IPv4Addr = "10.1.1.1" 47 Identity = identity.NumericIdentity(123) 48 ) 49 50 var PortRuleHTTP1 = &api.PortRuleHTTP{ 51 Path: "/foo", 52 Method: "GET", 53 Host: "foo.cilium.io", 54 Headers: []string{"header2 value", "header1"}, 55 } 56 57 var PortRuleHTTP2 = &api.PortRuleHTTP{ 58 Path: "/bar", 59 Method: "PUT", 60 } 61 62 var PortRuleHTTP3 = &api.PortRuleHTTP{ 63 Path: "/bar", 64 Method: "GET", 65 } 66 67 var googleRe2 = &envoy_type_matcher.RegexMatcher_GoogleRe2{ 68 GoogleRe2: &envoy_type_matcher.RegexMatcher_GoogleRE2{ 69 MaxProgramSize: &wrappers.UInt32Value{Value: 100}, // Envoy default 70 }} 71 72 var ExpectedHeaders1 = []*envoy_api_v2_route.HeaderMatcher{ 73 { 74 Name: ":authority", 75 HeaderMatchSpecifier: &envoy_api_v2_route.HeaderMatcher_SafeRegexMatch{ 76 SafeRegexMatch: &envoy_type_matcher.RegexMatcher{ 77 EngineType: googleRe2, 78 Regex: "foo.cilium.io", 79 }}, 80 }, 81 { 82 Name: ":method", 83 HeaderMatchSpecifier: &envoy_api_v2_route.HeaderMatcher_SafeRegexMatch{ 84 SafeRegexMatch: &envoy_type_matcher.RegexMatcher{ 85 EngineType: googleRe2, 86 Regex: "GET", 87 }}, 88 }, 89 { 90 Name: ":path", 91 HeaderMatchSpecifier: &envoy_api_v2_route.HeaderMatcher_SafeRegexMatch{ 92 SafeRegexMatch: &envoy_type_matcher.RegexMatcher{ 93 EngineType: googleRe2, 94 Regex: "/foo", 95 }}, 96 }, 97 { 98 Name: "header1", 99 HeaderMatchSpecifier: &envoy_api_v2_route.HeaderMatcher_PresentMatch{PresentMatch: true}, 100 }, 101 { 102 Name: "header2", 103 HeaderMatchSpecifier: &envoy_api_v2_route.HeaderMatcher_ExactMatch{ExactMatch: "value"}, 104 }, 105 } 106 107 var ExpectedHeaders2 = []*envoy_api_v2_route.HeaderMatcher{ 108 { 109 Name: ":method", 110 HeaderMatchSpecifier: &envoy_api_v2_route.HeaderMatcher_SafeRegexMatch{ 111 SafeRegexMatch: &envoy_type_matcher.RegexMatcher{ 112 EngineType: googleRe2, 113 Regex: "PUT", 114 }}, 115 }, 116 { 117 Name: ":path", 118 HeaderMatchSpecifier: &envoy_api_v2_route.HeaderMatcher_SafeRegexMatch{ 119 SafeRegexMatch: &envoy_type_matcher.RegexMatcher{ 120 EngineType: googleRe2, 121 Regex: "/bar", 122 }}, 123 }, 124 } 125 126 var ExpectedHeaders3 = []*envoy_api_v2_route.HeaderMatcher{ 127 { 128 Name: ":method", 129 HeaderMatchSpecifier: &envoy_api_v2_route.HeaderMatcher_SafeRegexMatch{ 130 SafeRegexMatch: &envoy_type_matcher.RegexMatcher{ 131 EngineType: googleRe2, 132 Regex: "GET", 133 }}, 134 }, 135 { 136 Name: ":path", 137 HeaderMatchSpecifier: &envoy_api_v2_route.HeaderMatcher_SafeRegexMatch{ 138 SafeRegexMatch: &envoy_type_matcher.RegexMatcher{ 139 EngineType: googleRe2, 140 Regex: "/bar", 141 }}, 142 }, 143 } 144 145 var ( 146 dummySelectorCacheUser = &DummySelectorCacheUser{} 147 148 IdentityCache = cache.IdentityCache{ 149 1001: labels.LabelArray{ 150 labels.NewLabel("app", "etcd", labels.LabelSourceK8s), 151 labels.NewLabel("version", "v1", labels.LabelSourceK8s), 152 }, 153 1002: labels.LabelArray{ 154 labels.NewLabel("app", "etcd", labels.LabelSourceK8s), 155 labels.NewLabel("version", "v2", labels.LabelSourceK8s), 156 }, 157 1003: labels.LabelArray{ 158 labels.NewLabel("app", "cassandra", labels.LabelSourceK8s), 159 labels.NewLabel("version", "v1", labels.LabelSourceK8s), 160 }, 161 } 162 163 testSelectorCache = policy.NewSelectorCache(IdentityCache) 164 165 wildcardCachedSelector, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, api.WildcardEndpointSelector) 166 167 EndpointSelector1 = api.NewESFromLabels( 168 labels.NewLabel("app", "etcd", labels.LabelSourceK8s), 169 ) 170 cachedSelector1, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, EndpointSelector1) 171 172 // EndpointSelector1 with FromRequires("k8s:version=v2") folded in 173 RequiresV2Selector1 = api.NewESFromLabels( 174 labels.NewLabel("app", "etcd", labels.LabelSourceK8s), 175 labels.NewLabel("version", "v2", labels.LabelSourceK8s), 176 ) 177 cachedRequiresV2Selector1, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, RequiresV2Selector1) 178 179 EndpointSelector2 = api.NewESFromLabels( 180 labels.NewLabel("version", "v1", labels.LabelSourceK8s), 181 ) 182 cachedSelector2, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, EndpointSelector2) 183 184 // Wildcard endpoint selector with FromRequires("k8s:version=v2") folded in 185 RequiresV2Selector = api.NewESFromLabels( 186 labels.NewLabel("version", "v2", labels.LabelSourceK8s), 187 ) 188 cachedRequiresV2Selector, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, RequiresV2Selector) 189 ) 190 191 var L7Rules1 = api.L7Rules{HTTP: []api.PortRuleHTTP{*PortRuleHTTP1, *PortRuleHTTP2}} 192 193 var L7Rules2 = api.L7Rules{HTTP: []api.PortRuleHTTP{*PortRuleHTTP1}} 194 195 var ExpectedPortNetworkPolicyRule1 = &cilium.PortNetworkPolicyRule{ 196 RemotePolicies: []uint64{1001, 1002}, 197 L7: &cilium.PortNetworkPolicyRule_HttpRules{ 198 HttpRules: &cilium.HttpNetworkPolicyRules{ 199 HttpRules: []*cilium.HttpNetworkPolicyRule{ 200 {Headers: ExpectedHeaders2}, 201 {Headers: ExpectedHeaders1}, 202 }, 203 }, 204 }, 205 } 206 207 var ExpectedPortNetworkPolicyRule2 = &cilium.PortNetworkPolicyRule{ 208 RemotePolicies: []uint64{1001, 1003}, 209 L7: &cilium.PortNetworkPolicyRule_HttpRules{ 210 HttpRules: &cilium.HttpNetworkPolicyRules{ 211 HttpRules: []*cilium.HttpNetworkPolicyRule{ 212 {Headers: ExpectedHeaders1}, 213 }, 214 }, 215 }, 216 } 217 218 var ExpectedPortNetworkPolicyRule3 = &cilium.PortNetworkPolicyRule{ 219 RemotePolicies: nil, // Wildcard. Select all. 220 L7: &cilium.PortNetworkPolicyRule_HttpRules{ 221 HttpRules: &cilium.HttpNetworkPolicyRules{ 222 HttpRules: []*cilium.HttpNetworkPolicyRule{ 223 {Headers: ExpectedHeaders2}, 224 {Headers: ExpectedHeaders1}, 225 }, 226 }, 227 }, 228 } 229 230 var ExpectedPortNetworkPolicyRule4RequiresV2 = &cilium.PortNetworkPolicyRule{ 231 RemotePolicies: []uint64{1002}, // Like ExpectedPortNetworkPolicyRule1 but "k8s:version=v2" is required. 232 L7: &cilium.PortNetworkPolicyRule_HttpRules{ 233 HttpRules: &cilium.HttpNetworkPolicyRules{ 234 HttpRules: []*cilium.HttpNetworkPolicyRule{ 235 {Headers: ExpectedHeaders2}, 236 {Headers: ExpectedHeaders1}, 237 }, 238 }, 239 }, 240 } 241 242 var ExpectedPortNetworkPolicyRule5RequiresV2 = &cilium.PortNetworkPolicyRule{ 243 RemotePolicies: []uint64{1002}, // Wildcard, but "k8s:version=v2" required 244 L7: &cilium.PortNetworkPolicyRule_HttpRules{ 245 HttpRules: &cilium.HttpNetworkPolicyRules{ 246 HttpRules: []*cilium.HttpNetworkPolicyRule{ 247 {Headers: ExpectedHeaders2}, 248 {Headers: ExpectedHeaders1}, 249 }, 250 }, 251 }, 252 } 253 254 var ExpectedPortNetworkPolicyRule6 = &cilium.PortNetworkPolicyRule{ 255 RemotePolicies: []uint64{1001, 1002}, 256 } 257 258 var L4PolicyMap1 = map[string]*policy.L4Filter{ 259 "80/TCP": { 260 Port: 80, 261 Protocol: api.ProtoTCP, 262 L7Parser: policy.ParserTypeHTTP, 263 L7RulesPerEp: policy.L7DataMap{ 264 cachedSelector1: L7Rules1, 265 }, 266 }, 267 } 268 269 var L4PolicyMap1RequiresV2 = map[string]*policy.L4Filter{ 270 "80/TCP": { 271 Port: 80, 272 Protocol: api.ProtoTCP, 273 L7Parser: policy.ParserTypeHTTP, 274 L7RulesPerEp: policy.L7DataMap{ 275 cachedRequiresV2Selector1: L7Rules1, 276 }, 277 }, 278 } 279 280 var L4PolicyMap2 = map[string]*policy.L4Filter{ 281 "8080/UDP": { 282 Port: 8080, 283 Protocol: api.ProtoUDP, 284 L7Parser: policy.ParserTypeHTTP, 285 L7RulesPerEp: policy.L7DataMap{ 286 cachedSelector2: L7Rules2, 287 }, 288 }, 289 } 290 291 var L4PolicyMap3 = map[string]*policy.L4Filter{ 292 "80/UDP": { 293 Port: 80, 294 Protocol: api.ProtoTCP, 295 L7Parser: policy.ParserTypeHTTP, 296 L7RulesPerEp: policy.L7DataMap{ 297 wildcardCachedSelector: L7Rules1, 298 }, 299 }, 300 } 301 302 var L4PolicyMap3RequiresV2 = map[string]*policy.L4Filter{ 303 "80/UDP": { 304 Port: 80, 305 Protocol: api.ProtoTCP, 306 L7Parser: policy.ParserTypeHTTP, 307 L7RulesPerEp: policy.L7DataMap{ 308 cachedRequiresV2Selector: L7Rules1, 309 }, 310 }, 311 } 312 313 // L4PolicyMap4 is an L4-only policy, with no L7 rules. 314 var L4PolicyMap4 = map[string]*policy.L4Filter{ 315 "80/TCP": { 316 Port: 80, 317 Protocol: api.ProtoTCP, 318 L7RulesPerEp: policy.L7DataMap{ 319 cachedSelector1: api.L7Rules{}, 320 }, 321 }, 322 } 323 324 // L4PolicyMap5 is an L4-only policy, with no L7 rules. 325 var L4PolicyMap5 = map[string]*policy.L4Filter{ 326 "80/TCP": { 327 Port: 80, 328 Protocol: api.ProtoTCP, 329 L7RulesPerEp: policy.L7DataMap{ 330 wildcardCachedSelector: api.L7Rules{}, 331 }, 332 }, 333 } 334 335 var ExpectedPerPortPolicies1 = []*cilium.PortNetworkPolicy{ 336 { 337 Port: 80, 338 Protocol: envoy_api_v2_core.SocketAddress_TCP, 339 Rules: []*cilium.PortNetworkPolicyRule{ 340 ExpectedPortNetworkPolicyRule1, 341 }, 342 }, 343 } 344 345 var ExpectedPerPortPolicies2 = []*cilium.PortNetworkPolicy{ 346 { 347 Port: 8080, 348 Protocol: envoy_api_v2_core.SocketAddress_UDP, 349 Rules: []*cilium.PortNetworkPolicyRule{ 350 ExpectedPortNetworkPolicyRule2, 351 }, 352 }, 353 } 354 355 var ExpectedPerPortPolicies3 = []*cilium.PortNetworkPolicy{ 356 { 357 Port: 80, 358 Protocol: envoy_api_v2_core.SocketAddress_TCP, 359 Rules: []*cilium.PortNetworkPolicyRule{ 360 ExpectedPortNetworkPolicyRule3, 361 }, 362 }, 363 } 364 365 var ExpectedPerPortPolicies4RequiresV2 = []*cilium.PortNetworkPolicy{ 366 { 367 Port: 80, 368 Protocol: envoy_api_v2_core.SocketAddress_TCP, 369 Rules: []*cilium.PortNetworkPolicyRule{ 370 ExpectedPortNetworkPolicyRule4RequiresV2, 371 }, 372 }, 373 } 374 375 var ExpectedPerPortPolicies5RequiresV2 = []*cilium.PortNetworkPolicy{ 376 { 377 Port: 80, 378 Protocol: envoy_api_v2_core.SocketAddress_TCP, 379 Rules: []*cilium.PortNetworkPolicyRule{ 380 ExpectedPortNetworkPolicyRule5RequiresV2, 381 }, 382 }, 383 } 384 385 var ExpectedPerPortPolicies6 = []*cilium.PortNetworkPolicy{ 386 { 387 Port: 80, 388 Protocol: envoy_api_v2_core.SocketAddress_TCP, 389 Rules: []*cilium.PortNetworkPolicyRule{ 390 ExpectedPortNetworkPolicyRule6, 391 }, 392 }, 393 } 394 395 var ExpectedPerPortPolicies7 = []*cilium.PortNetworkPolicy{ 396 { 397 Port: 80, 398 Protocol: envoy_api_v2_core.SocketAddress_TCP, 399 }, 400 } 401 402 var L4Policy1 = &policy.L4Policy{ 403 Ingress: L4PolicyMap1, 404 Egress: L4PolicyMap2, 405 } 406 407 var L4Policy1RequiresV2 = &policy.L4Policy{ 408 Ingress: L4PolicyMap1RequiresV2, 409 Egress: L4PolicyMap2, 410 } 411 412 var L4Policy2 = &policy.L4Policy{ 413 Ingress: L4PolicyMap3, 414 Egress: L4PolicyMap2, 415 } 416 417 var L4Policy2RequiresV2 = &policy.L4Policy{ 418 Ingress: L4PolicyMap3RequiresV2, 419 Egress: L4PolicyMap2, 420 } 421 422 func (s *ServerSuite) TestGetHTTPRule(c *C) { 423 obtained := getHTTPRule(PortRuleHTTP1) 424 c.Assert(obtained, checker.Equals, ExpectedHeaders1) 425 } 426 427 func (s *ServerSuite) TestGetPortNetworkPolicyRule(c *C) { 428 obtained := getPortNetworkPolicyRule(cachedSelector1, policy.ParserTypeHTTP, L7Rules1) 429 c.Assert(obtained, checker.Equals, ExpectedPortNetworkPolicyRule1) 430 431 obtained = getPortNetworkPolicyRule(cachedSelector2, policy.ParserTypeHTTP, L7Rules2) 432 c.Assert(obtained, checker.Equals, ExpectedPortNetworkPolicyRule2) 433 } 434 435 func (s *ServerSuite) TestGetDirectionNetworkPolicy(c *C) { 436 // L4+L7 437 obtained := getDirectionNetworkPolicy(L4PolicyMap1, true) 438 c.Assert(obtained, checker.Equals, ExpectedPerPortPolicies1) 439 440 // L4+L7 441 obtained = getDirectionNetworkPolicy(L4PolicyMap2, true) 442 c.Assert(obtained, checker.Equals, ExpectedPerPortPolicies2) 443 444 // L4-only 445 obtained = getDirectionNetworkPolicy(L4PolicyMap4, true) 446 c.Assert(obtained, checker.Equals, ExpectedPerPortPolicies6) 447 448 // L4-only 449 obtained = getDirectionNetworkPolicy(L4PolicyMap5, true) 450 c.Assert(obtained, checker.Equals, ExpectedPerPortPolicies7) 451 } 452 453 func (s *ServerSuite) TestGetNetworkPolicy(c *C) { 454 obtained := getNetworkPolicy(IPv4Addr, Identity, "", L4Policy1, true, true) 455 expected := &cilium.NetworkPolicy{ 456 Name: IPv4Addr, 457 Policy: uint64(Identity), 458 IngressPerPortPolicies: ExpectedPerPortPolicies1, 459 EgressPerPortPolicies: ExpectedPerPortPolicies2, 460 } 461 c.Assert(obtained, checker.Equals, expected) 462 } 463 464 func (s *ServerSuite) TestGetNetworkPolicyWildcard(c *C) { 465 obtained := getNetworkPolicy(IPv4Addr, Identity, "", L4Policy2, true, true) 466 expected := &cilium.NetworkPolicy{ 467 Name: IPv4Addr, 468 Policy: uint64(Identity), 469 IngressPerPortPolicies: ExpectedPerPortPolicies3, 470 EgressPerPortPolicies: ExpectedPerPortPolicies2, 471 } 472 c.Assert(obtained, checker.Equals, expected) 473 } 474 475 func (s *ServerSuite) TestGetNetworkPolicyDeny(c *C) { 476 obtained := getNetworkPolicy(IPv4Addr, Identity, "", L4Policy1RequiresV2, true, true) 477 expected := &cilium.NetworkPolicy{ 478 Name: IPv4Addr, 479 Policy: uint64(Identity), 480 IngressPerPortPolicies: ExpectedPerPortPolicies4RequiresV2, 481 EgressPerPortPolicies: ExpectedPerPortPolicies2, 482 } 483 c.Assert(obtained, checker.Equals, expected) 484 } 485 486 func (s *ServerSuite) TestGetNetworkPolicyWildcardDeny(c *C) { 487 obtained := getNetworkPolicy(IPv4Addr, Identity, "", L4Policy2RequiresV2, true, true) 488 expected := &cilium.NetworkPolicy{ 489 Name: IPv4Addr, 490 Policy: uint64(Identity), 491 IngressPerPortPolicies: ExpectedPerPortPolicies5RequiresV2, 492 EgressPerPortPolicies: ExpectedPerPortPolicies2, 493 } 494 c.Assert(obtained, checker.Equals, expected) 495 } 496 497 func (s *ServerSuite) TestGetNetworkPolicyNil(c *C) { 498 obtained := getNetworkPolicy(IPv4Addr, Identity, "", nil, true, true) 499 expected := &cilium.NetworkPolicy{ 500 Name: IPv4Addr, 501 Policy: uint64(Identity), 502 IngressPerPortPolicies: nil, 503 EgressPerPortPolicies: nil, 504 } 505 c.Assert(obtained, checker.Equals, expected) 506 } 507 508 func (s *ServerSuite) TestGetNetworkPolicyIngressNotEnforced(c *C) { 509 obtained := getNetworkPolicy(IPv4Addr, Identity, "", L4Policy2, false, true) 510 expected := &cilium.NetworkPolicy{ 511 Name: IPv4Addr, 512 Policy: uint64(Identity), 513 IngressPerPortPolicies: allowAllPortNetworkPolicy, 514 EgressPerPortPolicies: ExpectedPerPortPolicies2, 515 } 516 c.Assert(obtained, checker.Equals, expected) 517 } 518 519 func (s *ServerSuite) TestGetNetworkPolicyEgressNotEnforced(c *C) { 520 obtained := getNetworkPolicy(IPv4Addr, Identity, "", L4Policy2RequiresV2, true, false) 521 expected := &cilium.NetworkPolicy{ 522 Name: IPv4Addr, 523 Policy: uint64(Identity), 524 IngressPerPortPolicies: ExpectedPerPortPolicies5RequiresV2, 525 EgressPerPortPolicies: allowAllPortNetworkPolicy, 526 } 527 c.Assert(obtained, checker.Equals, expected) 528 } 529 530 var L4PolicyL7 = &policy.L4Policy{ 531 Ingress: map[string]*policy.L4Filter{ 532 "9090/TCP": { 533 Port: 9090, Protocol: api.ProtoTCP, 534 L7Parser: "tester", 535 L7RulesPerEp: policy.L7DataMap{ 536 cachedSelector1: api.L7Rules{ 537 L7Proto: "tester", 538 L7: []api.PortRuleL7{ 539 map[string]string{ 540 "method": "PUT", 541 "path": "/"}, 542 map[string]string{ 543 "method": "GET", 544 "path": "/"}, 545 }, 546 }, 547 }, 548 Ingress: true, 549 }, 550 }, 551 } 552 553 var ExpectedPerPortPoliciesL7 = []*cilium.PortNetworkPolicy{ 554 { 555 Port: 9090, 556 Protocol: envoy_api_v2_core.SocketAddress_TCP, 557 Rules: []*cilium.PortNetworkPolicyRule{{ 558 RemotePolicies: []uint64{1001, 1002}, 559 L7Proto: "tester", 560 L7: &cilium.PortNetworkPolicyRule_L7Rules{ 561 L7Rules: &cilium.L7NetworkPolicyRules{ 562 L7Rules: []*cilium.L7NetworkPolicyRule{ 563 {Rule: map[string]string{ 564 "method": "PUT", 565 "path": "/"}}, 566 {Rule: map[string]string{ 567 "method": "GET", 568 "path": "/"}}, 569 }, 570 }, 571 }}, 572 }, 573 }, 574 } 575 576 func (s *ServerSuite) TestGetNetworkPolicyL7(c *C) { 577 obtained := getNetworkPolicy(IPv4Addr, Identity, "", L4PolicyL7, true, true) 578 expected := &cilium.NetworkPolicy{ 579 Name: IPv4Addr, 580 Policy: uint64(Identity), 581 IngressPerPortPolicies: ExpectedPerPortPoliciesL7, 582 } 583 c.Assert(obtained, checker.Equals, expected) 584 }