From 83f3b1a4aae3304987db55111ca73104ed1cfc53 Mon Sep 17 00:00:00 2001 From: jaynis Date: Mon, 11 Mar 2024 16:22:17 +0100 Subject: [PATCH 1/5] added support for loadBalancerSourceRanges Signed-off-by: jaynis --- api/v1alpha1/envoyproxy_types.go | 1 + api/v1alpha1/shared_types.go | 8 +++ .../validation/envoyproxy_validate.go | 6 +++ .../validation/envoyproxy_validate_test.go | 43 ++++++++++++++++ .../gateway.envoyproxy.io_envoyproxies.yaml | 16 ++++++ .../kubernetes/resource/resource.go | 3 ++ .../kubernetes/resource/resource_test.go | 13 +++++ site/content/en/latest/api/extension_types.md | 1 + test/cel-validation/envoyproxy_test.go | 50 +++++++++++++++++++ 9 files changed, 141 insertions(+) diff --git a/api/v1alpha1/envoyproxy_types.go b/api/v1alpha1/envoyproxy_types.go index e11da79d850..b90208c5072 100644 --- a/api/v1alpha1/envoyproxy_types.go +++ b/api/v1alpha1/envoyproxy_types.go @@ -124,6 +124,7 @@ type EnvoyProxyKubernetesProvider struct { // // +optional // +kubebuilder:validation:XValidation:message="allocateLoadBalancerNodePorts can only be set for LoadBalancer type",rule="!has(self.allocateLoadBalancerNodePorts) || self.type == 'LoadBalancer'" + // +kubebuilder:validation:XValidation:message="loadBalancerSourceRanges can only be set for LoadBalancer type",rule="!has(self.loadBalancerSourceRanges) || self.type == 'LoadBalancer'" // +kubebuilder:validation:XValidation:message="loadBalancerIP can only be set for LoadBalancer type",rule="!has(self.loadBalancerIP) || self.type == 'LoadBalancer'" // +kubebuilder:validation:XValidation:message="loadBalancerIP must be a valid IPv4 address",rule="!has(self.loadBalancerIP) || self.loadBalancerIP.matches(r\"^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.|$)){4})\")" EnvoyService *KubernetesServiceSpec `json:"envoyService,omitempty"` diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index a75f7af43cd..a835ba6022a 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -239,6 +239,14 @@ type KubernetesServiceSpec struct { // +optional AllocateLoadBalancerNodePorts *bool `json:"allocateLoadBalancerNodePorts,omitempty"` + // LoadBalancerSourceRanges defines a list of allowed IP addresses which will be configured as + // firewall rules on the platform providers load balancer. This is not guaranteed to be working as + // it happens outside of kubernetes and has to be supported and handled by the platform provider. + // This field may only be set for services with type LoadBalancer and will be cleared if the type + // is changed to any other type. + // +optional + LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges,omitempty"` + // LoadBalancerIP defines the IP Address of the underlying load balancer service. This field // may be ignored if the load balancer provider does not support this feature. // This field has been deprecated in Kubernetes, but it is still used for setting the IP Address in some cloud diff --git a/api/v1alpha1/validation/envoyproxy_validate.go b/api/v1alpha1/validation/envoyproxy_validate.go index a61973dcaaf..fa6beb59914 100644 --- a/api/v1alpha1/validation/envoyproxy_validate.go +++ b/api/v1alpha1/validation/envoyproxy_validate.go @@ -98,6 +98,12 @@ func validateService(spec *egv1a1.EnvoyProxySpec) []error { errs = append(errs, fmt.Errorf("allocateLoadBalancerNodePorts can only be set for %v type", egv1a1.ServiceTypeLoadBalancer)) } } + if serviceType, serviceLoadBalancerSourceRanges := + spec.Provider.Kubernetes.EnvoyService.Type, spec.Provider.Kubernetes.EnvoyService.LoadBalancerSourceRanges; serviceType != nil && serviceLoadBalancerSourceRanges != nil { + if *serviceType != egv1a1.ServiceTypeLoadBalancer { + errs = append(errs, fmt.Errorf("loadBalancerSourceRanges can only be set for %v type", egv1a1.ServiceTypeLoadBalancer)) + } + } if serviceType, serviceLoadBalancerIP := spec.Provider.Kubernetes.EnvoyService.Type, spec.Provider.Kubernetes.EnvoyService.LoadBalancerIP; serviceType != nil && serviceLoadBalancerIP != nil { if *serviceType != egv1a1.ServiceTypeLoadBalancer { errs = append(errs, fmt.Errorf("loadBalancerIP can only be set for %v type", egv1a1.ServiceTypeLoadBalancer)) diff --git a/api/v1alpha1/validation/envoyproxy_validate_test.go b/api/v1alpha1/validation/envoyproxy_validate_test.go index f13e8a921fb..17137c4a15b 100644 --- a/api/v1alpha1/validation/envoyproxy_validate_test.go +++ b/api/v1alpha1/validation/envoyproxy_validate_test.go @@ -212,6 +212,49 @@ func TestValidateEnvoyProxy(t *testing.T) { }, expected: false, }, + + { + name: "envoy service type 'LoadBalancer' with loadBalancerSourceRanges", + proxy: &egv1a1.EnvoyProxy{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test", + }, + Spec: egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyService: &egv1a1.KubernetesServiceSpec{ + Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeLoadBalancer), + LoadBalancerSourceRanges: []string{"1.1.1.1"}, + }, + }, + }, + }, + }, + expected: true, + }, + { + name: "non envoy service type 'LoadBalancer' with loadBalancerSourceRanges", + proxy: &egv1a1.EnvoyProxy{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test", + }, + Spec: egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyService: &egv1a1.KubernetesServiceSpec{ + Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeClusterIP), + LoadBalancerSourceRanges: []string{"1.1.1.1"}, + }, + }, + }, + }, + }, + expected: false, + }, { name: "envoy service type 'LoadBalancer' with valid loadBalancerIP", proxy: &egv1a1.EnvoyProxy{ diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index e22f535aecf..7a505e9e554 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -6566,6 +6566,18 @@ spec: but it is still used for setting the IP Address in some cloud providers such as GCP. type: string + loadBalancerSourceRanges: + description: LoadBalancerSourceRanges defines a list of + allowed IP addresses which will be configured as firewall + rules on the platform providers load balancer. This + is not guaranteed to be working as it happens outside + of kubernetes and has to be supported and handled by + the platform provider. This field may only be set for + services with type LoadBalancer and will be cleared + if the type is changed to any other type. + items: + type: string + type: array type: default: LoadBalancer description: Type determines how the Service is exposed. @@ -6587,6 +6599,10 @@ spec: LoadBalancer type rule: '!has(self.allocateLoadBalancerNodePorts) || self.type == ''LoadBalancer''' + - message: loadBalancerSourceRanges can only be set for LoadBalancer + type + rule: '!has(self.loadBalancerSourceRanges) || self.type + == ''LoadBalancer''' - message: loadBalancerIP can only be set for LoadBalancer type rule: '!has(self.loadBalancerIP) || self.type == ''LoadBalancer''' diff --git a/internal/infrastructure/kubernetes/resource/resource.go b/internal/infrastructure/kubernetes/resource/resource.go index 0a98e155e06..014ad32668b 100644 --- a/internal/infrastructure/kubernetes/resource/resource.go +++ b/internal/infrastructure/kubernetes/resource/resource.go @@ -37,6 +37,9 @@ func ExpectedServiceSpec(service *egv1a1.KubernetesServiceSpec) corev1.ServiceSp if service.AllocateLoadBalancerNodePorts != nil { serviceSpec.AllocateLoadBalancerNodePorts = service.AllocateLoadBalancerNodePorts } + if service.LoadBalancerSourceRanges != nil && len(service.LoadBalancerSourceRanges) > 0 { + serviceSpec.LoadBalancerSourceRanges = service.LoadBalancerSourceRanges + } if service.LoadBalancerIP != nil { serviceSpec.LoadBalancerIP = *service.LoadBalancerIP } diff --git a/internal/infrastructure/kubernetes/resource/resource_test.go b/internal/infrastructure/kubernetes/resource/resource_test.go index 61bd0fb2444..80f801755e7 100644 --- a/internal/infrastructure/kubernetes/resource/resource_test.go +++ b/internal/infrastructure/kubernetes/resource/resource_test.go @@ -77,6 +77,19 @@ func TestExpectedServiceSpec(t *testing.T) { ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyTypeLocal, }, }, + { + name: "LoadBalancerWithLoadBalancerSourceRanges", + args: args{service: &egv1a1.KubernetesServiceSpec{ + Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeLoadBalancer), + LoadBalancerSourceRanges: []string{"1.1.1.1"}, + }}, + want: corev1.ServiceSpec{ + Type: corev1.ServiceTypeLoadBalancer, + LoadBalancerSourceRanges: []string{"1.1.1.1"}, + SessionAffinity: corev1.ServiceAffinityNone, + ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyTypeLocal, + }, + }, { name: "LoadBalancerWithLoadBalancerIP", args: args{service: &egv1a1.KubernetesServiceSpec{ diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index ab2f40bfcb2..663599548bd 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -1244,6 +1244,7 @@ _Appears in:_ | `type` _[ServiceType](#servicetype)_ | Type determines how the Service is exposed. Defaults to LoadBalancer. Valid options are ClusterIP, LoadBalancer and NodePort. "LoadBalancer" means a service will be exposed via an external load balancer (if the cloud provider supports it). "ClusterIP" means a service will only be accessible inside the cluster, via the cluster IP. "NodePort" means a service will be exposed on a static Port on all Nodes of the cluster. | | `loadBalancerClass` _string_ | LoadBalancerClass, when specified, allows for choosing the LoadBalancer provider implementation if more than one are available or is otherwise expected to be specified | | `allocateLoadBalancerNodePorts` _boolean_ | AllocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for services with type LoadBalancer. Default is "true". It may be set to "false" if the cluster load-balancer does not rely on NodePorts. If the caller requests specific NodePorts (by specifying a value), those requests will be respected, regardless of this field. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. | +| `loadBalancerSourceRanges` _string array_ | LoadBalancerSourceRanges defines a list of allowed IP addresses which will be configured as firewall rules on the platform providers load balancer. This is not guaranteed to be working as it happens outside of kubernetes and has to be supported and handled by the platform provider. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. | | `loadBalancerIP` _string_ | LoadBalancerIP defines the IP Address of the underlying load balancer service. This field may be ignored if the load balancer provider does not support this feature. This field has been deprecated in Kubernetes, but it is still used for setting the IP Address in some cloud providers such as GCP. | | `externalTrafficPolicy` _[ServiceExternalTrafficPolicy](#serviceexternaltrafficpolicy)_ | ExternalTrafficPolicy determines the externalTrafficPolicy for the Envoy Service. Valid options are Local and Cluster. Default is "Local". "Local" means traffic will only go to pods on the node receiving the traffic. "Cluster" means connections are loadbalanced to all pods in the cluster. | diff --git a/test/cel-validation/envoyproxy_test.go b/test/cel-validation/envoyproxy_test.go index 9f029534b12..a42cd5949f5 100644 --- a/test/cel-validation/envoyproxy_test.go +++ b/test/cel-validation/envoyproxy_test.go @@ -119,6 +119,56 @@ func TestEnvoyProxyProvider(t *testing.T) { }, wantErrors: []string{"allocateLoadBalancerNodePorts can only be set for LoadBalancer type"}, }, + { + desc: "loadBalancerSourceRanges-pass-case1", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyService: &egv1a1.KubernetesServiceSpec{ + Type: ptr.To(egv1a1.ServiceTypeLoadBalancer), + LoadBalancerSourceRanges: []string{"1.1.1.1"}, + }, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "loadBalancerSourceRanges-pass-case2", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyService: &egv1a1.KubernetesServiceSpec{ + Type: ptr.To(egv1a1.ServiceTypeClusterIP), + }, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "loadBalancerSourceRanges-fail", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyService: &egv1a1.KubernetesServiceSpec{ + Type: ptr.To(egv1a1.ServiceTypeClusterIP), + LoadBalancerSourceRanges: []string{"1.1.1.1"}, + }, + }, + }, + } + }, + wantErrors: []string{"loadBalancerSourceRanges can only be set for LoadBalancer type"}, + }, { desc: "ServiceTypeLoadBalancer-with-valid-IP", mutate: func(envoy *egv1a1.EnvoyProxy) { From abbdc65239e4b96c8ca0ccefbb1ae4c834ece61d Mon Sep 17 00:00:00 2001 From: jaynis Date: Mon, 11 Mar 2024 17:07:44 +0100 Subject: [PATCH 2/5] fixed auto-generated files Signed-off-by: jaynis --- api/v1alpha1/zz_generated.deepcopy.go | 5 +++++ site/content/en/latest/api/extension_types.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 1e02bc720f7..273a2c6f845 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -2319,6 +2319,11 @@ func (in *KubernetesServiceSpec) DeepCopyInto(out *KubernetesServiceSpec) { *out = new(bool) **out = **in } + if in.LoadBalancerSourceRanges != nil { + in, out := &in.LoadBalancerSourceRanges, &out.LoadBalancerSourceRanges + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.LoadBalancerIP != nil { in, out := &in.LoadBalancerIP, &out.LoadBalancerIP *out = new(string) diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 9c5e35569b8..c6167ea589a 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -1500,7 +1500,7 @@ _Appears in:_ | `type` | _[ServiceType](#servicetype)_ | false | Type determines how the Service is exposed. Defaults to LoadBalancer. Valid options are ClusterIP, LoadBalancer and NodePort. "LoadBalancer" means a service will be exposed via an external load balancer (if the cloud provider supports it). "ClusterIP" means a service will only be accessible inside the cluster, via the cluster IP. "NodePort" means a service will be exposed on a static Port on all Nodes of the cluster. | | `loadBalancerClass` | _string_ | false | LoadBalancerClass, when specified, allows for choosing the LoadBalancer provider implementation if more than one are available or is otherwise expected to be specified | | `allocateLoadBalancerNodePorts` | _boolean_ | false | AllocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for services with type LoadBalancer. Default is "true". It may be set to "false" if the cluster load-balancer does not rely on NodePorts. If the caller requests specific NodePorts (by specifying a value), those requests will be respected, regardless of this field. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. | -| `loadBalancerSourceRanges` _string array_ | LoadBalancerSourceRanges defines a list of allowed IP addresses which will be configured as firewall rules on the platform providers load balancer. This is not guaranteed to be working as it happens outside of kubernetes and has to be supported and handled by the platform provider. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. | +| `loadBalancerSourceRanges` | _string array_ | false | LoadBalancerSourceRanges defines a list of allowed IP addresses which will be configured as firewall rules on the platform providers load balancer. This is not guaranteed to be working as it happens outside of kubernetes and has to be supported and handled by the platform provider. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. | | `loadBalancerIP` | _string_ | false | LoadBalancerIP defines the IP Address of the underlying load balancer service. This field may be ignored if the load balancer provider does not support this feature. This field has been deprecated in Kubernetes, but it is still used for setting the IP Address in some cloud providers such as GCP. | | `externalTrafficPolicy` | _[ServiceExternalTrafficPolicy](#serviceexternaltrafficpolicy)_ | false | ExternalTrafficPolicy determines the externalTrafficPolicy for the Envoy Service. Valid options are Local and Cluster. Default is "Local". "Local" means traffic will only go to pods on the node receiving the traffic. "Cluster" means connections are loadbalanced to all pods in the cluster. | | `patch` | _[KubernetesPatchSpec](#kubernetespatchspec)_ | false | Patch defines how to perform the patch operation to the service | From 9421d98d49e5f955a4ad6d62320afd00fad273d3 Mon Sep 17 00:00:00 2001 From: jaynis Date: Mon, 11 Mar 2024 17:18:12 +0100 Subject: [PATCH 3/5] added missing kube validation Signed-off-by: jaynis --- api/v1alpha1/shared_types.go | 1 + .../crds/generated/gateway.envoyproxy.io_envoyproxies.yaml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index 926981e4157..a3df132551c 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -219,6 +219,7 @@ const ( // KubernetesServiceSpec defines the desired state of the Kubernetes service resource. // +kubebuilder:validation:XValidation:message="allocateLoadBalancerNodePorts can only be set for LoadBalancer type",rule="!has(self.allocateLoadBalancerNodePorts) || self.type == 'LoadBalancer'" +// +kubebuilder:validation:XValidation:message="loadBalancerSourceRanges can only be set for LoadBalancer type",rule="!has(self.loadBalancerSourceRanges) || self.type == 'LoadBalancer'" // +kubebuilder:validation:XValidation:message="loadBalancerIP can only be set for LoadBalancer type",rule="!has(self.loadBalancerIP) || self.type == 'LoadBalancer'" type KubernetesServiceSpec struct { // Annotations that should be appended to the service. diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index c6c73d8dfe1..28d7591f034 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -6642,6 +6642,10 @@ spec: LoadBalancer type rule: '!has(self.allocateLoadBalancerNodePorts) || self.type == ''LoadBalancer''' + - message: loadBalancerSourceRanges can only be set for LoadBalancer + type + rule: '!has(self.loadBalancerSourceRanges) || self.type + == ''LoadBalancer''' - message: loadBalancerIP can only be set for LoadBalancer type rule: '!has(self.loadBalancerIP) || self.type == ''LoadBalancer''' From b37bb251866c0fec6f42b92521557b5a83864f15 Mon Sep 17 00:00:00 2001 From: jaynis Date: Fri, 12 Apr 2024 17:53:11 +0200 Subject: [PATCH 4/5] added subnet validation for loadBalancerSourceRanges Signed-off-by: jaynis --- api/v1alpha1/shared_types.go | 1 + api/v1alpha1/validation/envoyproxy_validate.go | 7 +++++++ .../validation/envoyproxy_validate_test.go | 4 ++-- .../gateway.envoyproxy.io_envoyproxies.yaml | 18 ++++++++++-------- .../kubernetes/resource/resource_test.go | 4 ++-- site/content/en/latest/api/extension_types.md | 10 ++-------- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index cce1eaccd79..bdc4efc8590 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -256,6 +256,7 @@ type KubernetesServiceSpec struct { // it happens outside of kubernetes and has to be supported and handled by the platform provider. // This field may only be set for services with type LoadBalancer and will be cleared if the type // is changed to any other type. + // +kubebuilder:validation:XValidation:message="loadBalancerSourceRange must be a valid IPv4 subnet",rule="self.all(lbsr, lbsr.matches(r\"^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.|\\/\\d{1,2}$)){4})\"))" // +optional LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges,omitempty"` diff --git a/api/v1alpha1/validation/envoyproxy_validate.go b/api/v1alpha1/validation/envoyproxy_validate.go index 29424780f46..b885d8fadfc 100644 --- a/api/v1alpha1/validation/envoyproxy_validate.go +++ b/api/v1alpha1/validation/envoyproxy_validate.go @@ -8,6 +8,7 @@ package validation import ( "errors" "fmt" + "net" "net/netip" bootstrapv3 "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v3" @@ -120,6 +121,12 @@ func validateService(spec *egv1a1.EnvoyProxySpec) []error { if *serviceType != egv1a1.ServiceTypeLoadBalancer { errs = append(errs, fmt.Errorf("loadBalancerSourceRanges can only be set for %v type", egv1a1.ServiceTypeLoadBalancer)) } + + for _, serviceLoadBalancerSourceRange := range serviceLoadBalancerSourceRanges { + if ip, _, err := net.ParseCIDR(serviceLoadBalancerSourceRange); err != nil || ip.To4() == nil { + errs = append(errs, fmt.Errorf("loadBalancerSourceRange:%s is an invalid IPv4 subnet", serviceLoadBalancerSourceRange)) + } + } } if serviceType, serviceLoadBalancerIP := spec.Provider.Kubernetes.EnvoyService.Type, spec.Provider.Kubernetes.EnvoyService.LoadBalancerIP; serviceType != nil && serviceLoadBalancerIP != nil { if *serviceType != egv1a1.ServiceTypeLoadBalancer { diff --git a/api/v1alpha1/validation/envoyproxy_validate_test.go b/api/v1alpha1/validation/envoyproxy_validate_test.go index 40144b0df2e..27ab08f3091 100644 --- a/api/v1alpha1/validation/envoyproxy_validate_test.go +++ b/api/v1alpha1/validation/envoyproxy_validate_test.go @@ -227,7 +227,7 @@ func TestValidateEnvoyProxy(t *testing.T) { Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ EnvoyService: &egv1a1.KubernetesServiceSpec{ Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeLoadBalancer), - LoadBalancerSourceRanges: []string{"1.1.1.1"}, + LoadBalancerSourceRanges: []string{"1.1.1.1/32"}, }, }, }, @@ -248,7 +248,7 @@ func TestValidateEnvoyProxy(t *testing.T) { Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ EnvoyService: &egv1a1.KubernetesServiceSpec{ Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeClusterIP), - LoadBalancerSourceRanges: []string{"1.1.1.1"}, + LoadBalancerSourceRanges: []string{"1.1.1.1/32"}, }, }, }, diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 399aa1ac3aa..e499c461fe1 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -5762,17 +5762,19 @@ spec: - message: loadBalancerIP must be a valid IPv4 address rule: self.matches(r"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$") loadBalancerSourceRanges: - description: LoadBalancerSourceRanges defines a list of - allowed IP addresses which will be configured as firewall - rules on the platform providers load balancer. This - is not guaranteed to be working as it happens outside - of kubernetes and has to be supported and handled by - the platform provider. This field may only be set for - services with type LoadBalancer and will be cleared - if the type is changed to any other type. + description: |- + LoadBalancerSourceRanges defines a list of allowed IP addresses which will be configured as + firewall rules on the platform providers load balancer. This is not guaranteed to be working as + it happens outside of kubernetes and has to be supported and handled by the platform provider. + This field may only be set for services with type LoadBalancer and will be cleared if the type + is changed to any other type. items: type: string type: array + x-kubernetes-validations: + - message: loadBalancerSourceRange must be a valid IPv4 + subnet + rule: self.all(lbsr, lbsr.matches(r"^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|\/\d{1,2}$)){4})")) patch: description: Patch defines how to perform the patch operation to the service diff --git a/internal/infrastructure/kubernetes/resource/resource_test.go b/internal/infrastructure/kubernetes/resource/resource_test.go index e6e40970861..590a699df51 100644 --- a/internal/infrastructure/kubernetes/resource/resource_test.go +++ b/internal/infrastructure/kubernetes/resource/resource_test.go @@ -81,11 +81,11 @@ func TestExpectedServiceSpec(t *testing.T) { name: "LoadBalancerWithLoadBalancerSourceRanges", args: args{service: &egv1a1.KubernetesServiceSpec{ Type: egv1a1.GetKubernetesServiceType(egv1a1.ServiceTypeLoadBalancer), - LoadBalancerSourceRanges: []string{"1.1.1.1"}, + LoadBalancerSourceRanges: []string{"1.1.1.1/32"}, }}, want: corev1.ServiceSpec{ Type: corev1.ServiceTypeLoadBalancer, - LoadBalancerSourceRanges: []string{"1.1.1.1"}, + LoadBalancerSourceRanges: []string{"1.1.1.1/32"}, SessionAffinity: corev1.ServiceAffinityNone, ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyTypeLocal, }, diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 23e17b3dfbd..bf21ddbcb37 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -1689,19 +1689,12 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | -| `annotations` | _object (keys:string, values:string)_ | false | Annotations that should be appended to the service. By default, no annotations are appended. | -| `type` | _[ServiceType](#servicetype)_ | false | Type determines how the Service is exposed. Defaults to LoadBalancer. Valid options are ClusterIP, LoadBalancer and NodePort. "LoadBalancer" means a service will be exposed via an external load balancer (if the cloud provider supports it). "ClusterIP" means a service will only be accessible inside the cluster, via the cluster IP. "NodePort" means a service will be exposed on a static Port on all Nodes of the cluster. | -| `loadBalancerClass` | _string_ | false | LoadBalancerClass, when specified, allows for choosing the LoadBalancer provider implementation if more than one are available or is otherwise expected to be specified | -| `allocateLoadBalancerNodePorts` | _boolean_ | false | AllocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for services with type LoadBalancer. Default is "true". It may be set to "false" if the cluster load-balancer does not rely on NodePorts. If the caller requests specific NodePorts (by specifying a value), those requests will be respected, regardless of this field. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. | -| `loadBalancerSourceRanges` | _string array_ | false | LoadBalancerSourceRanges defines a list of allowed IP addresses which will be configured as firewall rules on the platform providers load balancer. This is not guaranteed to be working as it happens outside of kubernetes and has to be supported and handled by the platform provider. This field may only be set for services with type LoadBalancer and will be cleared if the type is changed to any other type. | -| `loadBalancerIP` | _string_ | false | LoadBalancerIP defines the IP Address of the underlying load balancer service. This field may be ignored if the load balancer provider does not support this feature. This field has been deprecated in Kubernetes, but it is still used for setting the IP Address in some cloud providers such as GCP. | -| `externalTrafficPolicy` | _[ServiceExternalTrafficPolicy](#serviceexternaltrafficpolicy)_ | false | ExternalTrafficPolicy determines the externalTrafficPolicy for the Envoy Service. Valid options are Local and Cluster. Default is "Local". "Local" means traffic will only go to pods on the node receiving the traffic. "Cluster" means connections are loadbalanced to all pods in the cluster. | -| `patch` | _[KubernetesPatchSpec](#kubernetespatchspec)_ | false | Patch defines how to perform the patch operation to the service | | `annotations` | _object (keys:string, values:string)_ | false | Annotations that should be appended to the service.
By default, no annotations are appended. | | `type` | _[ServiceType](#servicetype)_ | false | Type determines how the Service is exposed. Defaults to LoadBalancer.
Valid options are ClusterIP, LoadBalancer and NodePort.
"LoadBalancer" means a service will be exposed via an external load balancer (if the cloud provider supports it).
"ClusterIP" means a service will only be accessible inside the cluster, via the cluster IP.
"NodePort" means a service will be exposed on a static Port on all Nodes of the cluster. | | `loadBalancerClass` | _string_ | false | LoadBalancerClass, when specified, allows for choosing the LoadBalancer provider
implementation if more than one are available or is otherwise expected to be specified | | `allocateLoadBalancerNodePorts` | _boolean_ | false | AllocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for
services with type LoadBalancer. Default is "true". It may be set to "false" if the cluster
load-balancer does not rely on NodePorts. If the caller requests specific NodePorts (by specifying a
value), those requests will be respected, regardless of this field. This field may only be set for
services with type LoadBalancer and will be cleared if the type is changed to any other type. | +| `loadBalancerSourceRanges` | _string array_ | false | LoadBalancerSourceRanges defines a list of allowed IP addresses which will be configured as
firewall rules on the platform providers load balancer. This is not guaranteed to be working as
it happens outside of kubernetes and has to be supported and handled by the platform provider.
This field may only be set for services with type LoadBalancer and will be cleared if the type
is changed to any other type. | | `loadBalancerIP` | _string_ | false | LoadBalancerIP defines the IP Address of the underlying load balancer service. This field
may be ignored if the load balancer provider does not support this feature.
This field has been deprecated in Kubernetes, but it is still used for setting the IP Address in some cloud
providers such as GCP. | | `externalTrafficPolicy` | _[ServiceExternalTrafficPolicy](#serviceexternaltrafficpolicy)_ | false | ExternalTrafficPolicy determines the externalTrafficPolicy for the Envoy Service. Valid options
are Local and Cluster. Default is "Local". "Local" means traffic will only go to pods on the node
receiving the traffic. "Cluster" means connections are loadbalanced to all pods in the cluster. | | `patch` | _[KubernetesPatchSpec](#kubernetespatchspec)_ | false | Patch defines how to perform the patch operation to the service | @@ -2921,3 +2914,4 @@ _Appears in:_ | --- | --- | --- | --- | | `numTrustedHops` | _integer_ | false | NumTrustedHops controls the number of additional ingress proxy hops from the right side of XFF HTTP
headers to trust when determining the origin client's IP address.
Refer to https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#x-forwarded-for
for more details. | + From f26c30095c6428d2277a8a7cb32b8560e97ec439 Mon Sep 17 00:00:00 2001 From: jaynis Date: Wed, 17 Apr 2024 11:38:35 +0200 Subject: [PATCH 5/5] removed CEL validation rule again due to cost budget violation Signed-off-by: jaynis --- api/v1alpha1/shared_types.go | 1 - .../crds/generated/gateway.envoyproxy.io_envoyproxies.yaml | 4 ---- 2 files changed, 5 deletions(-) diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index bdc4efc8590..cce1eaccd79 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -256,7 +256,6 @@ type KubernetesServiceSpec struct { // it happens outside of kubernetes and has to be supported and handled by the platform provider. // This field may only be set for services with type LoadBalancer and will be cleared if the type // is changed to any other type. - // +kubebuilder:validation:XValidation:message="loadBalancerSourceRange must be a valid IPv4 subnet",rule="self.all(lbsr, lbsr.matches(r\"^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.|\\/\\d{1,2}$)){4})\"))" // +optional LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges,omitempty"` diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 6414d9d96ad..a41ad5c713d 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -5771,10 +5771,6 @@ spec: items: type: string type: array - x-kubernetes-validations: - - message: loadBalancerSourceRange must be a valid IPv4 - subnet - rule: self.all(lbsr, lbsr.matches(r"^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|\/\d{1,2}$)){4})")) patch: description: Patch defines how to perform the patch operation to the service