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

Support specific dynamic request headers #3234

Closed
erwbgy opened this issue Dec 30, 2020 · 6 comments · Fixed by #3236
Closed

Support specific dynamic request headers #3234

erwbgy opened this issue Dec 30, 2020 · 6 comments · Fixed by #3236
Assignees
Labels
area/httpproxy Issues or PRs related to the HTTPProxy API. kind/feature Categorizes issue or PR as related to a new feature.

Comments

@erwbgy
Copy link
Contributor

erwbgy commented Dec 30, 2020

Please describe the problem you have
From https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#custom-request-response-headers:

Envoy supports adding dynamic values to request and response headers. The percent symbol (%) is used to delimit variable names...
Supported variable names are:
%DOWNSTREAM_REMOTE_ADDRESS%
Remote address of the downstream connection. If the address is an IP address it includes both address and port.
...

I would like to use these dynamic values to set request headers - for example:

spec:
  routes:
  - services:
    - name: myservice
      port: 80
      requestHeadersPolicy:
        set:
        - name: X-Envoy-Hostname
          value: '%HOSTNAME%'

but currently the % is escaped so the result is a literal %HOSTNAME% rather than the expected dynamic value.

There have also been other requests like #2516 to set header values based on other header values.

There are legitimate concerns about sending invalid data to Envoy (see #1176 and #2569) as invalid custom headers cause route configuration failures - for example testing using a patched contour that allows %UNKNOWN% through:

      requestHeadersPolicy:
        set:
        - name: X-Envoy-unknown
          value: '%UNKNOWN%'  

results in:

envoy-wpvz4 envoy [2020-12-27 14:37:57.945][1][warning][config] [source/common/config/grpc_subscription_impl.cc:107] 
gRPC config for type.googleapis.com/envoy.config.route.v3.RouteConfiguration rejected: field 'UNKNOWN' not supported
 as custom header

The proposal is to only allow a specific set of known good Envoy dynamic headers to pass through unescaped and continue escaping the % for anything else:

  • %DOWNSTREAM_REMOTE_ADDRESS%
  • %DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%
  • %DOWNSTREAM_LOCAL_ADDRESS%
  • %DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%
  • %DOWNSTREAM_LOCAL_PORT%
  • %DOWNSTREAM_LOCAL_URI_SAN%
  • %DOWNSTREAM_PEER_URI_SAN%
  • %DOWNSTREAM_LOCAL_SUBJECT%
  • %DOWNSTREAM_PEER_SUBJECT%
  • %DOWNSTREAM_PEER_ISSUER%
  • %DOWNSTREAM_TLS_SESSION_ID%
  • %DOWNSTREAM_TLS_CIPHER%
  • %DOWNSTREAM_TLS_VERSION%
  • %DOWNSTREAM_PEER_FINGERPRINT_256%
  • %DOWNSTREAM_PEER_FINGERPRINT_1%
  • %DOWNSTREAM_PEER_SERIAL%
  • %DOWNSTREAM_PEER_CERT%
  • %DOWNSTREAM_PEER_CERT_V_START%
  • %DOWNSTREAM_PEER_CERT_V_END%
  • %HOSTNAME%
  • %PROTOCOL%
  • %REQ(header-name)%
  • %START_TIME%
  • %UPSTREAM_REMOTE_ADDRESS%
  • %RESPONSE_FLAGS%
  • %RESPONSE_CODE_DETAILS%

Notes:

  • None of these variables cause route failures when passed through unescaped
  • Envoy passes variables that can't be expanded through unchanged or skips them entirely - for example:
    • %UPSTREAM_REMOTE_ADDRESS% as a request header remains as %UPSTREAM_REMOTE_ADDRESS% because as noted in the Envoy docs: "The upstream remote address cannot be added to request headers as the upstream host has not been selected when custom request headers are generated."
    • %DOWNSTREAM_TLS_VERSION% is skipped if TLS is not in use
  • Envoy ignores REQ headers that refer to an non-existent header - for example %REQ(Host)% works as expected but %REQ(Missing-Header)% is skipped
  • The %DYNAMIC_METADATA([“namespace”, “key”, …])% and %PER_REQUEST_STATE(reverse.dns.data.name)% headers were explicitly excluded as this adds significant complexity and it is not clear these can be used safely

I think this provides useful functionality while still ensuring that bad config is not sent to Envoy.

Would you be open to a pull request that implements this?

@erwbgy erwbgy added kind/feature Categorizes issue or PR as related to a new feature. lifecycle/needs-triage Indicates that an issue needs to be triaged by a project contributor. labels Dec 30, 2020
@erwbgy
Copy link
Contributor Author

erwbgy commented Jan 2, 2021

See main...erwbgy:dynamic-headers for proposed changes.

@stevesloka
Copy link
Member

Hey @erwbgy yup I think that makes sense to me and would work. Also, your design leaves the door open to allow full customization later on. Will be curious what others think as well about this.

@sunjayBhatia
Copy link
Member

Agreed with @stevesloka, looks like your approach is simple enough, works, and provides value and as you note Envoy and the change to contour avoid some of the more convoluted scenarios. Might be worth examining if %START_TIME% needs to be special cased in the implementation or omitted (since it looks like it can take format parameters) and adding a test/end to end case around a desired header value with non-dynamic content/multiple dynamic fields (seems that is allowed since these are variable names), e.g. value: 'some content %HOSTNAME%' foo bar or value: '%HOSTNAME% - % PROTOCOL%'

@erwbgy
Copy link
Contributor Author

erwbgy commented Jan 4, 2021

Good catch about %START_TIME% @sunjayBhatia, I hadn't noticed that an optional format string could be passed. I think you're right that it should be omitted as special casing it would add unnecessary complication right now. The %REQ(header)% special case at least has a user request for this functionality.

Ack about the additional test cases required.

@youngnick
Copy link
Member

I'll take a look at the PR now, but overall, I think this design is good. I really appreciate that you've been cautious about the NACK problem #1176 (which the Envoy message in your OP would indicate we would run into).

Thanks for the great design, and the PR!

@xaleeks
Copy link

xaleeks commented Jan 11, 2021

Thanks for the awesome PR @erwbgy

Think we can get this in 1.12? @youngnick

@xaleeks xaleeks added the area/httpproxy Issues or PRs related to the HTTPProxy API. label Jan 11, 2021
@skriss skriss removed the lifecycle/needs-triage Indicates that an issue needs to be triaged by a project contributor. label Jan 14, 2021
skriss pushed a commit that referenced this issue Jan 14, 2021
Envoy supports adding dynamic values to request and response headers like %HOSTNAME% but currently the % is escaped over concerns about sending invalid data to Envoy which will be rejected and cause failures. These changes allow a specific set of known good Envoy dynamic headers to pass through unescaped and continue escaping the % for anything else.

Closes #3234.

Signed-off-by: Keith Burdis <keith.burdis@gs.com>
erwbgy added a commit to erwbgy/contour that referenced this issue Jan 23, 2021
Add support for %CONTOUR_NAMESPACE%, %CONTOUR_SERVICE_NAME% and
%CONTOUR_SERVICE_PORT% dynamic variables and have these expanded like
Envoy dynamic variables are in projectcontour#3234. (The CONTOUR_ prefix is used so
that there is no possibility of a clash with a future Envoy dynamic
variable.)

