From 0828d1a8bbceee8d677ce5a3bcf099e520740320 Mon Sep 17 00:00:00 2001 From: Isaiah Raya Date: Tue, 28 Jan 2025 00:53:25 +0000 Subject: [PATCH] npm to cilium validator script --- tools/azure-npm-to-cilium-validator.go | 210 +++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 tools/azure-npm-to-cilium-validator.go diff --git a/tools/azure-npm-to-cilium-validator.go b/tools/azure-npm-to-cilium-validator.go new file mode 100644 index 0000000000..243492beaf --- /dev/null +++ b/tools/azure-npm-to-cilium-validator.go @@ -0,0 +1,210 @@ +package main + +import ( + "context" + "flag" + "fmt" + "log" + + corev1 "k8s.io/api/core/v1" + networkingv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" +) + +// FOR DEMO +// kubectl delete networkpolicy --all --all-namespaces +// k apply -f network-polices +// k get networkpolicies -A -o wide +// cd AzureRepo/azure-container-networking/tools +// go run azure-npm-to-cilium-validator.go --kubeconfig ~/.kube/config +func main() { + // Parse the kubeconfig flag + kubeconfig := flag.String("kubeconfig", "~/.kube/config", "absolute path to the kubeconfig file") + flag.Parse() + + // Build the Kubernetes client config + config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) + if err != nil { + log.Fatalf("Error building kubeconfig: %v", err) + } + + // Create a Kubernetes client + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + log.Fatalf("Error creating Kubernetes client: %v", err) + } + + // Get all network policies in the cluster + networkPolicies, err := clientset.NetworkingV1().NetworkPolicies("").List(context.TODO(), metav1.ListOptions{}) + if err != nil { + log.Fatalf("Error fetching network policies: %v", err) + } + + // Get all services in the cluster + services, err := clientset.CoreV1().Services("").List(context.TODO(), metav1.ListOptions{}) + if err != nil { + log.Fatalf("Error fetching services: %v", err) + } + + // Store network policies by namespace + policiesByNamespace := make(map[string][]networkingv1.NetworkPolicy) + + // Store network policies in the map + for _, policy := range networkPolicies.Items { + namespace := policy.Namespace + policiesByNamespace[namespace] = append(policiesByNamespace[namespace], policy) + } + + // Store services by namespace + servicesByNamespace := make(map[string][]corev1.Service) + + // Store services in the map + for _, service := range services.Items { + namespace := service.Namespace + servicesByNamespace[namespace] = append(servicesByNamespace[namespace], service) + } + + fmt.Println("Migration Summary:") + fmt.Println("+------------------------------+-------------------------------+") + fmt.Printf("%-30s | %-30s \n", "Breaking Change", "No Impact / Safe to Migrate") + fmt.Println("+------------------------------+-------------------------------+") + + // Check the endports of the network policies + checkEndportNetworkPolicies(policiesByNamespace) + + fmt.Println("+------------------------------+-------------------------------+") + + // Check the cidr of the network policies + checkCIDRNetworkPolicies(policiesByNamespace) + + fmt.Println("+------------------------------+-------------------------------+") + + // Check services that have externalTrafficPolicy!=Local + checkExternalTrafficPolicyServices(servicesByNamespace, policiesByNamespace) + + fmt.Println("+------------------------------+-------------------------------+") + fmt.Println("Please see aka.ms/azurenpmtocilium for instructions on how to evaluate/assess the above warnings marked by ❌.") + fmt.Println("NOTE: rerun this script if any modifications (create/update/delete) are made to services or policies.") +} + +func checkEndportNetworkPolicies(policiesByNamespace map[string][]networkingv1.NetworkPolicy) { + networkPolicyWithEndport := false + for namespace, policies := range policiesByNamespace { + for _, policy := range policies { + foundEndPort := false + for _, egress := range policy.Spec.Egress { + for _, port := range egress.Ports { + if port.EndPort != nil { + foundEndPort = true + break // Exit egress.port loop + } + } + if foundEndPort { + break // Exit egress loop + } + } + if foundEndPort { + if !networkPolicyWithEndport { + fmt.Printf("%-30s | %-30s \n", "NetworkPolicy with endPort", "❌") + fmt.Println("Details:") + networkPolicyWithEndport = true + } + fmt.Printf("❌ Found NetworkPolicy: %s with endPort field in namespace: %s\n", policy.Name, namespace) + } + } + } + // Print no impact if no network policy has endport + if !networkPolicyWithEndport { + fmt.Printf("%-30s | %-30s \n", "NetworkPolicy with endPort", "✅") + } +} + +func checkCIDRNetworkPolicies(policiesByNamespace map[string][]networkingv1.NetworkPolicy) { + networkPolicyWithCIDR := false + for namespace, policies := range policiesByNamespace { + for _, policy := range policies { + foundCIDRIngress := false + foundCIDREgress := false + // Check the ingress field for cidr + for _, ingress := range policy.Spec.Ingress { + for _, from := range ingress.From { + if from.IPBlock != nil { + if from.IPBlock.CIDR != "" { + foundCIDRIngress = true + break // Exit ingress.from.ipBlock loop + } + } + } + if foundCIDRIngress { + break // Exit ingress loop + } + } + // Print the network policy if it has an ingress cidr + if foundCIDRIngress { + if !networkPolicyWithCIDR { + fmt.Printf("%-30s | %-30s \n", "NetworkPolicy with cidr", "❌") + fmt.Println("Details:") + networkPolicyWithCIDR = true + } + fmt.Printf("❌ Found NetworkPolicy: %s with ingress cidr field in namespace: %s\n", policy.Name, namespace) + } + // Check the egress field for cidr + for _, egress := range policy.Spec.Egress { + for _, to := range egress.To { + if to.IPBlock != nil { + if to.IPBlock.CIDR != "" { + foundCIDREgress = true + break // Exit egress.to.ipBlock loop + } + } + } + if foundCIDREgress { + break // Exit egress loop + } + } + // Print the network policy if it has an egress cidr + if foundCIDREgress { + if !networkPolicyWithCIDR { + fmt.Printf("%-30s | %-30s \n", "NetworkPolicy with cidr", "❌") + fmt.Println("Details:") + networkPolicyWithCIDR = true + } + fmt.Printf("❌ Found NetworkPolicy: %s with egress cidr field in namespace: %s\n", policy.Name, namespace) + } + } + } + // Print no impact if no network policy has cidr + if !networkPolicyWithCIDR { + fmt.Printf("%-30s | %-30s \n", "NetworkPolicy with cidr", "✅") + } +} + +func checkExternalTrafficPolicyServices(servicesByNamespace map[string][]corev1.Service, policiesByNamespace map[string][]networkingv1.NetworkPolicy) { + // Check 0: are there ingress policies in the namespace? + policiesByNamespaceAtRisk := map[string][]networkingv1.NetworkPolicy{} + serviceByNamespaceAtRisk := map[string][]corev1.Service{} + for namespace, services := range servicesByNamespace { + for _, service := range services { + for _, policy := range policiesByNamespace[namespace] { + // TODO: DO I NEED TO CHECK FOR policyTypes: Ingress as well? I.E default-deny-ingress + if len(policy.Spec.Ingress) > 0 { + policiesByNamespaceAtRisk[namespace] = append(policiesByNamespaceAtRisk[namespace], policy) + serviceByNamespaceAtRisk[namespace] = append(serviceByNamespaceAtRisk[namespace], service) + } + } + } + } +} + +// func printMigrationSummary(endPortPoliciesOutput string) { +// fmt.Println("Migration Summary:") +// fmt.Println("+--------------------------------+-------------------------------+") +// fmt.Printf("| %-30s | %-30s |\n", "Breaking Change", "No Impact / Safe to Migrate") +// fmt.Println("+--------------------------------+-------------------------------+") +// fmt.Printf("| %-30s | %-30s |\n", "NetworkPolicy with endPort", endPortPoliciesOutput) +// fmt.Println("+--------------------------------+-------------------------------+") +// fmt.Println("Please see aka.ms/azurenpmtocilium for instructions on how to evaluate/assess the above warnings marked by ❌.") +// fmt.Println("NOTE: rerun this script if any modifications (create/update/delete) are made to services or policies.") +// }