Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use appendAction for translated HeaderValueOptions #8678

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
changelog:
- type: NON_USER_FACING
issueLink: https://github.com/solo-io/gloo/issues/8525
resolvesIssue: false
description: >-
Translate header manipulation's `append` to Envoy's `append_action`, the newer non-deprecated field.
skipCI-kube-tests:true
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ Headers can be inherited by children options, such as shown in the following exa
- header:
key: x-route-table
value: alphabet
append: false # overwrite the value of `x-route-table` if it already exists
```
3. In the RouteTable child object, define other headers. In the following example, the `x-route-table` header is added to requests, and the `x-route-table: a` header is added to responses.
```yaml
Expand Down Expand Up @@ -282,4 +283,13 @@ Headers can be inherited by children options, such as shown in the following exa
4. Now, requests that match the route `/a/1` get the following headers:
* The `x-gateway-start-time` request header is inherited from the parent VirtualHost option.
* The `x-route-table` request header is set in the child Route option.
* The `x-route-table` response header in the child overwrites the parent object's value of `alphabet` instead to `a`, because child objects take precedence in case of conflict.
* The `x-route-table` response header in the parent overwrites the child object's value of `a` instead to `alphabet`.

Due to how header manipulations are processed, less specific headers overwrite more specific headers.

From the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#custom-request-response-headers):
> Headers are appended to requests/responses in the following order: weighted cluster level headers, route level headers, virtual host level headers and finally global level headers.

In the previous example of the `x-route-table` response header, the virtual host level header overwrites the route level header because the virtual host level header is evaluated after the route level header.
If you set `append: true` or omit this field on the virtual host, then the route level response header (`a`) would get appended to the virtual host level header (`alphabet`).
If you set `append: false` on the route, the route does not affect the virtual host because the route is evaluated before the virtual host. In the example, the response header would stay `x-route-table: alphabet`.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions pkg/utils/api_conversion/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ func CheckForbiddenCustomHeaders(header envoycore_sk.HeaderValue) error {
}

func ToEnvoyHeaderValueOptions(option *envoycore_sk.HeaderValueOption, secrets *v1.SecretList, secretOptions HeaderSecretOptions) ([]*envoy_config_core_v3.HeaderValueOption, error) {
appendAction := envoy_config_core_v3.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD
if appendOption := option.GetAppend(); appendOption != nil {
if appendOption.GetValue() == false {
appendAction = envoy_config_core_v3.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD
}
}

switch typedOption := option.GetHeaderOption().(type) {
case *envoycore_sk.HeaderValueOption_Header:
if err := CheckForbiddenCustomHeaders(*typedOption.Header); err != nil {
Expand All @@ -92,7 +99,7 @@ func ToEnvoyHeaderValueOptions(option *envoycore_sk.HeaderValueOption, secrets *
Key: typedOption.Header.GetKey(),
Value: typedOption.Header.GetValue(),
},
Append: option.GetAppend(),
AppendAction: appendAction,
},
}, nil
case *envoycore_sk.HeaderValueOption_HeaderSecretRef:
Expand All @@ -117,7 +124,7 @@ func ToEnvoyHeaderValueOptions(option *envoycore_sk.HeaderValueOption, secrets *
Key: key,
Value: value,
},
Append: option.GetAppend(),
AppendAction: appendAction,
})
}
return result, nil
Expand Down
4 changes: 1 addition & 3 deletions pkg/utils/api_conversion/type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ var _ = Describe("Type conversion", func() {
Key: "allowed",
Value: "header",
},
Append: &wrappers.BoolValue{
Value: true,
},
AppendAction: envoy_config_core_v3.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD,
},
}
headers, err := ToEnvoyHeaderValueOptionList(allowedHeaders, nil, HeaderSecretOptions{})
Expand Down
5 changes: 3 additions & 2 deletions projects/gloo/api/v1/options/headers/headers.proto
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ message HeaderValueOption {
// Header name/value pair that this option applies to.
HeaderValue header = 1;

// Should the value be appended? If true (default), the value is appended to
// existing values.
// Specifies if the value should be appended or overwrite an existing header. Defaults to true.
inFocus7 marked this conversation as resolved.
Show resolved Hide resolved
// If set to true, this maps to Envoy's `append_value: APPEND_IF_EXISTS_OR_ADD`, where the value gets be appended the header's value(s) if exists, or created if it does not.
// If set to false, this maps to Envoy's `append_value: OVERWRITE_IF_EXISTS_OR_ADD`, where the header's value will be overwritten if it exists, or created if it does not.
google.protobuf.BoolValue append = 2;
}

