github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/repository_test.go (about)

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