envoyproxy / envoy

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

Dynamic host determination for plaintext HTTP encapsulation in CONNECT #34435

Open marc-barry opened 1 month ago

marc-barry commented 1 month ago

Title: Dynamically extracting the plaintext HTTP host/authority and encapsulating in CONNECT

Description:

I have followed the example found in https://github.com/envoyproxy/envoy/blob/main/configs/encapsulate_http_in_http2_connect.yaml for setting up HTTP encapsulating in CONNECT. The example uses a fixed hostname of host.com:443 and I want to dynamically determine it from the :authority of the plaintext HTTP connection.

I have read about and see that with https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/tcp_proxy/v3/tcp_proxy.proto#extensions-filters-network-tcp-proxy-v3-tcpproxy-tunnelingconfig the hostname can be a command operator. In fact, I have an example which handles encrypted traffic, TLS inspector and %REQUESTED_SERVER_NAME% which works perfectly. But I need to also handle plaintext HTTP traffic and encapsulate that in CONNECT.

The suggestion in https://github.com/envoyproxy/envoy/issues/30674 seems to be to use dynamic metadata and propagate this to the internal listener and then use this metadata to set the hostname. https://www.envoyproxy.io/docs/envoy/latest/configuration/other_features/internal_listener#internal-upstream-transport allows for the exchange of the filter state from the downstream listener to the internal listener through a user space socket. I have configured https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/transport_sockets/internal_upstream/v3/internal_upstream.proto#envoy-v3-api-msg-extensions-transport-sockets-internal-upstream-v3-internalupstreamtransport and wrapped a https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/transport_sockets/raw_buffer/v3/raw_buffer.proto transport socket. My hope was that I could use something like the envoy.network.upstream_server_name metadata key and set it in an HTTP connection manager to the value of %REQ(:AUTHORITY)% and then set the hostname to something like %DYNAMIC_METADATA(envoy.network:upstream_server_name)%:443. This simply doesn't work for me and I cannot seem to figure out how to get this to work.

I've hit a wall as I cannot seem to figure out how to carry %REQ(:AUTHORITY)% to the internal listener so it can be used as the hostname. Any hints would be welcome.

Relevant Links:

marc-barry commented 1 month ago

Here's a config for a setup from the http://localhost:9901/config_dump endpoint (with some irrelevant data removed). I'm mostly confused at why setting the metadata for envoy.network.upstream_server_name isn't working and/or isn't being passed to the internal listener:

(I'm aware of the Basic auth string in the JSON as it is simply base64 encoded user1:password1.)

{
    "configs": [
        {
            "@type": "type.googleapis.com/envoy.admin.v3.ClustersConfigDump",
            "version_info": "1717190533136161000",
            "static_clusters": [
                {
                    "cluster": {
                        "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
                        "name": "ext_authz_cluster",
                        "type": "STATIC",
                        "load_assignment": {
                            "cluster_name": "ext_authz_cluster",
                            "endpoints": [
                                {
                                    "lb_endpoints": [
                                        {
                                            "endpoint": {
                                                "address": {
                                                    "socket_address": {
                                                        "address": "127.0.0.1",
                                                        "port_value": 18001
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            ]
                        },
                        "typed_extension_protocol_options": {
                            "envoy.extensions.upstreams.http.v3.HttpProtocolOptions": {
                                "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions",
                                "explicit_http_config": {
                                    "http2_protocol_options": {}
                                }
                            }
                        }
                    },
                    "last_updated": "2024-05-31T21:22:13.280Z"
                },
                {
                    "cluster": {
                        "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
                        "name": "xds_cluster",
                        "type": "STATIC",
                        "load_assignment": {
                            "cluster_name": "xds_cluster",
                            "endpoints": [
                                {
                                    "lb_endpoints": [
                                        {
                                            "endpoint": {
                                                "address": {
                                                    "socket_address": {
                                                        "address": "127.0.0.1",
                                                        "port_value": 18000
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            ]
                        },
                        "typed_extension_protocol_options": {
                            "envoy.extensions.upstreams.http.v3.HttpProtocolOptions": {
                                "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions",
                                "explicit_http_config": {
                                    "http2_protocol_options": {}
                                }
                            }
                        }
                    },
                    "last_updated": "2024-05-31T21:22:13.280Z"
                }
            ],
            "dynamic_active_clusters": [
                {
                    "version_info": "1717190533136161000",
                    "cluster": {
                        "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
                        "name": "connect_upstream_cluster",
                        "type": "LOGICAL_DNS",
                        "connect_timeout": "5s",
                        "circuit_breakers": {
                            "thresholds": [
                                {
                                    "max_connections": 10000,
                                    "max_pending_requests": 10000,
                                    "max_requests": 10000,
                                    "max_retries": 3
                                }
                            ]
                        },
                        "dns_lookup_family": "V4_ONLY",
                        "load_assignment": {
                            "cluster_name": "connect_upstream_cluster",
                            "endpoints": [
                                {
                                    "lb_endpoints": [
                                        {
                                            "endpoint": {
                                                "address": {
                                                    "socket_address": {
                                                        "address": "localhost",
                                                        "port_value": 10443
                                                    }
                                                },
                                                "hostname": "localhost"
                                            }
                                        }
                                    ]
                                }
                            ]
                        },
                        "typed_extension_protocol_options": {
                            "envoy.extensions.upstreams.http.v3.HttpProtocolOptions": {
                                "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions",
                                "use_downstream_protocol_config": {
                                    "http_protocol_options": {}
                                }
                            }
                        },
                        "respect_dns_ttl": true
                    },
                    "last_updated": "2024-05-31T21:22:13.286Z"
                },
                {
                    "version_info": "1717190533136161000",
                    "cluster": {
                        "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
                        "name": "encap_0.0.0.0:16080",
                        "connect_timeout": "5s",
                        "circuit_breakers": {
                            "thresholds": [
                                {
                                    "max_connections": 10000,
                                    "max_pending_requests": 10000,
                                    "max_requests": 10000,
                                    "max_retries": 3
                                }
                            ]
                        },
                        "transport_socket": {
                            "name": "envoy.transport_sockets.internal_upstream",
                            "typed_config": {
                                "@type": "type.googleapis.com/envoy.extensions.transport_sockets.internal_upstream.v3.InternalUpstreamTransport",
                                "passthrough_metadata": [
                                    {
                                        "kind": {
                                            "cluster": {}
                                        },
                                        "name": "envoy.network"
                                    },
                                    {
                                        "kind": {
                                            "host": {}
                                        },
                                        "name": "envoy.network"
                                    }
                                ],
                                "transport_socket": {
                                    "name": "envoy.transport_sockets.raw_buffer",
                                    "typed_config": {
                                        "@type": "type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer"
                                    }
                                }
                            }
                        },
                        "load_assignment": {
                            "cluster_name": "encap_0.0.0.0:16080",
                            "endpoints": [
                                {
                                    "lb_endpoints": [
                                        {
                                            "endpoint": {
                                                "address": {
                                                    "envoy_internal_address": {
                                                        "server_listener_name": "encap_0.0.0.0:16080"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            ]
                        },
                        "respect_dns_ttl": true
                    },
                    "last_updated": "2024-05-31T21:22:13.287Z"
                }
            ]
        },
        {
            "@type": "type.googleapis.com/envoy.admin.v3.ListenersConfigDump",
            "version_info": "1717190533136161000",
            "dynamic_listeners": [
                {
                    "name": "tcp_0.0.0.0:16443",
                    "active_state": {
                        "version_info": "1717190533136161000",
                        "listener": {
                            "@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
                            "name": "tcp_0.0.0.0:16443",
                            "address": {
                                "socket_address": {
                                    "address": "0.0.0.0",
                                    "port_value": 16443
                                }
                            },
                            "filter_chains": [
                                {
                                    "filters": [
                                        {
                                            "name": "envoy.tcp_proxy",
                                            "typed_config": {
                                                "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
                                                "stat_prefix": "tcp",
                                                "cluster": "connect_upstream_cluster",
                                                "access_log": [
                                                    {
                                                        "name": "envoy.access_loggers.file",
                                                        "typed_config": {
                                                            "@type": "type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog",
                                                            "path": "/dev/stdout",
                                                            "log_format": {
                                                                "json_format": {
                                                                    "upstreamRemoteAddress": "%UPSTREAM_REMOTE_ADDRESS%",
                                                                    "bytesReceived": "%BYTES_RECEIVED%",
                                                                    "bytesSent": "%BYTES_SENT%",
                                                                    "downstreamRemoteAddress": "%DOWNSTREAM_REMOTE_ADDRESS%",
                                                                    "duration": "%DURATION%",
                                                                    "requestedServerName": "%REQUESTED_SERVER_NAME%",
                                                                    "startTime": "%START_TIME%",
                                                                    "responseFlags": "%RESPONSE_FLAGS%",
                                                                    "upstreamCluster": "%UPSTREAM_CLUSTER%"
                                                                }
                                                            }
                                                        }
                                                    }
                                                ],
                                                "tunneling_config": {
                                                    "hostname": "%REQUESTED_SERVER_NAME%:443",
                                                    "headers_to_add": [
                                                        {
                                                            "header": {
                                                                "key": "Proxy-Authorization",
                                                                "value": "Basic dXNlcjE6cGFzc3dvcmQx"
                                                            }
                                                        }
                                                    ]
                                                }
                                            }
                                        }
                                    ]
                                }
                            ],
                            "listener_filters": [
                                {
                                    "name": "envoy.filters.listener.tls_inspector",
                                    "typed_config": {
                                        "@type": "type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector"
                                    }
                                }
                            ],
                            "enable_reuse_port": false
                        },
                        "last_updated": "2024-05-31T21:22:13.290Z"
                    }
                },
                {
                    "name": "tcp_0.0.0.0:16080",
                    "active_state": {
                        "version_info": "1717190533136161000",
                        "listener": {
                            "@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
                            "name": "tcp_0.0.0.0:16080",
                            "address": {
                                "socket_address": {
                                    "address": "0.0.0.0",
                                    "port_value": 16080
                                }
                            },
                            "filter_chains": [
                                {
                                    "filter_chain_match": {
                                        "application_protocols": [
                                            "http/1.1",
                                            "h2c",
                                            "http/1.0",
                                            "h3",
                                            "h2"
                                        ]
                                    },
                                    "filters": [
                                        {
                                            "name": "envoy.filters.network.http_connection_manager",
                                            "typed_config": {
                                                "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
                                                "stat_prefix": "http",
                                                "route_config": {
                                                    "name": "http",
                                                    "virtual_hosts": [
                                                        {
                                                            "name": "default",
                                                            "domains": [
                                                                "*"
                                                            ],
                                                            "routes": [
                                                                {
                                                                    "match": {
                                                                        "prefix": "/"
                                                                    },
                                                                    "route": {
                                                                        "cluster": "encap_0.0.0.0:16080"
                                                                    }
                                                                }
                                                            ]
                                                        }
                                                    ]
                                                },
                                                "http_filters": [
                                                    {
                                                        "name": "envoy.filters.http.set_filter_state",
                                                        "typed_config": {
                                                            "@type": "type.googleapis.com/envoy.extensions.filters.http.set_filter_state.v3.Config",
                                                            "on_request_headers": [
                                                                {
                                                                    "object_key": "envoy.network.upstream_server_name",
                                                                    "format_string": {
                                                                        "text_format_source": {
                                                                            "inline_string": "%REQ(:AUTHORITY)%"
                                                                        }
                                                                    },
                                                                    "shared_with_upstream": "TRANSITIVE"
                                                                }
                                                            ]
                                                        }
                                                    },
                                                    {
                                                        "name": "envoy.filters.http.router",
                                                        "typed_config": {
                                                            "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
                                                        }
                                                    }
                                                ],
                                                "http2_protocol_options": {
                                                    "allow_connect": true
                                                },
                                                "access_log": [
                                                    {
                                                        "name": "envoy.access_loggers.file",
                                                        "typed_config": {
                                                            "@type": "type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog",
                                                            "path": "/dev/stdout",
                                                            "log_format": {
                                                                "json_format": {
                                                                    "protocol": "%PROTOCOL%",
                                                                    "responseCodeDetails": "%RESPONSE_CODE_DETAILS%",
                                                                    "requestedServerName": "%REQUESTED_SERVER_NAME%",
                                                                    "upstreamCluster": "%UPSTREAM_CLUSTER%",
                                                                    "path": "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%",
                                                                    "downstreamRemoteAddress": "%DOWNSTREAM_REMOTE_ADDRESS%",
                                                                    "requestMethod": "%REQ(:METHOD)%",
                                                                    "responseCode": "%RESPONSE_CODE%",
                                                                    "bytesReceived": "%BYTES_RECEIVED%",
                                                                    "duration": "%DURATION%",
                                                                    "responseFlags": "%RESPONSE_FLAGS%",
                                                                    "requestId": "%REQ(X-REQUEST-ID)%",
                                                                    "startTime": "%START_TIME%",
                                                                    "upstreamRemoteAddress": "%UPSTREAM_REMOTE_ADDRESS%",
                                                                    "bytesSent": "%BYTES_SENT%",
                                                                    "upstreamProtocol": "%UPSTREAM_PROTOCOL%",
                                                                    "requestAuthority": "%REQ(:AUTHORITY)%"
                                                                }
                                                            }
                                                        }
                                                    }
                                                ],
                                                "use_remote_address": true,
                                                "upgrade_configs": [
                                                    {
                                                        "upgrade_type": "CONNECT"
                                                    },
                                                    {
                                                        "upgrade_type": "websocket",
                                                        "filters": [
                                                            {
                                                                "name": "envoy.filters.http.set_filter_state",
                                                                "typed_config": {
                                                                    "@type": "type.googleapis.com/envoy.extensions.filters.http.set_filter_state.v3.Config",
                                                                    "on_request_headers": [
                                                                        {
                                                                            "object_key": "envoy.network.upstream_server_name",
                                                                            "format_string": {
                                                                                "text_format_source": {
                                                                                    "inline_string": "%REQ(:AUTHORITY)%"
                                                                                }
                                                                            },
                                                                            "shared_with_upstream": "TRANSITIVE"
                                                                        }
                                                                    ]
                                                                }
                                                            },
                                                            {
                                                                "name": "envoy.filters.http.router",
                                                                "typed_config": {
                                                                    "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
                                                                }
                                                            }
                                                        ]
                                                    }
                                                ],
                                                "append_x_forwarded_port": true
                                            }
                                        }
                                    ]
                                }
                            ],
                            "listener_filters": [
                                {
                                    "name": "envoy.filters.listener.http_inspector",
                                    "typed_config": {
                                        "@type": "type.googleapis.com/envoy.extensions.filters.listener.http_inspector.v3.HttpInspector"
                                    }
                                }
                            ],
                            "enable_reuse_port": false
                        },
                        "last_updated": "2024-05-31T21:22:13.292Z"
                    }
                },
                {
                    "name": "encap_0.0.0.0:16080",
                    "active_state": {
                        "version_info": "1717190533136161000",
                        "listener": {
                            "@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
                            "name": "encap_0.0.0.0:16080",
                            "filter_chains": [
                                {
                                    "filters": [
                                        {
                                            "name": "envoy.tcp_proxy",
                                            "typed_config": {
                                                "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
                                                "stat_prefix": "tcp",
                                                "cluster": "connect_upstream_cluster",
                                                "access_log": [
                                                    {
                                                        "name": "envoy.access_loggers.file",
                                                        "typed_config": {
                                                            "@type": "type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog",
                                                            "path": "/dev/stdout",
                                                            "log_format": {
                                                                "json_format": {
                                                                    "upstreamCluster": "%UPSTREAM_CLUSTER%",
                                                                    "responseFlags": "%RESPONSE_FLAGS%",
                                                                    "bytesSent": "%BYTES_SENT%",
                                                                    "downstreamRemoteAddress": "%DOWNSTREAM_REMOTE_ADDRESS%",
                                                                    "duration": "%DURATION%",
                                                                    "requestedServerName": "%REQUESTED_SERVER_NAME%",
                                                                    "startTime": "%START_TIME%",
                                                                    "upstreamRemoteAddress": "%UPSTREAM_REMOTE_ADDRESS%",
                                                                    "bytesReceived": "%BYTES_RECEIVED%"
                                                                }
                                                            }
                                                        }
                                                    }
                                                ],
                                                "tunneling_config": {
                                                    "hostname": "%DYNAMIC_METADATA(envoy.network:upstream_server_name)%:80",
                                                    "headers_to_add": [
                                                        {
                                                            "header": {
                                                                "key": "Proxy-Authorization",
                                                                "value": "Basic dXNlcjE6cGFzc3dvcmQx"
                                                            }
                                                        }
                                                    ]
                                                }
                                            }
                                        }
                                    ]
                                }
                            ],
                            "internal_listener": {}
                        },
                        "last_updated": "2024-05-31T21:22:13.292Z"
                    }
                }
            ]
        },
        {
            "@type": "type.googleapis.com/envoy.admin.v3.ScopedRoutesConfigDump"
        },
        {
            "@type": "type.googleapis.com/envoy.admin.v3.RoutesConfigDump",
            "static_route_configs": [
                {
                    "route_config": {
                        "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
                        "name": "http",
                        "virtual_hosts": [
                            {
                                "name": "default",
                                "domains": [
                                    "*"
                                ],
                                "routes": [
                                    {
                                        "match": {
                                            "prefix": "/"
                                        },
                                        "route": {
                                            "cluster": "encap_0.0.0.0:16080"
                                        }
                                    }
                                ]
                            }
                        ]
                    },
                    "last_updated": "2024-05-31T21:22:13.291Z"
                }
            ]
        },
        {
            "@type": "type.googleapis.com/envoy.admin.v3.SecretsConfigDump"
        }
    ]
}
marc-barry commented 1 month ago

I should also point out that the tunnelling for TLS traffic on 16443 is working properly. The issue is with listener on 16080 as that is the one intended to handle the plaintext HTTP encapsulation in a CONNECT.

github-actions[bot] commented 5 days ago

This issue has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in the next 7 days unless it is tagged "help wanted" or "no stalebot" or other activity occurs. Thank you for your contributions.

marc-barry commented 4 days ago

I'd still like help if possible. I'm not able to tag it as "help wanted" on my own.