If any of these variables are used where they can't be expanded then
they are just passed through literally. For example if
%CONTOUR_SERVICE_NAME% is used at the route level then it is not
expanded and becomes %%CONTOUR_SERVICE_NAME%% when passed to Envoy. This
avoids any Envoy configuration errors due to bad dynamic variables.

Signed-off-by: Keith Burdis <keith.burdis@gs.com>
erwbgy added a commit to erwbgy/contour that referenced this issue Jan 27, 2021
Add support for %CONTOUR_NAMESPACE%, %CONTOUR_SERVICE_NAME% and
%CONTOUR_SERVICE_PORT% dynamic variables and have these expanded like
Envoy dynamic variables are in projectcontour#3234. (The CONTOUR_ prefix is used so
that there is no possibility of a clash with a future Envoy dynamic
variable.)

If any of these variables are used where they can't be expanded then
they are just passed through literally. For example if
%CONTOUR_SERVICE_NAME% is used at the route level then it is not
expanded and becomes %%CONTOUR_SERVICE_NAME%% when passed to Envoy. This
avoids any Envoy configuration errors due to bad dynamic variables.

Signed-off-by: Keith Burdis <keith.burdis@gs.com>
erwbgy added a commit to erwbgy/contour that referenced this issue Jan 27, 2021
Add support for %CONTOUR_NAMESPACE%, %CONTOUR_SERVICE_NAME% and
%CONTOUR_SERVICE_PORT% dynamic variables and have these expanded like
Envoy dynamic variables are in projectcontour#3234. (The CONTOUR_ prefix is used so
that there is no possibility of a clash with a future Envoy dynamic
variable.)

If any of these variables are used where they can't be expanded then
they are just passed through literally. For example if
%CONTOUR_SERVICE_NAME% is used at the route level then it is not
expanded and becomes %%CONTOUR_SERVICE_NAME%% when passed to Envoy. This
avoids any Envoy configuration errors due to bad dynamic variables.

Signed-off-by: Keith Burdis <keith.burdis@gs.com>
erwbgy added a commit to erwbgy/contour that referenced this issue Jan 29, 2021
Add support for %CONTOUR_NAMESPACE%, %CONTOUR_SERVICE_NAME% and
%CONTOUR_SERVICE_PORT% dynamic variables and have these expanded like
Envoy dynamic variables are in projectcontour#3234. (The CONTOUR_ prefix is used so
that there is no possibility of a clash with a future Envoy dynamic
variable.)

If any of these variables are used where they can't be expanded then
they are just passed through literally. For example if
%CONTOUR_SERVICE_NAME% is used at the route level then it is not
expanded and becomes %%CONTOUR_SERVICE_NAME%% when passed to Envoy. This
avoids any Envoy configuration errors due to bad dynamic variables.

Signed-off-by: Keith Burdis <keith.burdis@gs.com>
skriss pushed a commit that referenced this issue Feb 2, 2021
Add support for %CONTOUR_NAMESPACE%, %CONTOUR_SERVICE_NAME% and
%CONTOUR_SERVICE_PORT% dynamic variables and have these expanded like
Envoy dynamic variables are in #3234. (The CONTOUR_ prefix is used so
that there is no possibility of a clash with a future Envoy dynamic
variable.)

If any of these variables are used where they can't be expanded then
they are just passed through literally. For example if
%CONTOUR_SERVICE_NAME% is used at the route level then it is not
expanded and becomes %%CONTOUR_SERVICE_NAME%% when passed to Envoy. This
avoids any Envoy configuration errors due to bad dynamic variables.

Signed-off-by: Keith Burdis <keith.burdis@gs.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/httpproxy Issues or PRs related to the HTTPProxy API. kind/feature Categorizes issue or PR as related to a new feature.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants