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  }