diff --git a/tools/azure-npm-to-cilium-validator.go b/tools/azure-npm-to-cilium-validator.go index ceb0160bb7..1b23979ecf 100644 --- a/tools/azure-npm-to-cilium-validator.go +++ b/tools/azure-npm-to-cilium-validator.go @@ -211,7 +211,7 @@ func checkExternalTrafficPolicyServices(namespaces *corev1.NamespaceList, servic noSelectorServices = append(noSelectorServices, fmt.Sprintf("%s/%s", ns.Name, service.Name)) } else { // Check if are there services with selector that match the network policy - checkServiceRisk(&metav1.LabelSelector{MatchLabels: service.Spec.Selector}, ns.Name, servicePorts, policiesByNamespace[ns.Name], safeServices) + checkServiceRisk(service, ns.Name, servicePorts, policiesByNamespace[ns.Name], safeServices) } } } @@ -230,37 +230,32 @@ func hasIngressPolicies(policies []networkingv1.NetworkPolicy) bool { return false } -func checkServiceRisk(serviceSelector *metav1.LabelSelector, namespace string, servicePorts []string, policiesListAtNamespace []networkingv1.NetworkPolicy, safeServices []string) { +func checkServiceRisk(service v1.Service, namespace string, servicePorts []string, policiesListAtNamespace []networkingv1.NetworkPolicy, safeServices []string) { for _, policy := range policiesListAtNamespace { for _, ingress := range policy.Spec.Ingress { - // If there are no ingress from or ports in the policy the service is safe + // If there are no ingress from and ports in the policy check; check if the service is safe if len(ingress.From) == 0 && len(ingress.Ports) == 0 { - if matchSelector(serviceSelector, &policy.Spec.PodSelector) { - safeServices = append(safeServices, fmt.Sprintf("%s/%s", namespace, serviceSelector)) + if matchSelector(&metav1.LabelSelector{MatchLabels: service.Spec.Selector}, &policy.Spec.PodSelector) { + safeServices = append(safeServices, fmt.Sprintf("%s/%s", namespace, service.Name)) return } } + // If there are no ingress from but there are ports in the policy; check if the service is safe + if len(ingress.From) == 0 && len(ingress.Ports) > 0 { + if matchSelector(&metav1.LabelSelector{MatchLabels: service.Spec.Selector}, &policy.Spec.PodSelector) { + matchingPorts := []string{} + for _, port := range ingress.Ports { + matchingPorts = append(matchingPorts, fmt.Sprintf("%d/%s", port.Port.IntVal, string(*port.Protocol))) + } + for _, sevicePort := range servicePorts { + if contains(matchingPorts, sevicePort) { + safeServices = append(safeServices, fmt.Sprintf("%s/%s", namespace, service.Name)) + return + } + } + } + } } - // for _, policy := range policiesListAtNamespace { - // for _, ingress := range policy.Spec.Ingress { - // // Check 4: are there policies with no From and Ports? - // if len(ingress.From) == 0 && len(ingress.Ports) > 0 { - // if matchSelector(serviceSelector, &policy.Spec.PodSelector) { - // matchingPorts := []string{} - // for _, port := range ingress.Ports { - // matchingPorts = append(matchingPorts, fmt.Sprintf("%d/%s", port.Port.IntVal, port.Protocol)) - // } - // for _, svcPort := range servicePorts { - // if contains(matchingPorts, svcPort) { - // safeServices = append(safeServices, fmt.Sprintf("%s/%s", namespace, serviceSelector)) - // return - // } - // } - // } - // } - // } - // } - // } } } @@ -273,15 +268,70 @@ func matchSelector(serviceSelector *metav1.LabelSelector, policyPodSelector *met policyPodLabels := policyPodSelector.MatchLabels serviceLabels := serviceSelector.MatchLabels - // TODO CHECK - for key, value := range policyPodLabels { - if serviceLabels[key] != value { - return false - } + // If the labels in the policy pod selector are present in the service selector then return true + if checkPolicyMatchServiceLabels(serviceLabels, policyPodLabels) { + return true } + // Get the expressions from the pod selector in the network policy and selector in the service policyPodExpressions := policyPodSelector.MatchExpressions serviceExpressions := serviceSelector.MatchExpressions + for _, serviceExpression := range serviceExpressions { + key := serviceExpression.Key + operator := serviceExpression.Operator + values := serviceExpression.Values + + // Check if any of the policy expressions match the service expression + matchingExpression := metav1.LabelSelectorRequirement{} + foundMatchingExpression := false + for _, policyExpression := range policyPodExpressions { + if policyExpression.Key == key { + matchingExpression = policyExpression + foundMatchingExpression = true + break + } + } + // If the expression is not found then return false + if !foundMatchingExpression { + return false + } + + // Check if the values in the service expression are present in the matching policy expression + if operator == metav1.LabelSelectorOpIn { + for _, value := range values { + if !contains(matchingExpression.Values, value) { + return false + } + } + } else if operator == metav1.LabelSelectorOpNotIn { + for _, value := range values { + if contains(matchingExpression.Values, value) { + return false + } + } + } + } + return true } + +func checkPolicyMatchServiceLabels(serviceLabels, policyPodLabels map[string]string) bool { + // Count the number of labels that match + matchLabelCount := 0 + for policyKey, policyValue := range policyPodLabels { + for serviceKey, serviceValue := range serviceLabels { + if serviceKey == policyKey && serviceValue == policyValue { + matchLabelCount++ + } + } + } + + // If the number of labels that match is equal to the number of labels in the policy pod selector then return true + // as that means all the match labels in the policy pod selector are present in the service selector + if matchLabelCount == len(policyPodLabels) { + return true + } + + return false +}