diff --git a/e2e/suite_test.go b/e2e/suite_test.go index 9b9c0d7..eb9cb18 100644 --- a/e2e/suite_test.go +++ b/e2e/suite_test.go @@ -24,6 +24,9 @@ var ( //go:embed t/node-deny-npar.yaml nodeDenyNetworkPolicyAdmissionRule []byte + + //go:embed t/exclude-only-npar.yaml + excludeOnlyNetworkPolicyAdmissionRule []byte ) func TestE2E(t *testing.T) { @@ -47,4 +50,5 @@ var _ = BeforeSuite(func() { By("setting up default NetworkPolicyAdmissionRules") kubectlSafe(bmcDenyNetworkPolicyAdmissionRule, "apply", "-f", "-") kubectlSafe(nodeDenyNetworkPolicyAdmissionRule, "apply", "-f", "-") + kubectlSafe(excludeOnlyNetworkPolicyAdmissionRule, "apply", "-f", "-") }) diff --git a/e2e/t/exclude-only-npar.yaml b/e2e/t/exclude-only-npar.yaml new file mode 100644 index 0000000..c407392 --- /dev/null +++ b/e2e/t/exclude-only-npar.yaml @@ -0,0 +1,8 @@ +apiVersion: tenet.cybozu.io/v1beta2 +kind: NetworkPolicyAdmissionRule +metadata: + name: exclude-only-npar +spec: + namespaceSelector: + excludeLabels: + team: tenant diff --git a/hooks/ciliumnetworkpolicy.go b/hooks/ciliumnetworkpolicy.go index 2be15b6..eb2dcbb 100644 --- a/hooks/ciliumnetworkpolicy.go +++ b/hooks/ciliumnetworkpolicy.go @@ -73,25 +73,21 @@ func (v *ciliumNetworkPolicyValidator) handleCreateOrUpdate(ctx context.Context, return admission.Errored(http.StatusInternalServerError, err) } - if !v.shouldValidate(ns, &nparl) { - return admission.Allowed("") - } - - res = v.validateIP(nparl, cnp) + res = v.validateIP(nparl, cnp, ns.Labels) if !res.Allowed { return res } - return v.validateEntity(nparl, cnp) + return v.validateEntity(nparl, cnp, ns.Labels) } -func (v *ciliumNetworkPolicyValidator) validateIP(nparl tenetv1beta2.NetworkPolicyAdmissionRuleList, cnp *unstructured.Unstructured) admission.Response { +func (v *ciliumNetworkPolicyValidator) validateIP(nparl tenetv1beta2.NetworkPolicyAdmissionRuleList, cnp *unstructured.Unstructured, ls map[string]string) admission.Response { egressPolicies, ingressPolicies, err := v.gatherIPPolicies(cnp) if err != nil { return admission.Errored(http.StatusBadRequest, err) } - egressFilters, ingressFilters, err := v.gatherIPFilters(&nparl) + egressFilters, ingressFilters, err := v.gatherIPFilters(&nparl, ls) if err != nil { return admission.Errored(http.StatusInternalServerError, err) } @@ -112,12 +108,12 @@ func (v *ciliumNetworkPolicyValidator) validateIP(nparl tenetv1beta2.NetworkPoli return admission.Allowed("") } -func (v *ciliumNetworkPolicyValidator) validateEntity(nparl tenetv1beta2.NetworkPolicyAdmissionRuleList, cnp *unstructured.Unstructured) admission.Response { +func (v *ciliumNetworkPolicyValidator) validateEntity(nparl tenetv1beta2.NetworkPolicyAdmissionRuleList, cnp *unstructured.Unstructured, ls map[string]string) admission.Response { egressPolicies, ingressPolicies, err := v.gatherEntityPolicies(cnp) if err != nil { return admission.Errored(http.StatusBadRequest, err) } - egressFilters, ingressFilters := v.gatherEntityFilters(&nparl) + egressFilters, ingressFilters := v.gatherEntityFilters(&nparl, ls) for _, egressPolicy := range egressPolicies { for _, egressFilter := range egressFilters { if egressPolicy == egressFilter { @@ -135,12 +131,10 @@ func (v *ciliumNetworkPolicyValidator) validateEntity(nparl tenetv1beta2.Network return admission.Allowed("") } -func (v *ciliumNetworkPolicyValidator) shouldValidate(ns *corev1.Namespace, nparl *tenetv1beta2.NetworkPolicyAdmissionRuleList) bool { - for _, npar := range nparl.Items { - for k, v := range npar.Spec.NamespaceSelector.ExcludeLabels { - if ns.Labels[k] == v { - return false - } +func (v *ciliumNetworkPolicyValidator) shouldValidate(npar *tenetv1beta2.NetworkPolicyAdmissionRule, ls map[string]string) bool { + for k, v := range npar.Spec.NamespaceSelector.ExcludeLabels { + if ls[k] == v { + return false } } return true diff --git a/hooks/ciliumnetworkpolicy_util.go b/hooks/ciliumnetworkpolicy_util.go index c69b2b7..f994bc3 100644 --- a/hooks/ciliumnetworkpolicy_util.go +++ b/hooks/ciliumnetworkpolicy_util.go @@ -54,9 +54,13 @@ func (v *ciliumNetworkPolicyValidator) toIPNetSlice(raw []string) ([]*net.IPNet, return res, nil } -func (v *ciliumNetworkPolicyValidator) gatherIPFilters(nparl *tenetv1beta2.NetworkPolicyAdmissionRuleList) ([]*net.IPNet, []*net.IPNet, error) { +func (v *ciliumNetworkPolicyValidator) gatherIPFilters(nparl *tenetv1beta2.NetworkPolicyAdmissionRuleList, ls map[string]string) ([]*net.IPNet, []*net.IPNet, error) { var egressFilters, ingressFilters []*net.IPNet for _, npar := range nparl.Items { + if !v.shouldValidate(&npar, ls) { + continue + } + for _, ipRange := range npar.Spec.ForbiddenIPRanges { _, cidr, err := net.ParseCIDR(ipRange.CIDR) if err != nil { @@ -80,9 +84,13 @@ func (v *ciliumNetworkPolicyValidator) gatherEntityPolicies(cnp *unstructured.Un return v.gatherPolicies(cnp, cilium.EntityRuleKey, v.gatherPoliciesFromStringRule) } -func (v *ciliumNetworkPolicyValidator) gatherEntityFilters(nparl *tenetv1beta2.NetworkPolicyAdmissionRuleList) ([]string, []string) { +func (v *ciliumNetworkPolicyValidator) gatherEntityFilters(nparl *tenetv1beta2.NetworkPolicyAdmissionRuleList, ls map[string]string) ([]string, []string) { var egressFilters, ingressFilters []string for _, npar := range nparl.Items { + if !v.shouldValidate(&npar, ls) { + continue + } + for _, entity := range npar.Spec.ForbiddenEntities { switch entity.Type { case tenetv1beta2.NetworkPolicyAdmissionRuleTypeAll: