Skip to content

Commit 746d16d

Browse files
committed
Add path validation and deny app-root from minion
1 parent e1dd542 commit 746d16d

File tree

4 files changed

+119
-7
lines changed

4 files changed

+119
-7
lines changed

internal/configs/annotations.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ var minionDenylist = map[string]bool{
7575
"nginx.org/server-snippets": true,
7676
"nginx.org/ssl-ciphers": true,
7777
"nginx.org/ssl-prefer-server-ciphers": true,
78+
"nginx.org/app-root": true,
7879
"appprotect.f5.com/app_protect_enable": true,
7980
"appprotect.f5.com/app_protect_policy": true,
8081
"appprotect.f5.com/app_protect_security_log_enable": true,
@@ -504,7 +505,11 @@ func parseAnnotations(ingEx *IngressEx, baseCfgParams *ConfigParams, isPlus bool
504505
}
505506

506507
if appRoot, exists := ingEx.Ingress.Annotations["nginx.org/app-root"]; exists {
507-
cfgParams.AppRoot = appRoot
508+
if !VerifyPath(appRoot) {
509+
nl.Errorf(l, "Ingress %s/%s: Invalid value nginx.org/app-root: got %q. Must start with '/'", ingEx.Ingress.GetNamespace(), ingEx.Ingress.GetName(), appRoot)
510+
} else {
511+
cfgParams.AppRoot = appRoot
512+
}
508513
}
509514

510515
if useClusterIP, exists, err := GetMapKeyAsBool(ingEx.Ingress.Annotations, UseClusterIPAnnotation, ingEx.Ingress); exists {

internal/configs/annotations_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,3 +1011,113 @@ func TestSSLRedirectAnnotations(t *testing.T) {
10111011
})
10121012
}
10131013
}
1014+
1015+
func TestAppRootAnnotation(t *testing.T) {
1016+
t.Parallel()
1017+
1018+
tests := []struct {
1019+
name string
1020+
annotations map[string]string
1021+
expected string
1022+
}{
1023+
{
1024+
name: "valid app-root - coffee path",
1025+
annotations: map[string]string{
1026+
"nginx.org/app-root": "/coffee",
1027+
},
1028+
expected: "/coffee",
1029+
},
1030+
{
1031+
name: "valid app-root - nested path with mocha",
1032+
annotations: map[string]string{
1033+
"nginx.org/app-root": "/coffee/mocha",
1034+
},
1035+
expected: "/coffee/mocha",
1036+
},
1037+
{
1038+
name: "valid app-root - tea path",
1039+
annotations: map[string]string{
1040+
"nginx.org/app-root": "/tea",
1041+
},
1042+
expected: "/tea",
1043+
},
1044+
{
1045+
name: "valid app-root - nested tea path",
1046+
annotations: map[string]string{
1047+
"nginx.org/app-root": "/tea/green-tea",
1048+
},
1049+
expected: "/tea/green-tea",
1050+
},
1051+
{
1052+
name: "valid app-root - cafe path",
1053+
annotations: map[string]string{
1054+
"nginx.org/app-root": "/cafe",
1055+
},
1056+
expected: "/cafe",
1057+
},
1058+
{
1059+
name: "invalid app-root - does not start with slash",
1060+
annotations: map[string]string{
1061+
"nginx.org/app-root": "coffee",
1062+
},
1063+
expected: "", // Should remain empty due to invalid path
1064+
},
1065+
{
1066+
name: "invalid app-root - contains invalid characters",
1067+
annotations: map[string]string{
1068+
"nginx.org/app-root": "/tea$mocha",
1069+
},
1070+
expected: "", // Should remain empty due to invalid characters
1071+
},
1072+
{
1073+
name: "invalid app-root - contains curly braces",
1074+
annotations: map[string]string{
1075+
"nginx.org/app-root": "/coffee{test}",
1076+
},
1077+
expected: "", // Should remain empty due to invalid characters
1078+
},
1079+
{
1080+
name: "invalid app-root - contains semicolon",
1081+
annotations: map[string]string{
1082+
"nginx.org/app-root": "/tea;chai",
1083+
},
1084+
expected: "", // Should remain empty due to invalid characters
1085+
},
1086+
{
1087+
name: "invalid app-root - contains whitespace",
1088+
annotations: map[string]string{
1089+
"nginx.org/app-root": "/tea chai",
1090+
},
1091+
expected: "", // Should remain empty due to invalid characters
1092+
},
1093+
{
1094+
name: "no app-root annotation",
1095+
annotations: map[string]string{},
1096+
expected: "", // Should remain empty when annotation is missing
1097+
},
1098+
}
1099+
1100+
for _, tt := range tests {
1101+
tt := tt
1102+
t.Run(tt.name, func(t *testing.T) {
1103+
t.Parallel()
1104+
1105+
ingEx := &IngressEx{
1106+
Ingress: &networking.Ingress{
1107+
ObjectMeta: metav1.ObjectMeta{
1108+
Name: "test-ingress",
1109+
Namespace: "default",
1110+
Annotations: tt.annotations,
1111+
},
1112+
},
1113+
}
1114+
1115+
baseCfgParams := NewDefaultConfigParams(context.Background(), false)
1116+
result := parseAnnotations(ingEx, baseCfgParams, false, false, false, false, false)
1117+
1118+
if result.AppRoot != tt.expected {
1119+
t.Errorf("Test %q: expected AppRoot %q, got %q", tt.name, tt.expected, result.AppRoot)
1120+
}
1121+
})
1122+
}
1123+
}

internal/k8s/validation.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -394,11 +394,8 @@ func validateAppRootAnnotation(context *annotationValidationContext) field.Error
394394
return allErrs
395395
}
396396

397-
// Validate that the path doesn't contain invalid characters
398-
// Allow alphanumeric, hyphens, underscores, dots, and forward slashes
399-
validPath := regexp.MustCompile(`^/[a-zA-Z0-9\-_./]*$`)
400-
if !validPath.MatchString(path) {
401-
allErrs = append(allErrs, field.Invalid(context.fieldPath, path, "contains invalid characters, only alphanumeric, hyphens, underscores, dots, and forward slashes are allowed"))
397+
if !configs.VerifyPath(path) {
398+
allErrs = append(allErrs, field.Invalid(context.fieldPath, path, "path must start with '/' and must not include any special character, '{', '}', ';' or '$'"))
402399
return allErrs
403400
}
404401

internal/k8s/validation_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3485,7 +3485,7 @@ func TestValidateNginxIngressAnnotations(t *testing.T) {
34853485
appProtectDosEnabled: false,
34863486
internalRoutesEnabled: false,
34873487
expectedErrors: []string{
3488-
`annotations.nginx.org/app-root: Invalid value: "/tea$1": contains invalid characters, only alphanumeric, hyphens, underscores, dots, and forward slashes are allowed`,
3488+
`annotations.nginx.org/app-root: Invalid value: "/tea$1": path must start with '/' and must not include any special character, '{', '}', ';' or '$'`,
34893489
},
34903490
msg: "invalid nginx.org/app-root annotation, invalid characters",
34913491
},

0 commit comments

Comments
 (0)