Skip to content

Commit 28e8c5c

Browse files
authored
router: unified header formatters (envoyproxy#21932)
Signed-off-by: Christoph Pakulski <[email protected]>
1 parent fa309d1 commit 28e8c5c

File tree

26 files changed

+609
-337
lines changed

26 files changed

+609
-337
lines changed

changelogs/current.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ removed_config_or_runtime:
138138
removed ``envoy.reloadable_features.update_grpc_response_error_tag`` and legacy code paths.
139139
140140
new_features:
141+
- area: header_formatters
142+
change: |
143+
all access log formatters can be used as custom request/response headers. Custom header's syntax is parsed using access logger's parser and
144+
header values are obtained using access log's substitution formatters. This feature can be reversed by setting runtime guard
145+
``envoy.reloadable_features.unified_header_formatter`` to false.
141146
- area: http
142147
change: |
143148
made the :ref:`admission control <envoy_v3_api_msg_extensions.filters.http.admission_control.v3.AdmissionControl>` work as an upstream filter.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
static_resources:
2+
listeners:
3+
- name: listener_0
4+
address:
5+
socket_address:
6+
address: 0.0.0.0
7+
port_value: 15000
8+
filter_chains:
9+
- name: http
10+
filters:
11+
- name: http_connection_manager
12+
typed_config:
13+
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
14+
stat_prefix: ingress_http
15+
route_config:
16+
name: local_route
17+
request_headers_to_add:
18+
- header:
19+
key: "response-code"
20+
value: "%RESPONSE_CODE%"
21+
virtual_hosts:
22+
- name: local_service
23+
domains: ["*"]
24+
routes:
25+
- match:
26+
prefix: "/"
27+
route:
28+
cluster: some_service
29+
http_filters:
30+
- name: router
31+
typed_config:
32+
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
33+
clusters:
34+
- name: some_service
35+
load_assignment:
36+
cluster_name: some_service
37+
endpoints:
38+
- lb_endpoints:
39+
- endpoint:
40+
address:
41+
socket_address:
42+
address: 127.0.0.1
43+
port_value: 10002

docs/root/configuration/http/http_conn_man/headers.rst

+27-246
Original file line numberDiff line numberDiff line change
@@ -574,191 +574,34 @@ used to delimit variable names.
574574
doubling it. For example, to emit a header with the value ``100%``, the custom header value in
575575
the Envoy configuration must be ``100%%``.
576576

577-
Supported variable names are:
577+
All HTTP :ref:`Command Operators <config_access_log_command_operators>` used for access logging may be specified
578+
in custom request/response headers. However, depending where a particular command operator is used, the context needed for
579+
the operator may not be available and the produced output is empty string. For example, the following configuration
580+
uses ``%RESPONSE_CODE%`` operator to modify request headers using code from the response.
581+
The output is an empty string, because request headers are modified
582+
before the request is sent upstream and the response is not received yet.
583+
584+
.. literalinclude:: _include/header_formatters.yaml
585+
:language: yaml
586+
:linenos:
587+
:lines: 15-20
588+
:emphasize-lines: 3-6
589+
:caption: :download:`header_formatters.yaml <_include/header_formatters.yaml>`
578590

579-
%DOWNSTREAM_REMOTE_ADDRESS%
580-
Remote address of the downstream connection. If the address is an IP address it includes both
581-
address and port.
582-
583-
.. note::
584-
585-
This may not be the physical remote address of the peer if the address has been inferred from
586-
:ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>` or :ref:`x-forwarded-for
587-
<config_http_conn_man_headers_x-forwarded-for>`.
591+
.. attention::
588592

589-
%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%
590-
Remote address of the downstream connection, without any port component.
591-
IP addresses are the only address type with a port component.
593+
The following legacy header formatters are still supported, but will be deprecated in the future.
594+
The equivalent information can be accessed using indicated substitutes.
592595

593-
.. note::
596+
``%DYNAMIC_METADATA(["namespace", "key", ...])%``
597+
Populates the header with dynamic metadata available in a request
598+
(e.g.: added by filters like the header-to-metadata filter).
594599

595-
This may not be the physical remote address of the peer if the address has been inferred from
596-
:ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>` or :ref:`x-forwarded-for
597-
<config_http_conn_man_headers_x-forwarded-for>`.
600+
This works both on request and response headers.
598601

599-
%DOWNSTREAM_REMOTE_PORT%
600-
Remote port of the downstream connection.
601-
IP addresses are the only address type with a port component.
602+
Use :ref:`%DYNAMIC_METADATA(namespace:key:…):Z%<config_access_log_format_dynamic_metadata>` instead.
602603

603-
.. note::
604-
605-
This may not be the physical remote address of the peer if the address has been inferred from
606-
:ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>` or :ref:`x-forwarded-for
607-
<config_http_conn_man_headers_x-forwarded-for>`.
608-
609-
%DOWNSTREAM_DIRECT_REMOTE_ADDRESS%
610-
Direct remote address of the downstream connection. If the address is an IP address it includes both
611-
address and port.
612-
613-
.. note::
614-
615-
This is always the physical remote address of the peer even if the downstream remote address has
616-
been inferred from :ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>`
617-
or :ref:`x-forwarded-for <config_http_conn_man_headers_x-forwarded-for>`.
618-
619-
%DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT%
620-
Direct remote address of the downstream connection, without any port component.
621-
IP addresses are the only address type with a port component.
622-
623-
.. note::
624-
625-
This is always the physical remote address of the peer even if the downstream remote address has
626-
been inferred from :ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>`
627-
or :ref:`x-forwarded-for <config_http_conn_man_headers_x-forwarded-for>`.
628-
629-
%DOWNSTREAM_DIRECT_REMOTE_PORT%
630-
Direct remote port of the downstream connection.
631-
IP addresses are the only address type with a port component.
632-
633-
.. note::
634-
635-
This is always the physical remote address of the peer even if the downstream remote address has
636-
been inferred from :ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>`
637-
or :ref:`x-forwarded-for <config_http_conn_man_headers_x-forwarded-for>`.
638-
639-
640-
%DOWNSTREAM_LOCAL_ADDRESS%
641-
Local address of the downstream connection. If the address is an IP address it includes both
642-
address and port.
643-
644-
If the original connection was redirected by iptables REDIRECT, this represents
645-
the original destination address restored by the
646-
:ref:`Original Destination Filter <config_listener_filters_original_dst>` using SO_ORIGINAL_DST socket option.
647-
If the original connection was redirected by iptables TPROXY, and the listener's transparent
648-
option was set to true, this represents the original destination address and port.
649-
650-
%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%
651-
Local address of the downstream connection, without any port component.
652-
IP addresses are the only address type with a port component.
653-
654-
%DOWNSTREAM_LOCAL_PORT%
655-
Local port of the downstream connection.
656-
IP addresses are the only address type with a port component.
657-
658-
%DOWNSTREAM_LOCAL_URI_SAN%
659-
HTTP
660-
The URIs present in the SAN of the local certificate used to establish the downstream TLS connection.
661-
TCP
662-
The URIs present in the SAN of the local certificate used to establish the downstream TLS connection.
663-
664-
%DOWNSTREAM_PEER_URI_SAN%
665-
HTTP
666-
The URIs present in the SAN of the peer certificate used to establish the downstream TLS connection.
667-
TCP
668-
The URIs present in the SAN of the peer certificate used to establish the downstream TLS connection.
669-
670-
%DOWNSTREAM_LOCAL_SUBJECT%
671-
HTTP
672-
The subject present in the local certificate used to establish the downstream TLS connection.
673-
TCP
674-
The subject present in the local certificate used to establish the downstream TLS connection.
675-
676-
%DOWNSTREAM_PEER_SUBJECT%
677-
HTTP
678-
The subject present in the peer certificate used to establish the downstream TLS connection.
679-
TCP
680-
The subject present in the peer certificate used to establish the downstream TLS connection.
681-
682-
%DOWNSTREAM_PEER_ISSUER%
683-
HTTP
684-
The issuer present in the peer certificate used to establish the downstream TLS connection.
685-
TCP
686-
The issuer present in the peer certificate used to establish the downstream TLS connection.
687-
688-
%DOWNSTREAM_TLS_SESSION_ID%
689-
HTTP
690-
The session ID for the established downstream TLS connection.
691-
TCP
692-
The session ID for the established downstream TLS connection.
693-
694-
%DOWNSTREAM_TLS_CIPHER%
695-
HTTP
696-
The OpenSSL name for the set of ciphers used to establish the downstream TLS connection.
697-
TCP
698-
The OpenSSL name for the set of ciphers used to establish the downstream TLS connection.
699-
700-
%DOWNSTREAM_TLS_VERSION%
701-
HTTP
702-
The TLS version (e.g., ``TLSv1.2``, ``TLSv1.3``) used to establish the downstream TLS connection.
703-
TCP
704-
The TLS version (e.g., ``TLSv1.2``, ``TLSv1.3``) used to establish the downstream TLS connection.
705-
706-
%DOWNSTREAM_PEER_FINGERPRINT_256%
707-
HTTP
708-
The hex-encoded SHA256 fingerprint of the client certificate used to establish the downstream TLS connection.
709-
TCP
710-
The hex-encoded SHA256 fingerprint of the client certificate used to establish the downstream TLS connection.
711-
712-
%DOWNSTREAM_PEER_FINGERPRINT_1%
713-
HTTP
714-
The hex-encoded SHA1 fingerprint of the client certificate used to establish the downstream TLS connection.
715-
TCP
716-
The hex-encoded SHA1 fingerprint of the client certificate used to establish the downstream TLS connection.
717-
718-
%DOWNSTREAM_PEER_SERIAL%
719-
HTTP
720-
The serial number of the client certificate used to establish the downstream TLS connection.
721-
TCP
722-
The serial number of the client certificate used to establish the downstream TLS connection.
723-
724-
%DOWNSTREAM_PEER_CERT%
725-
HTTP
726-
The client certificate in the URL-encoded PEM format used to establish the downstream TLS connection.
727-
TCP
728-
The client certificate in the URL-encoded PEM format used to establish the downstream TLS connection.
729-
730-
%DOWNSTREAM_PEER_CERT_V_START%
731-
HTTP
732-
The validity start date of the client certificate used to establish the downstream TLS connection.
733-
TCP
734-
The validity start date of the client certificate used to establish the downstream TLS connection.
735-
736-
DOWNSTREAM_PEER_CERT_V_START can be customized with specifiers as specified in
737-
:ref:`access log format rules<config_access_log_format_downstream_peer_cert_v_start>`.
738-
739-
%DOWNSTREAM_PEER_CERT_V_END%
740-
HTTP
741-
The validity end date of the client certificate used to establish the downstream TLS connection.
742-
TCP
743-
The validity end date of the client certificate used to establish the downstream TLS connection.
744-
745-
DOWNSTREAM_PEER_CERT_V_END can be customized with specifiers as specified in
746-
:ref:`access log format rules<config_access_log_format_downstream_peer_cert_v_end>`.
747-
748-
%HOSTNAME%
749-
The system hostname.
750-
751-
%PROTOCOL%
752-
The original protocol which is already added by Envoy as a
753-
:ref:`x-forwarded-proto <config_http_conn_man_headers_x-forwarded-proto>` request header.
754-
755-
%REQUESTED_SERVER_NAME%
756-
HTTP
757-
String value set on ssl connection socket for Server Name Indication (SNI)
758-
TCP
759-
String value set on ssl connection socket for Server Name Indication (SNI)
760-
761-
%UPSTREAM_METADATA(["namespace", "key", ...])%
604+
``%UPSTREAM_METADATA(["namespace", "key", ...])%``
762605
Populates the header with :ref:`EDS endpoint metadata <envoy_v3_api_field_config.endpoint.v3.LbEndpoint.metadata>` from the
763606
upstream host selected by the router. Metadata may be selected from any namespace. In general,
764607
metadata values may be strings, numbers, booleans, lists, nested structures, or null. Upstream
@@ -771,74 +614,12 @@ Supported variable names are:
771614
Upstream metadata cannot be added to request headers as the upstream host has not been selected
772615
when custom request headers are generated.
773616

774-
%DYNAMIC_METADATA(["namespace", "key", ...])%
775-
Similar to UPSTREAM_METADATA, populates the header with dynamic metadata available in a request
776-
(e.g.: added by filters like the header-to-metadata filter).
777-
778-
This works both on request and response headers.
779-
780-
%UPSTREAM_LOCAL_ADDRESS%
781-
Local address of the upstream connection. If the address is an IP address it includes both
782-
address and port.
783-
784-
The upstream local address cannot be added to request headers as the upstream host
785-
hremote as not been selected when custom request headers are generated.
786-
787-
%UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%
788-
Local address of the upstream connection, without any port component.
789-
IP addresses are the only address type with a port component.
790-
791-
%UPSTREAM_LOCAL_PORT%
792-
Local port of the upstream connection.
793-
IP addresses are the only address type with a port component.
617+
Use :ref:`%UPSTREAM_METADATA(namespace:key:…):Z%<config_access_log_format_upstream_host_metadata>` instead.
794618

795-
%UPSTREAM_REMOTE_ADDRESS%
796-
Remote address of the upstream connection. If the address is an IP address it includes both
797-
address and port.
798-
799-
The upstream remote address cannot be added to request headers as the upstream host
800-
has not been selected when custom request headers are generated.
801-
802-
%UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%
803-
Remote address of the upstream connection, without any port component.
804-
IP addresses are the only address type with a port component.
805-
806-
%UPSTREAM_REMOTE_PORT%
807-
Remote port of the upstream connection.
808-
IP addresses are the only address type with a port component.
809-
810-
%PER_REQUEST_STATE(reverse.dns.data.name)%
811-
Populates the header with values set on the stream info filterState() object. To be
619+
``%PER_REQUEST_STATE(reverse.dns.data.name)%``
620+
Populates the header with values set on the stream info ``filterState()`` object. To be
812621
usable in custom request/response headers, these values must be of type
813-
Envoy::Router::StringAccessor. These values should be named in standard reverse DNS style,
622+
``Envoy::Router::StringAccessor``. These values should be named in standard reverse DNS style,
814623
identifying the organization that created the value and ending in a unique name for the data.
815624

816-
%REQ(header-name)%
817-
Populates the header with a value of the request header.
818-
819-
%START_TIME%
820-
Request start time. START_TIME can be customized with specifiers as specified in
821-
:ref:`access log format rules<config_access_log_format_start_time>`.
822-
823-
An example of setting a custom header with current time in seconds with the milliseconds resolution:
824-
825-
.. code-block:: none
826-
827-
route:
828-
cluster: www
829-
request_headers_to_add:
830-
- header:
831-
key: "x-request-start"
832-
value: "%START_TIME(%s.%3f)%"
833-
append_action: APPEND_IF_EXISTS_OR_ADD
834-
835-
%RESPONSE_FLAGS%
836-
Additional details about the response or connection, if any. Possible values and their meanings
837-
are listed in the access log formatter :ref:`documentation<config_access_log_format_response_flags>`.
838-
839-
%RESPONSE_CODE_DETAILS%
840-
Response code details provides additional information about the HTTP response code, such as
841-
who set it (the upstream or envoy) and why.
842-
843-
%VIRTUAL_CLUSTER_NAME%
844-
Name of the Virtual Cluster which gets matched (if any).
625+
Use :ref:`%FILTER_STATE(reverse.dns.data.name:PLAIN):Z%<config_access_log_format_filter_state>` instead.

envoy/http/header_evaluator.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@ class HeaderEvaluator {
1313
/**
1414
* Apply the header operations that are saved in the HeaderEvaluator. An example of the operation
1515
* is to add a new header name `foo` to the target header map and the header value is extracted
16-
* from the `bar` field in the stream_info.
16+
* from the `bar` field in the stream_info, request headers or response headers.
1717
*
1818
* @param headers the target header map to be mutated.
19+
* @param request_headers request headers to be used in the header manipulation.
20+
* @param response_headers response headers to be used in the header manipulation.
1921
* @param stream_info the source of values that can be used in the evaluation.
2022
*/
2123
virtual void evaluateHeaders(Http::HeaderMap& headers,
24+
const Http::RequestHeaderMap& request_headers,
25+
const Http::ResponseHeaderMap& response_headers,
2226
const StreamInfo::StreamInfo& stream_info) const PURE;
2327
};
2428
} // namespace Http