Expand Down
5 changes: 3 additions & 2 deletions projects/gloo/pkg/api/v1/options/headers/headers.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion projects/gloo/pkg/plugins/headers/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,19 @@ func convertResponseHeaderValueOption(
return nil, CantSetHostHeaderError
}

appendAction := envoy_config_core_v3.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD
sam-heilbron marked this conversation as resolved.
Show resolved Hide resolved
if appendOption := h.GetAppend(); appendOption != nil {
if appendOption.GetValue() == false {
appendAction = envoy_config_core_v3.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD
}
}

out = append(out, &envoy_config_core_v3.HeaderValueOption{
Header: &envoy_config_core_v3.HeaderValue{
Key: header.GetKey(),
Value: header.GetValue(),
},
Append: h.GetAppend(),
AppendAction: appendAction,
})
}
return out, nil
Expand Down
8 changes: 4 additions & 4 deletions projects/gloo/pkg/plugins/headers/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,9 @@ var testHeaderManip = &headers.HeaderManipulation{
}

var expectedHeaders = envoyHeaderManipulation{
RequestHeadersToAdd: []*envoy_config_core_v3.HeaderValueOption{{Header: &envoy_config_core_v3.HeaderValue{Key: "foo", Value: "bar"}, Append: &wrappers.BoolValue{Value: true}}},
RequestHeadersToAdd: []*envoy_config_core_v3.HeaderValueOption{{Header: &envoy_config_core_v3.HeaderValue{Key: "foo", Value: "bar"}, AppendAction: envoy_config_core_v3.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD}},
RequestHeadersToRemove: []string{"a"},
ResponseHeadersToAdd: []*envoy_config_core_v3.HeaderValueOption{{Header: &envoy_config_core_v3.HeaderValue{Key: "foo", Value: "bar"}, Append: &wrappers.BoolValue{Value: true}}},
ResponseHeadersToAdd: []*envoy_config_core_v3.HeaderValueOption{{Header: &envoy_config_core_v3.HeaderValue{Key: "foo", Value: "bar"}, AppendAction: envoy_config_core_v3.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD}},
ResponseHeadersToRemove: []string{"b"},
}

Expand All @@ -314,8 +314,8 @@ var testHeaderManipWithSecrets = &headers.HeaderManipulation{
}

var expectedHeadersWithSecrets = envoyHeaderManipulation{
RequestHeadersToAdd: []*envoy_config_core_v3.HeaderValueOption{{Header: &envoy_config_core_v3.HeaderValue{Key: "Authorization", Value: "basic dXNlcjpwYXNzd29yZA=="}, Append: &wrappers.BoolValue{Value: true}}},
RequestHeadersToAdd: []*envoy_config_core_v3.HeaderValueOption{{Header: &envoy_config_core_v3.HeaderValue{Key: "Authorization", Value: "basic dXNlcjpwYXNzd29yZA=="}, AppendAction: envoy_config_core_v3.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD}},
RequestHeadersToRemove: []string{"a"},
ResponseHeadersToAdd: []*envoy_config_core_v3.HeaderValueOption{{Header: &envoy_config_core_v3.HeaderValue{Key: "foo", Value: "bar"}, Append: &wrappers.BoolValue{Value: true}}},
ResponseHeadersToAdd: []*envoy_config_core_v3.HeaderValueOption{{Header: &envoy_config_core_v3.HeaderValue{Key: "foo", Value: "bar"}, AppendAction: envoy_config_core_v3.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD}},
ResponseHeadersToRemove: []string{"b"},
}
8 changes: 2 additions & 6 deletions projects/gloo/pkg/translator/translator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1277,9 +1277,7 @@ var _ = Describe("Translator", func() {
Key: "Authorization",
Value: "basic dXNlcjpwYXNzd29yZA==",
},
Append: &wrappers.BoolValue{
Value: true,
},
AppendAction: envoy_config_core_v3.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD,
},
}

Expand Down Expand Up @@ -2754,9 +2752,7 @@ var _ = Describe("Translator", func() {
Key: "client-id",
Value: "%REQ(client-id)%",
},
Append: &wrappers.BoolValue{
Value: false,
},
AppendAction: envoy_config_core_v3.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
},
))
})
Expand Down