Skip to content

Commit 4681969

Browse files
committed
Support NLB target group attributes
1 parent d1cc02a commit 4681969

File tree

4 files changed

+397
-29
lines changed

4 files changed

+397
-29
lines changed

docs/guide/service/annotations.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
|--------------------------------------------------------------------------------|------------|---------------------------|------------------------|
1414
| service.beta.kubernetes.io/aws-load-balancer-type | string | | |
1515
| service.beta.kubernetes.io/aws-load-balancer-internal | boolean | false | |
16-
| service.beta.kubernetes.io/aws-load-balancer-proxy-protocol | string | | Set to `"*"` to enable |
16+
| [service.beta.kubernetes.io/aws-load-balancer-proxy-protocol](#proxy-protocol-v2) | string | | Set to `"*"` to enable |
1717
| service.beta.kubernetes.io/aws-load-balancer-access-log-enabled | boolean | false | |
1818
| service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name | string | | |
1919
| service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix | string | | |
@@ -30,4 +30,32 @@
3030
| service.beta.kubernetes.io/aws-load-balancer-healthcheck-protocol | string | TCP | |
3131
| service.beta.kubernetes.io/aws-load-balancer-healthcheck-port | string | traffic-port | |
3232
| service.beta.kubernetes.io/aws-load-balancer-healthcheck-path | string | "/" for HTTP(S) protocols | |
33-
| service.beta.kubernetes.io/aws-load-balancer-eip-allocations | stringList | | |
33+
| service.beta.kubernetes.io/aws-load-balancer-eip-allocations | stringList | | |
34+
| [service.beta.kubernetes.io/aws-load-balancer-target-group-attributes](#target-group-attributes) | stringMap | | |
35+
36+
## Resource attributes
37+
NLB target group attributes can be controlled via the following annotations:
38+
39+
- <a name="proxy-protocol-v2">service.beta.kubernetes.io/aws-load-balancer-proxy-protocol</a> specifies whether to enable proxy protocol v2 on the target group.
40+
Set to '*' to enable proxy protocol v2. This annotation takes precedence over the annotation `service.beta.kubernetes.io/aws-load-balancer-target-group-attributes`
41+
for proxy protocol v2 configuration.
42+
43+
!!!note ""
44+
The only valid value for this annotation is `*`.
45+
46+
- <a name="target-group-attributes">`service.beta.kubernetes.io/aws-load-balancer-target-group-attributes`</a> specifies the
47+
[Target Group Attributes](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#target-group-attributes) to be configured.
48+
49+
!!!example
50+
- set the deregistration delay to 120 seconds (available range is 0-3600 seconds)
51+
```
52+
service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: deregistration_delay.timeout_seconds=120
53+
```
54+
- enable source IP affinity
55+
```
56+
service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: stickiness.enabled=true,stickiness.type=source_ip
57+
```
58+
- enable proxy protocol version 2
59+
```
60+
service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: proxy_protocol_v2.enabled=true
61+
```

pkg/annotations/constants.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,5 @@ const (
6464
SvcLBSuffixHCPort = "aws-load-balancer-healthcheck-port"
6565
SvcLBSuffixHCPath = "aws-load-balancer-healthcheck-path"
6666
SvcLBSuffixEIPAllocations = "aws-load-balancer-eip-allocations"
67+
SvcLBSuffixTargetGroupAttributes = "aws-load-balancer-target-group-attributes"
6768
)

pkg/service/model_build_target_group.go

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ import (
2121
)
2222

2323
const (
24-
TGAttrsProxyProtocolV2Enabled = "proxy_protocol_v2.enabled"
25-
healthCheckPortTrafficPort = "traffic-port"
24+
TGAttrsProxyProtocolV2Enabled = "proxy_protocol_v2.enabled"
25+
TGAttrsPreserveClientIPEnabled = "preserve_client_ip.enabled"
26+
healthCheckPortTrafficPort = "traffic-port"
2627
)
2728

2829
func (t *defaultModelBuildTask) buildTargetGroup(ctx context.Context, port corev1.ServicePort, tgProtocol elbv2model.Protocol) (*elbv2model.TargetGroup, error) {
@@ -39,13 +40,17 @@ func (t *defaultModelBuildTask) buildTargetGroup(ctx context.Context, port corev
3940
if err != nil {
4041
return nil, err
4142
}
43+
preserveClientIP, err := t.buildPreserveClientIPFlag(ctx, targetType)
44+
if err != nil {
45+
return nil, err
46+
}
4247
tgSpec, err := t.buildTargetGroupSpec(ctx, tgProtocol, targetType, port, healthCheckConfig)
4348
if err != nil {
4449
return nil, err
4550
}
4651
targetGroup := elbv2model.NewTargetGroup(t.stack, tgResourceID, tgSpec)
4752
t.tgByResID[tgResourceID] = targetGroup
48-
_ = t.buildTargetGroupBinding(ctx, targetGroup, port, healthCheckConfig)
53+
_ = t.buildTargetGroupBinding(ctx, targetGroup, preserveClientIP, port, healthCheckConfig)
4954
return targetGroup, nil
5055
}
5156

@@ -141,20 +146,53 @@ func (t *defaultModelBuildTask) buildTargetGroupName(_ context.Context, svcPort
141146
}
142147

143148
func (t *defaultModelBuildTask) buildTargetGroupAttributes(_ context.Context) ([]elbv2model.TargetGroupAttribute, error) {
144-
var attrs []elbv2model.TargetGroupAttribute
145-
proxyV2Enabled := t.defaultProxyProtocolV2Enabled
149+
var rawAttributes map[string]string
150+
if _, err := t.annotationParser.ParseStringMapAnnotation(annotations.SvcLBSuffixTargetGroupAttributes, &rawAttributes, t.service.Annotations); err != nil {
151+
return nil, err
152+
}
153+
if rawAttributes == nil {
154+
rawAttributes = make(map[string]string)
155+
}
156+
if _, ok := rawAttributes[TGAttrsProxyProtocolV2Enabled]; !ok {
157+
rawAttributes[TGAttrsProxyProtocolV2Enabled] = strconv.FormatBool(t.defaultProxyProtocolV2Enabled)
158+
}
146159
proxyV2Annotation := ""
147-
if t.annotationParser.ParseStringAnnotation(annotations.SvcLBSuffixProxyProtocol, &proxyV2Annotation, t.service.Annotations) {
160+
exists := t.annotationParser.ParseStringAnnotation(annotations.SvcLBSuffixProxyProtocol, &proxyV2Annotation, t.service.Annotations)
161+
if exists {
148162
if proxyV2Annotation != "*" {
149-
return []elbv2model.TargetGroupAttribute{}, errors.Errorf("Invalid value %v for Load Balancer proxy protocol v2 annotation, only value currently supported is *", proxyV2Annotation)
163+
return []elbv2model.TargetGroupAttribute{}, errors.Errorf("invalid value %v for Load Balancer proxy protocol v2 annotation, only value currently supported is *", proxyV2Annotation)
150164
}
151-
proxyV2Enabled = true
165+
rawAttributes[TGAttrsProxyProtocolV2Enabled] = "true"
166+
}
167+
attributes := make([]elbv2model.TargetGroupAttribute, 0, len(rawAttributes))
168+
for attrKey, attrValue := range rawAttributes {
169+
attributes = append(attributes, elbv2model.TargetGroupAttribute{
170+
Key: attrKey,
171+
Value: attrValue,
172+
})
173+
}
174+
return attributes, nil
175+
}
176+
177+
func (t *defaultModelBuildTask) buildPreserveClientIPFlag(_ context.Context, targetType elbv2model.TargetType) (bool, error) {
178+
var rawAttributes map[string]string
179+
if _, err := t.annotationParser.ParseStringMapAnnotation(annotations.SvcLBSuffixTargetGroupAttributes, &rawAttributes, t.service.Annotations); err != nil {
180+
return false, err
181+
}
182+
if rawVal, ok := rawAttributes[TGAttrsPreserveClientIPEnabled]; ok {
183+
val, err := strconv.ParseBool(rawVal)
184+
if err != nil {
185+
return false, errors.Wrapf(err, "failed to parse attribute %v=%v", TGAttrsPreserveClientIPEnabled, rawVal)
186+
}
187+
return val, nil
188+
}
189+
switch targetType {
190+
case elbv2model.TargetTypeIP:
191+
return false, nil
192+
case elbv2model.TargetTypeInstance:
193+
return true, nil
152194
}
153-
attrs = append(attrs, elbv2model.TargetGroupAttribute{
154-
Key: TGAttrsProxyProtocolV2Enabled,
155-
Value: strconv.FormatBool(proxyV2Enabled),
156-
})
157-
return attrs, nil
195+
return false, nil
158196
}
159197

160198
func (t *defaultModelBuildTask) buildTargetGroupHealthCheckPort(_ context.Context) (intstr.IntOrString, error) {
@@ -251,15 +289,15 @@ func (t *defaultModelBuildTask) buildTargetGroupTags(ctx context.Context) (map[s
251289
return t.buildAdditionalResourceTags(ctx)
252290
}
253291

254-
func (t *defaultModelBuildTask) buildTargetGroupBinding(ctx context.Context, targetGroup *elbv2model.TargetGroup,
292+
func (t *defaultModelBuildTask) buildTargetGroupBinding(ctx context.Context, targetGroup *elbv2model.TargetGroup, preserveClientIP bool,
255293
port corev1.ServicePort, hc *elbv2model.TargetGroupHealthCheckConfig) *elbv2model.TargetGroupBindingResource {
256-
tgbSpec := t.buildTargetGroupBindingSpec(ctx, targetGroup, port, hc)
294+
tgbSpec := t.buildTargetGroupBindingSpec(ctx, targetGroup, preserveClientIP, port, hc)
257295
return elbv2model.NewTargetGroupBindingResource(t.stack, targetGroup.ID(), tgbSpec)
258296
}
259297

260-
func (t *defaultModelBuildTask) buildTargetGroupBindingSpec(ctx context.Context, targetGroup *elbv2model.TargetGroup,
298+
func (t *defaultModelBuildTask) buildTargetGroupBindingSpec(ctx context.Context, targetGroup *elbv2model.TargetGroup, preserveClientIP bool,
261299
port corev1.ServicePort, hc *elbv2model.TargetGroupHealthCheckConfig) elbv2model.TargetGroupBindingResourceSpec {
262-
tgbNetworking := t.buildTargetGroupBindingNetworking(ctx, port.TargetPort, *hc.Port, port.Protocol)
300+
tgbNetworking := t.buildTargetGroupBindingNetworking(ctx, port.TargetPort, preserveClientIP, *hc.Port, port.Protocol)
263301
targetType := elbv2api.TargetType(targetGroup.Spec.TargetType)
264302
return elbv2model.TargetGroupBindingResourceSpec{
265303
Template: elbv2model.TargetGroupBindingTemplate{
@@ -302,7 +340,7 @@ func (t *defaultModelBuildTask) buildPeersFromSourceRanges(_ context.Context) []
302340
return peers
303341
}
304342

305-
func (t *defaultModelBuildTask) buildTargetGroupBindingNetworking(ctx context.Context, tgPort intstr.IntOrString,
343+
func (t *defaultModelBuildTask) buildTargetGroupBindingNetworking(ctx context.Context, tgPort intstr.IntOrString, preserveClientIP bool,
306344
hcPort intstr.IntOrString, tgProtocol corev1.Protocol) *elbv2model.TargetGroupBindingNetworking {
307345
var fromVPC []elbv2model.NetworkingPeer
308346
for _, subnet := range t.ec2Subnets {
@@ -323,7 +361,7 @@ func (t *defaultModelBuildTask) buildTargetGroupBindingNetworking(ctx context.Co
323361
},
324362
}
325363
trafficSource := fromVPC
326-
if networkingProtocol == elbv2api.NetworkingProtocolUDP {
364+
if networkingProtocol == elbv2api.NetworkingProtocolUDP || preserveClientIP {
327365
trafficSource = t.buildPeersFromSourceRanges(ctx)
328366
}
329367
tgbNetworking := &elbv2model.TargetGroupBindingNetworking{

0 commit comments

Comments
 (0)