@@ -19,9 +19,6 @@ import (
1919// go run azure-npm-to-cilium-validator.go --kubeconfig ~/.kube/config
2020
2121func main () {
22- // Remove timestamp from log
23- log .SetFlags (0 )
24-
2522 // Parse the kubeconfig flag
2623 kubeconfig := flag .String ("kubeconfig" , "~/.kube/config" , "absolute path to the kubeconfig file" )
2724 flag .Parse ()
@@ -73,31 +70,48 @@ func main() {
7370 servicesByNamespace [ns .Name ] = services .Items
7471 }
7572
73+ // Print the migration summary
74+ printMigrationSummary (namespaces , & policiesByNamespace , & servicesByNamespace )
75+ }
76+
77+ func printMigrationSummary (namespaces * corev1.NamespaceList , policiesByNamespace * map [string ][]networkingv1.NetworkPolicy , servicesByNamespace * map [string ][]corev1.Service ) {
7678 fmt .Println ("Migration Summary:" )
7779 fmt .Println ("+------------------------------+-------------------------------+" )
7880 fmt .Printf ("%-30s | %-30s \n " , "Breaking Change" , "No Policy Changes Needed" )
7981 fmt .Println ("+------------------------------+-------------------------------+" )
8082
8183 // Check the endports of the network policies
82- foundEnportNetworkPolicy := checkEndportNetworkPolicies (policiesByNamespace )
84+ ingressEndportNetworkPolicy , egressEndportNetworkPolicy := checkEndportNetworkPolicies (policiesByNamespace )
85+
86+ // Print the network policies with endport
87+ printPoliciesWithEndport (& ingressEndportNetworkPolicy , & egressEndportNetworkPolicy )
8388
8489 fmt .Println ("+------------------------------+-------------------------------+" )
8590
8691 // Check the cidr of the network policies
87- foundCIDRNetworkPolicy := checkCIDRNetworkPolicies (policiesByNamespace )
92+ ingressPoliciesWithCIDR , egressPoliciesWithCIDR := checkCIDRNetworkPolicies (policiesByNamespace )
93+
94+ // Print the network policies with CIDR
95+ printPoliciesWithCIDR (& ingressPoliciesWithCIDR , & egressPoliciesWithCIDR )
8896
8997 fmt .Println ("+------------------------------+-------------------------------+" )
9098
9199 // Check the egress of the network policies
92- foundEgressPolicy := checkForEgressPolicies (policiesByNamespace )
100+ egressPolicies := checkForEgressPolicies (policiesByNamespace )
101+
102+ // Print the network policies with egress
103+ printEgressPolicies (& egressPolicies )
93104
94105 fmt .Println ("+------------------------------+-------------------------------+" )
95106
96107 // Check services that have externalTrafficPolicy!=Local
97- foundServiceDispruption := checkExternalTrafficPolicyServices (namespaces , servicesByNamespace , policiesByNamespace )
108+ unsafeServices , noSelectorServices := checkExternalTrafficPolicyServices (namespaces , servicesByNamespace , policiesByNamespace )
109+
110+ // Print the services that are at risk
111+ printUnsafeServices (& unsafeServices , & noSelectorServices )
98112
99113 fmt .Println ("+------------------------------+-------------------------------+" )
100- if foundEnportNetworkPolicy || foundCIDRNetworkPolicy || foundEgressPolicy || foundServiceDispruption {
114+ if len ( ingressEndportNetworkPolicy ) > 0 || len ( egressEndportNetworkPolicy ) > 0 || len ( ingressPoliciesWithCIDR ) > 0 || len ( egressPoliciesWithCIDR ) > 0 || len ( egressPolicies ) > 0 || len ( unsafeServices ) > 0 {
101115 fmt .Println ("\033 [31m✘ Review above issues before migration.\033 [0m" )
102116 fmt .Println ("Please see \033 [32maka.ms/azurenpmtocilium\033 [0m for instructions on how to evaluate/assess the above warnings marked by ❌." )
103117 fmt .Println ("NOTE: rerun this script if any modifications (create/update/delete) are made to services or policies." )
@@ -107,125 +121,177 @@ func main() {
107121 }
108122}
109123
110- func checkEndportNetworkPolicies (policiesByNamespace map [string ][]networkingv1.NetworkPolicy ) bool {
111- foundNetworkPolicyWithEndport := false
112- for namespace , policies := range policiesByNamespace {
124+ func printPoliciesWithEndport (ingressEndportNetworkPolicy * []string , egressEndportNetworkPolicy * []string ) {
125+ if len (* ingressEndportNetworkPolicy ) == 0 && len (* egressEndportNetworkPolicy ) == 0 {
126+ fmt .Printf ("%-30s | %-30s \n " , "NetworkPolicy with endport" , "✅" )
127+ } else {
128+ fmt .Printf ("%-30s | %-30s \n " , "NetworkPolicy with endport" , "❌" )
129+ fmt .Println ("Policies affected:" )
130+ for _ , policy := range * ingressEndportNetworkPolicy {
131+ policyNamespace := strings .Split (policy , "/" )[0 ]
132+ policyName := strings .Split (policy , "/" )[1 ]
133+ fmt .Printf ("❌ Found NetworkPolicy: \033 [31m%s\033 [0m with ingress endPort field in namespace: \033 [31m%s\033 [0m\n " , policyName , policyNamespace )
134+ }
135+ for _ , policy := range * egressEndportNetworkPolicy {
136+ policyNamespace := strings .Split (policy , "/" )[0 ]
137+ policyName := strings .Split (policy , "/" )[1 ]
138+ fmt .Printf ("❌ Found NetworkPolicy: \033 [31m%s\033 [0m with engress endPort field in namespace: \033 [31m%s\033 [0m\n " , policyName , policyNamespace )
139+ }
140+ }
141+ }
142+
143+ func printPoliciesWithCIDR (ingressPoliciesWithCIDR * []string , egressPoliciesWithCIDR * []string ) {
144+ if len (* ingressPoliciesWithCIDR ) == 0 && len (* egressPoliciesWithCIDR ) == 0 {
145+ fmt .Printf ("%-30s | %-30s \n " , "NetworkPolicy with CIDR" , "✅" )
146+ } else {
147+ fmt .Printf ("%-30s | %-30s \n " , "NetworkPolicy with CIDR" , "❌" )
148+ fmt .Println ("Policies affected:" )
149+ for _ , policy := range * ingressPoliciesWithCIDR {
150+ policyNamespace := strings .Split (policy , "/" )[0 ]
151+ policyName := strings .Split (policy , "/" )[1 ]
152+ fmt .Printf ("❌ Found NetworkPolicy: \033 [31m%s\033 [0m with ingress CIDR field in namespace: \033 [31m%s\033 [0m\n " , policyName , policyNamespace )
153+ }
154+ for _ , policy := range * egressPoliciesWithCIDR {
155+ policyNamespace := strings .Split (policy , "/" )[0 ]
156+ policyName := strings .Split (policy , "/" )[1 ]
157+ fmt .Printf ("❌ Found NetworkPolicy: \033 [31m%s\033 [0m with egress CIDR field in namespace: \033 [31m%s\033 [0m\n " , policyName , policyNamespace )
158+ }
159+ }
160+ }
161+
162+ func printEgressPolicies (egressPolicies * []string ) {
163+ if len (* egressPolicies ) == 0 {
164+ fmt .Printf ("%-30s | %-30s \n " , "NetworkPolicy with egress" , "✅" )
165+ } else {
166+ fmt .Printf ("%-30s | %-30s \n " , "NetworkPolicy with egress" , "❌" )
167+ fmt .Printf ("%-30s | %-30s \n " , "(Not allow all egress)" , "" )
168+ fmt .Println ("Policies affected:" )
169+ for _ , policy := range * egressPolicies {
170+ policyNamespace := strings .Split (policy , "/" )[0 ]
171+ policyName := strings .Split (policy , "/" )[1 ]
172+ fmt .Printf ("❌ Found NetworkPolicy: \033 [31m%s\033 [0m with egress field (non-allow all) in namespace: \033 [31m%s\033 [0m\n " , policyName , policyNamespace )
173+ }
174+ }
175+ }
176+
177+ func printUnsafeServices (unsafeServices * []string , noSelectorServices * []string ) {
178+ // If there is no unsafe services then migration is safe for services with extranalTrafficPolicy=Cluster
179+ if len (* unsafeServices ) == 0 {
180+ fmt .Printf ("%-30s | %-30s \n " , "Disruption for some" , "✅" )
181+ fmt .Printf ("%-30s | %-30s \n " , "Services with" , "" )
182+ fmt .Printf ("%-30s | %-30s \n " , "externalTrafficPolicy=Cluster" , "" )
183+ } else {
184+ fmt .Printf ("%-30s | %-30s \n " , "Disruption for some" , "❌" )
185+ fmt .Printf ("%-30s | %-30s \n " , "Services with" , "" )
186+ fmt .Printf ("%-30s | %-30s \n " , "externalTrafficPolicy=Cluster" , "" )
187+ fmt .Println ("Services affected:" )
188+ // If there are any no selector services or unsafe services then print them as they could be impacted by migration
189+ if len (* noSelectorServices ) > 0 {
190+ for _ , service := range * noSelectorServices {
191+ serviceName := strings .Split (service , "/" )[1 ]
192+ serviceNamespace := strings .Split (service , "/" )[0 ]
193+ fmt .Printf ("❌ Found Service: \033 [31m%s\033 [0m without selectors in namespace: \033 [31m%s\033 [0m\n " , serviceName , serviceNamespace )
194+ }
195+ }
196+ if len (* unsafeServices ) > 0 {
197+ for _ , service := range * unsafeServices {
198+ serviceName := strings .Split (service , "/" )[1 ]
199+ serviceNamespace := strings .Split (service , "/" )[0 ]
200+ fmt .Printf ("❌ Found Service: \033 [31m%s\033 [0m with selectors in namespace: \033 [31m%s\033 [0m\n " , serviceName , serviceNamespace )
201+ }
202+ }
203+ fmt .Println ("Manual investigation is required to evaluate if ingress is allowed to the service's backend Pods." )
204+ fmt .Println ("Please evaluate if these services would be impacted by migration." )
205+ }
206+ }
207+
208+ func checkEndportNetworkPolicies (policiesByNamespace * map [string ][]networkingv1.NetworkPolicy ) ([]string , []string ) {
209+ var ingressPoliciesWithEndport []string
210+ var egressPoliciesWithEndport []string
211+ for namespace , policies := range * policiesByNamespace {
113212 for _ , policy := range policies {
114213 // Check the ingress field for endport
115214 for _ , ingress := range policy .Spec .Ingress {
116- foundEndPort := checkEndportInPolicyRules (ingress .Ports , policy . Name , namespace , "ingress" , foundNetworkPolicyWithEndport )
215+ foundEndPort := checkEndportInPolicyRules (& ingress .Ports )
117216 if foundEndPort {
118- foundNetworkPolicyWithEndport = true
217+ ingressPoliciesWithEndport = append ( ingressPoliciesWithEndport , fmt . Sprintf ( "%s/%s" , namespace , policy . Name ))
119218 break
120219 }
121220 }
122221 for _ , egress := range policy .Spec .Egress {
123- foundEndPort := checkEndportInPolicyRules (egress .Ports , policy . Name , namespace , "egress" , foundNetworkPolicyWithEndport )
222+ foundEndPort := checkEndportInPolicyRules (& egress .Ports )
124223 if foundEndPort {
125- foundNetworkPolicyWithEndport = true
224+ egressPoliciesWithEndport = append ( egressPoliciesWithEndport , fmt . Sprintf ( "%s/%s" , namespace , policy . Name ))
126225 break
127226 }
128227 }
129228 }
130229 }
131- // Print no impact if no network policy has endport
132- if ! foundNetworkPolicyWithEndport {
133- log .Printf ("%-30s | %-30s \n " , "NetworkPolicy with endPort" , "✅" )
134- return false
135- }
136- return true
230+ return ingressPoliciesWithEndport , egressPoliciesWithEndport
137231}
138232
139- func checkEndportInPolicyRules (ports []networkingv1.NetworkPolicyPort , policyName , namespace string , direction string , foundNetworkPolicyWithEndport bool ) bool {
140- foundEndPort := false
141- for _ , port := range ports {
233+ func checkEndportInPolicyRules (ports * []networkingv1.NetworkPolicyPort ) bool {
234+ for _ , port := range * ports {
142235 if port .EndPort != nil {
143- foundEndPort = true
144- if ! foundNetworkPolicyWithEndport {
145- log .Printf ("%-30s | %-30s \n " , "NetworkPolicy with endPort" , "❌" )
146- log .Println ("Policies affected:" )
147- }
148- log .Printf ("❌ Found NetworkPolicy: \033 [31m%s\033 [0m with %s endPort field in namespace: \033 [31m%s\033 [0m\n " , policyName , direction , namespace )
149- break
236+ return true
150237 }
151238 }
152- return foundEndPort
239+ return false
153240}
154241
155- func checkCIDRNetworkPolicies (policiesByNamespace map [string ][]networkingv1.NetworkPolicy ) bool {
156- foundNetworkPolicyWithCIDR := false
157- for namespace , policies := range policiesByNamespace {
242+ func checkCIDRNetworkPolicies (policiesByNamespace * map [string ][]networkingv1.NetworkPolicy ) ([]string , []string ) {
243+ var ingressPoliciesWithCIDR []string
244+ var egressPoliciesWithCIDR []string
245+ for namespace , policies := range * policiesByNamespace {
158246 for _ , policy := range policies {
159247 // Check the ingress field for cidr
160248 for _ , ingress := range policy .Spec .Ingress {
161- foundCIDRIngress := checkCIDRInPolicyRules (ingress .From , policy . Name , namespace , "ingress" , foundNetworkPolicyWithCIDR )
249+ foundCIDRIngress := checkCIDRInPolicyRules (& ingress .From )
162250 if foundCIDRIngress {
163- foundNetworkPolicyWithCIDR = true
251+ ingressPoliciesWithCIDR = append ( ingressPoliciesWithCIDR , fmt . Sprintf ( "%s/%s" , namespace , policy . Name ))
164252 break
165253 }
166254 }
167255 // Check the egress field for cidr
168256 for _ , egress := range policy .Spec .Egress {
169- foundCIDREgress := checkCIDRInPolicyRules (egress .To , policy . Name , namespace , "egress" , foundNetworkPolicyWithCIDR )
257+ foundCIDREgress := checkCIDRInPolicyRules (& egress .To )
170258 if foundCIDREgress {
171- foundNetworkPolicyWithCIDR = true
259+ egressPoliciesWithCIDR = append ( egressPoliciesWithCIDR , fmt . Sprintf ( "%s/%s" , namespace , policy . Name ))
172260 break
173261 }
174262 }
175263 }
176264 }
177- // Print no impact if no network policy has cidr
178- if ! foundNetworkPolicyWithCIDR {
179- log .Printf ("%-30s | %-30s \n " , "NetworkPolicy with cidr" , "✅" )
180- return false
181- }
182- return true
265+ return ingressPoliciesWithCIDR , egressPoliciesWithCIDR
183266}
184267
185268// Check for CIDR in ingress or egress rules
186- func checkCIDRInPolicyRules (rules []networkingv1.NetworkPolicyPeer , policyName , namespace string , direction string , foundNetworkPolicyWithCIDR bool ) bool {
187- foundCIDR := false
188- for _ , rule := range rules {
269+ func checkCIDRInPolicyRules (rules * []networkingv1.NetworkPolicyPeer ) bool {
270+ for _ , rule := range * rules {
189271 if rule .IPBlock != nil && rule .IPBlock .CIDR != "" {
190- foundCIDR = true
191- if ! foundNetworkPolicyWithCIDR {
192- log .Printf ("%-30s | %-30s \n " , "NetworkPolicy with cidr" , "❌" )
193- log .Println ("Policies affected:" )
194- }
195- log .Printf ("❌ Found NetworkPolicy: \033 [31m%s\033 [0m with %s cidr field in namespace: \033 [31m%s\033 [0m\n " , policyName , direction , namespace )
196- break
272+ return true
197273 }
198274 }
199- return foundCIDR
275+ return false
200276}
201277
202- func checkForEgressPolicies (policiesByNamespace map [string ][]networkingv1.NetworkPolicy ) bool {
203- foundNetworkPolicyWithEgress := false
204- for namespace , policies := range policiesByNamespace {
278+ func checkForEgressPolicies (policiesByNamespace * map [string ][]networkingv1.NetworkPolicy ) [] string {
279+ var egressPolicies [] string
280+ for namespace , policies := range * policiesByNamespace {
205281 for _ , policy := range policies {
206282 for _ , egress := range policy .Spec .Egress {
207283 // If the policy has a egress field thats not an egress allow all flag it
208284 if len (egress .To ) > 0 || len (egress .Ports ) > 0 {
209- if ! foundNetworkPolicyWithEgress {
210- log .Printf ("%-30s | %-30s \n " , "NetworkPolicy with egress" , "❌" )
211- log .Printf ("%-30s | %-30s \n " , "(Not allow all egress)" , "" )
212- log .Println ("Policies affected:" )
213- foundNetworkPolicyWithEgress = true
214- }
215- log .Printf ("❌ Found NetworkPolicy: \033 [31m%s\033 [0m with egress field (non-allow all) in namespace: \033 [31m%s\033 [0m\n " , policy .Name , namespace )
285+ egressPolicies = append (egressPolicies , fmt .Sprintf ("%s/%s" , namespace , policy .Name ))
216286 break
217287 }
218288 }
219289 }
220290 }
221- if ! foundNetworkPolicyWithEgress {
222- log .Printf ("%-30s | %-30s \n " , "NetworkPolicy with egress" , "✅" )
223- return false
224- }
225- return true
291+ return egressPolicies
226292}
227293
228- func checkExternalTrafficPolicyServices (namespaces * corev1.NamespaceList , servicesByNamespace map [string ][]corev1.Service , policiesByNamespace map [string ][]networkingv1.NetworkPolicy ) bool {
294+ func checkExternalTrafficPolicyServices (namespaces * corev1.NamespaceList , servicesByNamespace * map [string ][]corev1.Service , policiesByNamespace * map [string ][]networkingv1.NetworkPolicy ) ([] string , [] string ) {
229295 var servicesAtRisk , noSelectorServices , safeServices []string
230296
231297 for _ , namespace := range namespaces .Items {
@@ -260,42 +326,12 @@ func checkExternalTrafficPolicyServices(namespaces *corev1.NamespaceList, servic
260326 // Get the services that are at risk but not in the safe services or no selector services lists
261327 unsafeServices := difference (servicesAtRisk , safeServices , noSelectorServices )
262328
263- // If there is no unsafe services then migration is safe for services with extranalTrafficPolicy=Cluster
264- if len (unsafeServices ) == 0 {
265- fmt .Printf ("%-30s | %-30s \n " , "Disruption for some" , "✅" )
266- fmt .Printf ("%-30s | %-30s \n " , "Services with" , "" )
267- fmt .Printf ("%-30s | %-30s \n " , "externalTrafficPolicy=Cluster" , "" )
268- return false
269- } else {
270- fmt .Printf ("%-30s | %-30s \n " , "Disruption for some" , "❌" )
271- fmt .Printf ("%-30s | %-30s \n " , "Services with" , "" )
272- fmt .Printf ("%-30s | %-30s \n " , "externalTrafficPolicy=Cluster" , "" )
273- fmt .Println ("Services affected:" )
274- // If there are any no selector services or unsafe services then print them as they could be impacted by migration
275- if len (noSelectorServices ) > 0 {
276- for _ , service := range noSelectorServices {
277- serviceName := strings .Split (service , "/" )[1 ]
278- serviceNamespace := strings .Split (service , "/" )[0 ]
279- fmt .Printf ("❌ Found Service: \033 [31m%s\033 [0m without selectors in namespace: \033 [31m%s\033 [0m\n " , serviceName , serviceNamespace )
280- }
281- }
282- if len (unsafeServices ) > 0 {
283- for _ , service := range unsafeServices {
284- serviceName := strings .Split (service , "/" )[1 ]
285- serviceNamespace := strings .Split (service , "/" )[0 ]
286- fmt .Printf ("❌ Found Service: \033 [31m%s\033 [0m with selectors in namespace: \033 [31m%s\033 [0m\n " , serviceName , serviceNamespace )
287- }
288- }
289- fmt .Println ("Manual investigation is required to evaluate if ingress is allowed to the service's backend Pods." )
290- fmt .Println ("Please evaluate if these services would be impacted by migration." )
291- return true
292- }
293-
329+ return unsafeServices , noSelectorServices
294330}
295331
296- func hasIngressPolicies (policies []networkingv1.NetworkPolicy ) bool {
332+ func hasIngressPolicies (policies * []networkingv1.NetworkPolicy ) bool {
297333 // Check if any policy is ingress (including allow all and deny all)
298- for _ , policy := range policies {
334+ for _ , policy := range * policies {
299335 for _ , policyType := range policy .Spec .PolicyTypes {
300336 if policyType == networkingv1 .PolicyTypeIngress {
301337 return true
@@ -375,6 +411,10 @@ func checkServiceTargetPortMatchPolicyPorts(servicePorts []corev1.ServicePort, p
375411 // Check if all the services target ports are in the policies ingress ports
376412 serviceTargetPortPolicyPort := false
377413 for _ , policyPort := range policyPorts {
414+ // Check if the policys port exists
415+ if policyPort .Port == nil {
416+ return false
417+ }
378418 if servicePort .TargetPort .IntValue () == int (policyPort .Port .IntVal ) && string (servicePort .Protocol ) == string (* policyPort .Protocol ) {
379419 serviceTargetPortPolicyPort = true
380420 break
0 commit comments