Skip to content
Closed
Changes from 2 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
94 changes: 94 additions & 0 deletions A91-xds-authority-literal-rewrite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
Title
----
* Author(s): Zhiyan Foo
* Approver: a11r
Comment thread
zhiyanfoo marked this conversation as resolved.
Outdated
* Status: Draft
* Implemented in: TBD
* Last updated: 2025-04-23
* Discussion at: TBD (filled after thread exists)

## Abstract

Implement the
[`host_rewrite_literal`](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-host-rewrite-literal)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use a footnote link for nicer plain text formatting, like you did for gRFC links:

[`host_rewrite_literal`][envoy-host_rewrite_literal]

And then at the end of the doc:

[envoy-host_rewrite_literal]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-host-rewrite-literal

route_action feature in gRPC xDS client, enabling explicit authority header rewrites. This will
be conditioned on `trusted_xds_server` as described in [gRFC A81][A81].


## Background

gRPC xDS currently supports `auto_host_rewrite` as per [gRFC A81][A81] but lacks `host_rewrite_literal`
support, useful when a single cluster targets a reverse proxy routing based on the authority
header.
```
+------------------+
| gRPC xDS Client | <- (RDS configuration sets `host_rewrite_literal` to
+------------------+ target one of Svc A/B/C)
|
| <- (gRPC xDS client reuses the same CDS target for all connections to
| the proxy)
+---------+
| Proxy |
+---------+
| <- (Proxy routing logic based on Authority header)
.---------------+--------------.
/ | \
+--------+ +--------+ +--------+
| Svc A | | Svc B | | Svc C |
+--------+ +--------+ +--------+
```

### Related Proposals:
* [gRFC A29: xDS-Based Security for gRPC Clients and Servers][A29]
* [gRFC A81: xDS Authority Rewriting][A81]
* [gRFC A86: xDS-Based HTTP CONNECT][A86]


## Proposal

This proposal has the following parts:
- xDS resource unmarshalling: We will retrieve the `host_rewrite_literal` value from rds. The
protobuf option for authority rewriting is already set as a one-of, so there's no issue of
deciding precedence of the different authority writing options.

If the `xds_trusted_server` attribute is set to false, the `host_rewrite_literal` field will
be ignored.

- xDS ConfigSelector: We will propagate the `host_rewrite_literal` configuration to the
configSeletor where it would be stored in the rpc context.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think RPC context is a cross-language feature, unfortunately. I see two solutions for this:

  1. Do the same as auto_host_rewrite, where it's done in the picker (but in our case as you pointed out there's no need to involve the picker if we have another way to communicate between picker -> transport).

  2. Do the same as channel credentials (TLS identity) which is passed via "channel args": https://github.com/grpc/grpc/blob/master/src/core/load_balancing/lb_policy.h#L377. Perhaps C-core can use this mechanism here.

  3. sounds cleaner to me because it doesn't involve the picker (as you pointed out since the balancer is not involved for host_rewrite_literal).

So I think a better phrasing would be that of gRFC 29:

gRPC will pass down the hostname to use to the child policies via channel arguments, or a similar mechanism depending on the language.

It looks like Go does the following for TLS credentials (A69): it wraps the clientconn to intercept subchannel creation, and override the credentials for it. The code is at https://github.com/grpc/grpc-go/blob/68205d5d0a21ca0bf2fb849aeaa4f9bfa6292533/xds/internal/balancer/cdsbalancer/cdsbalancer.go#L689-L701. We could technically do the same for overriding the host used for the subconn. I wonder if this mechanism could also be used to support SNI setting via the transport socket configuration, something we've identified as lacking support in grpc?

For SNI I think we should start with a bug report on https://github.com/grpc/grpc/, but this seems quite related, since SNI is presumably taken from the ServerName field of the subconn, the same that you want to override in https://github.com/DataDog/grpc-go-private/pull/19/files#diff-5334018444bcb34d15bcb3c8a3050cdf9c8a40fe41305c3a602ea4bfeb0cd178L744-L749. This would remove the special logic in the stream creation in the transport, which is perhaps a bit cleaner. WDYT?


- During the stream creation, when the RPC call attributes are being set, if there is a non-empty
value for the `host_rewrite_literal`, it will take precedence over other options for the RPC
Call Host attribute. An exception would if a host override is specified either per-client or
per-RPC. In either case the per-client or per-RPC configuration would take precedence.


### Temporary environment variable protection

Feature guarded by `GRPC_XDS_EXPERIMENTAL_AUTHORIY_LITERAL_REWRITE`, disabled by default.

## Rationale

Alternative approaches considered.
- Exclusively use the existing [`auto_host_rewrite`][route_action] feature. This would require a
CDS cluster per upstream target, which means that there would be one connection per service
behind the proxy between each gRPC clients and the proxy.
- Using the HTTP CONNECT protocol has the same drawback in that connections to the proxy that
target different upstream services won't reuse the same connection.
- in the case where instead of a single proxy in between the client and target upstream
service there are two proxies (e.g. client -> egress proxy -> ingress proxy -> svc), this
would not only prevent connection reuse between the initial client to the proxy, but also
between the intermediary proxies (e.g. between the egress and ingress proxy).

Even if connection pooling was not a major concern, this addition will bring gRPC xDS client
functionality closer to parity with Envoy's capabilities, simplifying configurations for users
migrating to or using both systems concurrently.

## Implementation

[Go implementation](https://github.com/zhiyanfoo/grpc-go/pull/2/files).

[A29]: A29-xds-tls-security.md
[A81]: A81-xds-authority-rewriting.md
[A86]: https://github.com/grpc/proposal/pull/455
[route_action]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto