envoyproxy / envoy

Cloud-native high-performance edge/middle/service proxy
https://www.envoyproxy.io
Apache License 2.0
24.86k stars 4.78k forks source link

Feature Request: add support to remove response headers by prefix to VirtualHost #21054

Open pims opened 2 years ago

pims commented 2 years ago

Title: In addition to response_headers_to_remove, support for removing response headers by prefix would be useful

Description:

Envoy VirtualHost configuration currently supports removing headers by names with the response_headers_to_remove field.

response_headers_to_remove
(repeated [string](https://developers.google.com/protocol-buffers/docs/proto#scalar)) Specifies a list of HTTP headers that should be removed from each response handled by this virtual host.

When the list of upstream response headers to remove isn't known at "config time" or when the list of upstream response headers can change dynamically, having the ability to remove any response header with a given prefix would be useful.

Example:

HTTP/1.1 200 OK
date: Wed, 27 Apr 2022 15:55:26 GMT
content-length: 7
content-type: text/plain; charset=utf-8
x-envoy-upstream-service-time: 5
server: envoy
x-acme-inc-internal-user-id: 1234        🛑 
x-acme-inc-internal-vm-id: vm-bc0563f5   🛑 
x-acme-inc-features-enabled: foo,bar,baz 🛑 

Being able to remove all response headers having the prefix x-acme-inc- would limit leaking information via headers. The remove by prefix behavior could also be generalized by removing all headers matching a configured regexp, following the RouteMatch configuration:

# Precisely one of prefix, safe_regex must be set
{
  "prefix": "...", 
  "safe_regex": "{...}" 
}

🗣️ Removing headers by prefix can already be done with the Lua filter but ideally, one wouldn't need to invoke the Lua filter for "simple" headers manipulation.

Example:

http_filters:
- name: envoy.filters.http.lua
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
    inline_code: |
      -- Called on the request path.
      function envoy_on_request(request_handle)
      end

      function envoy_on_response(response_handle)
        local headers = response_handle:headers()
        local prefix = "x-acme-inc"
        -- In the current implementation, headers cannot be modified during iteration.
        -- store header names locally first and iterate over this table to remove them later
        local to_remove = {}
        for key, value in pairs(headers) do
          if key:find(prefix, 1, true) == 1 then
            response_handle:logInfo("found header matching prefix: "..key)
            table.insert(to_remove, key)
          end
        end

        for _, value in pairs(to_remove) do
          response_handle:logInfo("removing header: "..value)
          headers:remove(value)
        end
      end

If this sounds like a feature that would be accepted, I'd be happy to send a PR.

Relevant Links:

https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto.html?highlight=response_headers_to_remove#config-route-v3-virtualhost

https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/lua_filter#pairs

mattklein123 commented 2 years ago

Sure this sounds reasonable to me!