hashicorp / hashicorp/consul

[Connect] Support Envoy HTTP filter injection for outbound listeners

Open
#11,404 9 comments 6 reactions 0 assignees View on GitHub
theme/connect theme/envoy/xds type/enhancement
Dominant language
Go
Stars
30.1k
Forks
4.6k
Avg merge
2d 6h
Merged PRs (30d)
43

Description

#### Feature Description
Provide a way to inject Envoy HTTP filters to specified positions for outbound listeners. A possible configuration could look like this:
```json
{
"sidecar_service": {
"proxy": {
"upstreams": [
{
"destination_name": "bar-service",
"local_bind_port": 9000,
"http_filters": [
{
"position": "BEFORE envoy.filters.http.router",
"filter": {
"name": "envoy.filters.http.lua",
"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua",
"inline_code": "-- Envoy Lua filter implementation --"
}
}
}
]
}
]
}
}
}
```

To fully utilize the filter injection support, similar configuration should be supported for the [Nomad Upstream Stanza](https://www.nomadproject.io/docs/job-specification/upstreams#upstreams-stanza).

#### Use Case(s)
Currently, the only way to add Envoy filters is using [escape hatch overrides](https://www.consul.io/docs/connect/proxies/envoy#escape-hatch-overrides), more specifically `envoy_listener_json` for outbound listeners. However, `envoy_listener_json` is ignored when a `service-router`, `service-splitter` or `service-resolver` is used. It's also tricky to get configurations right with escape hatch overrides.

Adding Envoy filter injection support will unlock a lot of potential for users to [extend envoy](https://www.envoyproxy.io/docs/envoy/latest/extending/extending) for their use cases.

An example use case of this is to allow Envoy to call out to an external service before sending requests to the upstream, which can be done either by an Envoy Lua filter or the [Envoy external processing filter](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/ext_proc_filter).

In my current project we have a use case where a service `foo` sends requests to upstream services that were deployed into multiple consul datacenters. In order to make the right routing decision, a call to an external datacenter lookup service has to be made to locate the target consul datacenter. The datacenter name is then attached as a request header `x-consul-dc`. We have a consul `service-resolver` config which routes requests to the right consul datacenter based on the `x-consul-dc` header.

Now we can either integrate the datacenter lookup service call at the service level, or we can have an Envoy filter to do that. The problem with the service level integration is that we'll have to do the same integration for each service that requires the same thing (we have 30+ services with this requirement). Compared to that, Envoy is the right level to do the integration, since we can implement a filter and enable it for all services that use this pattern.

The request workflow would look like this:
```
datacenter lookup service
^
[x-foo-id: 200] | [x-foo-id: 200; x-consul-dc: dc2]
foo ------------------> custom envoy filter (DC lookup) ----------------------------------> router filter -> bar@dc2
```
As mentioned above, the custom envoy DC lookup filter queries the external datacenter lookup service with `x-foo-id` and sets `x-consul-dc` based on the response from the lookup service.

cc @blake

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.