From b27f43fafbe9f5c8828346c8766de1d55a4ca7ee Mon Sep 17 00:00:00 2001 From: Grant Spence Date: Fri, 16 Jan 2026 17:36:20 -0500 Subject: [PATCH] OCPBUGS-63219: Add clientIPPreservationMode to AWS NLB parameters Add clientIPPreservationMode field to AWSNetworkLoadBalancerParameters to control how client IP addresses are preserved. The field accepts "Preserved" (uses AWS's native client IP preservation, the default) and "ProxyProtocol" (uses PROXY protocol v2). When set to Preserved, the NLB target group has preserve_client_ip.enabled set to true, which may cause hairpin connection failures for internal load balancers when connections are made from pods to router pods on the same node. When set to ProxyProtocol, the NLB target group has preserve_client_ip.enabled set to false and proxy_protocol_v2.enabled set to true. This allows backends to receive the original client IP via PROXY protocol headers while avoiding hairpin connection failures. --- .../generated_openapi/zz_generated.openapi.go | 7 +++ openapi/openapi.json | 26 +++++++++++ operator/v1/types_ingress.go | 37 +++++++++++++++ ..._50_ingress_00_ingresscontrollers.crd.yaml | 46 +++++++++++++++++++ .../AAA_ungated.yaml | 46 +++++++++++++++++++ .../v1/zz_generated.swagger_doc_generated.go | 7 +-- 6 files changed, 166 insertions(+), 3 deletions(-) diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index 5b32d1d990b..7c845442dad 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -49012,6 +49012,13 @@ func schema_openshift_api_operator_v1_AWSNetworkLoadBalancerParameters(ref commo }, }, }, + "clientIPPreservationMode": { + SchemaProps: spec.SchemaProps{ + Description: "clientIPPreservationMode specifies how client IP addresses are preserved by the load balancer.\n\nValid values are \"Preserved\" and \"ProxyProtocol\".\n\nWhen set to \"Preserved\", the NLB uses AWS's native client IP preservation, which may cause hairpin connection failures for internal load balancers when connections are made from pods to router pods on the same node.\n\nWhen set to \"ProxyProtocol\", the NLB uses PROXY protocol v2 to preserve client IP addresses. This avoids hairpin connection failures.\n\nWhen omitted, the default behavior is \"Preserved\".\n\nNote that changing this field may cause brief connection failures during the transition as the NLB attribute change and router rollout occur independently.", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, diff --git a/openapi/openapi.json b/openapi/openapi.json index b605ecd869b..257482376c8 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -24706,6 +24706,10 @@ "format": "int32", "default": 0 }, + "synchronizedAPI": { + "description": "synchronizedAPI holds the last stable value of authoritativeAPI. It is used to detect migration cancellation requests and to restore the resource to its previous state. Valid values are \"MachineAPI\" and \"ClusterAPI\". When omitted, the resource has not yet been reconciled by the migration controller.", + "type": "string" + }, "synchronizedGeneration": { "description": "synchronizedGeneration is the generation of the authoritative resource that the non-authoritative resource is synchronised with. This field is set when the authoritative resource is updated and the sync controller has updated the non-authoritative resource to match.", "type": "integer", @@ -24809,6 +24813,10 @@ "description": "providerStatus details a Provider-specific status. It is recommended that providers maintain their own versioned API types that should be serialized/deserialized from this field.", "$ref": "#/definitions/io.k8s.apimachinery.pkg.runtime.RawExtension" }, + "synchronizedAPI": { + "description": "synchronizedAPI holds the last stable value of authoritativeAPI. It is used to detect migration cancellation requests and to restore the resource to its previous state. Valid values are \"MachineAPI\" and \"ClusterAPI\". When omitted, the resource has not yet been reconciled by the migration controller.", + "type": "string" + }, "synchronizedGeneration": { "description": "synchronizedGeneration is the generation of the authoritative resource that the non-authoritative resource is synchronised with. This field is set when the authoritative resource is updated and the sync controller has updated the non-authoritative resource to match.", "type": "integer", @@ -28387,12 +28395,30 @@ }, "x-kubernetes-list-type": "atomic" }, + "proxyProtocol": { + "description": "proxyProtocol enables PROXY protocol on the Network Load Balancer's target groups.\n\nWhen enabled, the NLB will prepend a PROXY protocol header to each TCP connection that contains the original source and destination IP addresses and ports. This allows the backend to see the true client IP address while preserving the ability to handle hairpin connections (connections from pods to a service that targets those same pods).\n\nWhen enabled, the NLB target group attribute `preserve_client_ip.enabled` is set to false and `proxy_protocol_v2.enabled` is set to true. Application backends must be configured to parse the PROXY protocol header to extract the original client IP address.\n\nWhen this field is not set or set to false, client IP preservation is enabled (the default AWS NLB behavior), which may cause hairpin connection failures for internal load balancers.\n\nSee https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#proxy-protocol for more information about PROXY protocol support on AWS Network Load Balancers.", + "$ref": "#/definitions/com.github.openshift.api.operator.v1.AWSProxyProtocol" + }, "subnets": { "description": "subnets specifies the subnets to which the load balancer will attach. The subnets may be specified by either their ID or name. The total number of subnets is limited to 10.\n\nIn order for the load balancer to be provisioned with subnets, each subnet must exist, each subnet must be from a different availability zone, and the load balancer service must be recreated to pick up new values.\n\nWhen omitted from the spec, the subnets will be auto-discovered for each availability zone. Auto-discovered subnets are not reported in the status of the IngressController object.", "$ref": "#/definitions/com.github.openshift.api.operator.v1.AWSSubnets" } } }, + "com.github.openshift.api.operator.v1.AWSProxyProtocol": { + "description": "AWSProxyProtocol contains configuration for enabling PROXY protocol on an AWS Network Load Balancer.", + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "description": "enabled specifies whether PROXY protocol should be enabled on the Network Load Balancer's target groups.\n\nWhen set to true, the NLB target group will have PROXY protocol v2 enabled and client IP preservation disabled. This allows backends to receive the original client IP via the PROXY protocol header while avoiding hairpin connection failures that can occur with client IP preservation on internal load balancers.\n\nWhen set to false or when the proxyProtocol field is omitted, client IP preservation remains enabled (the default NLB behavior).", + "type": "boolean", + "default": false + } + } + }, "com.github.openshift.api.operator.v1.AWSSubnets": { "description": "AWSSubnets contains a list of references to AWS subnets by ID or name.", "type": "object", diff --git a/operator/v1/types_ingress.go b/operator/v1/types_ingress.go index d54352f2cee..d7adb2057cc 100644 --- a/operator/v1/types_ingress.go +++ b/operator/v1/types_ingress.go @@ -898,8 +898,45 @@ type AWSNetworkLoadBalancerParameters struct { // +kubebuilder:validation:XValidation:rule=`self.all(x, self.exists_one(y, x == y))`,message="eipAllocations cannot contain duplicates" // +kubebuilder:validation:MaxItems=10 EIPAllocations []EIPAllocation `json:"eipAllocations"` + + // clientIPPreservationMode specifies how client IP addresses are + // preserved by the load balancer. + // + // Valid values are "Preserved" and "ProxyProtocol". + // + // When set to "Preserved", the NLB uses AWS's native client IP preservation, + // which may cause hairpin connection failures for internal load balancers when + // connections are made from pods to router pods on the same node. + // + // When set to "ProxyProtocol", the NLB uses PROXY protocol v2 to preserve + // client IP addresses. This avoids hairpin connection failures. + // + // When omitted, the default behavior is "Preserved". + // + // Note that changing this field may cause brief connection failures during + // the transition as the NLB attribute change and router rollout occur + // independently. + // + // +optional + ClientIPPreservationMode ClientIPPreservationMode `json:"clientIPPreservationMode,omitempty"` } +// ClientIPPreservationMode specifies how client IP addresses should be +// preserved by the Network Load Balancer. +// +kubebuilder:validation:Enum=Preserved;ProxyProtocol +type ClientIPPreservationMode string + +const ( + // ClientIPPreservationPreserved uses AWS's native client IP preservation, + // which may cause hairpin connection failures for internal load balancers when + // connections are made from pods to router pods on the same node. + ClientIPPreservationPreserved ClientIPPreservationMode = "Preserved" + + // ClientIPPreservationProxyProtocol uses PROXY protocol v2 to preserve + // client IP addresses. This avoids hairpin connection failures. + ClientIPPreservationProxyProtocol ClientIPPreservationMode = "ProxyProtocol" +) + // EIPAllocation is an ID for an Elastic IP (EIP) address that can be allocated to an ELB in the AWS environment. // Values must begin with `eipalloc-` followed by exactly 17 hexadecimal (`[0-9a-fA-F]`) characters. // + Explanation of the regex `^eipalloc-[0-9a-fA-F]{17}$` for validating value of the EIPAllocation: diff --git a/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers.crd.yaml b/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers.crd.yaml index fa03ef576c8..a00d86ea2ac 100644 --- a/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers.crd.yaml +++ b/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers.crd.yaml @@ -476,6 +476,29 @@ spec: networkLoadBalancerParameters holds configuration parameters for an AWS network load balancer. Present only if type is NLB. properties: + clientIPPreservationMode: + description: |- + clientIPPreservationMode specifies how client IP addresses are + preserved by the load balancer. + + Valid values are "Preserved" and "ProxyProtocol". + + When set to "Preserved", the NLB uses AWS's native client IP preservation, + which may cause hairpin connection failures for internal load balancers when + connections are made from pods to router pods on the same node. + + When set to "ProxyProtocol", the NLB uses PROXY protocol v2 to preserve + client IP addresses. This avoids hairpin connection failures. + + When omitted, the default behavior is "Preserved". + + Note that changing this field may cause brief connection failures during + the transition as the NLB attribute change and router rollout occur + independently. + enum: + - Preserved + - ProxyProtocol + type: string eipAllocations: description: |- eipAllocations is a list of IDs for Elastic IP (EIP) addresses that @@ -2728,6 +2751,29 @@ spec: networkLoadBalancerParameters holds configuration parameters for an AWS network load balancer. Present only if type is NLB. properties: + clientIPPreservationMode: + description: |- + clientIPPreservationMode specifies how client IP addresses are + preserved by the load balancer. + + Valid values are "Preserved" and "ProxyProtocol". + + When set to "Preserved", the NLB uses AWS's native client IP preservation, + which may cause hairpin connection failures for internal load balancers when + connections are made from pods to router pods on the same node. + + When set to "ProxyProtocol", the NLB uses PROXY protocol v2 to preserve + client IP addresses. This avoids hairpin connection failures. + + When omitted, the default behavior is "Preserved". + + Note that changing this field may cause brief connection failures during + the transition as the NLB attribute change and router rollout occur + independently. + enum: + - Preserved + - ProxyProtocol + type: string eipAllocations: description: |- eipAllocations is a list of IDs for Elastic IP (EIP) addresses that diff --git a/operator/v1/zz_generated.featuregated-crd-manifests/ingresscontrollers.operator.openshift.io/AAA_ungated.yaml b/operator/v1/zz_generated.featuregated-crd-manifests/ingresscontrollers.operator.openshift.io/AAA_ungated.yaml index 78744d6cb00..c3790e243c0 100644 --- a/operator/v1/zz_generated.featuregated-crd-manifests/ingresscontrollers.operator.openshift.io/AAA_ungated.yaml +++ b/operator/v1/zz_generated.featuregated-crd-manifests/ingresscontrollers.operator.openshift.io/AAA_ungated.yaml @@ -477,6 +477,29 @@ spec: networkLoadBalancerParameters holds configuration parameters for an AWS network load balancer. Present only if type is NLB. properties: + clientIPPreservationMode: + description: |- + clientIPPreservationMode specifies how client IP addresses are + preserved by the load balancer. + + Valid values are "Preserved" and "ProxyProtocol". + + When set to "Preserved", the NLB uses AWS's native client IP preservation, + which may cause hairpin connection failures for internal load balancers when + connections are made from pods to router pods on the same node. + + When set to "ProxyProtocol", the NLB uses PROXY protocol v2 to preserve + client IP addresses. This avoids hairpin connection failures. + + When omitted, the default behavior is "Preserved". + + Note that changing this field may cause brief connection failures during + the transition as the NLB attribute change and router rollout occur + independently. + enum: + - Preserved + - ProxyProtocol + type: string eipAllocations: description: |- eipAllocations is a list of IDs for Elastic IP (EIP) addresses that @@ -2711,6 +2734,29 @@ spec: networkLoadBalancerParameters holds configuration parameters for an AWS network load balancer. Present only if type is NLB. properties: + clientIPPreservationMode: + description: |- + clientIPPreservationMode specifies how client IP addresses are + preserved by the load balancer. + + Valid values are "Preserved" and "ProxyProtocol". + + When set to "Preserved", the NLB uses AWS's native client IP preservation, + which may cause hairpin connection failures for internal load balancers when + connections are made from pods to router pods on the same node. + + When set to "ProxyProtocol", the NLB uses PROXY protocol v2 to preserve + client IP addresses. This avoids hairpin connection failures. + + When omitted, the default behavior is "Preserved". + + Note that changing this field may cause brief connection failures during + the transition as the NLB attribute change and router rollout occur + independently. + enum: + - Preserved + - ProxyProtocol + type: string eipAllocations: description: |- eipAllocations is a list of IDs for Elastic IP (EIP) addresses that diff --git a/operator/v1/zz_generated.swagger_doc_generated.go b/operator/v1/zz_generated.swagger_doc_generated.go index 64aac26eb38..b86c83c7f1e 100644 --- a/operator/v1/zz_generated.swagger_doc_generated.go +++ b/operator/v1/zz_generated.swagger_doc_generated.go @@ -827,9 +827,10 @@ func (AWSLoadBalancerParameters) SwaggerDoc() map[string]string { } var map_AWSNetworkLoadBalancerParameters = map[string]string{ - "": "AWSNetworkLoadBalancerParameters holds configuration parameters for an AWS Network load balancer. For Example: Setting AWS EIPs https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html", - "subnets": "subnets specifies the subnets to which the load balancer will attach. The subnets may be specified by either their ID or name. The total number of subnets is limited to 10.\n\nIn order for the load balancer to be provisioned with subnets, each subnet must exist, each subnet must be from a different availability zone, and the load balancer service must be recreated to pick up new values.\n\nWhen omitted from the spec, the subnets will be auto-discovered for each availability zone. Auto-discovered subnets are not reported in the status of the IngressController object.", - "eipAllocations": "eipAllocations is a list of IDs for Elastic IP (EIP) addresses that are assigned to the Network Load Balancer. The following restrictions apply:\n\neipAllocations can only be used with external scope, not internal. An EIP can be allocated to only a single IngressController. The number of EIP allocations must match the number of subnets that are used for the load balancer. Each EIP allocation must be unique. A maximum of 10 EIP allocations are permitted.\n\nSee https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html for general information about configuration, characteristics, and limitations of Elastic IP addresses.", + "": "AWSNetworkLoadBalancerParameters holds configuration parameters for an AWS Network load balancer. For Example: Setting AWS EIPs https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html", + "subnets": "subnets specifies the subnets to which the load balancer will attach. The subnets may be specified by either their ID or name. The total number of subnets is limited to 10.\n\nIn order for the load balancer to be provisioned with subnets, each subnet must exist, each subnet must be from a different availability zone, and the load balancer service must be recreated to pick up new values.\n\nWhen omitted from the spec, the subnets will be auto-discovered for each availability zone. Auto-discovered subnets are not reported in the status of the IngressController object.", + "eipAllocations": "eipAllocations is a list of IDs for Elastic IP (EIP) addresses that are assigned to the Network Load Balancer. The following restrictions apply:\n\neipAllocations can only be used with external scope, not internal. An EIP can be allocated to only a single IngressController. The number of EIP allocations must match the number of subnets that are used for the load balancer. Each EIP allocation must be unique. A maximum of 10 EIP allocations are permitted.\n\nSee https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html for general information about configuration, characteristics, and limitations of Elastic IP addresses.", + "clientIPPreservationMode": "clientIPPreservationMode specifies how client IP addresses are preserved by the load balancer.\n\nValid values are \"Preserved\" and \"ProxyProtocol\".\n\nWhen set to \"Preserved\", the NLB uses AWS's native client IP preservation, which may cause hairpin connection failures for internal load balancers when connections are made from pods to router pods on the same node.\n\nWhen set to \"ProxyProtocol\", the NLB uses PROXY protocol v2 to preserve client IP addresses. This avoids hairpin connection failures.\n\nWhen omitted, the default behavior is \"Preserved\".\n\nNote that changing this field may cause brief connection failures during the transition as the NLB attribute change and router rollout occur independently.", } func (AWSNetworkLoadBalancerParameters) SwaggerDoc() map[string]string {