Skip to content

Commit 34889a4

Browse files
author
vbedi
committed
add validation for tags
1 parent f1b2465 commit 34889a4

File tree

2 files changed

+134
-4
lines changed

2 files changed

+134
-4
lines changed

pkg/k8s/utils.go

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package k8s
33
import (
44
"context"
55
"fmt"
6+
"regexp"
67
"strings"
78

89
"github.com/aws/aws-application-networking-k8s/pkg/config"
@@ -25,8 +26,20 @@ const (
2526
// without automatic service network association
2627
StandaloneAnnotation = AnnotationPrefix + "standalone"
2728

29+
// AWS reserved prefix that cannot be used in tag keys
30+
AWSReservedPrefix = "aws:"
31+
2832
// Additional tags
2933
TagsAnnotationKey = AnnotationPrefix + "tags"
34+
35+
// AWS tag validation limits
36+
maxTagKeyLength = 128
37+
maxTagValueLength = 256
38+
maxTagCount = 50
39+
)
40+
41+
var (
42+
tagPattern = regexp.MustCompile(`^([\p{L}\p{Z}\p{N}_.:\/=+\-@]*)$`)
3043
)
3144

3245
type Tags = map[string]*string
@@ -359,9 +372,24 @@ func ParseTagsFromAnnotation(annotationValue string) Tags {
359372

360373
key := strings.TrimSpace(parts[0])
361374
value := strings.TrimSpace(parts[1])
362-
if key != "" && value != "" {
363-
tags[key] = aws.String(value)
375+
376+
if key == "" || value == "" ||
377+
len(key) > maxTagKeyLength ||
378+
len(value) > maxTagValueLength ||
379+
!tagPattern.MatchString(key) ||
380+
!tagPattern.MatchString(value) {
381+
continue
364382
}
383+
384+
if _, exists := tags[key]; exists {
385+
continue
386+
}
387+
388+
if len(tags) >= maxTagCount {
389+
break
390+
}
391+
392+
tags[key] = aws.String(value)
365393
}
366394
return tags
367395
}
@@ -388,9 +416,10 @@ func CalculateTagDifference(currentTags Tags, desiredTags Tags) (tagsToAdd Tags,
388416
func GetNonAWSManagedTags(tags Tags) Tags {
389417
nonAWSManagedTags := make(Tags)
390418
for key, value := range tags {
391-
if !strings.HasPrefix(key, AnnotationPrefix) {
392-
nonAWSManagedTags[key] = value
419+
if strings.HasPrefix(key, AnnotationPrefix) || strings.HasPrefix(strings.ToLower(key), AWSReservedPrefix) {
420+
continue
393421
}
422+
nonAWSManagedTags[key] = value
394423
}
395424
return nonAWSManagedTags
396425
}

pkg/k8s/utils_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package k8s
22

33
import (
44
"context"
5+
"strings"
56
"testing"
67

78
"github.com/aws/aws-application-networking-k8s/pkg/model/core"
@@ -1014,6 +1015,56 @@ func TestParseTagsFromAnnotation(t *testing.T) {
10141015
expected: Tags{"Environment": aws.String("Dev"), "Project": aws.String("MyApp")},
10151016
description: "should skip whitespace-only pairs",
10161017
},
1018+
{
1019+
name: "tag key too long",
1020+
annotation: strings.Repeat("a", 129) + "=value,Project=MyApp",
1021+
expected: Tags{"Project": aws.String("MyApp")},
1022+
description: "should skip tags with keys longer than 128 characters",
1023+
},
1024+
{
1025+
name: "tag value too long",
1026+
annotation: "Environment=Dev,key=" + strings.Repeat("v", 257),
1027+
expected: Tags{"Environment": aws.String("Dev")},
1028+
description: "should skip tags with values longer than 256 characters",
1029+
},
1030+
{
1031+
name: "duplicate keys",
1032+
annotation: "Environment=Dev,Project=App1,Environment=Prod,Team=Platform",
1033+
expected: Tags{"Environment": aws.String("Dev"), "Project": aws.String("App1"), "Team": aws.String("Platform")},
1034+
description: "should keep first occurrence of duplicate keys",
1035+
},
1036+
{
1037+
name: "invalid characters in key",
1038+
annotation: "Env#ironment=Dev,Project=MyApp",
1039+
expected: Tags{"Project": aws.String("MyApp")},
1040+
description: "should skip tags with invalid characters in key",
1041+
},
1042+
{
1043+
name: "invalid characters in value",
1044+
annotation: "Environment=Dev,Project=My$App",
1045+
expected: Tags{"Environment": aws.String("Dev")},
1046+
description: "should skip tags with invalid characters in value",
1047+
},
1048+
{
1049+
name: "more than 50 tags should keep 50 tags",
1050+
annotation: func() string {
1051+
var pairs []string
1052+
for i := 1; i <= 60; i++ {
1053+
pairs = append(pairs, "key"+string(rune(i/10+48))+string(rune(i%10+48))+"=value"+string(rune(i/10+48))+string(rune(i%10+48)))
1054+
}
1055+
return strings.Join(pairs, ",")
1056+
}(),
1057+
expected: func() Tags {
1058+
tags := make(Tags)
1059+
for i := 1; i <= 50; i++ {
1060+
key := "key" + string(rune(i/10+48)) + string(rune(i%10+48))
1061+
value := "value" + string(rune(i/10+48)) + string(rune(i%10+48))
1062+
tags[key] = aws.String(value)
1063+
}
1064+
return tags
1065+
}(),
1066+
description: "should limit to 50 tags maximum",
1067+
},
10171068
}
10181069

10191070
for _, tt := range tests {
@@ -1081,6 +1132,56 @@ func TestGetNonAWSManagedTags(t *testing.T) {
10811132
},
10821133
description: "should filter out AWS managed tags and keep additional tags",
10831134
},
1135+
{
1136+
name: "AWS reserved tags lowercase",
1137+
tags: Tags{
1138+
"aws:cloudformation:stack-name": aws.String("my-stack"),
1139+
"aws:region": aws.String("us-west-2"),
1140+
"Environment": aws.String("Dev"),
1141+
},
1142+
expected: Tags{
1143+
"Environment": aws.String("Dev"),
1144+
},
1145+
description: "should filter out lowercase aws: prefixed tags",
1146+
},
1147+
{
1148+
name: "AWS reserved tags uppercase",
1149+
tags: Tags{
1150+
"AWS:CloudFormation:StackName": aws.String("my-stack"),
1151+
"AWS:Region": aws.String("us-west-2"),
1152+
"Environment": aws.String("Dev"),
1153+
},
1154+
expected: Tags{
1155+
"Environment": aws.String("Dev"),
1156+
},
1157+
description: "should filter out uppercase AWS: prefixed tags",
1158+
},
1159+
{
1160+
name: "AWS reserved tags mixed case",
1161+
tags: Tags{
1162+
"Aws:Service": aws.String("ec2"),
1163+
"aWs:Resource": aws.String("instance"),
1164+
"Environment": aws.String("Dev"),
1165+
},
1166+
expected: Tags{
1167+
"Environment": aws.String("Dev"),
1168+
},
1169+
description: "should filter out mixed case aws: prefixed tags",
1170+
},
1171+
{
1172+
name: "tags that start with aws but not aws:",
1173+
tags: Tags{
1174+
"awesome": aws.String("value"),
1175+
"aws-region": aws.String("us-west-2"),
1176+
"Environment": aws.String("Dev"),
1177+
},
1178+
expected: Tags{
1179+
"awesome": aws.String("value"),
1180+
"aws-region": aws.String("us-west-2"),
1181+
"Environment": aws.String("Dev"),
1182+
},
1183+
description: "should keep tags that start with 'aws' but not 'aws:'",
1184+
},
10841185
}
10851186

10861187
for _, tt := range tests {

0 commit comments

Comments
 (0)