From 5537c4084ec058fed0dfa7129e7aa79f42d0f44b Mon Sep 17 00:00:00 2001 From: Arnaud Dezandee Date: Sun, 22 Jun 2025 16:32:06 +0200 Subject: [PATCH] feat: svc enable proxy protocol on specified ports --- docs/guide/service/annotations.md | 17 ++++-- pkg/service/model_build_target_group.go | 18 ++++-- pkg/service/model_build_target_group_test.go | 63 ++++++++++++++++++-- 3 files changed, 81 insertions(+), 17 deletions(-) diff --git a/docs/guide/service/annotations.md b/docs/guide/service/annotations.md index 1b2c7f20a..ed0648f6f 100644 --- a/docs/guide/service/annotations.md +++ b/docs/guide/service/annotations.md @@ -27,7 +27,7 @@ | [service.beta.kubernetes.io/aws-load-balancer-name](#load-balancer-name) | string | | | | [service.beta.kubernetes.io/aws-load-balancer-internal](#lb-internal) | boolean | false | deprecated, in favor of [aws-load-balancer-scheme](#lb-scheme) | | [service.beta.kubernetes.io/aws-load-balancer-scheme](#lb-scheme) | string | internal | | -| [service.beta.kubernetes.io/aws-load-balancer-proxy-protocol](#proxy-protocol-v2) | string | | Set to `"*"` to enable | +| [service.beta.kubernetes.io/aws-load-balancer-proxy-protocol](#proxy-protocol-v2) | string | | Set to `"*"` to enable for all service ports | | [service.beta.kubernetes.io/aws-load-balancer-proxy-protocol-per-target-group](#proxy-protocol-v2) | string | | If specified,configures proxy protocol for the target groups corresponding to the ports mentioned and disables for the rest. For example, if you have services deployed on ports `"80, 443 and 22"`, the annotation value `"80, 443"` will enable proxy protocol for ports 80 and 443 only, and disable for port 22. This annotation is overriden by `"service.beta.kubernetes.io/aws-load-balancer-proxy-protocol"` | | [service.beta.kubernetes.io/aws-load-balancer-ip-address-type](#ip-address-type) | string | ipv4 | ipv4 \| dualstack | | [service.beta.kubernetes.io/aws-load-balancer-access-log-enabled](#deprecated-attributes) | boolean | false | deprecated, in favor of [aws-load-balancer-attributes](#load-balancer-attributes) | @@ -256,11 +256,18 @@ You can configure dualstack NLB to support UDP-based services over IPv6 via the NLB resource attributes can be controlled via the following annotations: - service.beta.kubernetes.io/aws-load-balancer-proxy-protocol specifies whether to enable proxy protocol v2 on the target group. -Set to '*' to enable proxy protocol v2. This annotation takes precedence over the annotation `service.beta.kubernetes.io/aws-load-balancer-target-group-attributes` -for proxy protocol v2 configuration. +This annotation takes precedence over the annotation `service.beta.kubernetes.io/aws-load-balancer-target-group-attributes` for proxy protocol v2 configuration. +If you specify `*`, proxy protocol v2 is enabled for all ports. If you specify a list of one or more ports, proxy protocol v2 is enabled only for those ports. - !!!note "" - The only valid value for this annotation is `*`. + !!!example + - enable proxy protocol for all ports + ``` + service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: * + ``` + - enable proxy protocol for ports 80 and 443 + ``` + service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: 80, 443 + ``` - `service.beta.kubernetes.io/aws-load-balancer-target-group-attributes` specifies the [Target Group Attributes](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#target-group-attributes) to be configured. diff --git a/pkg/service/model_build_target_group.go b/pkg/service/model_build_target_group.go index a3446b09e..b5f3c4cd6 100644 --- a/pkg/service/model_build_target_group.go +++ b/pkg/service/model_build_target_group.go @@ -6,7 +6,6 @@ import ( "encoding/hex" "fmt" "regexp" - "sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants" "sort" "strconv" "strings" @@ -23,6 +22,7 @@ import ( "sigs.k8s.io/aws-load-balancer-controller/pkg/k8s" elbv2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2" "sigs.k8s.io/aws-load-balancer-controller/pkg/networking" + "sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants" ) func (t *defaultModelBuildTask) buildTargetGroup(ctx context.Context, port corev1.ServicePort, tgProtocol elbv2model.Protocol, scheme elbv2model.LoadBalancerScheme) (*elbv2model.TargetGroup, error) { @@ -233,12 +233,18 @@ func (t *defaultModelBuildTask) buildTargetGroupAttributes(_ context.Context, po } } - proxyV2Annotation := "" - if exists := t.annotationParser.ParseStringAnnotation(annotations.SvcLBSuffixProxyProtocol, &proxyV2Annotation, t.service.Annotations); exists { - if proxyV2Annotation != "*" { - return []elbv2model.TargetGroupAttribute{}, errors.Errorf("invalid value %v for Load Balancer proxy protocol v2 annotation, only value currently supported is *", proxyV2Annotation) + var proxyV2Annotations []string + if exists := t.annotationParser.ParseStringSliceAnnotation(annotations.SvcLBSuffixProxyProtocol, &proxyV2Annotations, t.service.Annotations); exists { + for _, proxySelector := range proxyV2Annotations { + if proxySelector == "*" { + rawAttributes[shared_constants.TGAttributeProxyProtocolV2Enabled] = "true" + break + } + if proxySelector == strconv.Itoa(int(port.Port)) { + rawAttributes[shared_constants.TGAttributeProxyProtocolV2Enabled] = "true" + break + } } - rawAttributes[shared_constants.TGAttributeProxyProtocolV2Enabled] = "true" } if rawPreserveIPEnabled, ok := rawAttributes[shared_constants.TGAttributePreserveClientIPEnabled]; ok { diff --git a/pkg/service/model_build_target_group_test.go b/pkg/service/model_build_target_group_test.go index 669cd24e6..bfaaa4070 100644 --- a/pkg/service/model_build_target_group_test.go +++ b/pkg/service/model_build_target_group_test.go @@ -3,7 +3,6 @@ package service import ( "context" "errors" - "sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants" "sort" "strconv" "testing" @@ -11,9 +10,6 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/golang/mock/gomock" - "sigs.k8s.io/aws-load-balancer-controller/pkg/model/core" - "sigs.k8s.io/aws-load-balancer-controller/pkg/networking" - "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -21,7 +17,10 @@ import ( elbv2api "sigs.k8s.io/aws-load-balancer-controller/apis/elbv2/v1beta1" "sigs.k8s.io/aws-load-balancer-controller/pkg/annotations" "sigs.k8s.io/aws-load-balancer-controller/pkg/config" + "sigs.k8s.io/aws-load-balancer-controller/pkg/model/core" "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2" + "sigs.k8s.io/aws-load-balancer-controller/pkg/networking" + "sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants" ) func Test_defaultModelBuilderTask_targetGroupAttrs(t *testing.T) { @@ -65,7 +64,7 @@ func Test_defaultModelBuilderTask_targetGroupAttrs(t *testing.T) { }, }, { - testName: "Invalid value", + testName: "no matching value", svc: &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ @@ -73,7 +72,59 @@ func Test_defaultModelBuilderTask_targetGroupAttrs(t *testing.T) { }, }, }, - wantError: true, + wantValue: []elbv2.TargetGroupAttribute{ + { + Key: shared_constants.TGAttributeProxyProtocolV2Enabled, + Value: "false", + }, + }, + wantError: false, + }, + { + testName: "matching value", + svc: &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "service.beta.kubernetes.io/aws-load-balancer-proxy-protocol": "80", + }, + }, + }, + port: corev1.ServicePort{ + Name: "http", + Port: 80, + TargetPort: intstr.FromInt(8080), + NodePort: 32768, + }, + wantValue: []elbv2.TargetGroupAttribute{ + { + Key: shared_constants.TGAttributeProxyProtocolV2Enabled, + Value: "true", + }, + }, + wantError: false, + }, + { + testName: "multiple values", + svc: &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "service.beta.kubernetes.io/aws-load-balancer-proxy-protocol": "443, 80, 9090", + }, + }, + }, + port: corev1.ServicePort{ + Name: "http", + Port: 80, + TargetPort: intstr.FromInt(8080), + NodePort: 32768, + }, + wantValue: []elbv2.TargetGroupAttribute{ + { + Key: shared_constants.TGAttributeProxyProtocolV2Enabled, + Value: "true", + }, + }, + wantError: false, }, { testName: "target group attributes",