source/common/grpc/async_client_impl.cc

+5
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ void AsyncStreamImpl::initialize(bool buffer_body_for_retry) {
9696
parent_.host_name_.empty() ? parent_.remote_cluster_name_ : parent_.host_name_,
9797
service_full_name_, method_name_, options_.timeout);
9898
// Fill service-wide initial metadata.
99+
// TODO(cpakulski): Find a better way to access requestHeaders after runtime guard
100+
// envoy_reloadable_features_unified_header_formatter runtime guard is deprecated and
101+
// request headers are not stored in stream_info.
102+
// Maybe put it to parent_context?
103+
// Since request headers may be empty, consider using Envoy::OptRef.
99104
parent_.metadata_parser_->evaluateHeaders(headers_message_->headers(),
100105
options_.parent_context.stream_info);
101106

source/common/grpc/google_async_client_impl.cc

+4
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ void GoogleAsyncStreamImpl::initialize(bool /*buffer_body_for_retry*/) {
182182
ctxt_.set_deadline(abs_deadline);
183183
// Fill service-wide initial metadata.
184184
auto initial_metadata = Http::RequestHeaderMapImpl::create();
185+
// TODO(cpakulski): Find a better way to access requestHeaders after runtime guard
186+
// envoy_reloadable_features_unified_header_formatter runtime guard is deprecated
187+
// and request headers are not stored in stream_info.
188+
// Maybe put it to parent_context?
185189
parent_.metadata_parser_->evaluateHeaders(*initial_metadata, options_.parent_context.stream_info);
186190
callbacks_.onCreateInitialMetadata(*initial_metadata);
187191
initial_metadata->iterate([this](const Http::HeaderEntry& header) {

0 commit comments

Comments
 (0)