Skip to content

Commit

Permalink
Add webhook limitation on header actions
Browse files Browse the repository at this point in the history
Add an HTTPRoute webhook validation rule for RequestHeaderModifier and
ResponseHeaderModifier filters. The rule rejects filters that contain
multiple actions for the same header name.
  • Loading branch information
rainest committed Nov 2, 2022
1 parent 4abc828 commit ff8b759
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
42 changes: 42 additions & 0 deletions apis/v1beta1/validation/httproute.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ func validateHTTPRouteFilters(filters []gatewayv1b1.HTTPRouteFilter, matches []g
if filter.URLRewrite != nil && filter.URLRewrite.Path != nil {
errs = append(errs, validateHTTPPathModifier(*filter.URLRewrite.Path, matches, path.Index(i).Child("urlRewrite", "path"))...)
}
if filter.RequestHeaderModifier != nil {
errs = append(errs, validateHTTPHeaderModifier(*filter.RequestHeaderModifier, path.Index(i).Child("requestHeaderModifier"))...)
}
if filter.ResponseHeaderModifier != nil {
errs = append(errs, validateHTTPHeaderModifier(*filter.ResponseHeaderModifier, path.Index(i).Child("responseHeaderModifier"))...)
}
errs = append(errs, validateHTTPRouteFilterTypeMatchesValue(filter, path.Index(i))...)
}
// custom filters don't have any validation
Expand Down Expand Up @@ -276,6 +282,42 @@ func validateHTTPPathModifier(modifier gatewayv1b1.HTTPPathModifier, matches []g
return errs
}

func validateHTTPHeaderModifier(filter gatewayv1b1.HTTPHeaderFilter, path *field.Path) field.ErrorList {
var errs field.ErrorList
singleAction := make(map[string]bool)
for i, action := range filter.Add {
if needsErr, ok := singleAction[string(action.Name)]; ok {
if needsErr {
errs = append(errs, field.Invalid(path.Child("add"), filter.Add[i], "cannot specify multiple actions for header"))
}
singleAction[string(action.Name)] = false
} else {
singleAction[string(action.Name)] = true
}
}
for i, action := range filter.Set {
if needsErr, ok := singleAction[string(action.Name)]; ok {
if needsErr {
errs = append(errs, field.Invalid(path.Child("set"), filter.Set[i], "cannot specify multiple actions for header"))
}
singleAction[string(action.Name)] = false
} else {
singleAction[string(action.Name)] = true
}
}
for i, action := range filter.Remove {
if needsErr, ok := singleAction[action]; ok {
if needsErr {
errs = append(errs, field.Invalid(path.Child("remove"), filter.Remove[i], "cannot specify multiple actions for header"))
}
singleAction[action] = false
} else {
singleAction[action] = true
}
}
return errs
}

func hasExactlyOnePrefixMatch(matches []gatewayv1b1.HTTPRouteMatch) bool {
if len(matches) != 1 || matches[0].Path == nil {
return false
Expand Down
52 changes: 52 additions & 0 deletions apis/v1beta1/validation/httproute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,58 @@ func TestValidateHTTPRoute(t *testing.T) {
},
}},
}},
}, {
name: "multiple actions for the same request header (invalid)",
errCount: 2,
rules: []gatewayv1b1.HTTPRouteRule{{
Filters: []gatewayv1b1.HTTPRouteFilter{{
Type: gatewayv1b1.HTTPRouteFilterRequestHeaderModifier,
RequestHeaderModifier: &gatewayv1b1.HTTPHeaderFilter{
Add: []gatewayv1b1.HTTPHeader{
{
Name: gatewayv1b1.HTTPHeaderName("x-fruit"),
Value: "apple",
},
{
Name: gatewayv1b1.HTTPHeaderName("x-vegetable"),
Value: "carrot",
},
{
Name: gatewayv1b1.HTTPHeaderName("x-grain"),
Value: "rye",
},
},
Set: []gatewayv1b1.HTTPHeader{
{
Name: gatewayv1b1.HTTPHeaderName("x-fruit"),
Value: "watermelon",
},
{
Name: gatewayv1b1.HTTPHeaderName("x-grain"),
Value: "wheat",
},
},
},
}},
}},
}, {
name: "multiple actions for the same response header (invalid)",
errCount: 1,
rules: []gatewayv1b1.HTTPRouteRule{{
Filters: []gatewayv1b1.HTTPRouteFilter{{
Type: gatewayv1b1.HTTPRouteFilterResponseHeaderModifier,
ResponseHeaderModifier: &gatewayv1b1.HTTPHeaderFilter{
Add: []gatewayv1b1.HTTPHeader{{
Name: gatewayv1b1.HTTPHeaderName("x-example"),
Value: "blueberry",
}},
Set: []gatewayv1b1.HTTPHeader{{
Name: gatewayv1b1.HTTPHeaderName("x-example"),
Value: "turnip",
}},
},
}},
}},
}}

for _, tc := range tests {
Expand Down

0 comments on commit ff8b759

Please sign in to comment.