github.com/cilium/cilium@v1.16.2/pkg/k8s/network_policy_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package k8s
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/require"
    12  	"k8s.io/apimachinery/pkg/types"
    13  
    14  	"github.com/cilium/cilium/api/v1/models"
    15  	"github.com/cilium/cilium/pkg/annotation"
    16  	"github.com/cilium/cilium/pkg/identity"
    17  	k8sConst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io"
    18  	slim_corev1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1"
    19  	slim_networkingv1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/networking/v1"
    20  	slim_metav1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1"
    21  	"github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/util/intstr"
    22  	"github.com/cilium/cilium/pkg/labels"
    23  	"github.com/cilium/cilium/pkg/policy"
    24  	"github.com/cilium/cilium/pkg/policy/api"
    25  	testidentity "github.com/cilium/cilium/pkg/testutils/identity"
    26  )
    27  
    28  var (
    29  	labelsA = labels.LabelArray{
    30  		labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
    31  		labels.NewLabel("id", "a", labels.LabelSourceK8s),
    32  	}
    33  
    34  	labelSelectorA = slim_metav1.LabelSelector{
    35  		MatchLabels: map[string]string{
    36  			"id": "a",
    37  		},
    38  	}
    39  
    40  	labelsB = labels.LabelArray{
    41  		labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
    42  		labels.NewLabel("id1", "b", labels.LabelSourceK8s),
    43  		labels.NewLabel("id2", "c", labels.LabelSourceK8s),
    44  	}
    45  
    46  	labelsC = labels.LabelArray{
    47  		labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
    48  		labels.NewLabel("id", "c", labels.LabelSourceK8s),
    49  	}
    50  
    51  	labelSelectorC = slim_metav1.LabelSelector{
    52  		MatchLabels: map[string]string{
    53  			"id": "c",
    54  		},
    55  	}
    56  
    57  	ctxAToB = policy.SearchContext{
    58  		From:  labelsA,
    59  		To:    labelsB,
    60  		Trace: policy.TRACE_VERBOSE,
    61  	}
    62  
    63  	ctxAToC = policy.SearchContext{
    64  		From:  labelsA,
    65  		To:    labelsC,
    66  		Trace: policy.TRACE_VERBOSE,
    67  	}
    68  
    69  	port80 = slim_networkingv1.NetworkPolicyPort{
    70  		Port: &intstr.IntOrString{
    71  			Type:   intstr.Int,
    72  			IntVal: 80,
    73  		},
    74  	}
    75  
    76  	int8090        = int32(8090)
    77  	port8080to8090 = slim_networkingv1.NetworkPolicyPort{
    78  		Port: &intstr.IntOrString{
    79  			Type:   intstr.Int,
    80  			IntVal: 8080,
    81  		},
    82  		EndPort: &int8090,
    83  	}
    84  
    85  	dummySelectorCacheUser = &DummySelectorCacheUser{}
    86  )
    87  
    88  type DummySelectorCacheUser struct{}
    89  
    90  func testNewPolicyRepository() *policy.Repository {
    91  	repo := policy.NewPolicyRepository(nil, nil, nil)
    92  	repo.GetSelectorCache().SetLocalIdentityNotifier(testidentity.NewDummyIdentityNotifier())
    93  	return repo
    94  }
    95  
    96  func (d *DummySelectorCacheUser) IdentitySelectionUpdated(selector policy.CachedSelector, added, deleted []identity.NumericIdentity) {
    97  }
    98  
    99  func TestParseNetworkPolicyIngress(t *testing.T) {
   100  	netPolicy := &slim_networkingv1.NetworkPolicy{
   101  		Spec: slim_networkingv1.NetworkPolicySpec{
   102  			PodSelector: slim_metav1.LabelSelector{
   103  				MatchLabels: map[string]string{
   104  					"foo1": "bar1",
   105  					"foo2": "bar2",
   106  				},
   107  			},
   108  			Ingress: []slim_networkingv1.NetworkPolicyIngressRule{
   109  				{
   110  					From: []slim_networkingv1.NetworkPolicyPeer{
   111  						{
   112  							PodSelector: &slim_metav1.LabelSelector{
   113  								MatchLabels: map[string]string{
   114  									"foo3": "bar3",
   115  									"foo4": "bar4",
   116  								},
   117  							},
   118  						},
   119  					},
   120  					Ports: []slim_networkingv1.NetworkPolicyPort{
   121  						{
   122  							Port: &intstr.IntOrString{
   123  								Type:   intstr.Int,
   124  								IntVal: 80,
   125  							},
   126  						},
   127  					},
   128  				},
   129  			},
   130  		},
   131  	}
   132  
   133  	_, err := ParseNetworkPolicy(netPolicy)
   134  	require.NoError(t, err)
   135  
   136  	fromEndpoints := labels.LabelArray{
   137  		labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   138  		labels.NewLabel("foo3", "bar3", labels.LabelSourceK8s),
   139  		labels.NewLabel("foo4", "bar4", labels.LabelSourceK8s),
   140  	}
   141  
   142  	ctx := policy.SearchContext{
   143  		From: fromEndpoints,
   144  		To: labels.LabelArray{
   145  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   146  			labels.NewLabel("foo1", "bar1", labels.LabelSourceK8s),
   147  			labels.NewLabel("foo2", "bar2", labels.LabelSourceK8s),
   148  		},
   149  		Trace: policy.TRACE_VERBOSE,
   150  	}
   151  
   152  	rules, err := ParseNetworkPolicy(netPolicy)
   153  	require.NoError(t, err)
   154  	require.Equal(t, 1, len(rules))
   155  
   156  	repo := testNewPolicyRepository()
   157  
   158  	repo.MustAddList(rules)
   159  	require.Equal(t, api.Denied, repo.AllowsIngressRLocked(&ctx))
   160  
   161  	epSelector := api.NewESFromLabels(fromEndpoints...)
   162  	cachedEPSelector, _ := repo.GetSelectorCache().AddIdentitySelector(dummySelectorCacheUser, nil, epSelector)
   163  	defer func() { repo.GetSelectorCache().RemoveSelector(cachedEPSelector, dummySelectorCacheUser) }()
   164  
   165  	ingressL4Policy, err := repo.ResolveL4IngressPolicy(&ctx)
   166  	require.NotNil(t, ingressL4Policy)
   167  	require.NoError(t, err)
   168  	expected := policy.NewL4PolicyMapWithValues(map[string]*policy.L4Filter{
   169  		"80/TCP": {
   170  			Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
   171  			L7Parser:            policy.ParserTypeNone,
   172  			PerSelectorPolicies: policy.L7DataMap{cachedEPSelector: nil},
   173  			Ingress:             true,
   174  			RuleOrigin: map[policy.CachedSelector]labels.LabelArrayList{
   175  				cachedEPSelector: {labels.ParseLabelArray(
   176  					"k8s:"+k8sConst.PolicyLabelName,
   177  					"k8s:"+k8sConst.PolicyLabelUID,
   178  					"k8s:"+k8sConst.PolicyLabelNamespace+"=default",
   179  					"k8s:"+k8sConst.PolicyLabelDerivedFrom+"="+resourceTypeNetworkPolicy,
   180  				)},
   181  			},
   182  		},
   183  	})
   184  	require.True(t, ingressL4Policy.Equals(t, expected), ingressL4Policy.Diff(t, expected))
   185  	ingressL4Policy.Detach(repo.GetSelectorCache())
   186  
   187  	ctx.To = labels.LabelArray{
   188  		labels.NewLabel("foo2", "bar2", labels.LabelSourceK8s),
   189  	}
   190  
   191  	// ctx.To needs to have all labels from the policy in order to be accepted
   192  	require.NotEqual(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
   193  
   194  	ctx = policy.SearchContext{
   195  		From: labels.LabelArray{
   196  			labels.NewLabel("foo3", "bar3", labels.LabelSourceK8s),
   197  		},
   198  		To: labels.LabelArray{
   199  			labels.NewLabel("foo1", "bar1", labels.LabelSourceK8s),
   200  			labels.NewLabel("foo2", "bar2", labels.LabelSourceK8s),
   201  		},
   202  		Trace: policy.TRACE_VERBOSE,
   203  	}
   204  	// ctx.From also needs to have all labels from the policy in order to be accepted
   205  	require.NotEqual(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
   206  }
   207  
   208  func TestParseNetworkPolicyMultipleSelectors(t *testing.T) {
   209  
   210  	// Rule with multiple selectors in egress and ingress
   211  	ex1 := []byte(`{
   212  "kind":"NetworkPolicy",
   213  "apiVersion":"networking.k8s.io/v1",
   214  "metadata":{
   215    "name":"ingress-multiple-selectors"
   216  },
   217  "spec":{
   218    "podSelector":{
   219      "matchLabels":{
   220        "role":"backend"
   221      }
   222    },
   223    "egress":[
   224      {
   225        "ports":[
   226          {
   227            "protocol":"TCP",
   228            "port":5432
   229          }
   230        ],
   231        "to":[
   232          {
   233            "podSelector":{
   234              "matchLabels":{
   235                "app":"db1"
   236              }
   237            }
   238          },
   239          {
   240            "podSelector":{
   241              "matchLabels":{
   242                "app":"db2"
   243              }
   244            }
   245          }
   246        ]
   247      }
   248    ],
   249    "ingress":[
   250      {
   251        "from":[
   252          {
   253            "podSelector":{
   254              "matchLabels":{
   255                "role":"frontend"
   256              }
   257            },
   258            "namespaceSelector":{
   259              "matchLabels":{
   260                "project":"myproject"
   261              }
   262            }
   263          },
   264          {
   265            "podSelector":{
   266              "matchLabels":{
   267                "app":"inventory"
   268              }
   269            }
   270          }
   271        ]
   272      }
   273    ]
   274  }
   275  }`)
   276  
   277  	np := slim_networkingv1.NetworkPolicy{}
   278  	err := json.Unmarshal(ex1, &np)
   279  	require.NoError(t, err)
   280  
   281  	rules, err := ParseNetworkPolicy(&np)
   282  	require.NoError(t, err)
   283  	require.Equal(t, 1, len(rules))
   284  
   285  	repo := testNewPolicyRepository()
   286  	repo.MustAddList(rules)
   287  
   288  	endpointLabels := labels.LabelArray{
   289  		labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   290  		labels.NewLabel("role", "backend", labels.LabelSourceK8s),
   291  	}
   292  
   293  	// Ingress context
   294  	ctx := policy.SearchContext{
   295  		From: labels.LabelArray{
   296  			labels.NewLabel("role", "frontend", labels.LabelSourceK8s),
   297  		},
   298  		To:    endpointLabels,
   299  		Trace: policy.TRACE_VERBOSE,
   300  	}
   301  
   302  	// should be DENIED because ctx.From is missing the namespace selector
   303  	require.Equal(t, api.Denied, repo.AllowsIngressRLocked(&ctx))
   304  
   305  	ctx.From = labels.LabelArray{
   306  		labels.NewLabel("role", "frontend", labels.LabelSourceK8s),
   307  		labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "project"), "myproject", labels.LabelSourceK8s),
   308  	}
   309  
   310  	// should be ALLOWED with the namespace label properly set
   311  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
   312  
   313  	ctx.From = labels.LabelArray{
   314  		labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   315  		labels.NewLabel("app", "inventory", labels.LabelSourceK8s),
   316  	}
   317  
   318  	// should be ALLOWED since all rules in From must match
   319  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
   320  
   321  	// Egress context
   322  	ctx = policy.SearchContext{
   323  		From: endpointLabels,
   324  		To: labels.LabelArray{
   325  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   326  			labels.NewLabel("app", "db1", labels.LabelSourceK8s),
   327  		},
   328  		Trace: policy.TRACE_VERBOSE,
   329  	}
   330  
   331  	// should be DENIED because DPorts are missing in context
   332  	require.Equal(t, api.Denied, repo.AllowsEgressRLocked(&ctx))
   333  
   334  	ctx.DPorts = []*models.Port{{Port: 5432, Protocol: models.PortProtocolTCP}}
   335  
   336  	// should be ALLOWED with DPorts set correctly
   337  	require.Equal(t, api.Allowed, repo.AllowsEgressRLocked(&ctx))
   338  
   339  	ctx.To = labels.LabelArray{
   340  		labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   341  		labels.NewLabel("app", "db2", labels.LabelSourceK8s),
   342  	}
   343  
   344  	// should be ALLOWED for db2 as well
   345  	require.Equal(t, api.Allowed, repo.AllowsEgressRLocked(&ctx))
   346  }
   347  
   348  func TestParseNetworkPolicyNoSelectors(t *testing.T) {
   349  
   350  	// Ingress with neither pod nor namespace selector set.
   351  	ex1 := []byte(`{
   352  "kind": "NetworkPolicy",
   353  "apiVersion": "networking.k8s.io/v1",
   354  "metadata": {
   355    "name": "ingress-cidr-test",
   356    "namespace": "myns",
   357    "uid": "11bba160-ddca-11e8-b697-0800273b04ff"
   358  },
   359  "spec": {
   360    "podSelector": {
   361      "matchLabels": {
   362        "role": "backend"
   363      }
   364    },
   365    "ingress": [
   366      {
   367        "from": [
   368          {
   369            "ipBlock": {
   370              "cidr": "10.0.0.0/8",
   371  	          "except": [
   372  	            "10.96.0.0/12"
   373  	          ]
   374            }
   375          }
   376        ]
   377      }
   378    ]
   379  }
   380  }`)
   381  
   382  	fromEndpoints := labels.LabelArray{
   383  		labels.NewLabel(k8sConst.PodNamespaceLabel, "myns", labels.LabelSourceK8s),
   384  		labels.NewLabel("role", "backend", labels.LabelSourceK8s),
   385  	}
   386  
   387  	epSelector := api.NewESFromLabels(fromEndpoints...)
   388  	np := slim_networkingv1.NetworkPolicy{}
   389  	err := json.Unmarshal(ex1, &np)
   390  	require.NoError(t, err)
   391  
   392  	expectedRule := api.NewRule().
   393  		WithEndpointSelector(epSelector).
   394  		WithIngressRules([]api.IngressRule{
   395  			{
   396  				IngressCommonRule: api.IngressCommonRule{
   397  					FromCIDRSet: []api.CIDRRule{
   398  						{
   399  							Cidr: api.CIDR("10.0.0.0/8"),
   400  							ExceptCIDRs: []api.CIDR{
   401  								"10.96.0.0/12",
   402  							},
   403  						},
   404  					},
   405  				},
   406  			},
   407  		}).
   408  		WithEgressRules([]api.EgressRule{}).
   409  		WithLabels(labels.ParseLabelArray(
   410  			"k8s:"+k8sConst.PolicyLabelName+"=ingress-cidr-test",
   411  			"k8s:"+k8sConst.PolicyLabelUID+"=11bba160-ddca-11e8-b697-0800273b04ff",
   412  			"k8s:"+k8sConst.PolicyLabelNamespace+"=myns",
   413  			"k8s:"+k8sConst.PolicyLabelDerivedFrom+"="+resourceTypeNetworkPolicy,
   414  		))
   415  
   416  	expectedRule.Sanitize()
   417  
   418  	expectedRules := api.Rules{
   419  		expectedRule,
   420  	}
   421  
   422  	rules, err := ParseNetworkPolicy(&np)
   423  	require.NoError(t, err)
   424  	require.NotNil(t, rules)
   425  	require.EqualValues(t, expectedRules, rules)
   426  }
   427  
   428  func TestParseNetworkPolicyEgress(t *testing.T) {
   429  
   430  	netPolicy := &slim_networkingv1.NetworkPolicy{
   431  		Spec: slim_networkingv1.NetworkPolicySpec{
   432  			PodSelector: slim_metav1.LabelSelector{
   433  				MatchLabels: map[string]string{
   434  					"foo1": "bar1",
   435  					"foo2": "bar2",
   436  				},
   437  			},
   438  			Egress: []slim_networkingv1.NetworkPolicyEgressRule{
   439  				{
   440  					To: []slim_networkingv1.NetworkPolicyPeer{
   441  						{
   442  							PodSelector: &slim_metav1.LabelSelector{
   443  								MatchLabels: map[string]string{
   444  									"foo3": "bar3",
   445  									"foo4": "bar4",
   446  								},
   447  							},
   448  						},
   449  					},
   450  					Ports: []slim_networkingv1.NetworkPolicyPort{
   451  						{
   452  							Port: &intstr.IntOrString{
   453  								Type:   intstr.Int,
   454  								IntVal: 80,
   455  							},
   456  						},
   457  					},
   458  				},
   459  			},
   460  		},
   461  	}
   462  
   463  	rules, err := ParseNetworkPolicy(netPolicy)
   464  	require.NoError(t, err)
   465  	require.Equal(t, 1, len(rules))
   466  
   467  	fromEndpoints := labels.LabelArray{
   468  		labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   469  		labels.NewLabel("foo1", "bar1", labels.LabelSourceK8s),
   470  		labels.NewLabel("foo2", "bar2", labels.LabelSourceK8s),
   471  	}
   472  
   473  	toEndpoints := labels.LabelArray{
   474  		labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   475  		labels.NewLabel("foo3", "bar3", labels.LabelSourceK8s),
   476  		labels.NewLabel("foo4", "bar4", labels.LabelSourceK8s),
   477  	}
   478  
   479  	ctx := policy.SearchContext{
   480  		From:  fromEndpoints,
   481  		To:    toEndpoints,
   482  		Trace: policy.TRACE_VERBOSE,
   483  	}
   484  
   485  	repo := testNewPolicyRepository()
   486  	repo.MustAddList(rules)
   487  	// Because search context did not contain port-specific policy, deny is
   488  	// expected.
   489  	require.Equal(t, api.Denied, repo.AllowsEgressRLocked(&ctx))
   490  
   491  	epSelector := api.NewESFromLabels(toEndpoints...)
   492  	cachedEPSelector, _ := repo.GetSelectorCache().AddIdentitySelector(dummySelectorCacheUser, nil, epSelector)
   493  	defer func() { repo.GetSelectorCache().RemoveSelector(cachedEPSelector, dummySelectorCacheUser) }()
   494  
   495  	egressL4Policy, err := repo.ResolveL4EgressPolicy(&ctx)
   496  	require.NotNil(t, egressL4Policy)
   497  	require.NoError(t, err)
   498  	expected := policy.NewL4PolicyMapWithValues(map[string]*policy.L4Filter{
   499  		"80/TCP": {
   500  			Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
   501  			L7Parser:            policy.ParserTypeNone,
   502  			PerSelectorPolicies: policy.L7DataMap{cachedEPSelector: nil},
   503  			Ingress:             false,
   504  			RuleOrigin: map[policy.CachedSelector]labels.LabelArrayList{
   505  				cachedEPSelector: {rules[0].Labels},
   506  			},
   507  		},
   508  	})
   509  	require.True(t, egressL4Policy.Equals(t, expected), egressL4Policy.Diff(t, expected))
   510  	egressL4Policy.Detach(repo.GetSelectorCache())
   511  
   512  	ctx.From = labels.LabelArray{
   513  		labels.NewLabel("foo2", "bar2", labels.LabelSourceK8s),
   514  	}
   515  
   516  	// ctx.From needs to have all labels from the policy in order to be accepted
   517  	require.NotEqual(t, api.Allowed, repo.AllowsEgressRLocked(&ctx))
   518  
   519  	ctx = policy.SearchContext{
   520  		To: labels.LabelArray{
   521  			labels.NewLabel("foo3", "bar3", labels.LabelSourceK8s),
   522  		},
   523  		From: labels.LabelArray{
   524  			labels.NewLabel("foo1", "bar1", labels.LabelSourceK8s),
   525  			labels.NewLabel("foo2", "bar2", labels.LabelSourceK8s),
   526  		},
   527  		Trace: policy.TRACE_VERBOSE,
   528  	}
   529  
   530  	// ctx.To also needs to have all labels from the policy in order to be accepted.
   531  	require.NotEqual(t, api.Allowed, repo.AllowsEgressRLocked(&ctx))
   532  }
   533  
   534  func parseAndAddRules(t *testing.T, p *slim_networkingv1.NetworkPolicy) *policy.Repository {
   535  	repo := testNewPolicyRepository()
   536  	rules, err := ParseNetworkPolicy(p)
   537  	require.NoError(t, err)
   538  	rev := repo.GetRevision()
   539  	_, id := repo.MustAddList(rules)
   540  	require.Equal(t, rev+1, id)
   541  
   542  	return repo
   543  }
   544  
   545  func TestParseNetworkPolicyEgressAllowAll(t *testing.T) {
   546  	repo := parseAndAddRules(t, &slim_networkingv1.NetworkPolicy{
   547  		Spec: slim_networkingv1.NetworkPolicySpec{
   548  			PodSelector: labelSelectorA,
   549  			Egress: []slim_networkingv1.NetworkPolicyEgressRule{
   550  				{
   551  					To: []slim_networkingv1.NetworkPolicyPeer{},
   552  				},
   553  			},
   554  		},
   555  	})
   556  
   557  	require.Equal(t, api.Allowed, repo.AllowsEgressRLocked(&ctxAToB))
   558  	require.Equal(t, api.Allowed, repo.AllowsEgressRLocked(&ctxAToC))
   559  
   560  	ctxAToC80 := ctxAToC
   561  	ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
   562  	require.Equal(t, api.Allowed, repo.AllowsEgressRLocked(&ctxAToC80))
   563  
   564  	ctxAToC90 := ctxAToC
   565  	ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
   566  	require.Equal(t, api.Allowed, repo.AllowsEgressRLocked(&ctxAToC90))
   567  }
   568  
   569  func TestParseNetworkPolicyEgressL4AllowAll(t *testing.T) {
   570  	repo := parseAndAddRules(t, &slim_networkingv1.NetworkPolicy{
   571  		Spec: slim_networkingv1.NetworkPolicySpec{
   572  			PodSelector: labelSelectorA,
   573  			Egress: []slim_networkingv1.NetworkPolicyEgressRule{
   574  				{
   575  					Ports: []slim_networkingv1.NetworkPolicyPort{port80},
   576  					To:    []slim_networkingv1.NetworkPolicyPeer{},
   577  				},
   578  			},
   579  		},
   580  	})
   581  
   582  	ctxAToC80 := ctxAToC
   583  	ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
   584  	require.Equal(t, api.Allowed, repo.AllowsEgressRLocked(&ctxAToC80))
   585  
   586  	ctxAToC90 := ctxAToC
   587  	ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
   588  	require.Equal(t, api.Denied, repo.AllowsEgressRLocked(&ctxAToC90))
   589  }
   590  
   591  func TestParseNetworkPolicyEgressL4PortRangeAllowAll(t *testing.T) {
   592  	repo := parseAndAddRules(t, &slim_networkingv1.NetworkPolicy{
   593  		Spec: slim_networkingv1.NetworkPolicySpec{
   594  			PodSelector: labelSelectorA,
   595  			Egress: []slim_networkingv1.NetworkPolicyEgressRule{
   596  				{
   597  					Ports: []slim_networkingv1.NetworkPolicyPort{port8080to8090},
   598  					To:    []slim_networkingv1.NetworkPolicyPeer{},
   599  				},
   600  			},
   601  		},
   602  	})
   603  
   604  	ctxAToC8080 := ctxAToC
   605  	ctxAToC8080.DPorts = []*models.Port{{Port: 8080, Protocol: models.PortProtocolTCP}}
   606  	require.Equal(t, repo.AllowsEgressRLocked(&ctxAToC8080), api.Allowed)
   607  
   608  	ctxAToC8085 := ctxAToC
   609  	ctxAToC8085.DPorts = []*models.Port{{Port: 8085, Protocol: models.PortProtocolTCP}}
   610  	require.Equal(t, repo.AllowsEgressRLocked(&ctxAToC8085), api.Allowed)
   611  
   612  	ctxAToC8090 := ctxAToC
   613  	ctxAToC8090.DPorts = []*models.Port{{Port: 8090, Protocol: models.PortProtocolTCP}}
   614  	require.Equal(t, repo.AllowsEgressRLocked(&ctxAToC8090), api.Allowed)
   615  
   616  	ctxAToC8091 := ctxAToC
   617  	ctxAToC8091.DPorts = []*models.Port{{Port: 8091, Protocol: models.PortProtocolTCP}}
   618  	require.Equal(t, repo.AllowsEgressRLocked(&ctxAToC8091), api.Denied)
   619  }
   620  
   621  func TestParseNetworkPolicyIngressAllowAll(t *testing.T) {
   622  	repo := parseAndAddRules(t, &slim_networkingv1.NetworkPolicy{
   623  		Spec: slim_networkingv1.NetworkPolicySpec{
   624  			PodSelector: labelSelectorC,
   625  			Ingress: []slim_networkingv1.NetworkPolicyIngressRule{
   626  				{
   627  					From: []slim_networkingv1.NetworkPolicyPeer{},
   628  				},
   629  			},
   630  		},
   631  	})
   632  
   633  	require.Equal(t, api.Denied, repo.AllowsIngressRLocked(&ctxAToB))
   634  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctxAToC))
   635  
   636  	ctxAToC80 := ctxAToC
   637  	ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
   638  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctxAToC80))
   639  
   640  	ctxAToC90 := ctxAToC
   641  	ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
   642  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctxAToC90))
   643  }
   644  
   645  func TestParseNetworkPolicyIngressL4AllowAll(t *testing.T) {
   646  	repo := parseAndAddRules(t, &slim_networkingv1.NetworkPolicy{
   647  		Spec: slim_networkingv1.NetworkPolicySpec{
   648  			PodSelector: labelSelectorC,
   649  			Ingress: []slim_networkingv1.NetworkPolicyIngressRule{
   650  				{
   651  					Ports: []slim_networkingv1.NetworkPolicyPort{port80},
   652  					From:  []slim_networkingv1.NetworkPolicyPeer{},
   653  				},
   654  			},
   655  		},
   656  	})
   657  
   658  	require.Equal(t, api.Denied, repo.AllowsIngressRLocked(&ctxAToB))
   659  
   660  	ctxAToC80 := ctxAToC
   661  	ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
   662  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctxAToC80))
   663  
   664  	ctxAToC90 := ctxAToC
   665  	ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
   666  	require.Equal(t, api.Denied, repo.AllowsIngressRLocked(&ctxAToC90))
   667  }
   668  
   669  func TestParseNetworkPolicyNamedPort(t *testing.T) {
   670  	netPolicy := &slim_networkingv1.NetworkPolicy{
   671  		Spec: slim_networkingv1.NetworkPolicySpec{
   672  			Ingress: []slim_networkingv1.NetworkPolicyIngressRule{
   673  				{
   674  					Ports: []slim_networkingv1.NetworkPolicyPort{
   675  						{
   676  							Port: &intstr.IntOrString{
   677  								Type:   intstr.String,
   678  								StrVal: "port-80",
   679  							},
   680  						},
   681  					},
   682  				},
   683  			},
   684  		},
   685  	}
   686  
   687  	rules, err := ParseNetworkPolicy(netPolicy)
   688  	require.NoError(t, err)
   689  	require.Equal(t, 1, len(rules))
   690  }
   691  
   692  func TestParseNetworkPolicyEmptyPort(t *testing.T) {
   693  	netPolicy := &slim_networkingv1.NetworkPolicy{
   694  		Spec: slim_networkingv1.NetworkPolicySpec{
   695  			Ingress: []slim_networkingv1.NetworkPolicyIngressRule{
   696  				{
   697  					Ports: []slim_networkingv1.NetworkPolicyPort{
   698  						{},
   699  					},
   700  				},
   701  			},
   702  		},
   703  	}
   704  
   705  	rules, err := ParseNetworkPolicy(netPolicy)
   706  	require.NoError(t, err)
   707  	require.Equal(t, 1, len(rules))
   708  	require.Equal(t, 1, len(rules[0].Ingress))
   709  	require.Equal(t, 1, len(rules[0].Ingress[0].ToPorts))
   710  	ports := rules[0].Ingress[0].ToPorts[0].Ports
   711  	require.Equal(t, 1, len(ports))
   712  	require.Equal(t, "0", ports[0].Port)
   713  	require.Equal(t, api.ProtoTCP, ports[0].Protocol)
   714  }
   715  
   716  func TestParsePorts(t *testing.T) {
   717  	rules := parsePorts([]slim_networkingv1.NetworkPolicyPort{
   718  		{},
   719  	})
   720  	require.Equal(t, 1, len(rules))
   721  	require.Equal(t, 1, len(rules[0].Ports))
   722  	require.Equal(t, "0", rules[0].Ports[0].Port)
   723  	require.Equal(t, api.ProtoTCP, rules[0].Ports[0].Protocol)
   724  }
   725  
   726  func TestParseNetworkPolicyUnknownProto(t *testing.T) {
   727  	unknownProtocol := slim_corev1.Protocol("unknown")
   728  	netPolicy := &slim_networkingv1.NetworkPolicy{
   729  		Spec: slim_networkingv1.NetworkPolicySpec{
   730  			Ingress: []slim_networkingv1.NetworkPolicyIngressRule{
   731  				{
   732  					Ports: []slim_networkingv1.NetworkPolicyPort{
   733  						{
   734  							Port: &intstr.IntOrString{
   735  								Type:   intstr.String,
   736  								StrVal: "port-80",
   737  							},
   738  							Protocol: &unknownProtocol,
   739  						},
   740  					},
   741  				},
   742  			},
   743  		},
   744  	}
   745  
   746  	rules, err := ParseNetworkPolicy(netPolicy)
   747  	require.NotNil(t, err)
   748  	require.Equal(t, 0, len(rules))
   749  }
   750  
   751  func TestParseNetworkPolicyEmptyFrom(t *testing.T) {
   752  	// From missing, all sources should be allowed
   753  	netPolicy1 := &slim_networkingv1.NetworkPolicy{
   754  		Spec: slim_networkingv1.NetworkPolicySpec{
   755  			PodSelector: slim_metav1.LabelSelector{
   756  				MatchLabels: map[string]string{
   757  					"foo1": "bar1",
   758  				},
   759  			},
   760  			Ingress: []slim_networkingv1.NetworkPolicyIngressRule{
   761  				{},
   762  			},
   763  		},
   764  	}
   765  
   766  	rules, err := ParseNetworkPolicy(netPolicy1)
   767  	require.NoError(t, err)
   768  	require.Equal(t, 1, len(rules))
   769  
   770  	ctx := policy.SearchContext{
   771  		From: labels.LabelArray{
   772  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   773  			labels.NewLabel("foo0", "bar0", labels.LabelSourceK8s),
   774  		},
   775  		To: labels.LabelArray{
   776  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   777  			labels.NewLabel("foo1", "bar1", labels.LabelSourceK8s),
   778  		},
   779  		Trace: policy.TRACE_VERBOSE,
   780  	}
   781  
   782  	repo := testNewPolicyRepository()
   783  	repo.MustAddList(rules)
   784  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
   785  
   786  	// Empty From rules, all sources should be allowed
   787  	netPolicy2 := &slim_networkingv1.NetworkPolicy{
   788  		Spec: slim_networkingv1.NetworkPolicySpec{
   789  			PodSelector: slim_metav1.LabelSelector{
   790  				MatchLabels: map[string]string{
   791  					"foo1": "bar1",
   792  				},
   793  			},
   794  			Ingress: []slim_networkingv1.NetworkPolicyIngressRule{
   795  				{
   796  					From:  []slim_networkingv1.NetworkPolicyPeer{},
   797  					Ports: []slim_networkingv1.NetworkPolicyPort{},
   798  				},
   799  			},
   800  		},
   801  	}
   802  
   803  	rules, err = ParseNetworkPolicy(netPolicy2)
   804  	require.NoError(t, err)
   805  	require.Equal(t, 1, len(rules))
   806  	repo = testNewPolicyRepository()
   807  	repo.MustAddList(rules)
   808  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
   809  }
   810  
   811  func TestParseNetworkPolicyDenyAll(t *testing.T) {
   812  	// From missing, all sources should be allowed
   813  	netPolicy1 := &slim_networkingv1.NetworkPolicy{
   814  		Spec: slim_networkingv1.NetworkPolicySpec{
   815  			PodSelector: slim_metav1.LabelSelector{
   816  				MatchLabels: map[string]string{},
   817  			},
   818  		},
   819  	}
   820  
   821  	rules, err := ParseNetworkPolicy(netPolicy1)
   822  	require.NoError(t, err)
   823  	require.Equal(t, 1, len(rules))
   824  
   825  	ctx := policy.SearchContext{
   826  		From: labels.LabelArray{
   827  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   828  			labels.NewLabel("foo0", "bar0", labels.LabelSourceK8s),
   829  		},
   830  		To: labels.LabelArray{
   831  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   832  			labels.NewLabel("foo1", "bar1", labels.LabelSourceK8s),
   833  		},
   834  		Trace: policy.TRACE_VERBOSE,
   835  	}
   836  
   837  	repo := testNewPolicyRepository()
   838  	repo.MustAddList(rules)
   839  	require.Equal(t, api.Denied, repo.AllowsIngressRLocked(&ctx))
   840  }
   841  
   842  func TestParseNetworkPolicyNoIngress(t *testing.T) {
   843  	netPolicy := &slim_networkingv1.NetworkPolicy{
   844  		Spec: slim_networkingv1.NetworkPolicySpec{
   845  			PodSelector: slim_metav1.LabelSelector{
   846  				MatchLabels: map[string]string{
   847  					"foo1": "bar1",
   848  					"foo2": "bar2",
   849  				},
   850  			},
   851  		},
   852  	}
   853  
   854  	rules, err := ParseNetworkPolicy(netPolicy)
   855  	require.NoError(t, err)
   856  	require.Equal(t, 1, len(rules))
   857  }
   858  
   859  func TestNetworkPolicyExamples(t *testing.T) {
   860  	// Example 1a: Only allow traffic from frontend pods on TCP port 6379 to
   861  	// backend pods in the same namespace `myns`
   862  	ex1 := []byte(`{
   863    "kind": "NetworkPolicy",
   864    "apiVersion": "networking.k8s.io/v1",
   865    "metadata": {
   866      "name": "allow-frontend",
   867      "namespace": "myns"
   868    },
   869    "spec": {
   870      "podSelector": {
   871        "matchLabels": {
   872          "role": "backend"
   873        }
   874      },
   875      "ingress": [
   876        {
   877          "from": [
   878            {
   879              "podSelector": {
   880                "matchLabels": {
   881                  "role": "frontend"
   882                }
   883              }
   884            }
   885          ],
   886          "ports": [
   887            {
   888              "protocol": "TCP",
   889              "port": 6379
   890            }
   891          ]
   892        }
   893      ]
   894    }
   895  }`)
   896  	np := slim_networkingv1.NetworkPolicy{}
   897  	err := json.Unmarshal(ex1, &np)
   898  	require.NoError(t, err)
   899  
   900  	_, err = ParseNetworkPolicy(&np)
   901  	require.NoError(t, err)
   902  
   903  	// Example 1b: Only allow traffic from frontend pods to backend pods
   904  	// in the same namespace `myns`
   905  	ex1 = []byte(`{
   906    "kind": "NetworkPolicy",
   907    "apiVersion": "networking.k8s.io/v1",
   908    "metadata": {
   909      "name": "allow-frontend",
   910      "namespace": "myns"
   911    },
   912    "spec": {
   913      "podSelector": {
   914        "matchLabels": {
   915          "role": "backend"
   916        }
   917      },
   918      "ingress": [
   919        {
   920          "from": [
   921            {
   922              "podSelector": {
   923                "matchLabels": {
   924                  "role": "frontend"
   925                }
   926              }
   927            }
   928          ]
   929        },{
   930          "ports": [
   931            {
   932              "protocol": "TCP",
   933              "port": 6379
   934            }
   935          ]
   936        }
   937      ]
   938    }
   939  }`)
   940  	np = slim_networkingv1.NetworkPolicy{}
   941  	err = json.Unmarshal(ex1, &np)
   942  	require.NoError(t, err)
   943  
   944  	rules, err := ParseNetworkPolicy(&np)
   945  	require.NoError(t, err)
   946  	require.Equal(t, 1, len(rules))
   947  
   948  	repo := testNewPolicyRepository()
   949  	repo.MustAddList(rules)
   950  	ctx := policy.SearchContext{
   951  		From: labels.LabelArray{
   952  			labels.NewLabel(k8sConst.PodNamespaceLabel, "myns", labels.LabelSourceK8s),
   953  			labels.NewLabel("role", "frontend", labels.LabelSourceK8s),
   954  		},
   955  		To: labels.LabelArray{
   956  			labels.NewLabel("role", "backend", labels.LabelSourceK8s),
   957  		},
   958  		Trace: policy.TRACE_VERBOSE,
   959  	}
   960  	// Doesn't share the same namespace
   961  	require.Equal(t, api.Denied, repo.AllowsIngressRLocked(&ctx))
   962  
   963  	ctx = policy.SearchContext{
   964  		From: labels.LabelArray{
   965  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
   966  			labels.NewLabel("role", "frontend", labels.LabelSourceK8s),
   967  		},
   968  		To: labels.LabelArray{
   969  			labels.NewLabel("role", "backend", labels.LabelSourceK8s),
   970  		},
   971  		Trace: policy.TRACE_VERBOSE,
   972  	}
   973  	// Doesn't share the same namespace
   974  	require.Equal(t, api.Denied, repo.AllowsIngressRLocked(&ctx))
   975  
   976  	ctx = policy.SearchContext{
   977  		From: labels.LabelArray{
   978  			labels.NewLabel(k8sConst.PodNamespaceLabel, "myns", labels.LabelSourceK8s),
   979  			labels.NewLabel("role", "frontend", labels.LabelSourceK8s),
   980  		},
   981  		To: labels.LabelArray{
   982  			labels.NewLabel(k8sConst.PodNamespaceLabel, "myns", labels.LabelSourceK8s),
   983  			labels.NewLabel("role", "backend", labels.LabelSourceK8s),
   984  		},
   985  		DPorts: []*models.Port{
   986  			{
   987  				Port:     6379,
   988  				Protocol: models.PortProtocolTCP,
   989  			},
   990  		},
   991  		Trace: policy.TRACE_VERBOSE,
   992  	}
   993  	// Should be ACCEPT sense the traffic needs to come from `frontend` AND
   994  	// port 6379 and belong to the same namespace `myns`.
   995  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
   996  
   997  	// Example 2a: Allow TCP 443 from any source in Bob's namespaces.
   998  	ex2 := []byte(`{
   999    "kind": "NetworkPolicy",
  1000    "apiVersion": "networking.k8s.io/v1",
  1001    "metadata": {
  1002      "name": "allow-tcp-443"
  1003    },
  1004    "spec": {
  1005      "podSelector": {
  1006        "matchLabels": {
  1007          "role": "frontend"
  1008        }
  1009      },
  1010      "ingress": [
  1011        {
  1012          "ports": [
  1013            {
  1014              "protocol": "TCP",
  1015              "port": 443
  1016            }
  1017          ],
  1018          "from": [
  1019            {
  1020              "namespaceSelector": {
  1021                "matchLabels": {
  1022                  "user": "bob"
  1023                }
  1024              }
  1025            }
  1026          ]
  1027        }
  1028      ]
  1029    }
  1030  }`)
  1031  
  1032  	np = slim_networkingv1.NetworkPolicy{}
  1033  	err = json.Unmarshal(ex2, &np)
  1034  	require.NoError(t, err)
  1035  
  1036  	_, err = ParseNetworkPolicy(&np)
  1037  	require.NoError(t, err)
  1038  
  1039  	// Example 2b: Allow from any source in Bob's namespaces.
  1040  	ex2 = []byte(`{
  1041    "kind": "NetworkPolicy",
  1042    "apiVersion": "networking.k8s.io/v1",
  1043    "metadata": {
  1044      "name": "allow-tcp-443"
  1045    },
  1046    "spec": {
  1047      "podSelector": {
  1048        "matchLabels": {
  1049          "role": "frontend"
  1050        }
  1051      },
  1052      "ingress": [
  1053        {
  1054          "ports": [
  1055            {
  1056              "protocol": "TCP",
  1057              "port": 443
  1058            }
  1059          ],
  1060          "from": [
  1061            {
  1062              "namespaceSelector": {
  1063                "matchLabels": {
  1064                  "user": "bob"
  1065                }
  1066              }
  1067            }
  1068          ]
  1069        }
  1070      ]
  1071    }
  1072  }`)
  1073  
  1074  	np = slim_networkingv1.NetworkPolicy{}
  1075  	err = json.Unmarshal(ex2, &np)
  1076  	require.NoError(t, err)
  1077  
  1078  	rules, err = ParseNetworkPolicy(&np)
  1079  	require.NoError(t, err)
  1080  	require.Equal(t, 1, len(rules))
  1081  
  1082  	repo = testNewPolicyRepository()
  1083  	repo.MustAddList(rules)
  1084  	ctx = policy.SearchContext{
  1085  		From: labels.LabelArray{
  1086  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1087  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "user"), "bob", labels.LabelSourceK8s),
  1088  		},
  1089  		To: labels.LabelArray{
  1090  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1091  			labels.NewLabel("role", "frontend", labels.LabelSourceK8s),
  1092  		},
  1093  		Trace: policy.TRACE_VERBOSE,
  1094  	}
  1095  
  1096  	// Should be DENY sense the traffic needs to come from
  1097  	// namespace `user=bob` AND port 443.
  1098  	require.Equal(t, api.Denied, repo.AllowsIngressRLocked(&ctx))
  1099  
  1100  	l4Policy, err := repo.ResolveL4IngressPolicy(&ctx)
  1101  	require.NotNil(t, l4Policy)
  1102  	require.NoError(t, err)
  1103  	l4Policy.Detach(repo.GetSelectorCache())
  1104  
  1105  	ctx = policy.SearchContext{
  1106  		From: labels.LabelArray{
  1107  			labels.NewLabel(k8sConst.PodNamespaceLabel, "myns", labels.LabelSourceK8s),
  1108  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "user"), "bob", labels.LabelSourceK8s),
  1109  		},
  1110  		DPorts: []*models.Port{
  1111  			{
  1112  				Port:     443,
  1113  				Protocol: models.PortProtocolTCP,
  1114  			},
  1115  		},
  1116  		To: labels.LabelArray{
  1117  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1118  			labels.NewLabel("role", "frontend", labels.LabelSourceK8s),
  1119  		},
  1120  		Trace: policy.TRACE_VERBOSE,
  1121  	}
  1122  	// Should be ACCEPT sense the traffic comes from Bob's namespaces
  1123  	// (even if it's a different namespace than `default`) AND port 443.
  1124  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
  1125  
  1126  	// Example 3: Allow all traffic to all pods in this namespace.
  1127  	ex3 := []byte(`{
  1128    "kind": "NetworkPolicy",
  1129    "apiVersion": "networking.k8s.io/v1",
  1130    "metadata": {
  1131      "name": "allow-all"
  1132    },
  1133    "spec": {
  1134      "podSelector": null,
  1135      "ingress": [
  1136        {
  1137        }
  1138      ]
  1139    }
  1140  }`)
  1141  
  1142  	np = slim_networkingv1.NetworkPolicy{}
  1143  	err = json.Unmarshal(ex3, &np)
  1144  	require.NoError(t, err)
  1145  
  1146  	rules, err = ParseNetworkPolicy(&np)
  1147  	require.NoError(t, err)
  1148  	require.Equal(t, 1, len(rules))
  1149  
  1150  	repo = testNewPolicyRepository()
  1151  	repo.MustAddList(rules)
  1152  	ctx = policy.SearchContext{
  1153  		From: labels.LabelArray{
  1154  			labels.NewLabel(k8sConst.PodNamespaceLabel, "myns", labels.LabelSourceK8s),
  1155  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "user"), "bob", labels.LabelSourceK8s),
  1156  		},
  1157  		To: labels.LabelArray{
  1158  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1159  			labels.NewLabel("role", "backend", labels.LabelSourceK8s),
  1160  		},
  1161  		Trace: policy.TRACE_VERBOSE,
  1162  	}
  1163  	// Should be ACCEPT since it's going to `default` namespace
  1164  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
  1165  
  1166  	ctx = policy.SearchContext{
  1167  		From: labels.LabelArray{
  1168  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1169  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "user"), "bob", labels.LabelSourceK8s),
  1170  		},
  1171  		To: labels.LabelArray{
  1172  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1173  			labels.NewLabel("role", "backend", labels.LabelSourceK8s),
  1174  		},
  1175  		Trace: policy.TRACE_VERBOSE,
  1176  	}
  1177  	// Should be ACCEPT since it's coming from `default` and going to `default` ns
  1178  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
  1179  
  1180  	ctx = policy.SearchContext{
  1181  		From: labels.LabelArray{
  1182  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1183  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "user"), "bob", labels.LabelSourceK8s),
  1184  		},
  1185  		To: labels.LabelArray{
  1186  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1187  			labels.NewLabel("role", "backend", labels.LabelSourceK8s),
  1188  		},
  1189  		DPorts: []*models.Port{
  1190  			{
  1191  				Port:     443,
  1192  				Protocol: models.PortProtocolTCP,
  1193  			},
  1194  		},
  1195  		Trace: policy.TRACE_VERBOSE,
  1196  	}
  1197  	// Should be ACCEPT since it's coming from `default` and going to `default` namespace.
  1198  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
  1199  
  1200  	// Example 4a: Example 4 is similar to example 2 but we will add both network
  1201  	// policies to see if the rules are additive for the same podSelector.
  1202  	ex4 := []byte(`{
  1203    "kind": "NetworkPolicy",
  1204    "apiVersion": "networking.k8s.io/v1",
  1205    "metadata": {
  1206      "name": "allow-tcp-8080"
  1207    },
  1208    "spec": {
  1209      "podSelector": {
  1210        "matchLabels": {
  1211          "role": "frontend"
  1212        }
  1213      },
  1214      "ingress": [
  1215        {
  1216          "ports": [
  1217            {
  1218              "protocol": "UDP",
  1219              "port": 8080
  1220            }
  1221          ],
  1222          "from": [
  1223            {
  1224              "namespaceSelector": {
  1225                "matchLabels": {
  1226                  "user": "bob"
  1227                }
  1228              }
  1229            }
  1230          ]
  1231        }
  1232      ]
  1233    }
  1234  }`)
  1235  
  1236  	np = slim_networkingv1.NetworkPolicy{}
  1237  	err = json.Unmarshal(ex4, &np)
  1238  	require.NoError(t, err)
  1239  
  1240  	rules, err = ParseNetworkPolicy(&np)
  1241  	require.NoError(t, err)
  1242  	require.Equal(t, 1, len(rules))
  1243  
  1244  	// Example 4b: Example 4 is similar to example 2 but we will add both network
  1245  	// policies to see if the rules are additive for the same podSelector.
  1246  	ex4 = []byte(`{
  1247    "kind": "NetworkPolicy",
  1248    "apiVersion": "networking.k8s.io/v1",
  1249    "metadata": {
  1250      "name": "allow-tcp-8080"
  1251    },
  1252    "spec": {
  1253      "podSelector": {
  1254        "matchLabels": {
  1255          "role": "frontend"
  1256        }
  1257      },
  1258      "ingress": [
  1259        {
  1260          "ports": [
  1261            {
  1262              "protocol": "UDP",
  1263              "port": 8080
  1264            }
  1265          ]
  1266        },{
  1267          "from": [
  1268            {
  1269              "namespaceSelector": {
  1270                "matchLabels": {
  1271                  "user": "bob"
  1272                }
  1273              }
  1274            }
  1275          ]
  1276        }
  1277      ]
  1278    }
  1279  }`)
  1280  
  1281  	np = slim_networkingv1.NetworkPolicy{}
  1282  	err = json.Unmarshal(ex4, &np)
  1283  	require.NoError(t, err)
  1284  
  1285  	rules, err = ParseNetworkPolicy(&np)
  1286  	require.NoError(t, err)
  1287  	require.Equal(t, 1, len(rules))
  1288  
  1289  	repo = testNewPolicyRepository()
  1290  	// add example 4
  1291  	repo.MustAddList(rules)
  1292  
  1293  	np = slim_networkingv1.NetworkPolicy{}
  1294  	err = json.Unmarshal(ex2, &np)
  1295  	require.NoError(t, err)
  1296  
  1297  	rules, err = ParseNetworkPolicy(&np)
  1298  	require.NoError(t, err)
  1299  	// add example 2
  1300  	repo.MustAddList(rules)
  1301  
  1302  	ctx = policy.SearchContext{
  1303  		From: labels.LabelArray{
  1304  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1305  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "user"), "bob", labels.LabelSourceK8s),
  1306  		},
  1307  		DPorts: []*models.Port{
  1308  			{
  1309  				Protocol: models.PortProtocolUDP,
  1310  				Port:     8080,
  1311  			},
  1312  		},
  1313  		To: labels.LabelArray{
  1314  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1315  			labels.NewLabel("role", "frontend", labels.LabelSourceK8s),
  1316  		},
  1317  		Trace: policy.TRACE_VERBOSE,
  1318  	}
  1319  	// Should be ACCEPT sense traffic comes from Bob's namespaces AND port 8080 as specified in `ex4`.
  1320  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
  1321  
  1322  	ctx = policy.SearchContext{
  1323  		From: labels.LabelArray{
  1324  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1325  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "user"), "bob", labels.LabelSourceK8s),
  1326  		},
  1327  		DPorts: []*models.Port{
  1328  			{
  1329  				Port:     443,
  1330  				Protocol: models.PortProtocolTCP,
  1331  			},
  1332  		},
  1333  		To: labels.LabelArray{
  1334  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1335  			labels.NewLabel("role", "frontend", labels.LabelSourceK8s),
  1336  		},
  1337  		Trace: policy.TRACE_VERBOSE,
  1338  	}
  1339  	// Should be ACCEPT sense traffic comes from Bob's namespaces AND port 443 as specified in `ex2`.
  1340  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
  1341  
  1342  	ctx = policy.SearchContext{
  1343  		From: labels.LabelArray{
  1344  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1345  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "user"), "alice", labels.LabelSourceK8s),
  1346  		},
  1347  		DPorts: []*models.Port{
  1348  			{
  1349  				Protocol: models.PortProtocolUDP,
  1350  				Port:     8080,
  1351  			},
  1352  		},
  1353  		To: labels.LabelArray{
  1354  			labels.NewLabel(k8sConst.PodNamespaceLabel, slim_metav1.NamespaceDefault, labels.LabelSourceK8s),
  1355  			labels.NewLabel("role", "frontend", labels.LabelSourceK8s),
  1356  		},
  1357  		Trace: policy.TRACE_VERBOSE,
  1358  	}
  1359  	// Should be ACCEPT despite coming from Alice's namespaces since it's port 8080 as specified in `ex4`.
  1360  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
  1361  
  1362  	// Example 5: Some policies with match expressions.
  1363  	ex5 := []byte(`{
  1364    "kind": "NetworkPolicy",
  1365    "apiVersion": "networking.k8s.io/v1",
  1366    "metadata": {
  1367      "name": "allow-tcp-8080",
  1368      "namespace": "expressions"
  1369    },
  1370    "spec": {
  1371      "podSelector": {
  1372        "matchLabels": {
  1373          "component": "redis"
  1374        },
  1375        "matchExpressions": [
  1376          {
  1377            "key": "tier",
  1378            "operator": "In",
  1379            "values": [
  1380              "cache"
  1381            ]
  1382          },
  1383          {
  1384            "key": "environment",
  1385            "operator": "NotIn",
  1386            "values": [
  1387              "dev"
  1388            ]
  1389          }
  1390        ]
  1391      },
  1392      "ingress": [
  1393        {
  1394          "ports": [
  1395            {
  1396              "protocol": "UDP",
  1397              "port": 8080
  1398            }
  1399          ],
  1400          "from": [
  1401            {
  1402              "namespaceSelector": {
  1403                "matchLabels": {
  1404                  "component": "redis"
  1405                },
  1406                "matchExpressions": [
  1407                  {
  1408                    "key": "tier",
  1409                    "operator": "In",
  1410                    "values": [
  1411                      "cache"
  1412                    ]
  1413                  },
  1414                  {
  1415                    "key": "environment",
  1416                    "operator": "NotIn",
  1417                    "values": [
  1418                      "dev"
  1419                    ]
  1420                  }
  1421                ]
  1422              }
  1423            }
  1424          ]
  1425        }
  1426      ]
  1427    }
  1428  }`)
  1429  
  1430  	np = slim_networkingv1.NetworkPolicy{}
  1431  	err = json.Unmarshal(ex5, &np)
  1432  	require.NoError(t, err)
  1433  
  1434  	rules, err = ParseNetworkPolicy(&np)
  1435  	require.NoError(t, err)
  1436  	require.Equal(t, 1, len(rules))
  1437  	repo.MustAddList(rules)
  1438  
  1439  	// A reminder: from the kubernetes network policy spec:
  1440  	// namespaceSelector:
  1441  	//  Selects Namespaces using cluster scoped-labels.  This
  1442  	//  matches all pods in all namespaces selected by this label selector.
  1443  	//  This field follows standard label selector semantics.
  1444  	//  If omitted, this selector selects no namespaces.
  1445  	//  If present but empty, this selector selects all namespaces.
  1446  	ctx = policy.SearchContext{
  1447  		From: labels.LabelArray{
  1448  			// doesn't matter the namespace.
  1449  			labels.NewLabel(k8sConst.PodNamespaceLabel, "myns", labels.LabelSourceK8s),
  1450  			// component==redis is in the policy
  1451  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "component"), "redis", labels.LabelSourceK8s),
  1452  			// tier==cache is in the policy
  1453  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "tier"), "cache", labels.LabelSourceK8s),
  1454  			// environment is not in `dev` which is in the policy
  1455  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "environment"), "production", labels.LabelSourceK8s),
  1456  			// doesn't matter, there isn't any matchExpression denying traffic from any zone.
  1457  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "zone"), "eu-1", labels.LabelSourceK8s),
  1458  		},
  1459  		DPorts: []*models.Port{
  1460  			{
  1461  				Port:     8080,
  1462  				Protocol: models.PortProtocolUDP,
  1463  			},
  1464  		},
  1465  		To: labels.LabelArray{
  1466  			// Namespace needs to be in `expressions` since the policy is being enforced for that namespace.
  1467  			labels.NewLabel(k8sConst.PodNamespaceLabel, "expressions", labels.LabelSourceK8s),
  1468  			// component==redis is in the policy.
  1469  			labels.NewLabel("component", "redis", labels.LabelSourceK8s),
  1470  			// tier==cache is in the policy
  1471  			labels.NewLabel("tier", "cache", labels.LabelSourceK8s),
  1472  		},
  1473  		Trace: policy.TRACE_VERBOSE,
  1474  	}
  1475  	// Should be ACCEPT since the SearchContext is being covered by the rules.
  1476  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
  1477  
  1478  	ctx.To = labels.LabelArray{
  1479  		// Namespace needs to be in `expressions` since the policy is being enforced for that namespace.
  1480  		labels.NewLabel(k8sConst.PodNamespaceLabel, "myns", labels.LabelSourceK8s),
  1481  		// component==redis is in the policy.
  1482  		labels.NewLabel("component", "redis", labels.LabelSourceK8s),
  1483  		// tier==cache is in the policy
  1484  		labels.NewLabel("tier", "cache", labels.LabelSourceK8s),
  1485  	}
  1486  	// Should be DENY since the namespace doesn't belong to the policy.
  1487  	require.Equal(t, api.Denied, repo.AllowsIngressRLocked(&ctx))
  1488  
  1489  	ctx = policy.SearchContext{
  1490  		From: labels.LabelArray{
  1491  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "component"), "redis", labels.LabelSourceK8s),
  1492  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "tier"), "cache", labels.LabelSourceK8s),
  1493  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "environment"), "dev", labels.LabelSourceK8s),
  1494  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "zone"), "eu-1", labels.LabelSourceK8s),
  1495  		},
  1496  		DPorts: []*models.Port{
  1497  			{
  1498  				Port:     8080,
  1499  				Protocol: models.PortProtocolUDP,
  1500  			},
  1501  		},
  1502  		To: labels.LabelArray{
  1503  			labels.NewLabel(k8sConst.PodNamespaceLabel, "expressions", labels.LabelSourceK8s),
  1504  			labels.NewLabel("component", "redis", labels.LabelSourceK8s),
  1505  			labels.NewLabel("tier", "cache", labels.LabelSourceK8s),
  1506  		},
  1507  		Trace: policy.TRACE_VERBOSE,
  1508  	}
  1509  	// Should be DENY since the environment is from dev.
  1510  	require.Equal(t, api.Denied, repo.AllowsIngressRLocked(&ctx))
  1511  
  1512  	ctx = policy.SearchContext{
  1513  		From: labels.LabelArray{
  1514  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "component"), "redis", labels.LabelSourceK8s),
  1515  			labels.NewLabel(policy.JoinPath(k8sConst.PodNamespaceMetaLabels, "tier"), "cache", labels.LabelSourceK8s),
  1516  		},
  1517  		DPorts: []*models.Port{
  1518  			{
  1519  				Port:     8080,
  1520  				Protocol: models.PortProtocolUDP,
  1521  			},
  1522  		},
  1523  		To: labels.LabelArray{
  1524  			labels.NewLabel(k8sConst.PodNamespaceLabel, "expressions", labels.LabelSourceK8s),
  1525  			labels.NewLabel("component", "redis", labels.LabelSourceK8s),
  1526  			labels.NewLabel("tier", "cache", labels.LabelSourceK8s),
  1527  		},
  1528  		Trace: policy.TRACE_VERBOSE,
  1529  	}
  1530  	// Should be ACCEPT since the environment is from dev.
  1531  	require.Equal(t, api.Allowed, repo.AllowsIngressRLocked(&ctx))
  1532  }
  1533  
  1534  func TestCIDRPolicyExamples(t *testing.T) {
  1535  	ex1 := []byte(`{
  1536    "kind": "NetworkPolicy",
  1537    "apiVersion": "networking.k8s.io/v1",
  1538    "metadata": {
  1539      "name": "ingress-cidr-test",
  1540      "namespace": "myns"
  1541    },
  1542    "spec": {
  1543      "podSelector": {
  1544        "matchLabels": {
  1545          "role": "backend"
  1546        }
  1547      },
  1548      "ingress": [
  1549        {
  1550          "from": [
  1551            {
  1552              "namespaceSelector": {
  1553                "matchLabels": {
  1554                  "user": "bob"
  1555                }
  1556              }
  1557            }
  1558          ]
  1559        }, {
  1560          "from": [
  1561            {
  1562              "ipBlock": {
  1563                "cidr": "10.0.0.0/8",
  1564  	          "except": [
  1565  	            "10.96.0.0/12"
  1566  	          ]
  1567              }
  1568            }
  1569          ]
  1570        }
  1571      ]
  1572    }
  1573  }`)
  1574  	np := slim_networkingv1.NetworkPolicy{}
  1575  	err := json.Unmarshal(ex1, &np)
  1576  	require.NoError(t, err)
  1577  
  1578  	rules, err := ParseNetworkPolicy(&np)
  1579  	require.NoError(t, err)
  1580  	require.NotNil(t, rules)
  1581  	require.Equal(t, 1, len(rules))
  1582  	require.Equal(t, 2, len(rules[0].Ingress))
  1583  
  1584  	ex2 := []byte(`{
  1585    "kind": "NetworkPolicy",
  1586    "apiVersion": "networking.k8s.io/v1",
  1587    "metadata": {
  1588      "name": "ingress-cidr-test",
  1589      "namespace": "myns"
  1590    },
  1591    "spec": {
  1592      "podSelector": {
  1593        "matchLabels": {
  1594          "role": "backend"
  1595        }
  1596      },
  1597      "egress": [
  1598        {
  1599          "to": [
  1600            {
  1601              "ipBlock": {
  1602                "cidr": "10.0.0.0/8",
  1603  	          "except": [
  1604  	            "10.96.0.0/12", "10.255.255.254/32"
  1605  	          ]
  1606              }
  1607            },
  1608  	      {
  1609              "ipBlock": {
  1610                "cidr": "11.0.0.0/8",
  1611  	          "except": [
  1612  	            "11.96.0.0/12", "11.255.255.254/32"
  1613  	          ]
  1614              }
  1615            }
  1616          ]
  1617        }
  1618      ]
  1619    }
  1620  }`)
  1621  
  1622  	np = slim_networkingv1.NetworkPolicy{}
  1623  	err = json.Unmarshal(ex2, &np)
  1624  	require.NoError(t, err)
  1625  
  1626  	rules, err = ParseNetworkPolicy(&np)
  1627  	require.NoError(t, err)
  1628  	require.NotNil(t, rules)
  1629  	require.Equal(t, 1, len(rules))
  1630  	require.Equal(t, api.CIDR("10.0.0.0/8"), rules[0].Egress[0].ToCIDRSet[0].Cidr)
  1631  
  1632  	expectedCIDRs := []api.CIDR{"10.96.0.0/12", "10.255.255.254/32"}
  1633  	for k, v := range rules[0].Egress[0].ToCIDRSet[0].ExceptCIDRs {
  1634  		require.Equal(t, expectedCIDRs[k], v)
  1635  	}
  1636  
  1637  	expectedCIDRs = []api.CIDR{"11.96.0.0/12", "11.255.255.254/32"}
  1638  	for k, v := range rules[0].Egress[1].ToCIDRSet[0].ExceptCIDRs {
  1639  		require.Equal(t, expectedCIDRs[k], v)
  1640  	}
  1641  
  1642  	require.Equal(t, 2, len(rules[0].Egress))
  1643  
  1644  }
  1645  
  1646  func getSelectorPointer(sel api.EndpointSelector) *api.EndpointSelector {
  1647  	return &sel
  1648  }
  1649  
  1650  func Test_parseNetworkPolicyPeer(t *testing.T) {
  1651  	type args struct {
  1652  		namespace string
  1653  		peer      *slim_networkingv1.NetworkPolicyPeer
  1654  	}
  1655  	tests := []struct {
  1656  		name string
  1657  		args args
  1658  		want *api.EndpointSelector
  1659  	}{
  1660  		{
  1661  			name: "peer-with-pod-selector",
  1662  			args: args{
  1663  				namespace: "foo-namespace",
  1664  				peer: &slim_networkingv1.NetworkPolicyPeer{
  1665  					PodSelector: &slim_metav1.LabelSelector{
  1666  						MatchLabels: map[string]string{
  1667  							"foo": "bar",
  1668  						},
  1669  						MatchExpressions: []slim_metav1.LabelSelectorRequirement{
  1670  							{
  1671  								Key:      "foo",
  1672  								Operator: slim_metav1.LabelSelectorOpIn,
  1673  								Values:   []string{"bar", "baz"},
  1674  							},
  1675  						},
  1676  					},
  1677  				},
  1678  			},
  1679  			want: getSelectorPointer(
  1680  				api.NewESFromMatchRequirements(
  1681  					map[string]string{
  1682  						"k8s.foo":                         "bar",
  1683  						"k8s.io.kubernetes.pod.namespace": "foo-namespace",
  1684  					},
  1685  					[]slim_metav1.LabelSelectorRequirement{
  1686  						{
  1687  							Key:      "k8s.foo",
  1688  							Operator: slim_metav1.LabelSelectorOpIn,
  1689  							Values:   []string{"bar", "baz"},
  1690  						},
  1691  					},
  1692  				),
  1693  			),
  1694  		},
  1695  		{
  1696  			name: "peer-nil",
  1697  			args: args{
  1698  				namespace: "foo-namespace",
  1699  			},
  1700  			want: nil,
  1701  		},
  1702  		{
  1703  			name: "peer-with-pod-selector-and-ns-selector",
  1704  			args: args{
  1705  				namespace: "foo-namespace",
  1706  				peer: &slim_networkingv1.NetworkPolicyPeer{
  1707  					PodSelector: &slim_metav1.LabelSelector{
  1708  						MatchLabels: map[string]string{
  1709  							"foo": "bar",
  1710  						},
  1711  						MatchExpressions: []slim_metav1.LabelSelectorRequirement{
  1712  							{
  1713  								Key:      "foo",
  1714  								Operator: slim_metav1.LabelSelectorOpIn,
  1715  								Values:   []string{"bar", "baz"},
  1716  							},
  1717  						},
  1718  					},
  1719  					NamespaceSelector: &slim_metav1.LabelSelector{
  1720  						MatchLabels: map[string]string{
  1721  							"ns-foo": "ns-bar",
  1722  						},
  1723  						MatchExpressions: []slim_metav1.LabelSelectorRequirement{
  1724  							{
  1725  								Key:      "ns-foo-expression",
  1726  								Operator: slim_metav1.LabelSelectorOpExists,
  1727  							},
  1728  						},
  1729  					},
  1730  				},
  1731  			},
  1732  			want: getSelectorPointer(
  1733  				api.NewESFromMatchRequirements(
  1734  					map[string]string{
  1735  						"k8s.foo": "bar",
  1736  						"k8s.io.cilium.k8s.namespace.labels.ns-foo": "ns-bar",
  1737  					},
  1738  					[]slim_metav1.LabelSelectorRequirement{
  1739  						{
  1740  							Key:      "k8s.io.cilium.k8s.namespace.labels.ns-foo-expression",
  1741  							Operator: slim_metav1.LabelSelectorOpExists,
  1742  						},
  1743  						{
  1744  							Key:      "k8s.foo",
  1745  							Operator: slim_metav1.LabelSelectorOpIn,
  1746  							Values:   []string{"bar", "baz"},
  1747  						},
  1748  					},
  1749  				),
  1750  			),
  1751  		},
  1752  		{
  1753  			name: "peer-with-ns-selector",
  1754  			args: args{
  1755  				namespace: "foo-namespace",
  1756  				peer: &slim_networkingv1.NetworkPolicyPeer{
  1757  					NamespaceSelector: &slim_metav1.LabelSelector{
  1758  						MatchLabels: map[string]string{
  1759  							"ns-foo": "ns-bar",
  1760  						},
  1761  						MatchExpressions: []slim_metav1.LabelSelectorRequirement{
  1762  							{
  1763  								Key:      "ns-foo-expression",
  1764  								Operator: slim_metav1.LabelSelectorOpExists,
  1765  							},
  1766  						},
  1767  					},
  1768  				},
  1769  			},
  1770  			want: getSelectorPointer(
  1771  				api.NewESFromMatchRequirements(
  1772  					map[string]string{
  1773  						"k8s.io.cilium.k8s.namespace.labels.ns-foo": "ns-bar",
  1774  					},
  1775  					[]slim_metav1.LabelSelectorRequirement{
  1776  						{
  1777  							Key:      "k8s.io.cilium.k8s.namespace.labels.ns-foo-expression",
  1778  							Operator: slim_metav1.LabelSelectorOpExists,
  1779  						},
  1780  					},
  1781  				),
  1782  			),
  1783  		},
  1784  		{
  1785  			name: "peer-with-allow-all-ns-selector",
  1786  			args: args{
  1787  				namespace: "foo-namespace",
  1788  				peer: &slim_networkingv1.NetworkPolicyPeer{
  1789  					NamespaceSelector: &slim_metav1.LabelSelector{},
  1790  				},
  1791  			},
  1792  			want: getSelectorPointer(
  1793  				api.NewESFromMatchRequirements(
  1794  					map[string]string{},
  1795  					[]slim_metav1.LabelSelectorRequirement{
  1796  						{
  1797  							Key:      fmt.Sprintf("%s.%s", labels.LabelSourceK8s, k8sConst.PodNamespaceLabel),
  1798  							Operator: slim_metav1.LabelSelectorOpExists,
  1799  						},
  1800  					},
  1801  				),
  1802  			),
  1803  		},
  1804  	}
  1805  	for _, tt := range tests {
  1806  		t.Run(tt.name, func(t *testing.T) {
  1807  			got := parseNetworkPolicyPeer(tt.args.namespace, tt.args.peer)
  1808  			require.EqualValues(t, tt.want, got)
  1809  		})
  1810  	}
  1811  }
  1812  
  1813  func TestGetPolicyLabelsv1(t *testing.T) {
  1814  	uuid := "1bba160-ddca-11e8-b697-0800273b04ff"
  1815  	tests := []struct {
  1816  		np          *slim_networkingv1.NetworkPolicy // input network policy
  1817  		name        string                           // expected extracted name
  1818  		namespace   string                           // expected extracted namespace
  1819  		uuid        string                           // expected extracted uuid
  1820  		derivedFrom string                           // expected extracted derived
  1821  	}{
  1822  		{
  1823  			np:          &slim_networkingv1.NetworkPolicy{},
  1824  			name:        "",
  1825  			namespace:   slim_metav1.NamespaceDefault,
  1826  			uuid:        "",
  1827  			derivedFrom: resourceTypeNetworkPolicy,
  1828  		},
  1829  		{
  1830  			np: &slim_networkingv1.NetworkPolicy{
  1831  				ObjectMeta: slim_metav1.ObjectMeta{
  1832  					Annotations: map[string]string{
  1833  						annotation.PolicyName: "foo",
  1834  					},
  1835  				},
  1836  			},
  1837  			name:        "foo",
  1838  			uuid:        "",
  1839  			namespace:   slim_metav1.NamespaceDefault,
  1840  			derivedFrom: resourceTypeNetworkPolicy,
  1841  		},
  1842  		{
  1843  			np: &slim_networkingv1.NetworkPolicy{
  1844  				ObjectMeta: slim_metav1.ObjectMeta{
  1845  					Name:      "foo",
  1846  					Namespace: "bar",
  1847  					UID:       types.UID(uuid),
  1848  				},
  1849  			},
  1850  			name:        "foo",
  1851  			namespace:   "bar",
  1852  			uuid:        uuid,
  1853  			derivedFrom: resourceTypeNetworkPolicy,
  1854  		},
  1855  	}
  1856  
  1857  	assertLabel := func(lbl labels.Label, key, value string) {
  1858  		require.Equal(t, key, lbl.Key)
  1859  		require.Equal(t, value, lbl.Value)
  1860  		require.Equal(t, labels.LabelSourceK8s, lbl.Source)
  1861  	}
  1862  
  1863  	for _, tt := range tests {
  1864  		lbls := GetPolicyLabelsv1(tt.np)
  1865  		require.NotNil(t, lbls)
  1866  		require.Len(t, lbls, 4, "Incorrect number of labels: Expected DerivedFrom, Name, Namespace and UID labels.")
  1867  		assertLabel(lbls[0], "io.cilium.k8s.policy.derived-from", tt.derivedFrom)
  1868  		assertLabel(lbls[1], "io.cilium.k8s.policy.name", tt.name)
  1869  		assertLabel(lbls[2], "io.cilium.k8s.policy.namespace", tt.namespace)
  1870  		assertLabel(lbls[3], "io.cilium.k8s.policy.uid", tt.uuid)
  1871  	}
  1872  }
  1873  
  1874  func TestIPBlockToCIDRRule(t *testing.T) {
  1875  	blocks := []*slim_networkingv1.IPBlock{
  1876  		{},
  1877  		{CIDR: "192.168.1.1/24"},
  1878  		{CIDR: "192.168.1.1/24", Except: []string{}},
  1879  		{CIDR: "192.168.1.1/24", Except: []string{"192.168.1.1/28"}},
  1880  		{
  1881  			CIDR: "192.168.1.1/24",
  1882  			Except: []string{
  1883  				"192.168.1.1/30",
  1884  				"192.168.1.1/26",
  1885  				"192.168.1.1/28",
  1886  			},
  1887  		},
  1888  	}
  1889  
  1890  	for _, block := range blocks {
  1891  		cidrRule := ipBlockToCIDRRule(block)
  1892  
  1893  		exceptCIDRs := make([]api.CIDR, len(block.Except))
  1894  		for i, v := range block.Except {
  1895  			exceptCIDRs[i] = api.CIDR(v)
  1896  		}
  1897  
  1898  		require.Equal(t, false, cidrRule.Generated)
  1899  		require.Equal(t, api.CIDR(block.CIDR), cidrRule.Cidr)
  1900  
  1901  		if block.Except == nil || len(block.Except) == 0 {
  1902  			require.Nil(t, cidrRule.ExceptCIDRs)
  1903  		} else {
  1904  			require.EqualValues(t, exceptCIDRs, cidrRule.ExceptCIDRs)
  1905  		}
  1906  	}
  1907  }