From e81e0c082e8c013aa147a0461e185cd562836e5b Mon Sep 17 00:00:00 2001 From: envoy-bot Date: Tue, 3 Nov 2026 10:09:08 +0000 Subject: [PATCH] [protobuf] Update protobuf definitions to v1.40.2 Signed-off-by: envoy-bot --- .../main/proto/envoy/admin/v3/memory.proto | 2 +- .../proto/envoy/admin/v3/mutex_stats.proto | 4 +- .../envoy/config/bootstrap/v3/bootstrap.proto | 14 +- .../envoy/config/cluster/v3/cluster.proto | 27 +- .../proto/envoy/config/core/v3/address.proto | 22 +- .../proto/envoy/config/core/v3/base.proto | 5 + .../envoy/config/core/v3/config_source.proto | 38 ++- .../envoy/config/core/v3/health_check.proto | 32 +- .../envoy/config/core/v3/proxy_protocol.proto | 3 +- .../core/v3/substitution_format_string.proto | 10 +- .../envoy/config/listener/v3/listener.proto | 20 +- .../config/listener/v3/quic_config.proto | 5 +- .../proto/envoy/config/metrics/v3/stats.proto | 15 + .../envoy/config/overload/v3/overload.proto | 11 +- .../proto/envoy/config/route/v3/route.proto | 34 +- .../config/route/v3/route_components.proto | 55 ++- .../envoy/config/trace/v3/opentelemetry.proto | 18 +- .../proto/envoy/data/ai/v3/request_info.proto | 52 +++ .../proto/envoy/data/ai/v3/token_usage.proto | 112 ++++++ .../data/core/v3/health_check_event.proto | 1 + .../dynamic_modules/v3/dynamic_modules.proto | 3 +- .../open_telemetry/v3/logs_service.proto | 18 +- .../dynamic_modules/v3/dynamic_modules.proto | 3 +- ..._reverse_connection_socket_interface.proto | 24 +- ..._reverse_connection_socket_interface.proto | 11 +- .../clusters/composite/v3/cluster.proto | 8 +- .../mcp_multicluster/v3/cluster.proto | 45 +++ .../common/ratelimit/v3/ratelimit.proto | 4 + .../dynamic_modules/v3/dynamic_modules.proto | 58 ++++ .../filters/common/jwks/v3/jwks.proto | 105 ++++++ .../common/jwks/v3/jwt_handshake.proto | 77 +++++ .../v3/adaptive_concurrency.proto | 7 + .../v3/ai_protocol_manager.proto | 240 +++++++++++++ .../v3/aws_eventstream_parser.proto | 117 +++++++ .../http/basic_auth/v3/basic_auth.proto | 19 +- .../body_size_limit/v3/body_size_limit.proto | 24 ++ .../http/compressor/v3/compressor.proto | 15 +- .../dynamic_modules/v3/dynamic_modules.proto | 6 +- .../filters/http/ext_authz/v3/ext_authz.proto | 32 +- .../filters/http/ext_proc/v3/ext_proc.proto | 16 +- .../filters/http/fault/v3/fault.proto | 6 +- .../filters/http/gcp_authn/v3/gcp_authn.proto | 73 +++- .../grpc_field_extraction/v3/config.proto | 58 ++++ .../header_mutation/v3/header_mutation.proto | 12 +- .../filters/http/jwt_authn/v3/config.proto | 60 +++- .../local_ratelimit/v3/local_rate_limit.proto | 11 +- .../extensions/filters/http/lua/v3/lua.proto | 107 +++++- .../extensions/filters/http/mcp/v3/mcp.proto | 78 ++++- .../v3/mcp_json_rest_bridge.proto | 110 +++++- .../http/mcp_router/v3/mcp_router.proto | 44 +++ .../filters/http/oauth2/v3/oauth.proto | 64 +++- .../v3/rate_limit_quota.proto | 2 - .../http/ratelimit/v3/rate_limit.proto | 12 +- .../dynamic_modules/v3/dynamic_modules.proto | 3 +- .../dynamic_modules/v3/dynamic_modules.proto | 3 +- .../network/ext_authz/v3/ext_authz.proto | 14 +- .../network/ext_proc/v3/ext_proc.proto | 10 +- .../v3/http_connection_manager.proto | 12 +- .../network/redis_proxy/v3/redis_proxy.proto | 37 +- .../reverse_tunnel/v3/reverse_tunnel.proto | 55 ++- .../udp/dns_filter/v3/dns_filter.proto | 5 + .../dynamic_modules/v3/dynamic_modules.proto | 3 +- .../filters/udp/udp_proxy/v3/udp_proxy.proto | 9 +- .../extensions/formatter/cel/v3/cel.proto | 9 +- .../dynamic_modules/v3/dynamic_modules.proto | 3 +- .../dynamic_modules/v3/dynamic_modules.proto | 3 +- .../health_checkers/udp/v3/udp.proto | 51 +++ .../request_info/v3/request_info.proto | 40 +++ .../v3/schema_validation.proto | 38 +++ .../ai_filters/transcoder/v3/transcoder.proto | 53 +++ .../v3/local_response_policy.proto | 20 +- .../dynamic_modules/v3/dynamic_modules.proto | 90 +++++ .../dynamic_modules/v3/dynamic_modules.proto | 77 +++++ .../generic/v3/generic.proto | 2 +- .../oauth2/v3/oauth2.proto | 28 +- .../filter_state/v3/filter_state_config.proto | 41 +++ .../v3/client_side_weighted_round_robin.proto | 28 +- .../v3/load_aware_locality.proto | 29 +- .../dynamic_modules/v3/dynamic_modules.proto | 38 +++ .../dynamic_modules/v3/dynamic_modules.proto | 23 +- .../queue_policy/fifo/v3/fifo.proto | 18 + .../quic_lb/v3/quic_lb.proto | 7 - .../jwt_claim/v3/jwt_claim.proto | 101 ++++++ .../dynamic_modules/v3/dynamic_modules.proto | 131 +++++++ .../priority_group/v3/priority_group.proto | 193 +++++++++++ .../dynamic_modules/v3/dynamic_modules.proto | 218 ++++++++++++ .../dynamic_modules/v3/dynamic_modules.proto | 3 +- .../graphite_statsd/v3/graphite_statsd.proto | 7 + .../dynamic_modules/v3/dynamic_modules.proto | 3 +- .../quic/v3/quic_transport.proto | 19 +- .../dynamic_modules/v3/dynamic_modules.proto | 49 +++ .../transport_sockets/tls/v3/common.proto | 22 +- .../transport_sockets/tls/v3/tls.proto | 4 +- .../http/v3/http_protocol_options.proto | 12 +- .../proto/envoy/extensions/wasm/v3/wasm.proto | 17 +- .../v3/backtrace_action.proto | 25 ++ .../envoy/service/auth/v3/external_auth.proto | 6 + .../ext_proc/v3/external_processor.proto | 323 ++++++++++++++++-- .../v3/network_external_processor.proto | 7 +- .../service/rate_limit_quota/v3/rlqs.proto | 3 - .../envoy/service/ratelimit/v3/rls.proto | 5 + .../proto/envoy/type/ai/v3/llm_protocol.proto | 42 +++ .../envoy/type/metadata/v3/metadata.proto | 16 +- .../envoy/type/tracing/v3/custom_tag.proto | 43 ++- api/src/main/proto/envoy/type/v3/http.proto | 5 - .../main/proto/google/api/annotations.proto | 2 +- .../google/api/expr/v1alpha1/checked.proto | 2 +- .../google/api/expr/v1alpha1/syntax.proto | 2 +- api/src/main/proto/google/api/http.proto | 3 +- api/src/main/proto/google/rpc/status.proto | 2 +- .../controlplane/server/EnvoyContainer.java | 2 +- tools/API_SHAS | 16 +- tools/envoy_release | 2 +- 113 files changed, 3724 insertions(+), 259 deletions(-) create mode 100644 api/src/main/proto/envoy/data/ai/v3/request_info.proto create mode 100644 api/src/main/proto/envoy/data/ai/v3/token_usage.proto create mode 100644 api/src/main/proto/envoy/extensions/config/validators/dynamic_modules/v3/dynamic_modules.proto create mode 100644 api/src/main/proto/envoy/extensions/filters/common/jwks/v3/jwks.proto create mode 100644 api/src/main/proto/envoy/extensions/filters/common/jwks/v3/jwt_handshake.proto create mode 100644 api/src/main/proto/envoy/extensions/filters/http/aws_eventstream_parser/v3/aws_eventstream_parser.proto create mode 100644 api/src/main/proto/envoy/extensions/filters/http/body_size_limit/v3/body_size_limit.proto create mode 100644 api/src/main/proto/envoy/extensions/health_checkers/udp/v3/udp.proto create mode 100644 api/src/main/proto/envoy/extensions/http/ai_filters/request_info/v3/request_info.proto create mode 100644 api/src/main/proto/envoy/extensions/http/ai_filters/schema_validation/v3/schema_validation.proto create mode 100644 api/src/main/proto/envoy/extensions/http/ai_filters/transcoder/v3/transcoder.proto create mode 100644 api/src/main/proto/envoy/extensions/http/early_header_mutation/dynamic_modules/v3/dynamic_modules.proto create mode 100644 api/src/main/proto/envoy/extensions/http/header_formatters/dynamic_modules/v3/dynamic_modules.proto create mode 100644 api/src/main/proto/envoy/extensions/internal_redirect/filter_state/v3/filter_state_config.proto create mode 100644 api/src/main/proto/envoy/extensions/queue_policy/fifo/v3/fifo.proto create mode 100644 api/src/main/proto/envoy/extensions/rate_limit_descriptors/jwt_claim/v3/jwt_claim.proto create mode 100644 api/src/main/proto/envoy/extensions/router/cluster_specifiers/dynamic_modules/v3/dynamic_modules.proto create mode 100644 api/src/main/proto/envoy/extensions/router/cluster_specifiers/priority_group/v3/priority_group.proto create mode 100644 api/src/main/proto/envoy/extensions/router/route_specifiers/dynamic_modules/v3/dynamic_modules.proto create mode 100644 api/src/main/proto/envoy/extensions/transport_sockets/tls/handshakers/dynamic_modules/v3/dynamic_modules.proto create mode 100644 api/src/main/proto/envoy/extensions/watchdog/backtrace_action/v3/backtrace_action.proto create mode 100644 api/src/main/proto/envoy/type/ai/v3/llm_protocol.proto diff --git a/api/src/main/proto/envoy/admin/v3/memory.proto b/api/src/main/proto/envoy/admin/v3/memory.proto index b17e3c1b5..acd17263e 100644 --- a/api/src/main/proto/envoy/admin/v3/memory.proto +++ b/api/src/main/proto/envoy/admin/v3/memory.proto @@ -15,7 +15,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Proto representation of the internal memory consumption of an Envoy instance. These represent // values extracted from an internal TCMalloc instance. For more information, see the section of the -// docs entitled ["Generic Tcmalloc Status"](https://gperftools.github.io/gperftools/tcmalloc.html). +// docs entitled `"Generic Tcmalloc Status" `_. // [#next-free-field: 7] message Memory { option (udpa.annotations.versioning).previous_message_type = "envoy.admin.v2alpha.Memory"; diff --git a/api/src/main/proto/envoy/admin/v3/mutex_stats.proto b/api/src/main/proto/envoy/admin/v3/mutex_stats.proto index 430316706..bca2944d0 100644 --- a/api/src/main/proto/envoy/admin/v3/mutex_stats.proto +++ b/api/src/main/proto/envoy/admin/v3/mutex_stats.proto @@ -15,11 +15,11 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Proto representation of the statistics collected upon absl::Mutex contention, if Envoy is run // under :option:`--enable-mutex-tracing`. For more information, see the ``absl::Mutex`` -// [docs](https://abseil.io/about/design/mutex#extra-features). +// `docs `__. // // *NB*: The wait cycles below are measured by ``absl::base_internal::CycleClock``, and may not // correspond to core clock frequency. For more information, see the ``CycleClock`` -// [docs](https://github.com/abseil/abseil-cpp/blob/master/absl/base/internal/cycleclock.h). +// `docs `__. message MutexStats { option (udpa.annotations.versioning).previous_message_type = "envoy.admin.v2alpha.MutexStats"; diff --git a/api/src/main/proto/envoy/config/bootstrap/v3/bootstrap.proto b/api/src/main/proto/envoy/config/bootstrap/v3/bootstrap.proto index 90c2b62d5..6e705cd60 100644 --- a/api/src/main/proto/envoy/config/bootstrap/v3/bootstrap.proto +++ b/api/src/main/proto/envoy/config/bootstrap/v3/bootstrap.proto @@ -431,7 +431,8 @@ message Bootstrap { GrpcAsyncClientManagerConfig grpc_async_client_manager_config = 40; // Optional configuration for memory allocation manager. - // Memory releasing is only supported for `tcmalloc allocator `_. + // Memory releasing is supported with `tcmalloc `_ and + // `gperftools `_. MemoryAllocatorManager memory_allocator_manager = 41; // When enabled, Envoy pins each worker thread to a distinct CPU from the process affinity mask, @@ -790,13 +791,14 @@ message CustomInlineHeader { // [#next-free-field: 6] message MemoryAllocatorManager { - // Configures tcmalloc to perform background release of free memory in amount of bytes per ``memory_release_interval`` interval. - // If equals to ``0``, no memory release will occur. Defaults to ``0``. + // Configures tcmalloc to perform background release of free memory in amount of bytes per + // ``memory_release_interval`` interval. If equals to ``0``, no memory release will occur. + // Defaults to ``0``. uint64 bytes_to_release = 1; - // Interval in milliseconds for memory releasing. If specified, during every - // interval Envoy will try to release ``bytes_to_release`` of free memory back to operating system for reuse. - // Defaults to ``1000`` milliseconds. + // Interval in milliseconds for memory releasing. If specified, during every interval Envoy will + // try to release ``bytes_to_release`` of free memory back to operating system for reuse. If set + // to ``0``, no memory release will occur. Defaults to ``1000`` milliseconds. google.protobuf.Duration memory_release_interval = 2; // Sets the soft memory limit for tcmalloc. When the total memory used by tcmalloc exceeds this diff --git a/api/src/main/proto/envoy/config/cluster/v3/cluster.proto b/api/src/main/proto/envoy/config/cluster/v3/cluster.proto index a1fe515b0..32cd8419e 100644 --- a/api/src/main/proto/envoy/config/cluster/v3/cluster.proto +++ b/api/src/main/proto/envoy/config/cluster/v3/cluster.proto @@ -13,6 +13,8 @@ import "envoy/config/core/v3/health_check.proto"; import "envoy/config/core/v3/protocol.proto"; import "envoy/config/core/v3/resolver.proto"; import "envoy/config/endpoint/v3/endpoint.proto"; +import "envoy/config/metrics/v3/stats.proto"; +import "envoy/type/matcher/v3/metadata.proto"; import "envoy/type/metadata/v3/metadata.proto"; import "envoy/type/v3/percent.proto"; @@ -46,7 +48,7 @@ message ClusterCollection { } // Configuration for a single upstream cluster. -// [#next-free-field: 61] +// [#next-free-field: 63] message Cluster { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Cluster"; @@ -753,6 +755,18 @@ message Cluster { // harm latency more than the preconnecting helps. google.protobuf.DoubleValue predictive_preconnect_ratio = 2 [(validate.rules).double = {lte: 3.0 gte: 1.0}]; + + // Restricts anticipatory connections to hosts whose endpoint metadata matches this matcher. + // Non-matching hosts are never preconnected, and instead get connections only on demand, as they + // serve real requests. If unset, all healthy hosts are eligible. + type.matcher.v3.MetadataMatcher preconnect_enabled_metadata = 3; + } + + // Queueing policies for the cluster. + message QueuingPolicies { + // Queue policy for cluster pending requests. If unset, Envoy uses the FIFO queue policy. + // [#extension-category: envoy.queue_policy] + core.v3.TypedExtensionConfig pending_rq_policy = 1; } reserved 12, 15, 7, 11, 35; @@ -866,6 +880,12 @@ message Cluster { // :ref:`Router Filter Header `. string alt_stat_name = 28 [(udpa.annotations.field_migrate).rename = "observability_name"]; + // Optional stats matcher that can be used to configure which stats are instantiated for this + // cluster. If configured, this overrides the bootstrap :ref:`stats_config + // ` stats matcher configuration + // for this cluster. + metrics.v3.StatsMatcher stats_matcher = 61; + oneof cluster_discovery_type { // The :ref:`service discovery type ` // to use for resolving the cluster. @@ -914,7 +934,7 @@ message Cluster { // configuration for the cluster. If no // configuration is specified no health checking will be done and all cluster // members will be considered healthy at all times. - repeated core.v3.HealthCheck health_checks = 8; + repeated core.v3.HealthCheck health_checks = 8 [(validate.rules).repeated = {max_items: 8}]; // Optional maximum requests for a single upstream connection. This parameter // is respected by both the HTTP/1.1 and HTTP/2 connection pool @@ -1303,6 +1323,9 @@ message Cluster { // If ``connection_pool_per_downstream_connection`` is true, the cluster will use a separate // connection pool for every downstream connection bool connection_pool_per_downstream_connection = 51; + + // Queueing policies for the cluster (e.g. the queue policy for cluster pending requests). + QueuingPolicies queuing_policies = 62; } // Extensible load balancing policy configuration. diff --git a/api/src/main/proto/envoy/config/core/v3/address.proto b/api/src/main/proto/envoy/config/core/v3/address.proto index 3db6d98df..b9140f623 100644 --- a/api/src/main/proto/envoy/config/core/v3/address.proto +++ b/api/src/main/proto/envoy/config/core/v3/address.proto @@ -103,7 +103,7 @@ message SocketAddress { // network namespace. // // .. note:: - // Setting this parameter requires Envoy to run with the ``CAP_NET_ADMIN`` capability. + // Setting this parameter requires Envoy to run with the ``CAP_SYS_ADMIN`` capability. // // .. attention:: // Network namespaces are only configurable on Linux. Otherwise, this field has no effect. @@ -144,7 +144,7 @@ message ExtraSourceAddress { SocketOptionsOverride socket_options = 2; } -// [#next-free-field: 7] +// [#next-free-field: 8] message BindConfig { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.core.BindConfig"; @@ -180,6 +180,24 @@ message BindConfig { // `). // [#extension-category: envoy.upstream.local_address_selector] TypedExtensionConfig local_address_selector = 6; + + // If set to true, the :ref:`network_namespace_filepath + // ` of every source + // address in this bind config is validated when the configuration is loaded, and the + // configuration is rejected if a referenced network namespace cannot be opened. + // + // By default no such validation is performed: a network namespace that does not exist when the + // configuration is loaded may be created later, before connections are actually established, so + // eager validation would wrongly reject such configurations. If a namespace is unavailable when + // a connection is created, the connection attempt fails gracefully. + // + // Listener addresses do not need an equivalent option: a listener creates and binds its socket + // in the configured network namespace when the listener configuration is loaded, so an + // unavailable namespace always rejects the listener configuration. + // + // .. attention:: + // Network namespaces are only configurable on Linux. Otherwise, this field has no effect. + bool validate_network_namespaces = 7; } // Addresses specify either a logical or physical address and port, which are diff --git a/api/src/main/proto/envoy/config/core/v3/base.proto b/api/src/main/proto/envoy/config/core/v3/base.proto index 8d2ede9e6..103ca0ff3 100644 --- a/api/src/main/proto/envoy/config/core/v3/base.proto +++ b/api/src/main/proto/envoy/config/core/v3/base.proto @@ -486,6 +486,11 @@ message HeaderValueOption { // Is the header value allowed to be empty? If false (default), custom headers with empty values are dropped, // otherwise they are added. + // + // .. note:: + // In any context other than the router filter, we always act as if keep_empty_value is true, + // regardless of the setting of this field. + // bool keep_empty_value = 4; } diff --git a/api/src/main/proto/envoy/config/core/v3/config_source.proto b/api/src/main/proto/envoy/config/core/v3/config_source.proto index 430562aa5..6fc84d9fe 100644 --- a/api/src/main/proto/envoy/config/core/v3/config_source.proto +++ b/api/src/main/proto/envoy/config/core/v3/config_source.proto @@ -157,9 +157,10 @@ message RateLimitSettings { // Local filesystem path configuration source. message PathConfigSource { - // Path on the filesystem to source and watch for configuration updates. - // When sourcing configuration for a :ref:`secret `, - // the certificate and key files are also watched for updates. + // Path on the filesystem from which to source configuration updates. + // When sourcing configuration for a + // :ref:`secret `, file-based secret + // data supported for SDS rotation is also monitored for updates. // // .. note:: // @@ -167,12 +168,14 @@ message PathConfigSource { // // .. note:: // - // If ``watched_directory`` is *not* configured, Envoy will watch the file path for *moves*. - // This is because in general only moves are atomic. The same method of swapping files as is - // demonstrated in the :ref:`runtime documentation ` can be - // used here also. If ``watched_directory`` is configured, no watch will be placed directly on - // this path. Instead, the configured ``watched_directory`` will be used to trigger reloads of - // this path. This is required in certain deployment scenarios. See below for more information. + // If neither ``poll_interval`` nor ``watched_directory`` is configured, Envoy will watch the + // file path for *moves*. This is because in general only moves are atomic. The same method of + // swapping files as is demonstrated in the + // :ref:`runtime documentation ` can be used here also. + // One of ``poll_interval`` and ``watched_directory`` can also be configured; the configuration + // is rejected if both are set. With ``poll_interval``, the same path is reloaded periodically. + // With ``watched_directory``, no watch is placed directly on this path; events in the + // configured directory trigger this path to be reloaded. string path = 1 [(validate.rules).string = {min_len: 1}]; // If configured, this directory will be watched for *moves*. When an entry in this directory is @@ -188,7 +191,24 @@ message PathConfigSource { // // The above configuration will ensure that Envoy watches the owning directory for moves which is // required due to how Kubernetes manages ConfigMap symbolic links during atomic updates. + // + // This field cannot be used together with ``poll_interval``. WatchedDirectory watched_directory = 2; + + // If configured, the ``path`` will be polled at this interval instead of watched for filesystem + // events on either the file or ``watched_directory``. This is useful when the underlying + // filesystem does not reliably provide change notifications, or when a custom deployment model + // does not generate the move or modification events handled by watching the path or directory. + // The file is read on every poll, but an update is delivered only when its parsed contents + // change. + // + // When this configuration source provides a + // :ref:`Secret `, the same secret + // files that are watched in event-based mode are polled at this interval. The last successfully + // loaded configuration or secret remains active when a poll fails. + // + // This field cannot be used together with ``watched_directory`` and must be at least 1ms. + google.protobuf.Duration poll_interval = 3 [(validate.rules).duration = {gte {nanos: 1000000}}]; } // Configuration for :ref:`listeners `, :ref:`clusters diff --git a/api/src/main/proto/envoy/config/core/v3/health_check.proto b/api/src/main/proto/envoy/config/core/v3/health_check.proto index a4ed6e918..9b2c639be 100644 --- a/api/src/main/proto/envoy/config/core/v3/health_check.proto +++ b/api/src/main/proto/envoy/config/core/v3/health_check.proto @@ -63,7 +63,7 @@ message HealthStatusSet { [(validate.rules).repeated = {items {enum {defined_only: true}}}]; } -// [#next-free-field: 27] +// [#next-free-field: 28] message HealthCheck { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.core.HealthCheck"; @@ -83,7 +83,7 @@ message HealthCheck { } } - // [#next-free-field: 15] + // [#next-free-field: 16] message HttpHealthCheck { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.core.HealthCheck.HttpHealthCheck"; @@ -152,9 +152,24 @@ message HealthCheck { // non-200 response will result in the host being marked unhealthy. repeated type.v3.Int64Range retriable_statuses = 12; - // Use specified application protocol for health checks. + // Use specified application protocol for health checks. With :ref:`use_alpn_protocol + // ` this is + // the codec used when ALPN settles on neither ``h2`` nor ``http/1.1``. type.v3.CodecClientType codec_client_type = 10 [(validate.rules).enum = {defined_only: true}]; + // Select the codec from the protocol negotiated by ALPN on the health check connection: HTTP/2 + // when ``h2`` is negotiated, HTTP/1.1 when ``http/1.1`` is negotiated, and otherwise + // ``codec_client_type``, including when nothing is negotiated. With ``codec_client_type`` at + // its default this is the same mapping as the cluster's :ref:`auto_config + // `. Like + // ``auto_config``, it requires a transport socket that supports ALPN such as TLS and is + // rejected on a cluster whose transport sockets do not, unless the + // ``config.do_not_validate_alpn_support`` runtime key is set, as for ``auto_config``. It + // cannot be combined with ``codec_client_type`` ``HTTP3``. See :ref:`tls_options + // ` for what the connection + // advertises. + bool use_alpn_protocol = 15; + // An optional service name parameter which is used to validate the identity of // the health checked cluster using a :ref:`StringMatcher // `. See the :ref:`architecture overview @@ -260,12 +275,21 @@ message HealthCheck { // Specifies the ALPN protocols for health check connections. This is useful if the // corresponding upstream is using ALPN-based :ref:`FilterChainMatch // ` along with different protocols for health checks - // versus data connections. If empty, no ALPN protocols will be set on health check connections. + // versus data connections. If empty, health check connections advertise the ALPN protocols of + // the cluster's TLS context, if any. With :ref:`use_alpn_protocol + // `, + // the negotiated protocol selects the health check codec. repeated string alpn_protocols = 1; } reserved 10; + // Optional name for this health checker. When set, per-checker stats are emitted under + // ``health_check.name..`` instead of ``health_check.``. + // + // This is required if multiple health checks are configured on a cluster. + string name = 27; + // The time to wait for a health check response. If the timeout is reached the // health check attempt will be considered a failure. google.protobuf.Duration timeout = 1 [(validate.rules).duration = { diff --git a/api/src/main/proto/envoy/config/core/v3/proxy_protocol.proto b/api/src/main/proto/envoy/config/core/v3/proxy_protocol.proto index 2da5fe5fd..fea7dcc14 100644 --- a/api/src/main/proto/envoy/config/core/v3/proxy_protocol.proto +++ b/api/src/main/proto/envoy/config/core/v3/proxy_protocol.proto @@ -109,6 +109,7 @@ message ProxyProtocolConfig { } message PerHostConfig { - // Enables per-host configuration for Proxy Protocol. + // Enables per-host configuration for Proxy Protocol. Only the static ``value`` of each + // ``TlvEntry`` is applied to host-level TLVs. The ``format_string`` field is not evaluated here. repeated TlvEntry added_tlvs = 1; } diff --git a/api/src/main/proto/envoy/config/core/v3/substitution_format_string.proto b/api/src/main/proto/envoy/config/core/v3/substitution_format_string.proto index 3edbf5f5f..48c3cbc7e 100644 --- a/api/src/main/proto/envoy/config/core/v3/substitution_format_string.proto +++ b/api/src/main/proto/envoy/config/core/v3/substitution_format_string.proto @@ -105,13 +105,11 @@ message SubstitutionFormatString { // // * for ``text_format``, the output of the empty operator is changed from ``-`` to an // empty string, so that empty values are omitted entirely. - // * for ``json_format`` the keys with null values are omitted in the output structure. - // - // .. note:: - // This option does not work perfectly with ``json_format`` as keys with ``null`` values - // will still be included in the output. See https://github.com/envoyproxy/envoy/issues/37941 - // for more details. + // * for ``json_format``, the keys with null values are omitted in the output structure. Nested + // objects whose values are all omitted are removed as well, while empty arrays are preserved. + // The root object is always emitted, so a fully empty structure is rendered as ``{}``. // + // Defaults to false. bool omit_empty_values = 3; // Specify a ``content_type`` field. diff --git a/api/src/main/proto/envoy/config/listener/v3/listener.proto b/api/src/main/proto/envoy/config/listener/v3/listener.proto index 0668ae3f8..1ceee92c9 100644 --- a/api/src/main/proto/envoy/config/listener/v3/listener.proto +++ b/api/src/main/proto/envoy/config/listener/v3/listener.proto @@ -11,6 +11,7 @@ import "envoy/config/core/v3/socket_option.proto"; import "envoy/config/listener/v3/api_listener.proto"; import "envoy/config/listener/v3/listener_components.proto"; import "envoy/config/listener/v3/udp_listener_config.proto"; +import "envoy/config/metrics/v3/stats.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; @@ -61,7 +62,7 @@ message ListenerCollection { repeated xds.core.v3.CollectionEntry entries = 1; } -// [#next-free-field: 39] +// [#next-free-field: 40] message Listener { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Listener"; @@ -137,9 +138,7 @@ message Listener { // The listener will use the connection balancer according to ``type_url``. If ``type_url`` is invalid, // Envoy will not attempt to balance active connections between worker threads. - // The ``envoy.network.connection_balance`` extension category is currently empty - // because the only registered member (``envoy.network.connection_balance.dlb``) - // is disabled. See https://github.com/envoyproxy/envoy/issues/45491. + // The ``envoy.network.connection_balance`` extension category is currently empty. core.v3.TypedExtensionConfig extend_balance = 2; // If specified, the listener will steer new connections to worker threads using a kernel @@ -197,6 +196,12 @@ message Listener { // ``listener..``. string stat_prefix = 28; + // Optional stats matcher that can be used to configure which stats are instantiated for this + // listener. If configured, this overrides the bootstrap :ref:`stats_config + // ` stats matcher configuration + // for this listener. + metrics.v3.StatsMatcher stats_matcher = 39; + // A list of filter chains to consider for this listener. The // :ref:`FilterChain ` with the most specific // :ref:`FilterChainMatch ` criteria is used on a @@ -257,8 +262,11 @@ message Listener { // The following pre-defined metadata could be used by Envoy to manipulate the listener behavior: // // * ``envoy.stats_matcher``: this metadata could be used to customize the stats emitted by the - // listener. See :ref:`well-known metadata ` for more - // details. + // listener. See :ref:`well-known metadata + // ` for more details. + // If :ref:`stats_matcher + // ` is configured, this metadata + // is ignored. The ``stats_matcher`` field should be preferred. // core.v3.Metadata metadata = 6; diff --git a/api/src/main/proto/envoy/config/listener/v3/quic_config.proto b/api/src/main/proto/envoy/config/listener/v3/quic_config.proto index c208a58f4..62cb29088 100644 --- a/api/src/main/proto/envoy/config/listener/v3/quic_config.proto +++ b/api/src/main/proto/envoy/config/listener/v3/quic_config.proto @@ -10,8 +10,6 @@ import "envoy/config/core/v3/socket_cmsg_headers.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; -import "xds/annotations/v3/status.proto"; - import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -76,8 +74,7 @@ message QuicProtocolOptions { // The current QUICHE implementation will advertise only one of the preferred IPv4 and IPv6 addresses based on the address family the client initially connects with. // If not specified, Envoy will not advertise any server's preferred address. // [#extension-category: envoy.quic.server_preferred_address] - core.v3.TypedExtensionConfig server_preferred_address_config = 9 - [(xds.annotations.v3.field_status).work_in_progress = true]; + core.v3.TypedExtensionConfig server_preferred_address_config = 9; // Configure the server to send transport parameter `disable_active_migration `_. // Defaults to false (do not send this transport parameter). diff --git a/api/src/main/proto/envoy/config/metrics/v3/stats.proto b/api/src/main/proto/envoy/config/metrics/v3/stats.proto index 46331c1ab..c22e23fd5 100644 --- a/api/src/main/proto/envoy/config/metrics/v3/stats.proto +++ b/api/src/main/proto/envoy/config/metrics/v3/stats.proto @@ -362,6 +362,14 @@ message StatsdSink { // envoy.test_counter:1|c // envoy.test_timer:5|ms string prefix = 3; + + // If true, histogram samples are scaled to milliseconds according to the histogram's unit + // before being reported as timers: samples of histograms recording microseconds are divided by + // 1000 and reported as a fractional millisecond value, while histograms recording milliseconds + // or without a declared unit are reported unchanged. By default every sample is reported + // unchanged with an ``ms`` suffix regardless of the histogram's unit, so histograms recording + // microseconds are reported a factor of 1000 off. + bool scale_histogram_units_to_milliseconds = 4; } // Stats configuration proto schema for built-in ``envoy.stat_sinks.dog_statsd`` sink. @@ -369,6 +377,7 @@ message StatsdSink { // compatible tags. Tags are configurable via :ref:`StatsConfig // `. // [#extension: envoy.stat_sinks.dog_statsd] +// [#next-free-field: 6] message DogStatsdSink { option (udpa.annotations.versioning).previous_message_type = "envoy.config.metrics.v2.DogStatsdSink"; @@ -394,6 +403,12 @@ message DogStatsdSink { // // Note that this value may not be respected if smaller than a single metric. google.protobuf.UInt64Value max_bytes_per_datagram = 4 [(validate.rules).uint64 = {gt: 0}]; + + // If true, histogram samples are scaled to milliseconds according to the histogram's unit + // before being reported as timers. See :ref:`StatsdSink's scale_histogram_units_to_milliseconds + // field ` + // for more details. + bool scale_histogram_units_to_milliseconds = 5; } // Stats configuration proto schema for built-in ``envoy.stat_sinks.hystrix`` sink. diff --git a/api/src/main/proto/envoy/config/overload/v3/overload.proto b/api/src/main/proto/envoy/config/overload/v3/overload.proto index 05e6b2a12..b01760cae 100644 --- a/api/src/main/proto/envoy/config/overload/v3/overload.proto +++ b/api/src/main/proto/envoy/config/overload/v3/overload.proto @@ -157,8 +157,10 @@ message OverloadAction { option (udpa.annotations.versioning).previous_message_type = "envoy.config.overload.v2alpha.OverloadAction"; - // The name of the overload action. This is just a well-known string that - // listeners can use for registering callbacks. + // The action name. Most actions use a well-known string for listener callback registration. + // ``ScaleTimersOverloadActionConfig`` actions may use unique custom names for independently + // triggered ``reduce_timeouts`` instances. Custom names must not use the reserved + // ``envoy.overload_actions.`` prefix. No action name may duplicate a ``LoadShedPoint`` name. // Valid known overload actions include: // - envoy.overload_actions.stop_accepting_requests // - envoy.overload_actions.disable_http_keepalive @@ -178,7 +180,10 @@ message OverloadAction { // in this list. repeated Trigger triggers = 2 [(validate.rules).repeated = {min_items: 1}]; - // Configuration for the action being instantiated if applicable. + // Optional implementation configuration. Well-known names identify the action directly; for a + // custom name, this configuration's type identifies it. Currently only + // ``ScaleTimersOverloadActionConfig`` supports custom names, identifying a ``reduce_timeouts`` + // instance. google.protobuf.Any typed_config = 3; } diff --git a/api/src/main/proto/envoy/config/route/v3/route.proto b/api/src/main/proto/envoy/config/route/v3/route.proto index 5bd909f34..135ce3ef4 100644 --- a/api/src/main/proto/envoy/config/route/v3/route.proto +++ b/api/src/main/proto/envoy/config/route/v3/route.proto @@ -4,6 +4,7 @@ package envoy.config.route.v3; import "envoy/config/core/v3/base.proto"; import "envoy/config/core/v3/config_source.proto"; +import "envoy/config/core/v3/extension.proto"; import "envoy/config/route/v3/route_components.proto"; import "google/protobuf/any.proto"; @@ -23,7 +24,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // * Routing :ref:`architecture overview ` // * HTTP :ref:`router filter ` -// [#next-free-field: 19] +// [#next-free-field: 20] message RouteConfiguration { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.RouteConfiguration"; @@ -138,7 +139,8 @@ message RouteConfiguration { // Normally, virtual host matching is done using the :authority (or // Host: in HTTP < 2) HTTP header. Setting this will instead, use a // different HTTP header for this purpose. - string vhost_header = 18; + string vhost_header = 18 + [(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME strict: false}]; // Ignore path-parameters in path-matching. // Before RFC3986, URI were like(RFC1808): :///;?# @@ -162,6 +164,34 @@ message RouteConfiguration { // For instance, if the metadata is intended for the Router filter, // the filter name should be specified as ``envoy.filters.http.router``. core.v3.Metadata metadata = 17; + + // After the route matching has resolved a route for incoming request, the route specifiers + // are applied to the route to customize or monitor it and the output of the specifiers will be + // used as the final route by Envoy for the request. The specifiers here will not modify/affect + // the request attributes (e.g., headers, path) directly. + // + // Specifiers are executed in order, and the output of each is the input of the next. The route + // that comes out of the last one is the route Envoy uses for the request. + // + // Specifiers are configured at three levels. Specifiers in three levels will run in this order: + // + // 1. The ``route_specifiers`` of resolved + // :ref:`route ` + // 2. The ``route_specifiers`` of resolved + // :ref:`virtual host ` + // 3. The ``route_specifiers`` of + // :ref:`route configuration `. + // + // .. note:: + // If the route matching resolves no route, the route specifiers at the route configuration + // and the virtual host levels will still be applied to null. This allows route specifiers to + // optionally generate a valid route even when no route is resolved for the request. + // Similarly, if the route matching resolves a valid route, the route specifiers may drop it + // and return no route. Then Envoy will treat it as route not found and result in 404 response. + // + // See :ref:`route specifiers ` for more details. + // [#extension-category: envoy.router.route_specifiers] + repeated core.v3.TypedExtensionConfig route_specifiers = 19; } message Vhds { diff --git a/api/src/main/proto/envoy/config/route/v3/route_components.proto b/api/src/main/proto/envoy/config/route/v3/route_components.proto index bc3f57483..e6f4ae233 100644 --- a/api/src/main/proto/envoy/config/route/v3/route_components.proto +++ b/api/src/main/proto/envoy/config/route/v3/route_components.proto @@ -45,7 +45,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // host header. This allows a single listener to service multiple top level domain path trees. Once // a virtual host is selected based on the domain, the routes are processed in order to see which // upstream cluster to route to or whether to perform a redirect. -// [#next-free-field: 26] +// [#next-free-field: 27] message VirtualHost { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.route.VirtualHost"; @@ -258,6 +258,27 @@ message VirtualHost { // For instance, if the metadata is intended for the Router filter, // the filter name should be specified as ``envoy.filters.http.router``. core.v3.Metadata metadata = 24; + + // After the route matching has resolved a route for incoming request, the route specifiers + // are applied to the route to customize or monitor it and the output of the specifiers will be + // used as the final route by Envoy for the request. The specifiers here will not modify/affect + // the request attributes (e.g., headers, path) directly. + // + // Specifiers are executed in order, and the output of each is the input of the next. The + // specifiers here will run after the ``route_specifiers`` of the resolved + // :ref:`route ` + // and before the ``route_specifiers`` of + // :ref:`route configuration `. + // + // .. note:: + // If the route matching resolves no route, the route specifiers at the route configuration + // and the virtual host levels will still be applied to null. This allows route specifiers to + // optionally generate a valid route even when no route is resolved for the request. + // Similarly, if the route matching resolves a valid route, the route specifiers may drop it + // and return no route. Then Envoy will treat it as route not found and result in 404 response. + // + // See :ref:`route specifiers ` for more details. + repeated core.v3.TypedExtensionConfig route_specifiers = 26; } // A filter-defined action type. @@ -281,7 +302,7 @@ message RouteList { // // Envoy supports routing on HTTP method via :ref:`header matching // `. -// [#next-free-field: 21] +// [#next-free-field: 22] message Route { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.route.Route"; @@ -420,6 +441,28 @@ message Route { // Only one of :ref:`per_request_buffer_limit_bytes ` // and ``request_body_buffer_limit`` may be set. google.protobuf.UInt64Value request_body_buffer_limit = 20; + + // After the route matching has resolved this route for incoming request, the route specifiers + // are applied to the route to customize or monitor it and the output of the specifiers will be + // used as the final route by Envoy for the request. The specifiers here will not modify/affect + // the request attributes (e.g., headers, path) directly. + // + // Specifiers are executed in order, and the output of each is the input of the next. The + // specifiers here will run first, before the ``route_specifiers`` of + // :ref:`virtual host ` and + // :ref:`route configuration `, + // so the route that comes out of the last specifier here is the input of the specifiers of + // these two levels. + // + // .. note:: + // If the route matching resolves no route, the route specifiers at the route configuration + // and the virtual host levels will still be applied to null. This allows route specifiers to + // optionally generate a valid route even when no route is resolved for the request. + // Similarly, if the route matching resolves a valid route, the route specifiers may drop it + // and return no route. Then Envoy will treat it as route not found and result in 404 response. + // + // See :ref:`route specifiers ` for more details. + repeated core.v3.TypedExtensionConfig route_specifiers = 21; } // Compared to the :ref:`cluster ` field that specifies a @@ -831,8 +874,6 @@ message RouteAction { // Configures :ref:`internal redirect ` behavior. // [#next-major-version: remove this definition - it's defined in the InternalRedirectPolicy message.] enum InternalRedirectAction { - option deprecated = true; - PASS_THROUGH_INTERNAL_REDIRECT = 0; HANDLE_INTERNAL_REDIRECT = 1; } @@ -1799,7 +1840,11 @@ message RetryPolicy { // .. note:: // This currently works when the route cluster specifier support the dynamic refresh, // e.g. :ref:`matcher cluster specifier - // `. + // `, + // :ref:`priority group cluster specifier + // ` + // and :ref:`dynamic modules cluster specifier + // `. bool refresh_cluster_on_retry = 14; } diff --git a/api/src/main/proto/envoy/config/trace/v3/opentelemetry.proto b/api/src/main/proto/envoy/config/trace/v3/opentelemetry.proto index 928d5a5d9..9bc3549cd 100644 --- a/api/src/main/proto/envoy/config/trace/v3/opentelemetry.proto +++ b/api/src/main/proto/envoy/config/trace/v3/opentelemetry.proto @@ -21,18 +21,18 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Configuration for the OpenTelemetry tracer. // [#extension: envoy.tracers.opentelemetry] -// [#next-free-field: 9] +// [#next-free-field: 11] message OpenTelemetryConfig { // The upstream gRPC cluster that will receive OTLP traces. // Note that the tracer drops traces if the server does not read data fast enough. // This field can be left empty to disable reporting traces to the gRPC service. - // Only one of ``grpc_service``, ``http_service`` may be used. + // Only one of ``grpc_service``, ``http_service``, ``exporter`` may be used. core.v3.GrpcService grpc_service = 1 [(udpa.annotations.field_migrate).oneof_promotion = "otlp_exporter"]; // The upstream HTTP cluster that will receive OTLP traces. // This field can be left empty to disable reporting traces to the HTTP service. - // Only one of ``grpc_service``, ``http_service`` may be used. + // Only one of ``grpc_service``, ``http_service``, ``exporter`` may be used. // // .. note:: // @@ -42,6 +42,14 @@ message OpenTelemetryConfig { core.v3.HttpService http_service = 3 [(udpa.annotations.field_migrate).oneof_promotion = "otlp_exporter"]; + // Specifies the custom exporter to be used by the OpenTelemetry tracer. + // Only one of ``grpc_service``, ``http_service``, ``exporter`` may be used. + // + // [#extension-category: envoy.tracers.opentelemetry.exporters] + // [#not-implemented-hide:] + core.v3.TypedExtensionConfig exporter = 10 + [(udpa.annotations.field_migrate).oneof_promotion = "otlp_exporter"]; + // The name for the service. This will be populated in the ResourceSpan Resource attributes. // If it is not provided, it will default to "unknown_service:envoy". string service_name = 2; @@ -76,4 +84,8 @@ message OpenTelemetryConfig { // Specifies whether to set the ``service.name`` resource attribute. // If not specified, the default is to set this attribute. google.protobuf.BoolValue set_service_name_resource_attribute = 8; + + // Specifies whether to set the instrumentation scope name ("envoy") and version on emitted traces. + // If not specified, the default is to set the instrumentation scope name and version. + google.protobuf.BoolValue set_instrumentation_scope = 9; } diff --git a/api/src/main/proto/envoy/data/ai/v3/request_info.proto b/api/src/main/proto/envoy/data/ai/v3/request_info.proto new file mode 100644 index 000000000..644b837e1 --- /dev/null +++ b/api/src/main/proto/envoy/data/ai/v3/request_info.proto @@ -0,0 +1,52 @@ +syntax = "proto3"; + +package envoy.data.ai.v3; + +import "envoy/type/ai/v3/llm_protocol.proto"; + +import "google/protobuf/wrappers.proto"; + +import "xds/annotations/v3/status.proto"; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.data.ai.v3"; +option java_outer_classname = "RequestInfoProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/data/ai/v3;aiv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; +option (xds.annotations.v3.file_status).work_in_progress = true; + +// [#protodoc-title: AI request info] + +// Request attributes published as typed dynamic metadata by the :ref:`request info AI +// filter `. Values are +// client-declared and unverified, apart from ``estimated_input_tokens``, which Envoy computes. +// A value the client sent that Envoy cannot use, such as one of the wrong type, out of range, +// or a string over 256 bytes, is ignored. +// [#next-free-field: 8] +message RequestInfo { + // The route's declared wire API. When unspecified, only ``model`` and ``stream`` are read. + type.ai.v3.LLMProtocol input_llm_protocol = 1; + + // The requested model. + string model = 2; + + // Whether a streamed response was requested. + google.protobuf.BoolValue stream = 3; + + // The requested output token cap. + google.protobuf.UInt64Value max_output_tokens = 4; + + // Number of messages in the conversation. + google.protobuf.UInt32Value message_count = 5; + + // Number of tools declared. + google.protobuf.UInt32Value tool_count = 6; + + // Envoy's estimate of the input tokens, published only when :ref:`token_estimation + // ` + // is configured: ``ceil(tokens_per_byte * request payload bytes)``. A size heuristic, not a + // tokenizer result, and independent of the wire API. + google.protobuf.UInt64Value estimated_input_tokens = 7; +} diff --git a/api/src/main/proto/envoy/data/ai/v3/token_usage.proto b/api/src/main/proto/envoy/data/ai/v3/token_usage.proto new file mode 100644 index 000000000..311a3e906 --- /dev/null +++ b/api/src/main/proto/envoy/data/ai/v3/token_usage.proto @@ -0,0 +1,112 @@ +syntax = "proto3"; + +package envoy.data.ai.v3; + +import "envoy/type/ai/v3/llm_protocol.proto"; + +import "google/protobuf/wrappers.proto"; + +import "xds/annotations/v3/status.proto"; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.data.ai.v3"; +option java_outer_classname = "TokenUsageProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/data/ai/v3;aiv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; +option (xds.annotations.v3.file_status).work_in_progress = true; + +// [#protodoc-title: AI token usage] + +// Canonical LLM token usage extracted from a provider response by the +// :ref:`AI Protocol Manager filter `, +// published as typed dynamic metadata under one namespace at a clean end of +// stream. +// +// Counts are normalized onto one *inclusive* contract regardless of wire API: +// ``input_tokens`` covers all input consumed (uncached input, cached reads, +// cache writes, and tool-use prompt tokens) and ``output_tokens`` covers all +// generated output including reasoning/thought tokens; the detail messages +// are subsets of those canonical values. Every value remains +// provider-reported and is not independently verified by Envoy. +// +// Every count is optional: wire APIs report different subsets, and a +// status-only record (``llm_protocol``, ``model`` when captured, and +// ``extraction_status: FAILED``) is published when extraction failed +// outright, distinguishing that from a response that supplied no usage +// (which publishes nothing). +// [#next-free-field: 10] +message TokenUsage { + // Quality of the extraction result. + enum ExtractionStatus { + EXTRACTION_STATUS_UNSPECIFIED = 0; + + // All observed usage-bearing data was parsed successfully. + COMPLETE = 1; + + // Usable counts were extracted, but some usage-bearing input was lost: + // malformed, truncated, or skipped by a configured resource limit. The + // counts may be stale (an earlier cumulative snapshot) or incomplete. + PARTIAL = 2; + + // Usage-bearing input was observed but no usable canonical count could + // be extracted; only ``llm_protocol`` and ``model`` may be populated. + FAILED = 3; + } + + // The wire API the usage was extracted from. This names an API contract, + // not a provider identity: any OpenAI-compatible backend reports an OpenAI + // protocol here. + type.ai.v3.LLMProtocol llm_protocol = 1; + + // The model reported by the response, when present. + string model = 2; + + // Canonical inclusive input token count. + google.protobuf.UInt64Value input_tokens = 3; + + // Canonical inclusive output token count. + google.protobuf.UInt64Value output_tokens = 4; + + // Canonical total: ``input_tokens + output_tokens``. Present only when + // both canonical components are known, so the triple is always internally + // consistent. Compare against ``provider_total_tokens`` to detect a + // provider that reports inconsistently or in buckets unknown to the + // extractor. + google.protobuf.UInt64Value total_tokens = 5; + + // Canonical input token breakdown. + InputTokenDetails input_token_details = 6; + + // Canonical output token breakdown. + OutputTokenDetails output_token_details = 7; + + // The total token count reported directly by the provider, when it + // reported one — preserved regardless of whether it agrees with + // ``total_tokens``. + google.protobuf.UInt64Value provider_total_tokens = 8; + + // Quality of the extraction result. + ExtractionStatus extraction_status = 9; +} + +// Subsets of :ref:`input_tokens +// `. +message InputTokenDetails { + // Cache-read input tokens. + google.protobuf.UInt64Value cached_tokens = 1; + + // Cache-creation (cache-write) input tokens. + google.protobuf.UInt64Value cache_creation_tokens = 2; + + // Tool-use prompt tokens. + google.protobuf.UInt64Value tool_use_tokens = 3; +} + +// Subsets of :ref:`output_tokens +// `. +message OutputTokenDetails { + // Reasoning or thought tokens. + google.protobuf.UInt64Value reasoning_tokens = 1; +} diff --git a/api/src/main/proto/envoy/data/core/v3/health_check_event.proto b/api/src/main/proto/envoy/data/core/v3/health_check_event.proto index dc2e17445..a71b04d22 100644 --- a/api/src/main/proto/envoy/data/core/v3/health_check_event.proto +++ b/api/src/main/proto/envoy/data/core/v3/health_check_event.proto @@ -34,6 +34,7 @@ enum HealthCheckerType { REDIS = 3; THRIFT = 4; DYNAMIC_MODULE = 5; + UDP = 6; } // [#next-free-field: 13] diff --git a/api/src/main/proto/envoy/extensions/access_loggers/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/access_loggers/dynamic_modules/v3/dynamic_modules.proto index c169fe280..1ac474105 100644 --- a/api/src/main/proto/envoy/extensions/access_loggers/dynamic_modules/v3/dynamic_modules.proto +++ b/api/src/main/proto/envoy/extensions/access_loggers/dynamic_modules/v3/dynamic_modules.proto @@ -53,7 +53,8 @@ message DynamicModuleAccessLog { // The ``logger_config`` can be used to configure file paths, service endpoints, batching // parameters, format strings, etc. // - // ``google.protobuf.Struct`` is serialized as JSON before passing it to the module. + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly // without the wrapper. // diff --git a/api/src/main/proto/envoy/extensions/access_loggers/open_telemetry/v3/logs_service.proto b/api/src/main/proto/envoy/extensions/access_loggers/open_telemetry/v3/logs_service.proto index 954f38556..27822f21a 100644 --- a/api/src/main/proto/envoy/extensions/access_loggers/open_telemetry/v3/logs_service.proto +++ b/api/src/main/proto/envoy/extensions/access_loggers/open_telemetry/v3/logs_service.proto @@ -29,7 +29,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // populate `opentelemetry.proto.collector.v1.logs.ExportLogsServiceRequest.resource_logs `_. // In addition, the request start time is set in the dedicated field. // [#extension: envoy.access_loggers.open_telemetry] -// [#next-free-field: 15] +// [#next-free-field: 16] message OpenTelemetryAccessLogConfig { // [#comment:TODO(itamarkam): add 'filter_state_objects_to_log' to logs.] // Deprecated. Use ``grpc_service`` or ``http_service`` instead. @@ -54,13 +54,29 @@ message OpenTelemetryAccessLogConfig { // If specified, Envoy will not generate built-in resource labels // like ``log_name``, ``zone_name``, ``cluster_name``, ``node_name``. + // + // Built-in labels have the lowest precedence and can be overridden by matching keys in + // :ref:`resource_detectors ` + // or :ref:`resource_attributes `. bool disable_builtin_labels = 5; // OpenTelemetry `Resource `_ // attributes are filled with Envoy node info. // Example: ``resource_attributes { values { key: "region" value { string_value: "cn-north-7" } } }``. + // + // Attributes configured here take highest precedence (``resource_attributes`` > ``resource_detectors`` > built-in labels) + // and will override any matching keys. opentelemetry.proto.common.v1.KeyValueList resource_attributes = 4; + // An ordered list of resource detectors to detect OpenTelemetry resource information such as + // attributes and schema URL. + // + // Attributes detected here override built-in labels with matching keys, but are overridden by + // :ref:`resource_attributes ` + // (precedence: ``resource_attributes`` > ``resource_detectors`` > built-in labels). + // [#extension-category: envoy.tracers.opentelemetry.resource_detectors] + repeated config.core.v3.TypedExtensionConfig resource_detectors = 15; + // OpenTelemetry `LogResource `_ // fields, following `Envoy access logging formatting `_. // diff --git a/api/src/main/proto/envoy/extensions/bootstrap/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/bootstrap/dynamic_modules/v3/dynamic_modules.proto index a0c406bd9..dec9a4771 100644 --- a/api/src/main/proto/envoy/extensions/bootstrap/dynamic_modules/v3/dynamic_modules.proto +++ b/api/src/main/proto/envoy/extensions/bootstrap/dynamic_modules/v3/dynamic_modules.proto @@ -54,7 +54,8 @@ message DynamicModuleBootstrapExtension { // one for metric initialization, ``extension_name`` is used to choose the implementation. The // ``extension_config`` can be used to configure the specific behavior of each implementation. // - // ``google.protobuf.Struct`` is serialized as JSON before passing it to the module. + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly // without the wrapper. // diff --git a/api/src/main/proto/envoy/extensions/bootstrap/reverse_tunnel/downstream_socket_interface/v3/downstream_reverse_connection_socket_interface.proto b/api/src/main/proto/envoy/extensions/bootstrap/reverse_tunnel/downstream_socket_interface/v3/downstream_reverse_connection_socket_interface.proto index 9c6c3090d..0084255eb 100644 --- a/api/src/main/proto/envoy/extensions/bootstrap/reverse_tunnel/downstream_socket_interface/v3/downstream_reverse_connection_socket_interface.proto +++ b/api/src/main/proto/envoy/extensions/bootstrap/reverse_tunnel/downstream_socket_interface/v3/downstream_reverse_connection_socket_interface.proto @@ -23,9 +23,10 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Configuration for the downstream reverse connection socket interface. // This interface initiates reverse connections to upstream Envoys and provides // them as socket connections for downstream requests. -// [#next-free-field: 6] +// [#next-free-field: 7] message DownstreamReverseConnectionSocketInterface { // HTTP handshake settings for initiator envoy initiated reverse tunnels. + // [#next-free-field: 6] message HttpHandshakeConfig { // Request path used when issuing the HTTP reverse-connection handshake. Defaults to // "/reverse_connections/request". @@ -45,6 +46,14 @@ message DownstreamReverseConnectionSocketInterface { // as substitution format strings; when empty, the values are sent literally. // [#extension-category: envoy.formatter] repeated config.core.v3.TypedExtensionConfig formatters = 4; + + // Maximum time to receive the handshake response after the connection opens. If not specified, + // defaults to ``15s``. On expiry the attempt is closed, recorded with failure reason + // ``timeout``, and normal backoff applies. + google.protobuf.Duration handshake_timeout = 5 [(validate.rules).duration = { + lte {seconds: 300} + gt {} + }]; } // Stat prefix to be used for downstream reverse connection socket interface stats. @@ -60,9 +69,10 @@ message DownstreamReverseConnectionSocketInterface { HttpHandshakeConfig http_handshake = 3; // Access log configuration for reverse tunnel initiator lifecycle events. - // Logs are emitted on handshake success, handshake failure, and connection close. - // Reverse tunnel metadata (``node_id``, ``cluster_id``, ``tenant_id``, upstream cluster, etc.) - // is available via ``%DYNAMIC_METADATA(envoy.reverse_tunnel.initiator:*)%`` substitutions. + // Logs are emitted on handshake success, handshake failure, connection draining, and + // connection close. Reverse tunnel metadata (``node_id``, ``cluster_id``, ``tenant_id``, + // upstream cluster, ``connection_key``, ``connection_id``, etc.) is available via + // ``%DYNAMIC_METADATA(envoy.reverse_tunnel.initiator:*)%`` substitutions. repeated config.accesslog.v3.AccessLog access_log = 4; // Upper bound on the per-host reconnect backoff. The initiator retries a failed handshake on a @@ -70,4 +80,10 @@ message DownstreamReverseConnectionSocketInterface { // that schedule. google.protobuf.Duration max_reconnect_backoff = 5 [(validate.rules).duration = {gte {seconds: 1}}]; + + // How often the initiator re-checks each host and dials any missing reverse tunnels. + // Defaults to 10s. The re-check is jittered upward so agents that start together do not + // redial in lockstep. The minimum value is 100ms. + google.protobuf.Duration maintain_interval = 6 + [(validate.rules).duration = {gte {nanos: 100000000}}]; } diff --git a/api/src/main/proto/envoy/extensions/bootstrap/reverse_tunnel/upstream_socket_interface/v3/upstream_reverse_connection_socket_interface.proto b/api/src/main/proto/envoy/extensions/bootstrap/reverse_tunnel/upstream_socket_interface/v3/upstream_reverse_connection_socket_interface.proto index 1591290b6..63c2f406d 100644 --- a/api/src/main/proto/envoy/extensions/bootstrap/reverse_tunnel/upstream_socket_interface/v3/upstream_reverse_connection_socket_interface.proto +++ b/api/src/main/proto/envoy/extensions/bootstrap/reverse_tunnel/upstream_socket_interface/v3/upstream_reverse_connection_socket_interface.proto @@ -20,7 +20,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // [#extension: envoy.bootstrap.reverse_tunnel.upstream_socket_interface] // Configuration for the upstream reverse connection socket interface. -// [#next-free-field: 7] +// [#next-free-field: 8] message UpstreamReverseConnectionSocketInterface { // Stat prefix for upstream reverse connection socket interface stats. string stat_prefix = 1; @@ -49,4 +49,13 @@ message UpstreamReverseConnectionSocketInterface { // Access logs emitted for reverse tunnel lifecycle events. Entries are generated for tunnel setup, // socket handoff, tunnel close, and post-handoff HTTP/2 keepalive timeout observations. repeated config.accesslog.v3.AccessLog access_log = 6; + + // Maximum number of concurrently accepted reverse connections per node (and per tenant + // when tenant isolation is enabled). The cap is only consulted for reverse tunnel network + // filters that opt in via ``enable_connection_limit``; filters that leave it disabled ignore it. + // The cap is enforced per worker thread, so the effective ceiling is roughly this value + // multiplied by the number of workers; it is also only approximate when rebalancing is enabled. + // Defaults to 0; combined with ``enable_connection_limit: true`` a value of 0 rejects all + // connections, so set a non-zero value whenever a filter enables the limit. + uint32 max_connections_per_node = 7; } diff --git a/api/src/main/proto/envoy/extensions/clusters/composite/v3/cluster.proto b/api/src/main/proto/envoy/extensions/clusters/composite/v3/cluster.proto index 475f8d1ca..5a1323d6e 100644 --- a/api/src/main/proto/envoy/extensions/clusters/composite/v3/cluster.proto +++ b/api/src/main/proto/envoy/extensions/clusters/composite/v3/cluster.proto @@ -18,7 +18,9 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // cluster selection, allowing different retry attempts to automatically target // different upstream clusters. Unlike the standard aggregate cluster which uses // health-based selection, the composite cluster uses the retry attempt count to -// deterministically select which sub-cluster to route to. +// deterministically select which sub-cluster to route to. If the selected sub-cluster has no +// host available, the following sub-clusters in the list are tried in order within the same +// attempt. // // When retry attempts exceed the number of configured clusters, requests will fail with no // host available. @@ -50,6 +52,8 @@ message ClusterConfig { // List of clusters to use for request routing. The first cluster is used for the // initial request (attempt 1), the second cluster for the first retry (attempt 2), // and so on. Must contain at least one cluster. When retry attempts exceed the number - // of configured clusters, requests will fail with no host available. + // of configured clusters, requests will fail with no host available. When the cluster + // selected for an attempt has no host available, the following clusters in this list are + // tried in order for that attempt. repeated ClusterEntry clusters = 1 [(validate.rules).repeated = {min_items: 1}]; } diff --git a/api/src/main/proto/envoy/extensions/clusters/mcp_multicluster/v3/cluster.proto b/api/src/main/proto/envoy/extensions/clusters/mcp_multicluster/v3/cluster.proto index ae5b252ef..111ac34f2 100644 --- a/api/src/main/proto/envoy/extensions/clusters/mcp_multicluster/v3/cluster.proto +++ b/api/src/main/proto/envoy/extensions/clusters/mcp_multicluster/v3/cluster.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package envoy.extensions.clusters.mcp_multicluster.v3; +import "envoy/type/matcher/v3/string.proto"; + import "google/protobuf/duration.proto"; import "xds/annotations/v3/status.proto"; @@ -67,6 +69,40 @@ message ClusterConfig { string host_rewrite_literal = 4; } + // Specifies which downstream request headers are allowed to be forwarded to an MCP + // backend. Modeled after + // :ref:`ext_proc's HeaderForwardingRules `, + // but MCP-local and secure-by-default: unlike ext_proc, an unset/empty policy + // forwards nothing rather than everything, because MCP requires audience-bound + // tokens and prohibits implicit token passthrough between a client and a backend it + // did not authenticate to. + // + // Evaluation order per header: + // + // 1. If the header matches ``disallowed_headers``, it is never forwarded — this + // takes precedence over everything below, including ``forward_all``. + // 2. Otherwise, if ``forward_all`` is true, the header is forwarded. + // 3. Otherwise, if the header matches ``allowed_headers``, it is forwarded. + // 4. Otherwise, the header is not forwarded. + // + // This does not cover header *mutation* or credential injection, which remain a + // separate concern from this policy. + message HeaderForwarding { + // If true, forward all downstream request headers to this backend (subject to + // ``disallowed_headers`` above), matching the legacy forward-everything behavior. + // Defaults to false. Users relying on the legacy behavior must set this explicitly. + bool forward_all = 1; + + // If set, specifically allow any header in this list to be forwarded. Ignored for a + // header that also matches ``disallowed_headers``, and redundant (but harmless) for + // any header covered by ``forward_all``. + type.matcher.v3.ListStringMatcher allowed_headers = 2; + + // If set, specifically disallow any header in this list from being forwarded. This + // takes precedence over both ``forward_all`` and ``allowed_headers``. + type.matcher.v3.ListStringMatcher disallowed_headers = 3; + } + // Specification of the MCP server. message McpBackend { // Unique name for this backend. Used for: @@ -78,6 +114,15 @@ message ClusterConfig { // Backend target specification. McpCluster mcp_cluster = 2; + + // Controls which downstream request headers are forwarded to this backend. + // If not set, no downstream-controlled headers are forwarded beyond those the + // router itself must synthesize (e.g. ``content-type``, ``accept``, the session + // header) — in particular, a client's ``authorization`` header is NOT forwarded + // by default. Router-owned, framing, session, and hop-by-hop headers are never + // affected by this policy; they are handled separately and can never be forwarded + // via this mechanism. + HeaderForwarding header_forwarding = 3; } // A list of remote MCP servers. diff --git a/api/src/main/proto/envoy/extensions/common/ratelimit/v3/ratelimit.proto b/api/src/main/proto/envoy/extensions/common/ratelimit/v3/ratelimit.proto index 76d7d16f9..2d15452b3 100644 --- a/api/src/main/proto/envoy/extensions/common/ratelimit/v3/ratelimit.proto +++ b/api/src/main/proto/envoy/extensions/common/ratelimit/v3/ratelimit.proto @@ -118,6 +118,10 @@ message RateLimitDescriptor { // The unit of time. type.v3.RateLimitUnit unit = 2 [(validate.rules).enum = {defined_only: true}]; + + // The number of units in the rate limit period. For example, a value of ``30`` with a unit + // of ``SECOND`` specifies a 30-second rate limit period. If not specified, defaults to ``1``. + google.protobuf.UInt32Value unit_multiplier = 3 [(validate.rules).uint32 = {gt: 0}]; } // Descriptor entries. diff --git a/api/src/main/proto/envoy/extensions/config/validators/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/config/validators/dynamic_modules/v3/dynamic_modules.proto new file mode 100644 index 000000000..a6537e449 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/config/validators/dynamic_modules/v3/dynamic_modules.proto @@ -0,0 +1,58 @@ +syntax = "proto3"; + +package envoy.extensions.config.validators.dynamic_modules.v3; + +import "envoy/extensions/dynamic_modules/v3/dynamic_modules.proto"; + +import "google/protobuf/any.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.config.validators.dynamic_modules.v3"; +option java_outer_classname = "DynamicModulesProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/config/validators/dynamic_modules/v3;dynamic_modulesv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Dynamic Modules Config Validator] +// [#extension: envoy.config.validators.dynamic_modules] + +// Configuration for an xDS config validator implemented by a dynamic module. For each xDS update the +// module receives the xDS type URL and the decoded resources, with each resource carrying its name, +// version, aliases, TTL, and re-serialized protobuf payload. During validation the module can also +// read current server state, such as the dynamic cluster count, through the validation context. A +// rejection from the module follows Envoy's normal xDS rejection path, so the xDS client receives a +// NACK and the last accepted configuration is retained. +message DynamicModuleConfigValidator { + // Specifies the shared-object level configuration. This field is required. + // + // Only the ``name`` and ``module.local.filename`` sources are supported. Remote module sources + // are not supported because config validators are created without a factory context. + envoy.extensions.dynamic_modules.v3.DynamicModuleConfig dynamic_module_config = 1 + [(validate.rules).message = {required: true}]; + + // The name identifying the config validator implementation within the module. This is passed to + // the module's config validator init function so that a module can host multiple + // implementations. This field is required. + string extension_name = 2 [(validate.rules).string = {min_len: 1}]; + + // The configuration for the implementation chosen by ``extension_name``. If not specified, an + // empty configuration is passed to the module. + // + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. + // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly without + // the wrapper. Otherwise the serialized bytes of the configured message are passed. + google.protobuf.Any extension_config = 3; + + // The xDS resource type URLs handled by this validator. Only updates whose type URL matches one + // of these values invoke the module. Each value must use the canonical + // ``type.googleapis.com/`` form. Exactly one type URL is supported today and this + // restriction may be relaxed in the future. This field is required. + repeated string type_urls = 4 [(validate.rules).repeated = { + min_items: 1 + max_items: 1 + items {string {min_len: 1}} + }]; +} diff --git a/api/src/main/proto/envoy/extensions/filters/common/jwks/v3/jwks.proto b/api/src/main/proto/envoy/extensions/filters/common/jwks/v3/jwks.proto new file mode 100644 index 000000000..3b11d536b --- /dev/null +++ b/api/src/main/proto/envoy/extensions/filters/common/jwks/v3/jwks.proto @@ -0,0 +1,105 @@ +syntax = "proto3"; + +package envoy.extensions.filters.common.jwks.v3; + +import "envoy/config/core/v3/base.proto"; +import "envoy/config/core/v3/http_uri.proto"; + +import "google/protobuf/duration.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.filters.common.jwks.v3"; +option java_outer_classname = "JwksProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/common/jwks/v3;jwksv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Common JWKS fetch] +// Configuration for fetching a JSON Web Key Set (JWKS) from a remote HTTP server and caching it, +// shared by extensions that need remote JWKS. + +// This message specifies how to fetch JWKS from remote and how to cache it. +message RemoteJwks { + // The HTTP URI to fetch the JWKS. For example: + // + // .. code-block:: yaml + // + // http_uri: + // uri: https://www.googleapis.com/oauth2/v1/certs + // cluster: jwt.www.googleapis.com|443 + // timeout: 1s + // + config.core.v3.HttpUri http_uri = 1 [(validate.rules).message = {required: true}]; + + // Duration after which the cached JWKS should be expired. If not specified, default cache + // duration is 10 minutes. + google.protobuf.Duration cache_duration = 2 [(validate.rules).duration = { + lt {seconds: 9000000000} + gte {nanos: 1000000} + }]; + + // Fetch Jwks asynchronously in the main thread before the listener is activated. + // Fetched Jwks can be used by all worker threads. + // + // If this feature is not enabled: + // + // * The Jwks is fetched on-demand when the requests come. During the fetching, first + // few requests are paused until the Jwks is fetched. + // * Each worker thread fetches its own Jwks since Jwks cache is per worker thread. + // + // If this feature is enabled: + // + // * Fetched Jwks is done in the main thread before the listener is activated. Its fetched + // Jwks can be used by all worker threads. Each worker thread doesn't need to fetch its own. + // * Jwks is ready when the requests come, not need to wait for the Jwks fetching. + // + JwksAsyncFetch async_fetch = 3; + + // Retry policy for fetching Jwks. optional. turned off by default. + // + // For example: + // + // .. code-block:: yaml + // + // retry_policy: + // retry_back_off: + // base_interval: 0.01s + // max_interval: 20s + // num_retries: 10 + // + // will yield a randomized truncated exponential backoff policy with an initial delay of 10ms + // 10 maximum attempts spaced at most 20s seconds. + // + // .. code-block:: yaml + // + // retry_policy: + // num_retries:1 + // + // uses the default :ref:`retry backoff strategy `. + // with the default base interval is 1000 milliseconds. and the default maximum interval of 10 times the base interval. + // + // if num_retries is omitted, the default is to allow only one retry. + // + // + // If enabled, the retry policy will apply to all Jwks fetching approaches, e.g. on demand or asynchronously in background. + // + // + config.core.v3.RetryPolicy retry_policy = 4; +} + +// Fetch Jwks asynchronously in the main thread when the filter config is parsed. +// The listener is activated only after the Jwks is fetched. +// When the Jwks is expired in the cache, it is fetched again in the main thread. +// The fetched Jwks from the main thread can be used by all worker threads. +message JwksAsyncFetch { + // If false, the listener is activated after the initial fetch is completed. + // The initial fetch result can be either successful or failed. + // If true, it is activated without waiting for the initial fetch to complete. + // Default is false. + bool fast_listener = 1; + + // The duration to refetch after a failed fetch. If not specified, default is 1 second. + google.protobuf.Duration failed_refetch_duration = 2; +} diff --git a/api/src/main/proto/envoy/extensions/filters/common/jwks/v3/jwt_handshake.proto b/api/src/main/proto/envoy/extensions/filters/common/jwks/v3/jwt_handshake.proto new file mode 100644 index 000000000..78581c704 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/filters/common/jwks/v3/jwt_handshake.proto @@ -0,0 +1,77 @@ +syntax = "proto3"; + +package envoy.extensions.filters.common.jwks.v3; + +import "envoy/config/core/v3/base.proto"; +import "envoy/extensions/filters/common/jwks/v3/jwks.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.filters.common.jwks.v3"; +option java_outer_classname = "JwtHandshakeProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/common/jwks/v3;jwksv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: JWT handshake validation] +// Configuration for verifying a bearer JWT during handshake authentication, shared by extensions +// that authenticate a connection or request by validating a token. + +// Validation of a bearer JWT. A consuming extension verifies the token against the configured JWKS, +// issuer, audiences, and time constraints. On success it publishes the verified claims as dynamic +// metadata under ``claims_metadata_namespace``, so the consumer can bind a claimed identifier to a +// verified claim via ``%DYNAMIC_METADATA(namespace:claim)%``. What a validation failure does, and +// any per-field defaults, are defined by the consuming extension. +// +// .. attention:: +// Verifying the token proves only that the caller *holds* a valid token; it does **not** by itself +// prove the caller is the identity it claims. To authenticate the claimed identity, bind a verified +// claim from the consuming extension's own validation configuration. Without such a binding, a token +// minted for one identity can be presented for another. Tokens without an ``exp`` claim are +// rejected. All top-level claims are published as dynamic metadata (see +// ``claims_metadata_namespace``), so do not put secrets in the token. +// [#next-free-field: 9] +message JwtHandshakeValidator { + // Required. Expected token issuer. The JWT ``iss`` claim must equal this value. + string issuer = 1 [(validate.rules).string = {min_len: 1 max_len: 1024}]; + + // Allowed audiences. If non-empty, the JWT must carry at least one of these in its ``aud`` claim. + // If empty, the audience is not checked. + repeated string audiences = 2; + + // Source of the JSON Web Key Set (JWKS) used to verify the token signature. Exactly one source + // must be configured. + oneof jwks_source_specifier { + option (validate.required) = true; + + // The JWKS provided inline as a data source (``inline_string``, ``inline_bytes``, or + // ``filename``). The keys are read once when the configuration is loaded. + config.core.v3.DataSource local_jwks = 3; + + // The JWKS fetched over HTTP. See :ref:`RemoteJwks + // ` for the fetch, cache, + // ``async_fetch``, and ``retry_policy`` options. + RemoteJwks remote_jwks = 8; + } + + // Name of the header carrying the token. When unset, the consuming extension applies its own + // default (commonly ``authorization``, with a leading ``Bearer`` prefix stripped). + string token_header = 4 [(validate.rules).string = {max_len: 255 ignore_empty: true}]; + + // Namespace under which verified claims are emitted as dynamic metadata. If unset, the consuming + // extension's default namespace is used. Each top-level JWT claim is written as a field in this + // namespace so it can be referenced via ``%DYNAMIC_METADATA(namespace:claim)%`` by the consuming + // extension's validation configuration. + string claims_metadata_namespace = 5 + [(validate.rules).string = {max_len: 255 ignore_empty: true}]; + + // If ``true``, a missing or invalid token does **not** fail validation; the verified claims are + // simply not published. Useful for a staged rollout or audit mode. Defaults to ``false``. How a + // validation failure is handled is defined by the consuming extension. + bool allow_missing_or_failed = 6; + + // Clock skew, in seconds, allowed when checking the ``exp`` and ``nbf`` time constraints. When + // unset (``0``), the consuming extension applies its own default. + uint32 clock_skew_seconds = 7; +} diff --git a/api/src/main/proto/envoy/extensions/filters/http/adaptive_concurrency/v3/adaptive_concurrency.proto b/api/src/main/proto/envoy/extensions/filters/http/adaptive_concurrency/v3/adaptive_concurrency.proto index 6ba7477e9..378d74baa 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/adaptive_concurrency/v3/adaptive_concurrency.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/adaptive_concurrency/v3/adaptive_concurrency.proto @@ -44,6 +44,13 @@ message GradientControllerConfig { required: true gt {} }]; + + // The allowed lower-bound on the calculated concurrency limit. If unset, this defaults to + // :ref:`min_concurrency + // ` + // to preserve the existing behavior where the same value controls both the minimum calculated + // limit and the limit used while measuring minRTT. + google.protobuf.UInt32Value min_concurrency_limit = 4 [(validate.rules).uint32 = {gt: 0}]; } // Parameters controlling the periodic minRTT recalculation. diff --git a/api/src/main/proto/envoy/extensions/filters/http/ai_protocol_manager/v3/ai_protocol_manager.proto b/api/src/main/proto/envoy/extensions/filters/http/ai_protocol_manager/v3/ai_protocol_manager.proto index d7950a423..ee379e8d1 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/ai_protocol_manager/v3/ai_protocol_manager.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/ai_protocol_manager/v3/ai_protocol_manager.proto @@ -2,9 +2,15 @@ syntax = "proto3"; package envoy.extensions.filters.http.ai_protocol_manager.v3; +import "envoy/config/core/v3/extension.proto"; +import "envoy/type/ai/v3/llm_protocol.proto"; + +import "google/protobuf/wrappers.proto"; + import "xds/annotations/v3/status.proto"; import "udpa/annotations/status.proto"; +import "validate/validate.proto"; option java_package = "io.envoyproxy.envoy.extensions.filters.http.ai_protocol_manager.v3"; option java_outer_classname = "AiProtocolManagerProto"; @@ -19,5 +25,239 @@ option (xds.annotations.v3.file_status).work_in_progress = true; // [#extension: envoy.filters.http.ai_protocol_manager] // Configuration for the AI Protocol Manager filter. +// +// The filter manages AI endpoint traffic on both directions of a stream. On +// the request path it holds a declared AI endpoint's payload and parses it, +// which is what lets routing, admission and policy act on a payload the proxy +// understands rather than on opaque bytes. On the response path it can +// extract normalized LLM token usage into dynamic metadata. +// +// Request and response processing are independently enabled by the presence +// of ``request_handling`` and ``response_handling``. Which routes are AI +// endpoints — and which :ref:`wire API ` +// each speaks — is declared with the :ref:`per-route configuration +// `. message AiProtocolManager { + // Request-side AI protocol processing. When unset, the decode path is a + // pure passthrough — including on routes carrying per-route configuration. + RequestHandling request_handling = 1; + + // Response-side AI protocol processing. When unset, the encode path is a + // pure passthrough. + ResponseHandling response_handling = 2; + + // AI filters, in order. They run over a declared AI endpoint's parsed request payload + // before it continues down the HTTP filter chain, and require ``request_handling``. + // [#extension-category: envoy.http.ai_filters] + repeated config.core.v3.TypedExtensionConfig filters = 3; +} + +// Request-side processing configuration. A route that carries a +// :ref:`per-route request declaration +// ` +// has its payload held, offloaded, and parsed strictly: a body that is not +// well-formed JSON is rejected with a 400 rather than forwarded for the +// upstream to interpret differently. +message RequestHandling { + // How the request body is written out once the :ref:`AI filters + // ` + // finish. + enum BodyReserialization { + // Re-serialize the parsed document, so the edits AI filters make to it reach the upstream. + ALWAYS = 0; + + // Forward the received body byte for byte. Edits AI filters make to the parsed document are + // not sent, so use this only with AI filters that read the request, such as request info. + DISABLE = 1; + } + + // Attempt best-effort JSON parsing on routes without a per-route + // configuration. + // + // Defaults to ``false``: unconfigured routes are not buffered or parsed. + // When ``true``, such routes are parsed too, but never failed over it — a + // route that declared no AI wire contract has nothing to hold its payload + // to, so a body that fails to parse is forwarded unchanged. + // + // Only requests that can be held to end of stream are taken: the request must + // carry a JSON content type (``application/json`` or a ``+json`` suffix) and + // must not be gRPC or Connect streaming, an upgrade, or a CONNECT. Holding a + // full-duplex request would stall it, since the client may not finish the + // request until it sees a response the held upstream cannot produce. + bool parse_unconfigured_routes = 1; + + // Request-path parsing limits. Defaults apply when unset. + RequestParsingLimits limits = 2; + + // Whether the parsed request is re-serialized once the AI filters finish. Defaults to ``ALWAYS``. + // Requests that run no AI filters are forwarded as received either way. + BodyReserialization reserialize_body = 3 [(validate.rules).enum = {defined_only: true}]; +} + +// Per-stream limits for request payload parsing. +message RequestParsingLimits { + // Maximum size, in bytes, of a decoded string value kept inline in the + // parsed document; a larger value stays in the external buffer and is + // referenced by offset. Object keys are always inline. + // + // This is the deployment-wide default, applied when a declared API's payload + // schema does not pin its own threshold. Defaults to 1KiB, which keeps + // ordinary metadata (model names, roles, tool names) inline while + // conversation content goes to the buffer. + // + // Keep it above the longest ``model`` name in use. Values over the threshold + // are offloaded, and the :ref:`schema validation AI filter + // ` + // requires ``model`` inline, so it rejects an offloaded one with a 400. + google.protobuf.UInt32Value inline_string_threshold_bytes = 1 + [(validate.rules).uint32 = {lte: 1048576 gte: 64}]; +} + +// Response-side processing configuration. Individual response features are +// enabled by the presence of their corresponding messages. +message ResponseHandling { + // Extract canonical token usage from eligible AI responses. When unset, + // token usage extraction is disabled. + TokenUsageExtraction token_usage = 1; +} + +// Configuration for canonical response token-usage extraction. +// +// Eligible 2xx SSE and JSON responses are observed as they stream through; +// the filter never stops iteration or modifies the response, and no +// extraction failure can affect it. The result is published at a clean end +// of stream under one namespace as typed dynamic metadata: the authoritative +// record is :ref:`envoy.data.ai.v3.TokenUsage +// `, consumable through typed +// metadata readers such as ext_proc typed forwarding. No untyped ``Struct`` +// mirror is emitted. +// [#next-free-field: 6] +message TokenUsageExtraction { + // Stream signals emitted upon publishing token usage metadata. + enum UsageSignal { + USAGE_SIGNAL_UNSPECIFIED = 0; + + // Synthesize empty response trailers at end of stream if none exist. + // This wakes downstream trailer-driven consumers (such as ext_proc with + // ``response_trailer_mode: SEND``) with metadata context without transferring + // response body bytes. + SYNTHESIZE_TRAILERS = 1; + } + + // Also inspect responses on routes without per-route configuration. + // + // Defaults to ``false``: only routes carrying an + // :ref:`AiProtocolManagerPerRoute + // ` + // configuration are inspected, so enabling token usage on a mixed listener + // does not silently parse unrelated JSON/SSE responses. Enable this for + // response-only installations whose routes cannot be declared — for + // example an upstream installation on a dynamic-forward-proxy cluster. + bool include_unconfigured_routes = 1; + + // Fallback wire API used when the route does not identify a response API. + // + // ``LLM_PROTOCOL_UNSPECIFIED`` means auto-detect from the response shape + // (only strongly shaped, value-validated markers lock a stream). This is a + // fallback, not an override of per-route response configuration; see the + // :ref:`per-route configuration + // ` + // for the full precedence. + type.ai.v3.LLMProtocol default_llm_protocol = 2 [(validate.rules).enum = {defined_only: true}]; + + // Namespace for the emitted typed dynamic metadata. + // Defaults to ``envoy.ai.token_usage``. + string metadata_namespace = 3; + + // Extraction resource limits. Defaults apply when unset. + TokenUsageExtractionLimits limits = 4; + + // Optional signal to emit at end of stream after publishing token usage. + UsageSignal usage_signal = 5 [(validate.rules).enum = {defined_only: true}]; +} + +// Per-stream memory and work limits for token-usage extraction. The response +// itself always streams through unaffected; on any limit only extraction +// state is dropped and the published record is flagged. +message TokenUsageExtractionLimits { + // Maximum size of one SSE event inspected for token usage. This is a hard + // bound on retained extraction state, regardless of how large individual + // data frames are: a pending event over the cap is discarded through its + // real terminating blank line, and a complete event over the cap is + // skipped without parsing. + // + // Defaults to 1MiB: OpenAI Responses API streams carry usage on terminal + // lifecycle events that embed the complete response object, so ordinary + // long generations produce usage-bearing events far larger than typical + // SSE deltas. Lower this in constrained deployments at the cost of losing + // usage from long generations. + google.protobuf.UInt32Value max_sse_event_size = 1 + [(validate.rules).uint32 = {lte: 10485760 gte: 1}]; + + // Maximum JSON response body inspected for token usage. A larger body — + // including one whose ``content-length`` already exceeds the cap — is not + // inspected. Defaults to 4MiB. + google.protobuf.UInt32Value max_json_body_size = 2 + [(validate.rules).uint32 = {lte: 10485760 gte: 1}]; + + // Maximum number of SSE payloads parsed as JSON for one response, counting + // malformed payloads; events skipped by name (keepalives, content deltas) + // do not count. ``max_sse_event_size`` bounds one event; this bounds the + // parse work a long-lived stream can extract from the worker. On + // exhaustion the accumulated usage is kept and published as partial, and + // extraction goes inert. + // + // Defaults to 65536 — far above ordinary streams. Raise it for extremely + // long generations whose every chunk must be parsed (OpenAI Chat + // Completions streams, whose chunks are unnamed and cannot be skipped by + // classification). + google.protobuf.UInt32Value max_parsed_sse_events = 3 [(validate.rules).uint32 = {gte: 1}]; +} + +// Per-route configuration. Its presence declares the route an AI endpoint. +// +// Request and response wire protocols are declared separately because +// protocol translation can make the client-facing request API differ from +// the provider's response API. For response token-usage extraction the +// effective wire API is resolved in precedence order: per-route +// ``response.llm_protocol``, then per-route ``request.llm_protocol``, then +// :ref:`default_llm_protocol +// `, +// then auto-detection. +message AiProtocolManagerPerRoute { + // Request-side route configuration. Its presence hands the request payload + // to the filter to hold and validate (when :ref:`request_handling + // ` + // is enabled). + RequestPerRoute request = 1; + + // Optional response-side route configuration. When absent, response + // processing inherits ``request.llm_protocol`` when available, then the + // global fallback. + ResponsePerRoute response = 2; +} + +// Per-route request-side behavior. +message RequestPerRoute { + // The wire API a request payload on this route follows. + // ``LLM_PROTOCOL_UNSPECIFIED`` declares the endpoint without naming its + // API. The ``envoy.ai.llm_protocol.request`` filter state object, when it + // names one, takes precedence. + // + // The :ref:`schema validation AI filter + // ` + // holds a payload to its API's schema. + // + // [#comment: Normalization is not implemented yet; a normalization knob + // will be added here once the transformation and its output contract + // exist.] + type.ai.v3.LLMProtocol llm_protocol = 1 [(validate.rules).enum = {defined_only: true}]; +} + +// Per-route response-side behavior. +message ResponsePerRoute { + // The wire API the response on this route follows. This can differ from + // ``request.llm_protocol`` when the gateway performs protocol translation. + // ``LLM_PROTOCOL_UNSPECIFIED`` falls through the precedence chain above. + type.ai.v3.LLMProtocol llm_protocol = 1 [(validate.rules).enum = {defined_only: true}]; } diff --git a/api/src/main/proto/envoy/extensions/filters/http/aws_eventstream_parser/v3/aws_eventstream_parser.proto b/api/src/main/proto/envoy/extensions/filters/http/aws_eventstream_parser/v3/aws_eventstream_parser.proto new file mode 100644 index 000000000..558cd7a63 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/filters/http/aws_eventstream_parser/v3/aws_eventstream_parser.proto @@ -0,0 +1,117 @@ +syntax = "proto3"; + +package envoy.extensions.filters.http.aws_eventstream_parser.v3; + +import "envoy/config/core/v3/extension.proto"; + +import "google/protobuf/struct.proto"; +import "google/protobuf/wrappers.proto"; + +import "xds/annotations/v3/status.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.filters.http.aws_eventstream_parser.v3"; +option java_outer_classname = "AwsEventstreamParserProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/aws_eventstream_parser/v3;aws_eventstream_parserv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; +option (xds.annotations.v3.file_status).work_in_progress = true; + +// [#protodoc-title: AWS-EventStream-Parser Filter] +// +// The AWS-EventStream-Parser filter extracts values from AWS EventStream HTTP response bodies +// and writes them to dynamic metadata. This is useful for AWS Bedrock streaming response processing, +// token usage tracking, logging, and other observability use cases. +// +// The filter specifically handles the AWS EventStream binary protocol +// (application/vnd.amazon.eventstream) and uses pluggable content parsers to extract values +// from the message payloads. The content parser is a typed extension that can be configured +// to handle different content types (JSON, plaintext, XML, etc.). +// +// The filter only processes responses with Content-Type "application/vnd.amazon.eventstream". +// Content-Type parameters are ignored. +// +// See AWS-EventStream-Parser :ref:`configuration overview ` for more details. +// [#extension: envoy.filters.http.aws_eventstream_parser] + +message AwsEventstreamParser { + // Metadata action to write when an EventStream header matches or is missing. + message HeaderKeyValuePair { + // The namespace — if this is empty, the filter's namespace will be used. + // Default: "envoy.filters.http.aws_eventstream_parser". + string metadata_namespace = 1; + + // The key to use within the namespace. + string key = 2 [(validate.rules).string = {min_len: 1}]; + + // Optional: a fixed value to use instead of the header's actual value. + // When set for on_present, uses this value instead of the header value. + // Required for on_missing (since there is no header value available). + google.protobuf.Value value = 3; + } + + // A rule for extracting an EventStream message header to dynamic metadata. + message HeaderRule { + // The EventStream header name to match. Case-sensitive. + string header_name = 1 [(validate.rules).string = {min_len: 1}]; + + // If the header is present in a message, apply this metadata action. + HeaderKeyValuePair on_present = 2; + + // If the header was not found in any message by end-of-stream, apply this metadata action. + // The value field in the HeaderKeyValuePair must be set (since there is no header value). + HeaderKeyValuePair on_missing = 3; + + // Controls how many times this rule should successfully match before stopping evaluation + // of this rule for subsequent messages. + // + // - If set to 0 (default): This rule is evaluated against all messages. + // Later matches overwrite earlier values, effectively extracting the LAST occurrence. + // + // - If set to 1: Stop evaluating this rule after the first successful match. + // This is useful for extracting header values that appear early in the stream + // to avoid unnecessary processing of subsequent messages. + // + // - If set to N > 1: Reserved for future use. Values > 1 are currently rejected. + // + // When all header rules AND all content parser rules have stop_processing_after_matches + // limits set and all limits are satisfied, the filter stops processing the stream entirely. + google.protobuf.UInt32Value stop_processing_after_matches = 4 + [(validate.rules).uint32 = {lte: 1}]; + } + + // Rules for processing AWS EventStream streams and extracting metadata. + // + // The filter parses the AWS EventStream binary protocol (messages with headers and payloads), + // then delegates to a content parser to parse the message payload and extract metadata. + // The content parser determines which values to extract and how to write them to metadata. + message ProcessingRules { + // Content parser configuration for parsing message payloads and extracting metadata. + // + // The content parser specifies: + // - How to parse the message payload (e.g., JSON, XML, plaintext) + // - Which values to extract from the parsed content (e.g., JSON paths like usage.total_tokens) + // - How to map extracted values to metadata (namespace, key, type conversions) + // - When to write metadata (on_present, on_missing, on_error actions) + // [#extension-category: envoy.content_parsers] + config.core.v3.TypedExtensionConfig content_parser = 1 + [(validate.rules).message = {required: true}]; + + // Rules for extracting EventStream message headers to dynamic metadata. + // These are evaluated directly by the filter (not by the content parser). + // Headers are simple typed key-value pairs at the EventStream protocol level. + // + // Header values are automatically converted to the appropriate Protobuf value type: + // - BoolTrue/BoolFalse -> bool_value + // - Byte/Short/Int32/Int64/Timestamp -> number_value + // - String -> string_value + // - ByteArray -> string_value (hex-encoded) + // - UUID -> string_value (formatted as xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) + repeated HeaderRule header_rules = 2; + } + + // Rules for processing AWS EventStream response streams. + ProcessingRules response_rules = 1 [(validate.rules).message = {required: true}]; +} diff --git a/api/src/main/proto/envoy/extensions/filters/http/basic_auth/v3/basic_auth.proto b/api/src/main/proto/envoy/extensions/filters/http/basic_auth/v3/basic_auth.proto index af163642a..67aa1fab6 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/basic_auth/v3/basic_auth.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/basic_auth/v3/basic_auth.proto @@ -29,7 +29,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // user1:{SHA}hashed_user1_password // user2:{SHA}hashed_user2_password // -// [#next-free-field: 6] +// [#next-free-field: 7] message BasicAuth { // Username-password pairs used to verify user credentials in the "Authorization" header. // The value needs to be the htpasswd format. @@ -71,6 +71,16 @@ message BasicAuth { // other authentication methods (e.g. JWT) and using a downstream RBAC filter to enforce // OR semantics. bool emit_dynamic_metadata = 5; + + // The realm to use in the ``WWW-Authenticate`` response header when authentication fails. + // The value is placed verbatim into ``WWW-Authenticate: Basic realm=""``. + // + // If not specified, Envoy falls back to using the full request URI + // (scheme + authority + path, truncated to 256 characters), which differs per path and + // prevents browsers from reusing cached credentials across paths on the same origin. + // Set a fixed realm to enable correct credential caching. The realm pattern dose not + // allow DEL, 32 C0 control chars including CRLF injection chars. + string realm = 6 [(validate.rules).string = {pattern: "^[^\\x00-\\x1f\\x7f]*$"}]; } // Extra settings that may be added to per-route configuration for @@ -79,4 +89,11 @@ message BasicAuthPerRoute { // Username-password pairs for this route. config.core.v3.DataSource users = 1 [(validate.rules).message = {required: true}, (udpa.annotations.sensitive) = true]; + + // Per-route realm override for the ``WWW-Authenticate`` response header. If set, takes + // precedence over the filter-level ``BasicAuth.realm``. Same escaping semantics apply. + // If neither this nor the filter-level realm is set, the full request URI is used. + // Set a fixed realm to enable correct credential caching. The realm pattern dose not + // allow DEL, 32 C0 control chars including CRLF injection chars. + string realm = 2 [(validate.rules).string = {pattern: "^[^\\x00-\\x1f\\x7f]*$"}]; } diff --git a/api/src/main/proto/envoy/extensions/filters/http/body_size_limit/v3/body_size_limit.proto b/api/src/main/proto/envoy/extensions/filters/http/body_size_limit/v3/body_size_limit.proto new file mode 100644 index 000000000..b5132bb68 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/filters/http/body_size_limit/v3/body_size_limit.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package envoy.extensions.filters.http.body_size_limit.v3; + +import "google/protobuf/wrappers.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.filters.http.body_size_limit.v3"; +option java_outer_classname = "BodySizeLimitProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/body_size_limit/v3;body_size_limitv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Body Size Limit] +// Body Size Limit :ref:`configuration overview `. +// [#extension: envoy.filters.http.body_size_limit] + +message BodySizeLimit { + // The maximum request body size allowed. If the request body exceeds this limit, + // the filter will return a 413 response. + google.protobuf.UInt64Value max_request_bytes = 1 [(validate.rules).uint64 = {gt: 0}]; +} diff --git a/api/src/main/proto/envoy/extensions/filters/http/compressor/v3/compressor.proto b/api/src/main/proto/envoy/extensions/filters/http/compressor/v3/compressor.proto index 41031ed60..30869f60a 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/compressor/v3/compressor.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/compressor/v3/compressor.proto @@ -4,6 +4,7 @@ package envoy.extensions.filters.http.compressor.v3; import "envoy/config/core/v3/base.proto"; import "envoy/config/core/v3/extension.proto"; +import "envoy/type/matcher/v3/string.proto"; import "google/protobuf/wrappers.proto"; @@ -38,6 +39,8 @@ message Compressor { // direction this common config is applied to), in bytes, that will trigger compression. Defaults to 30. google.protobuf.UInt32Value min_content_length = 2; + // Using ``content_type`` is deprecated. Use ``content_type_matcher`` instead. + // // Set of strings that allows specifying which mime-types yield compression; e.g., // ``application/json``, ``text/html``, etc. // @@ -53,7 +56,17 @@ message Compressor { // * ``text/plain`` // * ``text/xml`` // - repeated string content_type = 3; + repeated string content_type = 3 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; + + // Allows specifying which content types yield compression using + // envoy.type.matcher.v3.StringMatcher. + // + // When this field is specified, the default content type list is not used. + // If both ``content_type`` and ``content_type_matcher`` are specified, + // ``content_type_matcher`` takes precedence and the deprecated ``content_type`` + // field is ignored. + repeated type.matcher.v3.StringMatcher content_type_matcher = 4; } // Configuration for filter behavior on the request direction. diff --git a/api/src/main/proto/envoy/extensions/filters/http/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/filters/http/dynamic_modules/v3/dynamic_modules.proto index d8fdd5e02..b376b844a 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/dynamic_modules/v3/dynamic_modules.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/dynamic_modules/v3/dynamic_modules.proto @@ -53,7 +53,8 @@ message DynamicModuleFilter { // ``filter_config`` can be used to configure the logging level or the header manipulation // behavior. // - // ``google.protobuf.Struct`` is serialized as JSON before passing it to the plugin. + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the plugin. // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly without // the wrapper. // @@ -120,7 +121,8 @@ message DynamicModuleFilterPerRoute { // manipulation. The ``filter_config`` can be used to configure the logging level or the header // manipulation behavior. // - // ``google.protobuf.Struct`` is serialized as JSON before passing it to the plugin. + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the plugin. // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly without // the wrapper. // diff --git a/api/src/main/proto/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto b/api/src/main/proto/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto index 2b565dea3..38bd581b4 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto @@ -30,7 +30,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // External Authorization :ref:`configuration overview `. // [#extension: envoy.filters.http.ext_authz] -// [#next-free-field: 33] +// [#next-free-field: 35] message ExtAuthz { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.http.ext_authz.v3.ExtAuthz"; @@ -101,6 +101,24 @@ message ExtAuthz { // also use decoder_header_mutation_rules to restrict sensitive request header mutations. bool clear_route_cache = 6; + // A list of the request header names the routes match on. When this list is not empty and + // ``clear_route_cache`` is ``true``, an ``OK`` response clears the route cache only when it sets, + // appends, or removes one of these headers, or mutates a query parameter, rather than on any request + // mutation. This avoids re-resolving the route when the response only touches headers that no route + // matches on. + // + // If not specified, the route cache is cleared whenever an ``OK`` response sets, appends, or removes + // any request header, or mutates a query parameter. + // + // .. attention:: + // + // List every request header the routes match on. A route that matches on a header omitted here is + // not re-resolved when the authorization service mutates that header, which can route the request + // as if the mutation had not happened. + repeated string clear_route_cache_headers = 34 [(validate.rules).repeated = { + items {string {min_len: 1 well_known_regex: HTTP_HEADER_NAME strict: false}} + }]; + // Sets the HTTP status that is returned to the client when the authorization server returns an error // or cannot be reached. // @@ -397,6 +415,13 @@ message ExtAuthz { // // Defaults to ``false``. bool shadow_mode = 32; + + // Whether to emit client-side spans for external authorization requests (e.g. gRPC or HTTP calls). + // When set to false, client-side egress spans will not be emitted/exported to trace collectors, + // but trace context (e.g. ``traceparent``) will still be propagated to the authorization server. + // + // If unset, defaults to ``true``. + google.protobuf.BoolValue emit_client_span = 33; } // Serialized form of the shadow-mode authorization decision written to FilterState @@ -624,7 +649,7 @@ message ExtAuthzPerRoute { } // Extra settings for the check request. -// [#next-free-field: 6] +// [#next-free-field: 7] message CheckSettings { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.http.ext_authz.v2.CheckSettings"; @@ -673,4 +698,7 @@ message CheckSettings { // Override with an HTTP service configuration. HttpService http_service = 5; } + + // Overrides the filter-level ``emit_client_span`` setting for this route. + google.protobuf.BoolValue emit_client_span = 6; } diff --git a/api/src/main/proto/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto b/api/src/main/proto/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto index ec0c901a9..cd126b18c 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto @@ -98,7 +98,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // ` object in a namespace matching the filter // name. // -// [#next-free-field: 27] +// [#next-free-field: 28] message ExternalProcessor { // Describes the route cache action to be taken when an external processor response // is received in response to request headers. @@ -386,6 +386,13 @@ message ExternalProcessor { // request smuggling. Thus, please use your own discretion when enabling this feature. // bool allow_content_length_header = 26; + + // Whether to emit client-side spans for external processing requests. + // When set to false, client-side egress spans will not be emitted/exported to trace collectors, + // but trace context (e.g. ``traceparent``) will still be propagated to the external processor. + // + // If unset, defaults to ``true``. + google.protobuf.BoolValue emit_client_span = 27; } // ExtProcHttpService is used for HTTP communication between the filter and the external processing service. @@ -416,7 +423,7 @@ message MetadataOptions { // Describes which typed or untyped filter dynamic metadata namespaces to accept from // the external processing server. Set to empty or leave unset to disallow writing - // any received dynamic metadata. Receiving of typed metadata is not supported. + // any received dynamic metadata. MetadataNamespaces receiving_namespaces = 2; // Describes which cluster metadata namespaces to forward to @@ -467,7 +474,7 @@ message ExtProcPerRoute { } // Overrides that may be set on a per-route basis -// [#next-free-field: 10] +// [#next-free-field: 11] message ExtProcOverrides { // Set a different processing mode for this route than the default. ProcessingMode processing_mode = 1; @@ -514,4 +521,7 @@ message ExtProcOverrides { // :ref:`processing_request_modifier `. config.core.v3.TypedExtensionConfig processing_request_modifier = 9 [(xds.annotations.v3.field_status).work_in_progress = true]; + + // Overrides the filter-level ``emit_client_span`` setting for this route. + google.protobuf.BoolValue emit_client_span = 10; } diff --git a/api/src/main/proto/envoy/extensions/filters/http/fault/v3/fault.proto b/api/src/main/proto/envoy/extensions/filters/http/fault/v3/fault.proto index 01f056e79..ec52981aa 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/fault/v3/fault.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/fault/v3/fault.proto @@ -23,7 +23,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Fault Injection :ref:`configuration overview `. // [#extension: envoy.filters.http.fault] -// [#next-free-field: 6] +// [#next-free-field: 7] message FaultAbort { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.http.fault.v2.FaultAbort"; @@ -54,6 +54,10 @@ message FaultAbort { // The percentage of requests/operations/connections that will be aborted with the error code // provided. type.v3.FractionalPercent percentage = 3; + + // The response body to be returned when aborting the request. + // If not specified, defaults to "fault filter abort". + string response_body = 6; } // [#next-free-field: 17] diff --git a/api/src/main/proto/envoy/extensions/filters/http/gcp_authn/v3/gcp_authn.proto b/api/src/main/proto/envoy/extensions/filters/http/gcp_authn/v3/gcp_authn.proto index b741120c1..dcf367f1e 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/gcp_authn/v3/gcp_authn.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/gcp_authn/v3/gcp_authn.proto @@ -23,7 +23,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // [#extension: envoy.filters.http.gcp_authn] // Filter configuration. -// [#next-free-field: 7] +// [#next-free-field: 9] message GcpAuthnFilterConfig { // The HTTP URI to fetch tokens from GCE Metadata Server(https://cloud.google.com/compute/docs/metadata/overview). // The URL format is "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=[AUDIENCE]" @@ -45,9 +45,14 @@ message GcpAuthnFilterConfig { // Request header location to extract the token. By default (i.e. if this field is not specified), the token // is extracted to the Authorization HTTP header, in the format "Authorization: Bearer ". + // If ``token_metadata_key`` is set, this field takes no effect. // Not supported by all data planes. TokenHeader token_header = 4; + // Optional dynamic metadata key to save the token. The metadata uses the filter config name as the namespace. + // Takes precedence over ``token_header``. + string token_metadata_key = 7; + // Cluster to send traffic to the GCE metadata server. Not supported // by all data planes; a data plane may instead have its own mechanism // for contacting the metadata server. @@ -59,12 +64,28 @@ message GcpAuthnFilterConfig { lt {seconds: 4294967296} gte {} }]; + + // Defines the authentication service. This field overrides the cluster's typed_filter_metadata definition. + Audience audience = 8; } // Audience is the URL of the receiving service that performs token authentication. // It will be provided to the filter through cluster's typed_filter_metadata. +// [#next-free-field: 6] message Audience { message AccessToken { + // Optional custom OAuth scopes for the access token request. + // If empty, the filter will not request scopes explicitly, so the metadata server's default + // scopes will be used. + // When populated, the filter appends "?scopes=" to the + // metadata server token request. Note that the metadata server replaces default + // scopes with the provided list rather than appending; to preserve general GCP API + // access, callers should explicitly include "https://www.googleapis.com/auth/cloud-platform". + // Validation rules require each scope to be non-empty and disallow whitespace or commas, + // as commas are used as the delimiter for the metadata server and OAuth 2.0 scopes + // cannot contain whitespace (RFC 6749 Section 3.3). + repeated string scopes = 1 + [(validate.rules).repeated = {items {string {min_len: 1 pattern: "^[^\\s,]+$"}}}]; } message BoundJwt { @@ -73,6 +94,33 @@ message Audience { } message BoundAccessToken { + // Optional custom OAuth scopes for the bound access token request. + // If empty, the filter will not request scopes explicitly, so the metadata server's default + // scopes will be used. + // When populated, the filter appends "&scopes=" to the + // metadata server token request. Note that the metadata server replaces default + // scopes with the provided list rather than appending; to preserve general GCP API + // access, callers should explicitly include "https://www.googleapis.com/auth/cloud-platform". + // Validation rules require each scope to be non-empty and disallow whitespace or commas, + // as commas are used as the delimiter for the metadata server and OAuth 2.0 scopes + // cannot contain whitespace (RFC 6749 Section 3.3). + repeated string scopes = 1 + [(validate.rules).repeated = {items {string {min_len: 1 pattern: "^[^\\s,]+$"}}}]; + } + + // Default lifetime is 1h. + message IAMAccessToken { + // A template string for the account email or unique ID for which the credentials are requested, + // e.g. ``my-sa-%DYNAMIC_METADATA(my_filter:tenant_project)%@my-project.iam.gserviceaccount.com``. + string account = 1 [(validate.rules).string = {min_len: 1}]; + + // A template string for the authorization header value, + // e.g. ``Bearer %DYNAMIC_METADATA(gcp_authn:token)%``. + string authorization = 2 [(validate.rules).string = {min_len: 1}]; + + // Optional custom scopes for the token request. + // Default scope is https://www.googleapis.com/auth/cloud-platform. + repeated string scopes = 3; } // The audience URL, used for fetching unbound JWT token. @@ -89,6 +137,11 @@ message Audience { // If defined, the filter will fetch bound Access Token instead of unbound. // It takes precedence over ``bound_jwt``, ``access_token`` and ``url``. BoundAccessToken bound_access_token = 4; + + // If defined, the filter will fetch an access token for a service account. + // It takes precedence over ``bound_access_token``, ``bound_jwt``, ``access_token``, and ``url``. + // Requires inlined audience definition in the filter configuration. + IAMAccessToken iam_access_token = 5; } // Token Cache configuration. @@ -99,13 +152,25 @@ message TokenCacheConfig { } message TokenHeader { - // The HTTP header's name. - string name = 1 - [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME strict: false}]; + // Configuration options for preserving an existing token header. + message PreserveExisting { + } + + // The HTTP header's name. Defaults to ``Authorization`` if not specified. + string name = 1 [ + (validate.rules).string = {well_known_regex: HTTP_HEADER_NAME strict: false ignore_empty: true} + ]; // The header's prefix. The format is "value_prefix" // For example, for "Authorization: Bearer ", value_prefix="Bearer " with a space at the // end. string value_prefix = 2 [(validate.rules).string = {well_known_regex: HTTP_HEADER_VALUE strict: false}]; + + // If set, the filter checks if the target header is already present (by header key existence, + // even if the header value is empty). If present, it skips token fetching and preserves the + // existing header intact (``value_prefix`` has no effect on the preserved header). If absent, + // a new token is fetched and written using ``name`` and ``value_prefix``. + // If not set, the default behavior is to unconditionally overwrite the header. + PreserveExisting preserve_existing = 3; } diff --git a/api/src/main/proto/envoy/extensions/filters/http/grpc_field_extraction/v3/config.proto b/api/src/main/proto/envoy/extensions/filters/http/grpc_field_extraction/v3/config.proto index 6eb225980..cf1b908bb 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/grpc_field_extraction/v3/config.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/grpc_field_extraction/v3/config.proto @@ -68,6 +68,23 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // // 2. if the field value is empty, an empty ``Value`` will be set. // +// **IMPORTANT**: All extracted values are stored as ``ListValue``, even for singular (non-repeated) fields. +// Filters consuming this metadata (e.g., :ref:`ratelimit `) +// must use :ref:`MetadataKey ` with an ``index`` segment to access the value. +// +// Example: to access a singular ``string tenant_id`` field extracted to ``envoy.filters.http.grpc_field_extraction``: +// +// .. code-block:: yaml +// +// metadata_key: +// key: envoy.filters.http.grpc_field_extraction +// path: +// - key: tenant_id +// - index: 0 # Required: unwrap the ListValue containing the singular value +// +// Omitting the ``index`` segment will cause the consumer to receive the ``ListValue`` itself rather than +// its element, which typically results in empty or incorrect metadata descriptor values. +// // Performance // ----------- // @@ -139,6 +156,37 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // "baz":[ // ] // } +// +// Normalizing the metadata key +// ---------------------------- +// +// By default the dynamic metadata key is the field path. ``metadata_key`` overrides it, which +// allows different gRPC methods to write the same logical value under a common key. +// +// .. code-block:: json +// +// { +// "descriptor_set":{}, +// "extractions_by_method":{ +// "pkg.svc.Method":{ +// "request_field_extractions":{ +// "nested.bar":{ +// "metadata_key":"bar" +// } +// } +// } +// } +// } +// +// writes +// +// .. code-block:: json +// +// { +// "bar":[ +// "val_bar1", "val_bar2" +// ] +// } message GrpcFieldExtractionConfig { // The proto descriptor set binary for the gRPC services. @@ -187,4 +235,14 @@ message RequestFieldValueDisposition { // Unimplemented. Uses "envoy.filters.http.grpc_field_extraction" for now. string dynamic_metadata = 1; } + + // The key that the extracted value is written to within the dynamic metadata. + // If empty, the field path (the key of ``request_field_extractions``) is used. + // + // This is useful for normalizing the metadata written by different gRPC methods whose + // request messages name the same logical field differently. + // + // Within a single gRPC method, two field extractions must not resolve to the same + // metadata key, otherwise the configuration is rejected. + string metadata_key = 2; } diff --git a/api/src/main/proto/envoy/extensions/filters/http/header_mutation/v3/header_mutation.proto b/api/src/main/proto/envoy/extensions/filters/http/header_mutation/v3/header_mutation.proto index 6215eab83..8503468c5 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/header_mutation/v3/header_mutation.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/header_mutation/v3/header_mutation.proto @@ -4,6 +4,7 @@ package envoy.extensions.filters.http.header_mutation.v3; import "envoy/config/common/mutation_rules/v3/mutation_rules.proto"; import "envoy/config/core/v3/base.proto"; +import "envoy/config/core/v3/extension.proto"; import "udpa/annotations/status.proto"; @@ -17,7 +18,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Mutate HTTP headers and trailers in requests and responses. // [#extension: envoy.filters.http.header_mutation] -// [#next-free-field: 6] +// [#next-free-field: 7] message Mutations { // The request mutations are applied before the request is forwarded to the upstream cluster. repeated config.common.mutation_rules.v3.HeaderMutation request_mutations = 1; @@ -34,6 +35,15 @@ message Mutations { // The request trailer mutations are applied before the request is sent to the upstream cluster. repeated config.common.mutation_rules.v3.HeaderMutation request_trailers_mutations = 5; + + // Specifies a collection of Formatter plugins that can be used in substitution formatters + // in this message. + // If not specified, only the built-in command operators are available. + // Configured plugins take precedence over the built-in command operators. + // The plugins apply only to this message and are not inherited from other configuration levels. + // See the formatters extensions documentation for details. + // [#extension-category: envoy.formatter] + repeated config.core.v3.TypedExtensionConfig formatters = 6; } // Per route configuration for the header mutation filter. diff --git a/api/src/main/proto/envoy/extensions/filters/http/jwt_authn/v3/config.proto b/api/src/main/proto/envoy/extensions/filters/http/jwt_authn/v3/config.proto index 20baa3183..f5023f170 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/jwt_authn/v3/config.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/jwt_authn/v3/config.proto @@ -358,11 +358,12 @@ message JwtProvider { // Add JWT claim to HTTP Header // Specify the claim name you want to copy in which HTTP header. For examples, following config: - // The claim must be of type; string, int, double, bool. Array type claims are not supported + // Claims of type string, int, double and bool are copied verbatim. Claims of type array or + // object are serialized to JSON and copied base64-encoded. // // .. literalinclude:: /_configs/repo/jwt_authn.yaml // :language: yaml - // :lines: 44-48 + // :lines: 44-51 // :linenos: // :lineno-start: 44 // :caption: :download:`jwt_authn.yaml ` @@ -904,13 +905,58 @@ message PerRouteConfig { // This message specifies a combination of header name and claim name. message JwtClaimToHeader { + // Specifies a segment in a path for retrieving a claim from the JWT payload. + message PathSegment { + // The key to retrieve the value with in the enclosing JSON object. The key is matched in + // full, so it may itself contain dots. + string key = 1 [(validate.rules).string = {min_len: 1}]; + } + // The HTTP header name to copy the claim to. - // The header name will be sanitized and replaced. + // The header name is sanitized from the request for every provider configured on the filter + // (including on paths that bypass JWT verification) and then replaced with the claim value when + // verification succeeds. string header_name = 1 [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME strict: false}]; - // The field name for the JWT Claim : it can be a nested claim of type (eg. "claim.nested.key", "sub") - // String separated with "." in case of nested claims. The nested claim name must use dot "." to separate - // the JSON name path. - string claim_name = 2 [(validate.rules).string = {min_len: 1}]; + // The name of the claim to copy, split on "." to address nested claims: ``sub`` selects the + // top-level ``sub`` claim, and ``nested.claim.key`` selects ``key`` inside ``claim`` inside + // ``nested``. + // + // Because the name is always split, a claim whose own name contains a dot -- a URL-namespaced + // claim such as ``http://example.org/parent_token`` -- is not addressable this way. Use + // :ref:`claim_path + // ` for + // those. + // + // Exactly one of ``claim_name`` and ``claim_path`` must be set. + string claim_name = 2; + + // The path to the claim to copy, given as an explicit list of segments. Each segment is matched + // in full against a key of the enclosing JSON object, so claim names containing dots are + // addressable. For the payload ``{"a.b": {"c.d": "x.y.z"}}``, the value ``x.y.z`` is selected + // by: + // + // .. code-block:: yaml + // + // claim_to_headers: + // - header_name: x-jwt-claim + // claim_path: + // - key: a.b + // - key: c.d + // + // and a URL-namespaced top-level claim by: + // + // .. code-block:: yaml + // + // claim_to_headers: + // - header_name: x-jwt-claim + // claim_path: + // - key: http://example.org/parent_token + // + // Exactly one of ``claim_name`` and ``claim_path`` must be set. + // + // [#comment: A ``min_items`` PGV rule cannot express this: a repeated field has no presence, so + // ``min_items: 1`` would make ``claim_path`` mandatory and reject every ``claim_name`` config.] + repeated PathSegment claim_path = 3; } diff --git a/api/src/main/proto/envoy/extensions/filters/http/local_ratelimit/v3/local_rate_limit.proto b/api/src/main/proto/envoy/extensions/filters/http/local_ratelimit/v3/local_rate_limit.proto index 8306adda2..534e49bc8 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/local_ratelimit/v3/local_rate_limit.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/local_ratelimit/v3/local_rate_limit.proto @@ -23,7 +23,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Local Rate limit :ref:`configuration overview `. // [#extension: envoy.filters.http.local_ratelimit] -// [#next-free-field: 19] +// [#next-free-field: 20] message LocalRateLimit { // The human readable prefix to use when emitting stats. string stat_prefix = 1 [(validate.rules).string = {min_len: 1}]; @@ -190,4 +190,13 @@ message LocalRateLimit { // values. // Minimum is 1. Default is 20. google.protobuf.UInt32Value max_dynamic_descriptors = 18 [(validate.rules).uint32 = {gte: 1}]; + + // Specifies whether the filter emits a ``Retry-After`` header when it enforces an HTTP 429 + // response. This option has no effect on responses with any other status code. The value is the + // number of seconds until the next token is available in the bucket that rejected the request, + // clamped to at least 1. + // If ``response_headers_to_add`` sets a ``Retry-After`` header, the filter does not overwrite it. + // + // Disabled by default. + bool enable_retry_after_header = 19; } diff --git a/api/src/main/proto/envoy/extensions/filters/http/lua/v3/lua.proto b/api/src/main/proto/envoy/extensions/filters/http/lua/v3/lua.proto index 115749e72..5acf676c8 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/lua/v3/lua.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/lua/v3/lua.proto @@ -22,7 +22,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Lua :ref:`configuration overview `. // [#extension: envoy.filters.http.lua] -// [#next-free-field: 6] +// [#next-free-field: 10] message Lua { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.http.lua.v2.Lua"; @@ -88,8 +88,78 @@ message Lua { // route cache automatically. // Default is true for backward compatibility. google.protobuf.BoolValue clear_route_cache = 5; + + // Optional filter context for the Lua script, accessed the same way as the per-route + // :ref:`filter_context + // `, via + // ``handle:filterContext()``. This is the context a request gets when it has no + // ``LuaPerRoute`` configuration, or when the one it has does not set ``filter_context``. + // + // A ``LuaPerRoute`` which does set ``filter_context`` replaces this value rather than merging + // into it, so a route which sets an empty ``filter_context`` sees an empty context rather than + // this one. Only the most specific ``LuaPerRoute`` is consulted: a ``filter_context`` on a less + // specific one, such as a virtual host when the route has its own ``LuaPerRoute``, is not + // reached, and this value is used instead. + google.protobuf.Struct filter_context = 6; + + // Additional patterns for the Lua ``package.path`` of every VM this filter creates, so that a + // script can ``require`` modules from locations the interpreter does not search on its own. + // Each entry is one Lua path pattern; the entries are joined with ``;`` in the order given and + // placed ahead of the interpreter's built-in default path, which is kept. + // + // .. code-block:: yaml + // + // package_paths: + // - /etc/envoy/lua/?.lua + // - /etc/envoy/lua/?/init.lua + // + // The patterns are in place before any configured code runs, including the run that validates + // the configuration, so a ``require`` at the top level of a script whose module cannot be found + // is rejected as a configuration error rather than failing per request. + // + // Each worker builds its own VM and runs the script again to do so, after the configuration has + // been accepted, so the files a script requires must stay readable for as long as the process + // runs and not only while the configuration is loaded. + repeated string package_paths = 7 [(validate.rules).repeated = {items {string {min_len: 1}}}]; + + // As :ref:`package_paths + // `, but for + // ``package.cpath``, i.e. modules which are loadable C libraries rather than Lua source, for + // example ``/etc/envoy/lua/?.so``. + repeated string package_cpaths = 8 [(validate.rules).repeated = {items {string {min_len: 1}}}]; + + // If set, the Lua VMs this filter builds are shared with every other Lua filter configuration + // that sets the same ``shared_vm_id`` and configures the same script, rather than each + // configuration building its own. This applies to every script this message configures: + // :ref:`default_source_code + // `, + // :ref:`inline_code ` and + // every entry of :ref:`source_codes + // `. + // + // Sharing is decided per script, not per configuration: two configurations that agree on this + // id share a VM only for the scripts whose contents match, and whose :ref:`package_paths + // ` and + // :ref:`package_cpaths + // ` match, since a + // script that resolves its ``require`` calls differently does not produce an equivalent VM. + // A :ref:`LuaPerRoute.shared_vm_id + // ` participates in + // the same sharing, so a route's inline script can reuse a VM built here and the other way + // around. + // + // A VM is not only an amount of memory, it is also a set of Lua globals that outlive a request. + // Scripts sharing a VM therefore see each other's globals, exactly as separate requests through + // one configuration already do. Leave this field unset, which is the default, to keep every + // configuration's scripts in VMs of their own. + // + // A shared VM lives for as long as at least one configuration using it is alive. Once the last + // one is drained the VM is torn down, and the next configuration asking for that id and script + // builds a fresh one. + string shared_vm_id = 9; } +// [#next-free-field: 8] message LuaPerRoute { oneof override { // Disable the Lua filter for this particular vhost or route. If disabled is specified in @@ -112,9 +182,42 @@ message LuaPerRoute { // // function envoy_on_request(request_handle) // local filter_context = request_handle:filterContext() - // local filter_context_value = filter_context["key"] + // local filter_context_value = filter_context:get("key") // -- Do something with filter_context_value. // end // + // This replaces the filter-level :ref:`filter_context + // ` rather than merging + // into it. google.protobuf.Struct filter_context = 4; + + // Additional patterns for the Lua ``package.path`` of the VM built from this route's + // :ref:`source_code + // `, with the same + // meaning as the filter-level :ref:`package_paths + // `. + // + // This route's inline source code gets its own VM, which is why it needs its own patterns: the + // filter-level ones are not visible to it. Setting these has no effect when this route selects a + // script by :ref:`name + // `, or configures no script + // at all, since that VM belongs to the filter and carries the filter-level patterns. + repeated string package_paths = 5 [(validate.rules).repeated = {items {string {min_len: 1}}}]; + + // As :ref:`package_paths + // `, but for + // ``package.cpath``. + repeated string package_cpaths = 6 [(validate.rules).repeated = {items {string {min_len: 1}}}]; + + // As :ref:`Lua.shared_vm_id + // `, but for the VM built + // from this route's :ref:`source_code + // `. Routes and + // filter configurations share one pool of VMs, so a route setting the same id as a filter + // configuration reuses that configuration's VM when the script matches. + // + // Setting this has no effect when this route selects a script by :ref:`name + // `, or configures no + // script at all, since that VM belongs to the filter and follows the filter's setting. + string shared_vm_id = 7; } diff --git a/api/src/main/proto/envoy/extensions/filters/http/mcp/v3/mcp.proto b/api/src/main/proto/envoy/extensions/filters/http/mcp/v3/mcp.proto index fe87574ac..475f4580b 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/mcp/v3/mcp.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/mcp/v3/mcp.proto @@ -21,7 +21,7 @@ option (xds.annotations.v3.file_status).work_in_progress = true; // [#extension: envoy.filters.http.mcp] // This filter will inspect and get attributes from MCP traffic. -// [#next-free-field: 9] +// [#next-free-field: 12] message Mcp { // Traffic handling mode for non-MCP traffic. enum TrafficMode { @@ -35,6 +35,11 @@ message Mcp { // - GET requests for SSE streams (with Accept: text/event-stream) // - DELETE requests for session termination (with MCP-Session-Id header) REJECT_NO_MCP = 1; + + // Disables MCP processing entirely. The filter performs no inspection, + // attribute extraction, trace context propagation, or rejection; all + // traffic is proxied as-is. + NOOP = 2; } // Where to store parsed MCP request attributes. @@ -53,6 +58,20 @@ message Mcp { DYNAMIC_METADATA_AND_FILTER_STATE = 3; } + // Source used to obtain MCP request attributes. + enum AttributeSource { + // Parse attributes from the request body and ignore MCP attribute headers. + BODY = 0; + + // Use MCP attribute headers and verify that values parsed from the body agree. + VERIFY = 1; + + // Trust MCP attribute headers for ``method`` and the method-specific + // identifier carried by ``Mcp-Name`` (``params.name``, ``params.uri``, or + // ``params.taskId``), and avoid parsing the body when nothing else requires it. + HEADERS = 2; + } + message TraceContextPropagationConfig { option (xds.annotations.v3.message_status).work_in_progress = true; } @@ -111,10 +130,46 @@ message Mcp { // If unset (default), do not extract or inject baggage. BaggagePropagationConfig propagate_baggage = 7; - // When true, reject requests that contain duplicate JSON keys at any - // nesting level. RFC 8259 Section 4 states that names within an object SHOULD be - // unique. Defaults to false (last-key-wins / last-win). + // When true, disallow requests that contain duplicate JSON keys at any + // nesting level. RFC 8259 Section 4 states that names within an object SHOULD + // be unique. Defaults to false (last-key-wins / last-win). If traffic mode is + // REJECT_NO_MCP, reject these requests; if PASS_THROUGH, log an error status + // but don't reject the request. google.protobuf.BoolValue reject_duplicate_keys = 8; + + // Controls whether MCP request attributes are obtained from the request body + // or from MCP request headers. Header-based extraction is limited to ``method`` + // and the method-specific identifier carried by ``Mcp-Name``; other configured + // extraction rules still require body parsing. + AttributeSource attribute_source = 9 [(validate.rules).enum = {defined_only: true}]; + + // When true, stop parsing (and buffering) the request body as soon as all the + // required routing attributes for the request's method have been collected + // (for example ``method`` and ``params.name`` for ``tools/call``), even if + // optional attributes such as ``params._meta`` or the remainder of the body + // have not been parsed yet. This decouples routing from body size, so a large + // trailing payload (for example ``params.arguments``) does not need to be + // buffered at the proxy just to route the request. + // + // Early termination is intentionally skipped when it could change observable + // behavior, so it has no effect when any of the following holds: + // + // - ``reject_duplicate_keys`` is set (duplicate detection needs a full-body scan); + // - ``propagate_trace_context`` or ``propagate_baggage`` is set (both read + // ``params._meta``, which may appear after the routing attributes); + // - ``attribute_source`` is not ``BODY``. + // + // Requests whose body arrives complete in a single chunk are unaffected, since + // the whole root object is observed before iteration continues. + // + // Defaults to false. + bool early_terminate_when_routable = 10; + + // The latest MCP protocol revision supported by the filter. + // + // Requests using a known protocol revision newer than this value are rejected. + // When unset, no protocol-version restriction is applied. + google.protobuf.StringValue max_supported_protocol_version = 11; } // Parser configuration with method-specific rules. @@ -156,12 +211,25 @@ message ParserConfig { } // Per-route override configuration for MCP filter +// [#next-free-field: 7] message McpOverride { - // Optional per-route traffic mode override + // Overrides the global traffic mode for this route. Mcp.TrafficMode traffic_mode = 1 [(validate.rules).enum = {defined_only: true}]; // Optional per-route max request body size override. // When set, this overrides the global max_request_body_size for this route. // It defaults to 8KB (8192 bytes) and the maximum allowed value is 10MB (10485760 bytes). google.protobuf.UInt32Value max_request_body_size = 2 [(validate.rules).uint32 = {lte: 10485760}]; + + // Overrides the global clear_route_cache setting for this route. + bool clear_route_cache = 3; + + // Overrides the global parser config for this route. + ParserConfig parser_config = 4; + + // Overrides the global request storage mode for this route. + Mcp.RequestStorageMode request_storage_mode = 5 [(validate.rules).enum = {defined_only: true}]; + + // Overrides the global reject_duplicate_keys setting for this route. + bool reject_duplicate_keys = 6; } diff --git a/api/src/main/proto/envoy/extensions/filters/http/mcp_json_rest_bridge/v3/mcp_json_rest_bridge.proto b/api/src/main/proto/envoy/extensions/filters/http/mcp_json_rest_bridge/v3/mcp_json_rest_bridge.proto index 4eb8a794d..e50d31f5e 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/mcp_json_rest_bridge/v3/mcp_json_rest_bridge.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/mcp_json_rest_bridge/v3/mcp_json_rest_bridge.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package envoy.extensions.filters.http.mcp_json_rest_bridge.v3; +import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; import "xds/annotations/v3/status.proto"; @@ -19,6 +20,18 @@ option (xds.annotations.v3.file_status).work_in_progress = true; // [#protodoc-title: MCP JSON REST Bridge] // [#extension: envoy.filters.http.mcp_json_rest_bridge] +// The cache scope of a cacheable MCP result, emitted as the ``cacheScope`` result field. +enum CacheScope { + // Unspecified. Treated as ``CACHE_SCOPE_PUBLIC``. + CACHE_SCOPE_UNSPECIFIED = 0; + + // The result may be stored in a shared cache and reused across clients. + CACHE_SCOPE_PUBLIC = 1; + + // The result may only be stored in a per-client cache. + CACHE_SCOPE_PRIVATE = 2; +} + // Configuration for the MCP MCP JSON REST Bridge. // // This extension translates Model Context Protocol (MCP) JSON-RPC requests into standard JSON-REST @@ -90,7 +103,7 @@ option (xds.annotations.v3.file_status).work_in_progress = true; // - Body: {"data": "updated value"} // (Only the "payload" field from arguments is used as the body. Other arguments not in the // path, like 'resource_id', become query parameters.) -// [#next-free-field: 8] +// [#next-free-field: 9] message McpJsonRestBridge { // Where to store parsed MCP request attributes. enum RequestStorageMode { @@ -146,25 +159,40 @@ message McpJsonRestBridge { // When set to true, the filter will not clear the route cache after transcoding. // This allows the route to be re-selected based on the updated request path or method. bool disable_clear_route_cache = 7; + + // When set to true, the filter will take no action unless per-route config is available. + bool per_route_only = 8; } // Options for trace context extraction. message TraceContextExtractionOptions { } +// Cache configuration for a locally-generated, cacheable MCP result. +message CacheConfig { + // How long the result may be reused, emitted as the MCP ``ttlMs`` result field. + // + // If not provided: Defaults to 0, meaning clients should revalidate before reusing the result. + google.protobuf.Duration ttl = 1 [(validate.rules).duration = {gte {}}]; + + // The cache scope of the result. + // + // If not provided: Defaults to ``CACHE_SCOPE_PUBLIC``. + CacheScope cache_scope = 2 [(validate.rules).enum = {defined_only: true}]; +} + // Configuration for the server metadata. message ServerInfo { - // [#not-implemented-hide:] - // [#comment:TODO(guoyilin42): Implement supported_protocol_versions] - // Lists the MCP protocol versions supported by this MCP endpoint. + // The maximum MCP protocol version supported by this MCP endpoint. // - // - If provided: The extension enforces version negotiation according to the MCP specification: - // https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#version-negotiation - // - If not provided: The extension accepts any version sent by the client during negotiation and - // skips validation of the mcp-protocol-version header on subsequent requests. + // Supported values are ``2025-11-25`` and ``2026-07-28``. Versions prior + // to ``2025-11-25`` are rejected because the filter unconditionally supports features + // up to ``2025-11-25`` and does not support downgrading below that baseline. + // If not provided: Defaults to ``2025-11-25``. // - // Example values: ["2025-11-25", "2025-06-18"] - repeated string supported_protocol_versions = 1; + // Example value: "2026-07-28" + google.protobuf.StringValue max_supported_protocol_version = 1 + [(validate.rules).string = {in: "2025-11-25" in: "2026-07-28"}]; // [#not-implemented-hide:] // [#comment:TODO(guoyilin42): Implement description] @@ -175,10 +203,15 @@ message ServerInfo { // // - If provided: The extension uses this version as the fallback protocol version. // - If not provided: The extension uses the fallback protocol version defined in the latest MCP - // specification. For example, the current latest 2025-11-25 specification designates "2025-03-26" + // specification. For example, the current latest 2026-07-28 specification designates "2025-03-26" // as the fallback protocol version. - // See https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#protocol-version-header + // See https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#protocol-version-header google.protobuf.StringValue fallback_protocol_version = 3; + + // Cache configuration advertised in locally-generated ``server/discover`` responses. + // + // If not provided: the response advertises ``ttlMs: 0`` and ``cacheScope: public``. + CacheConfig server_discovery_cache_config = 4; } // Configuration for sending locally-generated responses to tools/list requests. @@ -212,8 +245,7 @@ message ServerToolConfig { ToolsListLocal tool_list_local = 4; } - // [#not-implemented-hide:] - // Default server info for tools without specific ones. + // Default server info for tools without specific ones. If not provided, a fallback path of '/mcp' will be used. McpServerInfo default_server_info = 5; } @@ -223,7 +255,7 @@ message ToolsListSpecificConfig { string title = 1; // Human-readable description of functionality. - string description = 2 [(validate.rules).string = {min_len: 1}]; + string description = 2; // A JSON Schema describing expected parameters, as a serialized JSON string, in the JSON Schema // 2020-12 dialect. This should be raw JSON, including the "properties" and "required" keys, but @@ -257,6 +289,10 @@ message ToolConfig { // When enabled, the response body is streamed directly to the client without buffering. Each // chunk is JSON escaped as it arrives and wrapped with a pre-built JSON-RPC prefix and suffix. // + // For Server-Sent Events (SSE) responses (i.e. ``text/event-stream`` content type), Envoy parses + // the stream and wraps each extracted complete event payload into a distinct text content item + // within the JSON-RPC ``content`` array on the fly. + // // Streaming flow: // // .. code-block:: text @@ -284,8 +320,46 @@ message ToolConfig { // - If specify a field: Only that specific argument becomes the HTTP JSON body. // - If empty: No body is sent. // 3. Query: Any leaf arguments not mapped to Path or Body are added as URL query parameters. -// [#next-free-field: 7] +// [#next-free-field: 8] message HttpRule { + // Represents a mapping from a request message field to an HTTP element. + // If the specified argument is missing from the tools/call request, the binding is silently + // ignored and the corresponding HTTP element (header or cookie) is not added. + message ParameterBinding { + // The target HTTP element type to bind to. + enum Type { + // Unspecified element type. + TYPE_UNSPECIFIED = 0; + + // The argument value is bound to an HTTP request header. + // Conceptually maps to an OpenAPI parameter with ``in: header``. + HEADER = 1; + + // The argument value is bound to an HTTP request cookie. + // Conceptually maps to an OpenAPI parameter with ``in: cookie``. + COOKIE = 2; + } + + // The type of the HTTP element to bind to. + Type type = 1; + + // The name of the HTTP header (e.g., "X-API-Key", "Authorization") or the + // name of the cookie (e.g.,"SESSION_ID"). Note: Envoy normalizes the header names to lowercase. + // The following headers are reserved for Envoy's internal use and cannot be overridden by + // bindings: ``content-length``, ``transfer-encoding``, ``host``, ``:authority``, ``cookie``, + // ``accept-encoding``, and any header starting with ``x-envoy-``. Attempting to bind to these + // will be ignored. + string name = 2 + [(validate.rules).string = + {min_len: 1 max_bytes: 16384 well_known_regex: HTTP_HEADER_NAME strict: false}]; + + // Path to the field within the JSON arguments object from a tools/call + // request. Uses dot-notation for nested fields. + // E.g. if arguments object is ``{"user":{"auth_token":"foo"}}``, then + // ``argument_path`` should be "user.auth_token". + string argument_path = 3 [(validate.rules).string = {min_len: 1}]; + } + // Determines the HTTP method and the URL path template. // // Path templating uses curly braces ``{}`` to mark a section of the URL path as replaceable. @@ -319,6 +393,10 @@ message HttpRule { // fields (e.g., "user.data" maps the value of the "data" field inside "user"). // - If omitted: There is no HTTP request body; fields not in the path become query parameters. string body = 6; + + // Bindings to extract values from the 'arguments' object of a tools/call + // request and inject them as HTTP elements. + repeated ParameterBinding bindings = 7; } // Per-route override configuration for the MCP JSON REST Bridge filter. diff --git a/api/src/main/proto/envoy/extensions/filters/http/mcp_router/v3/mcp_router.proto b/api/src/main/proto/envoy/extensions/filters/http/mcp_router/v3/mcp_router.proto index 185a61e01..a3d9abc65 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/mcp_router/v3/mcp_router.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/mcp_router/v3/mcp_router.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package envoy.extensions.filters.http.mcp_router.v3; +import "envoy/type/matcher/v3/string.proto"; import "envoy/type/metadata/v3/metadata.proto"; import "google/protobuf/duration.proto"; @@ -98,6 +99,15 @@ message McpRouter { // Backend target specification. McpCluster mcp_cluster = 2; + + // Controls which downstream request headers are forwarded to this backend. + // If not set, no downstream-controlled headers are forwarded beyond those the + // router itself must synthesize (e.g. ``content-type``, ``accept``, the session + // header) — in particular, a client's ``authorization`` header is NOT forwarded + // by default. Router-owned, framing, session, and hop-by-hop headers are never + // affected by this policy; they are handled separately and can never be forwarded + // via this mechanism. + HeaderForwarding header_forwarding = 3; } // Cluster-based backend configuration. @@ -117,6 +127,40 @@ message McpRouter { string host_rewrite_literal = 4; } + // Specifies which downstream request headers are allowed to be forwarded to an MCP + // backend. Modeled after + // :ref:`ext_proc's HeaderForwardingRules `, + // but MCP-local and secure-by-default: unlike ext_proc, an unset/empty policy + // forwards nothing rather than everything, because MCP requires audience-bound + // tokens and prohibits implicit token passthrough between a client and a backend it + // did not authenticate to. + // + // Evaluation order per header: + // + // 1. If the header matches ``disallowed_headers``, it is never forwarded — this + // takes precedence over everything below, including ``forward_all``. + // 2. Otherwise, if ``forward_all`` is true, the header is forwarded. + // 3. Otherwise, if the header matches ``allowed_headers``, it is forwarded. + // 4. Otherwise, the header is not forwarded. + // + // This does not cover header *mutation* or credential injection, which remain a + // separate concern from this filter's forwarding policy. + message HeaderForwarding { + // If true, forward all downstream request headers to this backend (subject to + // ``disallowed_headers`` above), matching the legacy forward-everything behavior. + // Defaults to false. Users relying on the legacy behavior must set this explicitly. + bool forward_all = 1; + + // If set, specifically allow any header in this list to be forwarded. Ignored for a + // header that also matches ``disallowed_headers``, and redundant (but harmless) for + // any header covered by ``forward_all``. + type.matcher.v3.ListStringMatcher allowed_headers = 2; + + // If set, specifically disallow any header in this list from being forwarded. This + // takes precedence over both ``forward_all`` and ``allowed_headers``. + type.matcher.v3.ListStringMatcher disallowed_headers = 3; + } + // A list of remote MCP servers. MCP router aggregates capabilities, tools and resources from remote MCP servers // and presents itself as single MCP server to the client. All remote MCP servers are sent the same capabilities // that the client presented to Envoy. diff --git a/api/src/main/proto/envoy/extensions/filters/http/oauth2/v3/oauth.proto b/api/src/main/proto/envoy/extensions/filters/http/oauth2/v3/oauth.proto index fbe20a537..4b692cf9f 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/oauth2/v3/oauth.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/oauth2/v3/oauth.proto @@ -130,7 +130,20 @@ message OAuth2Credentials { // This field is required unless :ref:`auth_type ` // is set to ``TLS_CLIENT_AUTH``, in which case authentication is done via the client certificate. // When ``auth_type`` is ``PRIVATE_KEY_JWT``, this field must contain the PEM-encoded private key - // used to sign the JWT client assertion. + // used to sign the JWT client assertion. The key may be supplied in either of two forms: + // + // * As a single-value generic secret holding the PEM-encoded private key. No ``kid`` header + // parameter is included in the client assertion. + // * As a multi-entry generic secret with a ``private_key`` entry holding the PEM-encoded private + // key and an optional ``key_id`` entry. When present, the ``key_id`` value is set as the + // ``kid`` header parameter of the client assertion, per + // `RFC 7515 Section 4.1.4 `_. + // Identity providers use it to select the correct verification key when more than one key is + // registered for the client. Distributing both in one secret means the key ID is always + // rotated together with the key it identifies. + // + // The multi-entry form is only read when ``auth_type`` is ``PRIVATE_KEY_JWT``. The other auth + // types read the single-value form only. transport_sockets.tls.v3.SdsSecretConfig token_secret = 2; // Configures how the secret token should be created. @@ -184,6 +197,20 @@ message PrivateKeyJwtConfig { // The value is truncated to whole seconds, so it must be at least ``1s`` when set. // Default: ``60s``. google.protobuf.Duration assertion_lifetime = 2 [(validate.rules).duration = {gte {seconds: 1}}]; + + // The value to use as the ``aud`` (audience) claim in the JWT client assertion. + // + // `RFC 7523 Section 3 `_ requires the + // ``aud`` claim to identify the authorization server, and allows the token endpoint URL to be + // used for this purpose. + // `RFC 9126 Section 2.1 `_ recommends + // the authorization server's issuer identifier instead, and + // `FAPI 2.0 `_ requires it, as a + // single canonical value identifies the server regardless of which endpoint receives the + // assertion. + // + // If not set, defaults to the configured ``token_endpoint`` URI. + string assertion_audience = 3; } // Defines how an OAuth token is forwarded upstream. @@ -213,9 +240,32 @@ message PostLogoutRedirectUri { } } +// Splits OAuth token cookies that are too large for a browser to store. +// +// A token that fits in one cookie is written as a single cookie, as without chunking. A larger +// token is written as ``_0`` to ``_N-1``, plus a ``_chunks`` cookie that holds +// the count ``N``. If a token needs more than +// :ref:`max_chunks ` +// cookies, the filter responds with ``503`` instead of setting cookies that the client would drop. +// +// Chunked cookies add to the request header size. A session with more than one large token may +// need a larger :ref:`max_request_headers_kb +// `. +message TokenCookieChunking { + // The largest cookie Envoy writes for a token, counting its name, value and attributes. A token + // whose cookie would be larger is split. Defaults to ``4096``, the limit browsers enforce. + google.protobuf.UInt32Value max_cookie_size = 1 [(validate.rules).uint32 = {lte: 4096 gte: 512}]; + + // The most cookies a single token is split into. Defaults to ``8``. + // + // Envoy rejoins up to 16 chunks on requests regardless of this value, so lowering it does not + // invalidate existing sessions. + google.protobuf.UInt32Value max_chunks = 2 [(validate.rules).uint32 = {lte: 16 gte: 2}]; +} + // OAuth config // -// [#next-free-field: 34] +// [#next-free-field: 35] message OAuth2Config { enum AuthType { // The ``client_id`` and ``client_secret`` will be sent in the URL encoded request body. @@ -446,6 +496,16 @@ message OAuth2Config { // Only used when :ref:`auth_type ` // is set to ``PRIVATE_KEY_JWT``. PrivateKeyJwtConfig private_key_jwt_config = 32; + + // If set, an access, ID or refresh token cookie that is larger than + // :ref:`max_cookie_size ` + // is split across multiple cookies. If not set, every token is written as a single cookie, + // which a browser drops when it is larger than 4096 bytes. + // + // Envoy always rejoins chunked token cookies on requests, whether or not this is set, so it can + // be removed safely. In a rolling upgrade, set it only after every Envoy that may serve the same + // client understands chunked cookies. + TokenCookieChunking token_cookie_chunking = 34; } // Per-route OAuth2 config. diff --git a/api/src/main/proto/envoy/extensions/filters/http/rate_limit_quota/v3/rate_limit_quota.proto b/api/src/main/proto/envoy/extensions/filters/http/rate_limit_quota/v3/rate_limit_quota.proto index 57b8bdecd..db190536b 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/rate_limit_quota/v3/rate_limit_quota.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/rate_limit_quota/v3/rate_limit_quota.proto @@ -12,7 +12,6 @@ import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; import "google/rpc/status.proto"; -import "xds/annotations/v3/status.proto"; import "xds/type/matcher/v3/matcher.proto"; import "udpa/annotations/status.proto"; @@ -23,7 +22,6 @@ option java_outer_classname = "RateLimitQuotaProto"; option java_multiple_files = true; option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/rate_limit_quota/v3;rate_limit_quotav3"; option (udpa.annotations.file_status).package_version_status = ACTIVE; -option (xds.annotations.v3.file_status).work_in_progress = true; // [#protodoc-title: Rate Limit Quota] // Rate Limit Quota :ref:`configuration overview `. diff --git a/api/src/main/proto/envoy/extensions/filters/http/ratelimit/v3/rate_limit.proto b/api/src/main/proto/envoy/extensions/filters/http/ratelimit/v3/rate_limit.proto index 0286617ee..f5b9b8d45 100644 --- a/api/src/main/proto/envoy/extensions/filters/http/ratelimit/v3/rate_limit.proto +++ b/api/src/main/proto/envoy/extensions/filters/http/ratelimit/v3/rate_limit.proto @@ -23,7 +23,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Rate limit :ref:`configuration overview `. // [#extension: envoy.filters.http.ratelimit] -// [#next-free-field: 19] +// [#next-free-field: 20] message RateLimit { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.http.rate_limit.v2.RateLimit"; @@ -190,6 +190,16 @@ message RateLimit { // The namespace where dynamic metadata from rate limit response is saved. // If not set, the default is "envoy.filters.http.ratelimit". string metadata_namespace = 18; + + // Specifies whether the filter emits a ``Retry-After`` header when it enforces an HTTP 429 + // response. This option has no effect on responses with any other status code. The value is the + // largest ``duration_until_reset`` among the over-limit descriptor statuses returned by the rate + // limit service, expressed in seconds and clamped to at least 1. The header is not emitted when no + // over-limit descriptor status is present. + // If the rate limit service returns a ``Retry-After`` header, the filter does not overwrite it. + // + // Disabled by default. + bool enable_retry_after_header = 19; } message RateLimitPerRoute { diff --git a/api/src/main/proto/envoy/extensions/filters/listener/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/filters/listener/dynamic_modules/v3/dynamic_modules.proto index f2a4eca7d..9ad43f2aa 100644 --- a/api/src/main/proto/envoy/extensions/filters/listener/dynamic_modules/v3/dynamic_modules.proto +++ b/api/src/main/proto/envoy/extensions/filters/listener/dynamic_modules/v3/dynamic_modules.proto @@ -53,7 +53,8 @@ message DynamicModuleListenerFilter { // rate limiting, ``filter_name`` is used to choose either TLS or rate limiting. The ``filter_config`` // can be used to configure the TLS inspection options or the rate limiting parameters. // - // ``google.protobuf.Struct`` is serialized as JSON before passing it to the module. + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly // without the wrapper. // diff --git a/api/src/main/proto/envoy/extensions/filters/network/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/filters/network/dynamic_modules/v3/dynamic_modules.proto index 808acc6ce..c56bc716b 100644 --- a/api/src/main/proto/envoy/extensions/filters/network/dynamic_modules/v3/dynamic_modules.proto +++ b/api/src/main/proto/envoy/extensions/filters/network/dynamic_modules/v3/dynamic_modules.proto @@ -52,7 +52,8 @@ message DynamicModuleNetworkFilter { // limiting, ``filter_name`` is used to choose either echo or rate limiting. The // ``filter_config`` can be used to configure the echo behavior or the rate limiting parameters. // - // ``google.protobuf.Struct`` is serialized as JSON before passing it to the module. + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly // without the wrapper. // diff --git a/api/src/main/proto/envoy/extensions/filters/network/ext_authz/v3/ext_authz.proto b/api/src/main/proto/envoy/extensions/filters/network/ext_authz/v3/ext_authz.proto index 64668a76f..721bdc78a 100644 --- a/api/src/main/proto/envoy/extensions/filters/network/ext_authz/v3/ext_authz.proto +++ b/api/src/main/proto/envoy/extensions/filters/network/ext_authz/v3/ext_authz.proto @@ -24,8 +24,9 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // External Authorization filter calls out to an external service over the // gRPC Authorization API defined by // :ref:`CheckRequest `. -// A failed check will cause this filter to close the TCP connection. -// [#next-free-field: 12] +// A failed check will cause this filter to close the TCP connection, unless ``shadow_mode`` is +// enabled. +// [#next-free-field: 13] message ExtAuthz { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.network.ext_authz.v2.ExtAuthz"; @@ -100,4 +101,13 @@ message ExtAuthz { // the protobuf message definition in order to perform safe parsing. // repeated string typed_metadata_context_namespaces = 11; + + // When set to ``true``, the filter operates in shadow mode. The filter still calls the external + // authorization service but never closes the connection. The authorization decision is instead + // recorded in the connection's :ref:`FilterState ` + // under the key ``envoy.filters.network.ext_authz`` so that a subsequent filter can read and + // optionally enforce it. + // + // Defaults to ``false``. + bool shadow_mode = 12; } diff --git a/api/src/main/proto/envoy/extensions/filters/network/ext_proc/v3/ext_proc.proto b/api/src/main/proto/envoy/extensions/filters/network/ext_proc/v3/ext_proc.proto index a72773323..90cf96acb 100644 --- a/api/src/main/proto/envoy/extensions/filters/network/ext_proc/v3/ext_proc.proto +++ b/api/src/main/proto/envoy/extensions/filters/network/ext_proc/v3/ext_proc.proto @@ -34,7 +34,7 @@ option (xds.annotations.v3.file_status).work_in_progress = true; // // By using the filter's processing mode, you can selectively choose which data // directions to process (read, write or both), allowing for efficient processing. -// [#next-free-field: 7] +// [#next-free-field: 8] message NetworkExternalProcessor { // The gRPC service that will process network traffic. // This service must implement the NetworkExternalProcessor service @@ -64,6 +64,14 @@ message NetworkExternalProcessor { // Options related to the sending and receiving of dynamic metadata. MetadataOptions metadata_options = 6; + + // The data plane provides a number of :ref:`attributes ` + // for expressive policies. Each attribute name provided in this field will be + // evaluated against the connection and filter state and populated in the + // :ref:`ProcessingRequest.attributes ` field. + // See the :ref:`attribute documentation ` + // for the list of supported attributes and their types. + repeated string connection_attributes = 7; } // Options for controlling processing behavior. diff --git a/api/src/main/proto/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto b/api/src/main/proto/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto index 53b118f02..669afc93e 100644 --- a/api/src/main/proto/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto +++ b/api/src/main/proto/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto @@ -39,7 +39,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // HTTP connection manager :ref:`configuration overview `. // [#extension: envoy.filters.network.http_connection_manager] -// [#next-free-field: 63] +// [#next-free-field: 64] message HttpConnectionManager { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager"; @@ -283,7 +283,7 @@ message HttpConnectionManager { repeated config.core.v3.CidrRange cidr_ranges = 2; } - // [#next-free-field: 8] + // [#next-free-field: 9] message SetCurrentClientCertDetails { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager." @@ -313,6 +313,9 @@ message HttpConnectionManager { // false. bool uri = 5; + // Whether to forward the issuer of the client cert. Defaults to false. + bool issuer = 8; + // The format for the header. When the :ref:`forward_client_cert_details // ` // is APPEND_FORWARD and an existing XFCC header is present, the format of the existing header @@ -1128,6 +1131,11 @@ message HttpConnectionManager { // If not configured, defaults to disabled and the standard behavior applies (using connection // TLS status or trusted downstream headers). ForwardProtoConfig forward_proto_config = 61; + + // If true, records two per stream histograms, ``downstream_rq_route_resolution_time_us`` for the + // total wall time spent resolving the route and ``downstream_rq_route_resolutions`` for the number + // of resolutions. Defaults to false, so the default stat set is unchanged. + bool record_route_resolution_stats = 63; } // Configuration options for setting the ``x-forwarded-proto`` header. diff --git a/api/src/main/proto/envoy/extensions/filters/network/redis_proxy/v3/redis_proxy.proto b/api/src/main/proto/envoy/extensions/filters/network/redis_proxy/v3/redis_proxy.proto index 59d728c80..515fddf79 100644 --- a/api/src/main/proto/envoy/extensions/filters/network/redis_proxy/v3/redis_proxy.proto +++ b/api/src/main/proto/envoy/extensions/filters/network/redis_proxy/v3/redis_proxy.proto @@ -28,11 +28,32 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Redis Proxy :ref:`configuration overview `. // [#extension: envoy.filters.network.redis_proxy] -// [#next-free-field: 12] +// [#next-free-field: 13] message RedisProxy { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.network.redis_proxy.v2.RedisProxy"; + // RESP protocol version supported on this listener. + enum ProtocolVersion { + // Default. The listener speaks RESP2 on both downstream connections and + // every routed upstream conn pool: no ``HELLO 3`` is sent upstream and a + // downstream ``HELLO 3`` is rejected with ``-NOPROTO``. (RESP3-aware + // handling such as the local ``HELLO`` reply, ``CLIENT SETINFO`` / + // ``SETNAME`` acceptance, and the RESP3 decoder is always present; this + // value only controls the negotiated wire version.) + RESP2 = 0; + + // The listener speaks RESP3 on both downstream connections and every + // routed upstream conn pool. Upstream conn pools negotiate ``HELLO 3`` + // (combined with ``AUTH`` when credentials or AWS IAM authentication are + // configured) on each new connection; ``upstream_resp3_hello_failure`` + // tracks negotiation failures. Downstream clients must perform an + // explicit ``HELLO 3`` handshake before any data command — bare ``HELLO`` + // on a fresh connection or any non-HELLO/AUTH/QUIT command before + // ``HELLO 3`` is rejected with ``-NOPROTO``. + RESP3 = 1; + } + // Redis connection pool settings. // [#next-free-field: 11] message ConnPoolSettings { @@ -389,6 +410,20 @@ message RedisProxy { // The is to support redis's feature wherein new commands can be added using redis' modules api: // https://redis.io/docs/latest/develop/reference/modules/ repeated string custom_commands = 11; + + // RESP protocol version enforced for both downstream connections and every + // routed upstream conn pool for this listener. Mismatched negotiation is + // rejected at HELLO (``HELLO N`` where ``N`` does not match returns + // ``-NOPROTO``) and, when set to ``RESP3``, at every non-HELLO/AUTH/QUIT + // command on a connection that has not yet negotiated RESP3 (so clients + // must perform an explicit ``HELLO 3`` handshake before any data command). + // + // When ``protocol_version`` is ``RESP3``, every routed upstream + // Redis-compatible backend must support ``HELLO 3`` / RESP3 (e.g. + // Redis 6.0+, where RESP3 was introduced). Misconfigured upstreams will + // fail every connection's HELLO 3 negotiation, surfaced as + // ``upstream_resp3_hello_failure`` stat increments. + ProtocolVersion protocol_version = 12 [(validate.rules).enum = {defined_only: true}]; } // RedisProtocolOptions specifies Redis upstream protocol options. This object is used in diff --git a/api/src/main/proto/envoy/extensions/filters/network/reverse_tunnel/v3/reverse_tunnel.proto b/api/src/main/proto/envoy/extensions/filters/network/reverse_tunnel/v3/reverse_tunnel.proto index 77e155216..1e6b39879 100644 --- a/api/src/main/proto/envoy/extensions/filters/network/reverse_tunnel/v3/reverse_tunnel.proto +++ b/api/src/main/proto/envoy/extensions/filters/network/reverse_tunnel/v3/reverse_tunnel.proto @@ -3,9 +3,11 @@ syntax = "proto3"; package envoy.extensions.filters.network.reverse_tunnel.v3; import "envoy/config/core/v3/base.proto"; +import "envoy/extensions/filters/common/jwks/v3/jwt_handshake.proto"; import "google/protobuf/duration.proto"; +import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; import "validate/validate.proto"; @@ -96,7 +98,7 @@ message Validation { // Configuration for the reverse tunnel network filter. // This filter handles reverse tunnel connection acceptance and rejection by processing // HTTP requests where required identification values are provided via HTTP headers. -// [#next-free-field: 9] +// [#next-free-field: 12] message ReverseTunnel { // Ping interval for health checks on established reverse tunnel connections. // If not specified, defaults to ``2 seconds``. @@ -105,13 +107,10 @@ message ReverseTunnel { gte {nanos: 1000000} }]; - // Whether to automatically close connections after processing reverse tunnel requests. - // - // * When set to ``true``, connections are closed after acceptance or rejection. - // * When set to ``false``, connections remain open for potential reuse. - // - // Defaults to ``false``. - bool auto_close_connections = 2; + // Deprecated. The handshake connection is always detached once the acceptance response is + // flushed so tunnel bytes have a single reader. Ignored. + bool auto_close_connections = 2 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // HTTP path to match for reverse tunnel requests. // If not specified, defaults to ``/reverse_connections/request``. @@ -145,4 +144,44 @@ message ReverseTunnel { // This avoids the cross-worker lock in pickLeastLoadedSocketManager. // Default: false (rebalancing enabled). bool skip_rebalancing = 8; + + // Optional JWT authentication for the handshake. When set, the bearer token carried in the + // handshake request is verified before the connection is accepted or its socket registered, so a + // forged or expired token can never produce a usable reverse tunnel. This runs on the real + // accepted socket, before registration, so it does not interfere with socket reuse. A missing or + // invalid token rejects the handshake with HTTP ``401 Unauthorized`` unless + // ``allow_missing_or_failed`` is set. + // + // On success, the verified claims are published as dynamic metadata (default namespace + // ``envoy.filters.network.reverse_tunnel.jwt``) so the :ref:`Validation + // ` block can bind a + // claimed handshake identifier to a verified claim, e.g.:: + // + // tenant_id_format: "%DYNAMIC_METADATA(envoy.filters.network.reverse_tunnel.jwt:tenant)%" + // + // forces the ``x-envoy-reverse-tunnel-tenant-id`` header to equal the verified ``tenant`` claim. + // Without such a binding, a token minted for one tenant can open a tunnel claiming another. + // + // Token verification is synchronous. With ``remote_jwks`` the keys are fetched and refreshed in the + // background (at startup and every ``cache_duration``) and cached, never on the accept path. Before + // the first successful fetch, or while a refresh is failing with nothing cached, every token is + // rejected. ``token_header`` defaults to ``authorization`` and ``clock_skew_seconds`` to 60. + // + // See :ref:`JwtHandshakeValidator + // `. + common.jwks.v3.JwtHandshakeValidator jwt_validator = 10; + + // Enforces the per-node concurrent connection cap (``max_connections_per_node``, configured on + // the ``UpstreamReverseConnectionSocketInterface`` bootstrap extension) for tunnels accepted by + // this filter. The cap is checked on the accepting worker but the connection is counted on the + // worker it is finally rebalanced to, so it is best-effort unless ``skip_rebalancing`` is ``true``. + // Default: false. + bool enable_connection_limit = 9; + + // Maximum time to receive a complete handshake request. If not specified, defaults to ``10s``. + // On expiry the connection is closed and ``handshake.timeout`` is incremented. + google.protobuf.Duration handshake_timeout = 11 [(validate.rules).duration = { + lte {seconds: 300} + gt {} + }]; } diff --git a/api/src/main/proto/envoy/extensions/filters/udp/dns_filter/v3/dns_filter.proto b/api/src/main/proto/envoy/extensions/filters/udp/dns_filter/v3/dns_filter.proto index 621a0ffce..701f1c6a7 100644 --- a/api/src/main/proto/envoy/extensions/filters/udp/dns_filter/v3/dns_filter.proto +++ b/api/src/main/proto/envoy/extensions/filters/udp/dns_filter/v3/dns_filter.proto @@ -26,6 +26,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // [#extension: envoy.filters.udp.dns_filter] // Configuration for the DNS filter. +// [#next-free-field: 6] message DnsFilterConfig { // This message contains the configuration for the DNS Filter operating // in a server context. This message will contain the virtual hosts and @@ -123,4 +124,8 @@ message DnsFilterConfig { // - ``RESPONSE_CODE``: DNS response code // - ``PARSE_STATUS``: Whether the query was successfully parsed repeated config.accesslog.v3.AccessLog access_log = 4; + + // When true, virtual domain names are matched case-insensitively. The response echoes the + // client's original query-name case. Defaults to false. + bool case_insensitive = 5; } diff --git a/api/src/main/proto/envoy/extensions/filters/udp/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/filters/udp/dynamic_modules/v3/dynamic_modules.proto index 7f0defc71..986c099e9 100644 --- a/api/src/main/proto/envoy/extensions/filters/udp/dynamic_modules/v3/dynamic_modules.proto +++ b/api/src/main/proto/envoy/extensions/filters/udp/dynamic_modules/v3/dynamic_modules.proto @@ -45,7 +45,8 @@ message DynamicModuleUdpListenerFilter { // limiting, ``filter_name`` is used to choose either echo or rate limiting. The // ``filter_config`` can be used to configure the echo behavior or the rate limiting parameters. // - // ``google.protobuf.Struct`` is serialized as JSON before passing it to the module. + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly // without the wrapper. // diff --git a/api/src/main/proto/envoy/extensions/filters/udp/udp_proxy/v3/udp_proxy.proto b/api/src/main/proto/envoy/extensions/filters/udp/udp_proxy/v3/udp_proxy.proto index 6de0c1e40..3efec163c 100644 --- a/api/src/main/proto/envoy/extensions/filters/udp/udp_proxy/v3/udp_proxy.proto +++ b/api/src/main/proto/envoy/extensions/filters/udp/udp_proxy/v3/udp_proxy.proto @@ -6,6 +6,7 @@ import "envoy/config/accesslog/v3/accesslog.proto"; import "envoy/config/core/v3/backoff.proto"; import "envoy/config/core/v3/base.proto"; import "envoy/config/core/v3/config_source.proto"; +import "envoy/config/core/v3/extension.proto"; import "envoy/config/core/v3/udp_socket_config.proto"; import "google/protobuf/any.proto"; @@ -73,7 +74,7 @@ message UdpProxyConfig { // Configuration for tunneling UDP over other transports or application layers. // Tunneling is currently supported over HTTP/2. - // [#next-free-field: 12] + // [#next-free-field: 13] message UdpTunnelingConfig { // Configuration for UDP datagrams buffering. message BufferOptions { @@ -178,6 +179,12 @@ message UdpProxyConfig { // Save the response trailers to the downstream info filter state for consumption // by the session filters. The filter state key is ``envoy.udp_proxy.propagate_response_trailers``. bool propagate_response_trailers = 11; + + // Specifies a collection of Formatter plugins that can be used in substitution formatters + // in ``headers_to_add``. + // See the formatters extensions documentation for details. + // [#extension-category: envoy.formatter] + repeated config.core.v3.TypedExtensionConfig formatters = 12; } message UdpAccessLogOptions { diff --git a/api/src/main/proto/envoy/extensions/formatter/cel/v3/cel.proto b/api/src/main/proto/envoy/extensions/formatter/cel/v3/cel.proto index ced34e735..0cf4b7769 100644 --- a/api/src/main/proto/envoy/extensions/formatter/cel/v3/cel.proto +++ b/api/src/main/proto/envoy/extensions/formatter/cel/v3/cel.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package envoy.extensions.formatter.cel.v3; +import "envoy/config/core/v3/cel.proto"; + import "udpa/annotations/status.proto"; option java_package = "io.envoyproxy.envoy.extensions.formatter.cel.v3"; @@ -50,7 +52,10 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Configuration for the CEL formatter. // // .. warning:: -// This extension is treated as built-in extension and will be enabled by default now. -// It is unnecessary to configure this extension. +// This extension is treated as a built-in extension and is enabled by default. +// It is unnecessary to configure this extension unless overriding the CEL expression runtime +// via ``cel_config``. message Cel { + // Configuration for the CEL expression runtime used by this formatter. + config.core.v3.CelExpressionConfig cel_config = 1; } diff --git a/api/src/main/proto/envoy/extensions/formatter/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/formatter/dynamic_modules/v3/dynamic_modules.proto index 4ba383458..121bfcb77 100644 --- a/api/src/main/proto/envoy/extensions/formatter/dynamic_modules/v3/dynamic_modules.proto +++ b/api/src/main/proto/envoy/extensions/formatter/dynamic_modules/v3/dynamic_modules.proto @@ -47,7 +47,8 @@ message DynamicModuleFormatter { // ``formatter_name``, the module can decide which in-module command parser implementation to use // and fine-tune which commands it recognizes. // - // ``google.protobuf.Struct`` is serialized as JSON before passing it to the module. + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly // without the wrapper. // diff --git a/api/src/main/proto/envoy/extensions/health_checkers/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/health_checkers/dynamic_modules/v3/dynamic_modules.proto index d881af7cc..d89ef2359 100644 --- a/api/src/main/proto/envoy/extensions/health_checkers/dynamic_modules/v3/dynamic_modules.proto +++ b/api/src/main/proto/envoy/extensions/health_checkers/dynamic_modules/v3/dynamic_modules.proto @@ -50,7 +50,8 @@ message DynamicModuleHealthCheck { // ``health_checker_name``, the module can decide which in-module health checker implementation to // use and fine-tune the behavior of the health checker. // - // ``google.protobuf.Struct`` is serialized as JSON before passing it to the module. + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly // without the wrapper. // diff --git a/api/src/main/proto/envoy/extensions/health_checkers/udp/v3/udp.proto b/api/src/main/proto/envoy/extensions/health_checkers/udp/v3/udp.proto new file mode 100644 index 000000000..5b7829803 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/health_checkers/udp/v3/udp.proto @@ -0,0 +1,51 @@ +syntax = "proto3"; + +package envoy.extensions.health_checkers.udp.v3; + +import "envoy/config/core/v3/health_check.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.health_checkers.udp.v3"; +option java_outer_classname = "UdpProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/health_checkers/udp/v3;udpv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: UDP Health Checker] +// [#extension: envoy.health_checkers.udp] + +// Configuration for the UDP health checker. +// +// For every health-check attempt, Envoy creates a fresh connected UDP socket targeting the host's +// :ref:`health check address +// `. UDP ``connect()`` +// only selects the peer; it does not establish connectivity and does not count as a successful +// health check. The :ref:`reuse_connection +// ` setting does not apply. +// +// Attempts for a host are serialized so that only one attempt is active at a time. Envoy sends +// exactly one datagram containing ``send`` and waits for a response until the enclosing +// :ref:`HealthCheck.timeout ` expires. +// +// The connected socket accepts datagrams only from the configured peer. Each complete response +// datagram is compared byte-for-byte with ``receive``. A matching datagram completes the attempt +// successfully. Non-matching datagrams do not satisfy the check; Envoy continues waiting until a +// matching datagram arrives or the attempt times out. A timeout or local socket error completes +// the attempt unsuccessfully. +// +// The enclosing :ref:`HealthCheck +// ` controls thresholds, intervals, jitter, +// statistics, and event logging. +message UdpHealthCheck { + // Payload sent as exactly one UDP datagram at the start of each health-check attempt. The decoded + // payload must not exceed 65,507 bytes. A smaller payload may be required to avoid IP + // fragmentation along the network path. + config.core.v3.HealthCheck.Payload send = 1 [(validate.rules).message = {required: true}]; + + // Expected response payload. A response datagram must match the entire payload exactly to make + // the health-check attempt successful. The decoded payload must not exceed 65,507 bytes. A + // smaller payload may be required to avoid IP fragmentation along the network path. + config.core.v3.HealthCheck.Payload receive = 2 [(validate.rules).message = {required: true}]; +} diff --git a/api/src/main/proto/envoy/extensions/http/ai_filters/request_info/v3/request_info.proto b/api/src/main/proto/envoy/extensions/http/ai_filters/request_info/v3/request_info.proto new file mode 100644 index 000000000..752f91753 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/http/ai_filters/request_info/v3/request_info.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; + +package envoy.extensions.http.ai_filters.request_info.v3; + +import "xds/annotations/v3/status.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.http.ai_filters.request_info.v3"; +option java_outer_classname = "RequestInfoProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/http/ai_filters/request_info/v3;request_infov3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; +option (xds.annotations.v3.file_status).work_in_progress = true; + +// [#protodoc-title: Request info AI filter] +// Request info AI filter :ref:`configuration overview +// `. +// [#extension: envoy.http.ai_filters.request_info] + +// Publishes :ref:`RequestInfo ` as typed +// dynamic metadata. On a declared endpoint with a body, it is written before the +// request headers continue, so later HTTP filters see it from their first callback. +message RequestInfo { + // Estimates the input tokens from the size of the request payload, for consumers that must + // budget before the provider reports what it actually charged. + message TokenEstimation { + // Estimated input tokens, as ``ceil(tokens_per_byte * request payload bytes)``. No token + // spans fewer than one byte, so the ratio cannot exceed 1.0; ``0.5`` is a rough fit for + // JSON chat payloads. + double tokens_per_byte = 1 [(validate.rules).double = {lte: 1.0 gt: 0.0}]; + } + + // Metadata namespace. Defaults to ``envoy.ai.request_info``. + string metadata_namespace = 1; + + // When unset, no estimate is published. + TokenEstimation token_estimation = 2; +} diff --git a/api/src/main/proto/envoy/extensions/http/ai_filters/schema_validation/v3/schema_validation.proto b/api/src/main/proto/envoy/extensions/http/ai_filters/schema_validation/v3/schema_validation.proto new file mode 100644 index 000000000..8e146b579 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/http/ai_filters/schema_validation/v3/schema_validation.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; + +package envoy.extensions.http.ai_filters.schema_validation.v3; + +import "envoy/type/ai/v3/llm_protocol.proto"; + +import "xds/annotations/v3/status.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.http.ai_filters.schema_validation.v3"; +option java_outer_classname = "SchemaValidationProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/http/ai_filters/schema_validation/v3;schema_validationv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; +option (xds.annotations.v3.file_status).work_in_progress = true; + +// [#protodoc-title: Schema validation AI filter] +// Schema validation AI filter :ref:`configuration overview +// `. +// [#extension: envoy.http.ai_filters.schema_validation] + +// Validates the request payload against the payload schema of its wire API, and rejects a payload +// that violates it with a 400. Configure it first, so the AI filters after it see the API it +// resolved and only a payload that passed. +message SchemaValidation { + // The wire API for a request that declares none, through either the + // ``envoy.ai.llm_protocol.request`` filter state object or the route's :ref:`llm_protocol + // `. + // ``LLM_PROTOCOL_UNSPECIFIED``, the default, detects it from the request path, then the + // ``anthropic-version`` header, then the payload's shape. A request none of them identifies is + // forwarded unvalidated. + type.ai.v3.LLMProtocol default_llm_protocol = 1 [(validate.rules).enum = {defined_only: true}]; + + // Forward a payload that violates its schema instead of rejecting it. It is still counted. + bool fail_open = 2; +} diff --git a/api/src/main/proto/envoy/extensions/http/ai_filters/transcoder/v3/transcoder.proto b/api/src/main/proto/envoy/extensions/http/ai_filters/transcoder/v3/transcoder.proto new file mode 100644 index 000000000..154304536 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/http/ai_filters/transcoder/v3/transcoder.proto @@ -0,0 +1,53 @@ +syntax = "proto3"; + +package envoy.extensions.http.ai_filters.transcoder.v3; + +import "xds/annotations/v3/status.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.http.ai_filters.transcoder.v3"; +option java_outer_classname = "TranscoderProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/http/ai_filters/transcoder/v3;transcoderv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; +option (xds.annotations.v3.file_status).work_in_progress = true; + +// [#protodoc-title: Transcoder AI filter] +// Transcoder AI filter :ref:`configuration overview +// `. +// [#extension: envoy.http.ai_filters.transcoder] + +// Rewrites an AI request or response payload from one vendor's API schema into another's, using +// the declarative transcoding engine. +// +// All schemas are translated through a single canonical form -- OpenAI Chat Completions -- so +// that adding a dialect costs one declarative rule set rather than a rule set per pair. Filters +// placed between the two legs therefore only ever need to understand the canonical form. +message Transcoder { + // Which schema translation leg to perform on a given path. + enum Direction { + DIRECTION_UNSPECIFIED = 0; + + // Translates into the canonical IR (OpenAI Chat Completions): + // - In ``request_handling`` (decode): translates client schema -> canonical IR. + // - In ``response_handling`` (encode): translates target backend schema -> canonical IR. + TO_IR = 1; + + // Translates out of the canonical IR (OpenAI Chat Completions): + // - In ``request_handling`` (decode): translates canonical IR -> target backend schema. + // - In ``response_handling`` (encode): translates canonical IR -> client schema. + FROM_IR = 2; + } + + // Request-side transcoding direction. When unset (``DIRECTION_UNSPECIFIED``), the request + // decode path forwards the payload untouched. At least one of ``request_handling`` or + // ``response_handling`` must be set. + Direction request_handling = 1 [(validate.rules).enum = {defined_only: true}]; + + // Response-side transcoding direction. When unset (``DIRECTION_UNSPECIFIED``), response + // transcoding (``encodeUnary`` and ``encodeSSE``) is disabled and responses pass through + // untouched. + Direction response_handling = 2 [(validate.rules).enum = {defined_only: true}]; +} diff --git a/api/src/main/proto/envoy/extensions/http/custom_response/local_response_policy/v3/local_response_policy.proto b/api/src/main/proto/envoy/extensions/http/custom_response/local_response_policy/v3/local_response_policy.proto index b40800c01..c93ad7e8e 100644 --- a/api/src/main/proto/envoy/extensions/http/custom_response/local_response_policy/v3/local_response_policy.proto +++ b/api/src/main/proto/envoy/extensions/http/custom_response/local_response_policy/v3/local_response_policy.proto @@ -24,9 +24,12 @@ option (xds.annotations.v3.file_status).work_in_progress = true; // Custom response policy to serve a locally stored response to the // downstream. +// [#next-free-field: 7] message LocalResponsePolicy { // Optional new local reply body text. It will be used - // in the ``%LOCAL_REPLY_BODY%`` command operator in the ``body_format``. + // in the ``%LOCAL_REPLY_BODY%`` command operator in the ``body_format``. If unset when + // ``body_format`` is configured for an existing local reply, the existing body will be used as + // the formatter input instead. config.core.v3.DataSource body = 1; // Optional body format to be used for this response. If ``body_format`` is not @@ -43,4 +46,19 @@ message LocalResponsePolicy { // remote body, before it is sent to a downstream client. repeated config.core.v3.HeaderValueOption response_headers_to_add = 4 [(validate.rules).repeated = {max_items: 1000}]; + + // Controls what is written to ``stream_info.response_code_details`` when this + // policy sends its local reply. + // + // If unset, details are cleared (empty string), matching legacy behavior. + // Use ``preserve_response_code_details`` to keep the existing value (e.g. + // ``csrf_origin_mismatch``), or ``response_code_details`` to set an explicit + // replacement. + oneof response_code_details_action { + // If set, keep the existing ``response_code_details`` already present on StreamInfo. + bool preserve_response_code_details = 5 [(validate.rules).bool = {const: true}]; + + // Replace ``response_code_details`` with this value. + string response_code_details = 6 [(validate.rules).string = {min_len: 1}]; + } } diff --git a/api/src/main/proto/envoy/extensions/http/early_header_mutation/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/http/early_header_mutation/dynamic_modules/v3/dynamic_modules.proto new file mode 100644 index 000000000..876a2d9e3 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/http/early_header_mutation/dynamic_modules/v3/dynamic_modules.proto @@ -0,0 +1,90 @@ +syntax = "proto3"; + +package envoy.extensions.http.early_header_mutation.dynamic_modules.v3; + +import "envoy/extensions/dynamic_modules/v3/dynamic_modules.proto"; + +import "google/protobuf/any.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.http.early_header_mutation.dynamic_modules.v3"; +option java_outer_classname = "DynamicModulesProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/http/early_header_mutation/dynamic_modules/v3;dynamic_modulesv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Dynamic Modules Early Header Mutation] +// [#extension: envoy.http.early_header_mutation.dynamic_modules] + +// Configuration for the Dynamic Modules Early Header Mutation. This extension allows loading shared +// object files via ``dlopen`` to rewrite request headers before routing, tracing, request ID +// generation and any HTTP filter runs. +// +// Exactly one instance is created per configured entry, on the main thread, and it is shared by +// every worker thread for the lifetime of the connection manager configuration. The module is +// therefore invoked concurrently and must treat its configuration as read-only. +// +// The module can read and rewrite the request headers, and read the stream info attributes, dynamic +// metadata and filter state. Because the extension runs before routing and before the upstream +// request, the route, the response and every upstream attribute are not yet populated. The stream +// info is read-only at this point, so a module that needs to publish state for later extensions +// should do so from an :ref:`HTTP filter +// ` instead. +// +// When multiple early header mutation extensions are configured, they run in order and the module +// controls whether the ones after it run: see +// :ref:`early_header_mutation_extensions +// `. +message DynamicModuleEarlyHeaderMutation { + // Specifies the shared-object level configuration. This field is required. + // + // Only sources that are available synchronously are supported, i.e. ``name``, ``module.local``, + // and a ``module.remote`` that is already present in the on-disk cache. A remote source that + // would need to be fetched is rejected, since the extension must be usable for the first request + // the connection manager serves. + envoy.extensions.dynamic_modules.v3.DynamicModuleConfig dynamic_module_config = 1 + [(validate.rules).message = {required: true}]; + + // The name for this early header mutation configuration. If not specified, defaults to an empty + // string. + // + // This can be used to distinguish between different early header mutation implementations inside + // a dynamic module. When Envoy receives this configuration, it passes the + // ``early_header_mutation_name`` to the dynamic module's early header mutation config init + // function together with the ``early_header_mutation_config``. That way a module can decide which + // in-module implementation to use based on the name at load time. + // + // This is also used as the ``config_name`` tag of the ``dynamic_modules.module_load_error`` and + // ``dynamic_modules.config_init_error`` counters. + string early_header_mutation_name = 2; + + // The configuration for the early header mutation chosen by ``early_header_mutation_name``. If + // not specified, an empty configuration is passed to the module. + // + // This is passed to the module's early header mutation initialization function. Together with the + // ``early_header_mutation_name``, the module can decide which in-module implementation to use and + // fine-tune its behavior. + // + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. + // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly + // without the wrapper. + // + // .. code-block:: yaml + // + // # Passing a JSON struct configuration + // early_header_mutation_config: + // "@type": "type.googleapis.com/google.protobuf.Struct" + // value: + // copy_headers: + // - x-original-authority + // + // # Passing a simple string configuration + // early_header_mutation_config: + // "@type": "type.googleapis.com/google.protobuf.StringValue" + // value: "x-tenant-id" + // + google.protobuf.Any early_header_mutation_config = 3; +} diff --git a/api/src/main/proto/envoy/extensions/http/header_formatters/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/http/header_formatters/dynamic_modules/v3/dynamic_modules.proto new file mode 100644 index 000000000..091eccce7 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/http/header_formatters/dynamic_modules/v3/dynamic_modules.proto @@ -0,0 +1,77 @@ +syntax = "proto3"; + +package envoy.extensions.http.header_formatters.dynamic_modules.v3; + +import "envoy/extensions/dynamic_modules/v3/dynamic_modules.proto"; + +import "google/protobuf/any.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.http.header_formatters.dynamic_modules.v3"; +option java_outer_classname = "DynamicModulesProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/http/header_formatters/dynamic_modules/v3;dynamic_modulesv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Dynamic Modules Header Formatter] +// [#extension: envoy.http.stateful_header_formatters.dynamic_modules] + +// Configuration for the Dynamic Modules HTTP/1 header formatter. This extension allows loading +// shared object files via ``dlopen`` to decide the casing of header keys written on the wire, +// which is what the :ref:`preserve case formatter +// ` +// does with a fixed policy. See the :ref:`header casing +// ` configuration guide for how to select a stateful +// formatter. +// +// This extension only affects HTTP/1 traffic: HTTP/2 and HTTP/3 require lower-cased header keys. +message DynamicModuleHeaderFormatter { + // Specifies the shared-object level configuration. This field is required. + // + // Only sources that are available synchronously are supported, i.e. ``name``, ``module.local``, + // and a ``module.remote`` that is already present in the on-disk cache. A remote source that + // would need to be fetched is rejected, since the codec must be able to format headers for the + // first message the connection serves. + envoy.extensions.dynamic_modules.v3.DynamicModuleConfig dynamic_module_config = 1 + [(validate.rules).message = {required: true}]; + + // The name for this header formatter configuration. If not specified, defaults to an empty + // string. + // + // This can be used to distinguish between different header formatter implementations inside a + // dynamic module. When Envoy receives this configuration, it passes the + // ``header_formatter_name`` to the dynamic module's header formatter config init function + // together with the ``header_formatter_config``. That way a module can decide which in-module + // implementation to use based on the name at load time. + string header_formatter_name = 2; + + // The configuration for the header formatter chosen by ``header_formatter_name``. If not + // specified, an empty configuration is passed to the module. + // + // This is passed to the module's header formatter initialization function. Together with the + // ``header_formatter_name``, the module can decide which in-module implementation to use and + // fine-tune its behavior. + // + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. + // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly + // without the wrapper. + // + // .. code-block:: yaml + // + // # Passing a JSON struct configuration + // header_formatter_config: + // "@type": "type.googleapis.com/google.protobuf.Struct" + // value: + // known_headers: + // - X-Request-ID + // + // # Passing a simple string configuration + // header_formatter_config: + // "@type": "type.googleapis.com/google.protobuf.StringValue" + // value: "proper_case" + // + google.protobuf.Any header_formatter_config = 3; +} diff --git a/api/src/main/proto/envoy/extensions/http/injected_credentials/generic/v3/generic.proto b/api/src/main/proto/envoy/extensions/http/injected_credentials/generic/v3/generic.proto index e6c3bfaf5..c6be053bf 100644 --- a/api/src/main/proto/envoy/extensions/http/injected_credentials/generic/v3/generic.proto +++ b/api/src/main/proto/envoy/extensions/http/injected_credentials/generic/v3/generic.proto @@ -19,7 +19,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Generic extension can be used to inject HTTP Basic Auth, Bearer Token, or any arbitrary credential // into the proxied requests. // The credential will be injected into the specified HTTP request header. -// Refer to [RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://www.rfc-editor.org/rfc/rfc6750) for details. +// Refer to `RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage `_ for details. // message Generic { // The SDS configuration for the credential that will be injected to the specified HTTP request header. diff --git a/api/src/main/proto/envoy/extensions/http/injected_credentials/oauth2/v3/oauth2.proto b/api/src/main/proto/envoy/extensions/http/injected_credentials/oauth2/v3/oauth2.proto index 9b013cdb9..1538d0ca1 100644 --- a/api/src/main/proto/envoy/extensions/http/injected_credentials/oauth2/v3/oauth2.proto +++ b/api/src/main/proto/envoy/extensions/http/injected_credentials/oauth2/v3/oauth2.proto @@ -35,22 +35,32 @@ message OAuth2 { // The ``client_id`` and ``client_secret`` will be sent in the URL encoded request body. // This type should only be used when Auth server does not support Basic authentication. URL_ENCODED_BODY = 1; + + // The client will be authenticated using mutual TLS (mTLS) with a client certificate. + // The ``client_secret`` is not required and will not be sent in the request to the + // authorization server. + // The client certificate must be configured in the cluster used by ``token_endpoint`` via + // transport socket configuration. + // This implements OAuth 2.0 Mutual-TLS Client Authentication as defined in RFC 8705. + TLS_CLIENT_AUTH = 2; } // Credentials to authenticate client to the authorization server. - // Refer to [RFC 6749: The OAuth 2.0 Authorization Framework](https://www.rfc-editor.org/rfc/rfc6749#section-2.3) for details. + // Refer to `RFC 6749: The OAuth 2.0 Authorization Framework `__ for details. message ClientCredentials { // Client ID. - // Refer to [RFC 6749: The OAuth 2.0 Authorization Framework](https://www.rfc-editor.org/rfc/rfc6749#section-2.3.1) for details. + // Refer to `RFC 6749: The OAuth 2.0 Authorization Framework `__ for details. string client_id = 1 [(validate.rules).string = {min_len: 1}]; // Client secret. - // Refer to [RFC 6749: The OAuth 2.0 Authorization Framework](https://www.rfc-editor.org/rfc/rfc6749#section-2.3.1) for details. - transport_sockets.tls.v3.SdsSecretConfig client_secret = 2 - [(validate.rules).message = {required: true}]; + // Refer to `RFC 6749: The OAuth 2.0 Authorization Framework `__ for details. + // This field is required unless :ref:`auth_type + // ` + // is set to ``TLS_CLIENT_AUTH``, in which case authentication is done via the client certificate. + transport_sockets.tls.v3.SdsSecretConfig client_secret = 2; // The method to use when sending credentials to the authorization server. - // Refer to [RFC 6749: The OAuth 2.0 Authorization Framework](https://www.rfc-editor.org/rfc/rfc6749#section-2.3.1) for details. + // Refer to `RFC 6749: The OAuth 2.0 Authorization Framework `__ for details. AuthType auth_type = 3; } @@ -66,18 +76,18 @@ message OAuth2 { } // Endpoint on the authorization server to retrieve the access token from. - // Refer to [RFC 6749: The OAuth 2.0 Authorization Framework](https://www.rfc-editor.org/rfc/rfc6749#section-3.2) for details. + // Refer to `RFC 6749: The OAuth 2.0 Authorization Framework `__ for details. config.core.v3.HttpUri token_endpoint = 1 [(validate.rules).message = {required: true}]; // Optional list of OAuth scopes to be claimed in the authorization request. - // Refer to [RFC 6749: The OAuth 2.0 Authorization Framework](https://www.rfc-editor.org/rfc/rfc6749#section-4.4.2) for details. + // Refer to `RFC 6749: The OAuth 2.0 Authorization Framework `__ for details. repeated string scopes = 2; oneof flow_type { option (validate.required) = true; // Client Credentials Grant. - // Refer to [RFC 6749: The OAuth 2.0 Authorization Framework](https://www.rfc-editor.org/rfc/rfc6749#section-4.4) for details. + // Refer to `RFC 6749: The OAuth 2.0 Authorization Framework `__ for details. ClientCredentials client_credentials = 3; } diff --git a/api/src/main/proto/envoy/extensions/internal_redirect/filter_state/v3/filter_state_config.proto b/api/src/main/proto/envoy/extensions/internal_redirect/filter_state/v3/filter_state_config.proto new file mode 100644 index 000000000..04b98160c --- /dev/null +++ b/api/src/main/proto/envoy/extensions/internal_redirect/filter_state/v3/filter_state_config.proto @@ -0,0 +1,41 @@ +syntax = "proto3"; + +package envoy.extensions.internal_redirect.filter_state.v3; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.internal_redirect.filter_state.v3"; +option java_outer_classname = "FilterStateConfigProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/internal_redirect/filter_state/v3;filter_statev3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Filter-state internal redirect predicate] + +// An internal redirect predicate that decides whether to follow a redirect by +// reading a boolean filter-state object set earlier in the request by another +// filter (Lua, ext_proc, ``set_filter_state``, a dynamic module, ...). +// +// The predicate reads the filter-state boolean object named ``redirect_enabled_key``: +// +// * If the value is ``true``: follows the redirect +// * If the value is ``false``: does not follow the redirect +// * If the object is absent: ``redirect_if_absent`` decides (default: false) +// +// This lets a request-phase filter decide, per request, whether an +// otherwise-enabled internal redirect is actually taken, without changing route +// matching. Rich, request-time logic (tenant, JWT claim, header, time-of-day, +// rollout %) belongs in the filter that *sets* the boolean value; this predicate +// is a thin reader. +// [#extension: envoy.internal_redirect_predicates.filter_state] +message FilterStateConfig { + // Name of the filter-state boolean object to read. If true, the redirect is + // followed; if false, the redirect is skipped. Must be non-empty. + string redirect_enabled_key = 1 [(validate.rules).string = {min_len: 1}]; + + // Whether to follow the redirect when the filter-state object is absent. + // Defaults to false (do not redirect if the gate wasn't explicitly set), + // giving an opt-in posture. + bool redirect_if_absent = 2; +} diff --git a/api/src/main/proto/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.proto b/api/src/main/proto/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.proto index 7c47e6d15..dade9fde0 100644 --- a/api/src/main/proto/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.proto +++ b/api/src/main/proto/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.proto @@ -26,13 +26,20 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // the endpoint weights are sent by the control plane via EDS. However, // in this policy, the endpoint weights are instead determined via qps (queries // per second), eps (errors per second), and utilization metrics sent by the -// endpoint using the Open Request Cost Aggregation (ORCA) protocol. Utilization -// is determined by using the ORCA application_utilization field, if set, or -// else falling back to the cpu_utilization field. All queries count toward qps, -// regardless of result. Only failed queries count toward eps. A config -// parameter error_utilization_penalty controls the penalty to adjust endpoint -// weights using eps and qps. The weight of a given endpoint is computed as: -// ``qps / (utilization + eps/qps * error_utilization_penalty)``. +// endpoint using the Open Request Cost Aggregation (ORCA) protocol. All queries +// count toward qps, regardless of result. Only failed queries count toward eps. +// A config parameter error_utilization_penalty controls the penalty to adjust +// endpoint weights using eps and qps. The weight of a given endpoint is computed +// as: ``qps / (utilization + eps/qps * error_utilization_penalty)``. +// +// For a load report to update an endpoint's weight, it must set :ref:`rps_fractional +// ` (used as +// qps) greater than 0, and the final utilization (resolved utilization plus any +// error penalty) must be greater than 0. Resolved utilization (see +// :ref:`metric_names_for_computing_utilization +// `) +// is used as the baseline. Reports that fail to do so are ignored, and an endpoint +// with no valid weight is assigned the median weight of the endpoints that have one. // // Note that Envoy will forward the ORCA response headers/trailers from the upstream // cluster to the downstream client. This means that if the downstream client is also @@ -79,10 +86,11 @@ message ClientSideWeightedRoundRobin { // Default is 1.0. google.protobuf.FloatValue error_utilization_penalty = 6 [(validate.rules).float = {gte: 0.0}]; - // By default, endpoint weight is computed based on the :ref:`application_utilization ` field reported by the endpoint. - // If that field is not set, then utilization will instead be computed by taking the max of the values of the metrics specified here. + // Specifies the metrics used to compute the endpoint utilization from which weight is derived. // For map fields in the ORCA proto, the string will be of the form ``.``. For example, the string ``named_metrics.foo`` will mean to look for the key ``foo`` in the ORCA :ref:`named_metrics ` field. - // If none of the specified metrics are present in the load report, then :ref:`cpu_utilization ` is used instead. + // Utilization is the max of the values of the metrics specified here, when that max is greater than 0. + // Otherwise :ref:`application_utilization ` is used if greater than 0, with :ref:`cpu_utilization ` as the final fallback. + // Disabling the runtime flag ``envoy.reloadable_features.orca_weight_manager_use_named_metrics_first`` restores the legacy order, preferring ``application_utilization`` over these metrics. repeated string metric_names_for_computing_utilization = 7; // Configuration for slow start mode. diff --git a/api/src/main/proto/envoy/extensions/load_balancing_policies/load_aware_locality/v3/load_aware_locality.proto b/api/src/main/proto/envoy/extensions/load_balancing_policies/load_aware_locality/v3/load_aware_locality.proto index ec573dc86..f45075d81 100644 --- a/api/src/main/proto/envoy/extensions/load_balancing_policies/load_aware_locality/v3/load_aware_locality.proto +++ b/api/src/main/proto/envoy/extensions/load_balancing_policies/load_aware_locality/v3/load_aware_locality.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package envoy.extensions.load_balancing_policies.load_aware_locality.v3; import "envoy/config/cluster/v3/cluster.proto"; +import "envoy/extensions/load_balancing_policies/common/v3/common.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; @@ -21,7 +22,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Configuration for the load_aware_locality LB policy which uses ORCA utilization data // to route traffic between localities based on available headroom. -// [#next-free-field: 10] +// [#next-free-field: 11] message LoadAwareLocality { // The child LB policy to create for endpoint-picking within each locality. config.cluster.v3.LoadBalancingPolicy endpoint_picking_policy = 1 @@ -32,17 +33,20 @@ message LoadAwareLocality { google.protobuf.Duration weight_update_period = 2 [(validate.rules).duration = {gte {nanos: 100000000}}]; - // By default, endpoint utilization is computed based on the - // :ref:`application_utilization ` - // field reported by the endpoint. If that field is not set, then utilization - // will instead be computed by taking the max of the values of the metrics - // specified here. For map fields in the ORCA proto, the string will be of - // the form ``.``. For example, the string + // Specifies the metrics used to compute endpoint utilization. For map + // fields in the ORCA proto, the string will be of the form + // ``.``. For example, the string // ``named_metrics.foo`` will mean to look for the key ``foo`` in the ORCA // :ref:`named_metrics ` - // field. If none of the specified metrics are present in the load report, - // then :ref:`cpu_utilization ` - // is used instead. + // field. Utilization is the max of the values of the metrics specified + // here, when that max is greater than 0. Otherwise + // :ref:`application_utilization ` + // is used if greater than 0, with + // :ref:`cpu_utilization ` + // as the final fallback. Disabling the runtime flag + // ``envoy.reloadable_features.orca_weight_manager_use_named_metrics_first`` + // restores the legacy order, preferring ``application_utilization`` over + // these metrics. repeated string metric_names_for_computing_utilization = 3; // When the local locality's utilization is at most this threshold above the @@ -92,4 +96,9 @@ message LoadAwareLocality { // server may not provide reports as frequently as the client requests. // Used only when enable_oob_load_report is true. Default is 10 seconds. google.protobuf.Duration oob_reporting_period = 9; + + // Optional overrides for the OOB reporting connection (alternative port, + // ``:authority``, transport socket selection). Honored only when + // ``enable_oob_load_report`` is true. + common.v3.OrcaOobReportingConfig oob_reporting_config = 10; } diff --git a/api/src/main/proto/envoy/extensions/matching/http/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/matching/http/dynamic_modules/v3/dynamic_modules.proto index b5fcb3293..e46da8120 100644 --- a/api/src/main/proto/envoy/extensions/matching/http/dynamic_modules/v3/dynamic_modules.proto +++ b/api/src/main/proto/envoy/extensions/matching/http/dynamic_modules/v3/dynamic_modules.proto @@ -2,7 +2,12 @@ syntax = "proto3"; package envoy.extensions.matching.http.dynamic_modules.v3; +import "envoy/extensions/dynamic_modules/v3/dynamic_modules.proto"; + +import "google/protobuf/any.proto"; + import "udpa/annotations/status.proto"; +import "validate/validate.proto"; option java_package = "io.envoyproxy.envoy.extensions.matching.http.dynamic_modules.v3"; option java_outer_classname = "DynamicModulesProto"; @@ -22,3 +27,36 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // `. message HttpDynamicModuleMatchInput { } + +// Configuration for the dynamic modules data input. This input loads a shared object file +// via ``dlopen`` and invokes it during match evaluation to extract a value from the HTTP +// request and response. The extracted value is a string that an exact match map can dispatch on, +// so a module can select one of many matches with a single evaluation. +// +// Unlike :ref:`HttpDynamicModuleMatchInput +// `, the +// module produces the value directly rather than pairing with the dynamic modules input matcher. +// [#extension: envoy.matching.inputs.dynamic_module_string_data_input] +message DynamicModuleDataInput { + // Specifies the shared-object level configuration. This field is required. Remote module sources + // are not supported for data inputs, so the module must be available locally or by name. + envoy.extensions.dynamic_modules.v3.DynamicModuleConfig dynamic_module_config = 1 + [(validate.rules).message = {required: true}]; + + // The name for this data input configuration. If not specified, defaults to an empty string. + // + // This can be used to distinguish between different data input implementations inside a dynamic + // module. When Envoy receives this configuration, it passes the ``input_name`` to the dynamic + // module's data input config init function together with the ``input_config``. That way a module + // can decide which in-module implementation to use based on the name at load time. + string input_name = 2; + + // The configuration for the data input chosen by ``input_name``. If not specified, an empty + // configuration is passed to the module. + // + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. + // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly without + // the wrapper. + google.protobuf.Any input_config = 3; +} diff --git a/api/src/main/proto/envoy/extensions/matching/input_matchers/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/matching/input_matchers/dynamic_modules/v3/dynamic_modules.proto index 49f4143c5..126209c65 100644 --- a/api/src/main/proto/envoy/extensions/matching/input_matchers/dynamic_modules/v3/dynamic_modules.proto +++ b/api/src/main/proto/envoy/extensions/matching/input_matchers/dynamic_modules/v3/dynamic_modules.proto @@ -26,6 +26,16 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // matching beyond what built-in matchers provide, such as JWT/OAuth token analysis, custom // routing decisions, or integration with external data sources. message DynamicModuleMatcher { + // The policy applied when the module cannot evaluate a match, for example after a panic in the + // module's match hook. + enum OnError { + // Treat an evaluation that could not complete as no match. This is the default. + NO_MATCH = 0; + + // Treat an evaluation that could not complete as a match. + MATCH = 1; + } + // Specifies the shared-object level configuration. This field is required. envoy.extensions.dynamic_modules.v3.DynamicModuleConfig dynamic_module_config = 1 [(validate.rules).message = {required: true}]; @@ -47,8 +57,19 @@ message DynamicModuleMatcher { // ``matcher_name``, the module can decide which in-module matcher implementation to use and // fine-tune the behavior of the matcher. // - // ``google.protobuf.Struct`` is serialized as JSON before passing it to the module. + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly // without the wrapper. google.protobuf.Any matcher_config = 3; + + // The result applied for an evaluation that the module could not complete, for example when the + // module's match hook panics. A panic is caught at the ABI boundary and cannot report a match + // result, so the matcher applies this policy for that single evaluation. If not specified, + // defaults to ``NO_MATCH``. + // + // ``NO_MATCH`` is safe for allow-on-match trees where a missed match denies the request. + // ``MATCH`` is safe for deny-on-match trees where a missed match would let a request bypass the + // rule. + OnError on_error = 4; } diff --git a/api/src/main/proto/envoy/extensions/queue_policy/fifo/v3/fifo.proto b/api/src/main/proto/envoy/extensions/queue_policy/fifo/v3/fifo.proto new file mode 100644 index 000000000..b00b2e440 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/queue_policy/fifo/v3/fifo.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +package envoy.extensions.queue_policy.fifo.v3; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.queue_policy.fifo.v3"; +option java_outer_classname = "FifoProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/queue_policy/fifo/v3;fifov3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: FIFO Queue Policy] +// [#extension: envoy.queue_policy.fifo] + +// Configuration for the FIFO pending requests queue policy. +message FifoQueuePolicyConfig { +} diff --git a/api/src/main/proto/envoy/extensions/quic/connection_id_generator/quic_lb/v3/quic_lb.proto b/api/src/main/proto/envoy/extensions/quic/connection_id_generator/quic_lb/v3/quic_lb.proto index fac25959d..4aaf121df 100644 --- a/api/src/main/proto/envoy/extensions/quic/connection_id_generator/quic_lb/v3/quic_lb.proto +++ b/api/src/main/proto/envoy/extensions/quic/connection_id_generator/quic_lb/v3/quic_lb.proto @@ -5,8 +5,6 @@ package envoy.extensions.quic.connection_id_generator.quic_lb.v3; import "envoy/config/core/v3/base.proto"; import "envoy/extensions/transport_sockets/tls/v3/secret.proto"; -import "xds/annotations/v3/status.proto"; - import "udpa/annotations/status.proto"; import "validate/validate.proto"; @@ -27,13 +25,8 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // // See https://datatracker.ietf.org/doc/html/draft-ietf-quic-load-balancers for details. // -// .. warning:: -// -// This is still a work in progress. Interoperability testing has not yet been performed. // [#next-free-field: 7] message Config { - option (xds.annotations.v3.message_status).work_in_progress = true; - // Must be at least 1 octet. // The length of server_id and nonce_length_bytes must be 18 or less. // See https://datatracker.ietf.org/doc/html/draft-ietf-quic-load-balancers#name-server-id-allocation. diff --git a/api/src/main/proto/envoy/extensions/rate_limit_descriptors/jwt_claim/v3/jwt_claim.proto b/api/src/main/proto/envoy/extensions/rate_limit_descriptors/jwt_claim/v3/jwt_claim.proto new file mode 100644 index 000000000..fa4d7d50d --- /dev/null +++ b/api/src/main/proto/envoy/extensions/rate_limit_descriptors/jwt_claim/v3/jwt_claim.proto @@ -0,0 +1,101 @@ +syntax = "proto3"; + +package envoy.extensions.rate_limit_descriptors.jwt_claim.v3; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.rate_limit_descriptors.jwt_claim.v3"; +option java_outer_classname = "JwtClaimProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/rate_limit_descriptors/jwt_claim/v3;jwt_claimv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Rate limit descriptor from JWT claim] +// [#extension: envoy.rate_limit_descriptors.jwt_claim] + +// The following descriptor entry is appended with a value extracted from a +// named claim in a JWT found in an HTTP request header or cookie. +// +// .. code-block:: cpp +// +// ("", "") +// +// .. warning:: +// +// SECURITY WARNING: This extension does NOT verify JWT signatures. Any +// party can present a forged or expired JWT with arbitrary claims, and +// those claims will be used as rate limit descriptor values. This means +// an attacker can trivially evade or manipulate per-claim rate limits +// (e.g. impersonate another subject, or rotate a fake claim value on +// every request to bypass limiting entirely) unless the JWT signature +// is verified elsewhere in the request path — for example, by an +// upstream mTLS-authenticated service, or by an +// :ref:`envoy.filters.http.jwt_authn +// ` +// filter earlier in the same filter chain that rejects invalid tokens +// before this descriptor action runs. +// +// DO NOT use this extension to gate access, apply differentiated rate +// limits by trust level, or make any authorization-adjacent decision +// based on the extracted claim, unless signature verification is +// PROVABLY performed elsewhere in the request path. +// +// If you need Envoy itself to verify the JWT before rate limiting, +// use the :ref:`envoy.filters.http.jwt_authn +// ` +// filter (placed before the rate limit filter) together with a +// :ref:`request_headers +// ` +// or :ref:`metadata +// ` +// descriptor action instead of this extension. +// [#next-free-field: 8] +message Descriptor { + // The key to use in the descriptor entry. + string descriptor_key = 1 [(validate.rules).string = {min_len: 1}]; + + // The name of the HTTP header containing the JWT, e.g. "authorization". + // + // Exactly one of ``header_name`` or ``cookie`` must be set. + string header_name = 2 + [(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME strict: false}]; + + // The name of the cookie containing the JWT, e.g. "auth_token". The cookie + // is looked up in the request's ``Cookie`` header. + // + // Exactly one of ``header_name`` or ``cookie`` must be set. + string cookie = 7 [(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME strict: false}]; + + // The value prefix to strip before parsing the remainder as a JWT, e.g. + // "Bearer " (with a trailing space) for an "authorization" header + // formatted as "Authorization: Bearer ". If the header or cookie + // value does not start with this prefix, the descriptor is not populated + // (falls through to ``default_value``/``skip_if_absent`` below). + // + // This is typically only needed for ``header_name``; cookie values do not + // usually carry a prefix. + string value_prefix = 3 + [(validate.rules).string = {well_known_regex: HTTP_HEADER_VALUE strict: false}]; + + // The name of the JWT claim to extract. Can be a nested claim, dot- + // separated, e.g. "claim.nested.key". Matches the same convention as + // :ref:`JwtClaimToHeader.claim_name + // `. + // Only string-valued claims are supported; non-string claims (numbers, + // booleans, arrays, objects) are treated as absent. An empty string-valued + // claim populates the descriptor with an empty value. + string claim_name = 4 [(validate.rules).string = {min_len: 1}]; + + // The default value to use if the header or cookie is absent, is not a + // structurally valid JWT, or the named claim is absent/non-string. + string default_value = 5; + + // If true, Envoy skips this descriptor entry (rather than aborting the + // whole descriptor for this action list) when the header or cookie is + // absent, the JWT cannot be parsed, or the named claim is absent/non-string, and + // ``default_value`` is not specified. An empty string-valued claim is + // present and produces an entry with an empty value regardless of this + // setting. + bool skip_if_absent = 6; +} diff --git a/api/src/main/proto/envoy/extensions/router/cluster_specifiers/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/router/cluster_specifiers/dynamic_modules/v3/dynamic_modules.proto new file mode 100644 index 000000000..3a71b8137 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/router/cluster_specifiers/dynamic_modules/v3/dynamic_modules.proto @@ -0,0 +1,131 @@ +syntax = "proto3"; + +package envoy.extensions.router.cluster_specifiers.dynamic_modules.v3; + +import "envoy/config/core/v3/base.proto"; +import "envoy/config/route/v3/route_components.proto"; +import "envoy/extensions/dynamic_modules/v3/dynamic_modules.proto"; + +import "google/protobuf/any.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.router.cluster_specifiers.dynamic_modules.v3"; +option java_outer_classname = "DynamicModulesProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/router/cluster_specifiers/dynamic_modules/v3;dynamic_modulesv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Dynamic Modules Cluster Specifier] +// +// Dynamic modules cluster specifier :ref:`configuration reference documentation +// `. +// [#extension: envoy.router.cluster_specifier_plugin.dynamic_modules] + +// Route action properties that a dynamic module may select for a request in place of the properties +// of the matched route. These properties are themselves built from other extensions, such as retry +// host predicates and retry priorities, so they must be declared here in advance rather than chosen +// freely by the module on each request. +// +// Each entry is built and validated when the cluster specifier is configured, so an invalid entry +// is rejected at configuration load rather than on the request path. Every entry must replace at +// least one property, so an entry that builds to no replacement is rejected as well. +message RouteActionOverride { + // Retry policy replacing the retry policy of the matched route. If not specified, the retry + // policy of the matched route is used, so an entry cannot be used to remove a retry policy that + // the matched route configures. + config.route.v3.RetryPolicy retry_policy = 1; + + // Metadata match criteria replacing the criteria of the matched route, used by subset load + // balancing. Only the ``envoy.lb`` entry of :ref:`filter_metadata + // ` is used, matching the behavior of + // :ref:`RouteAction.metadata_match + // `. If not specified, or if there + // is no ``envoy.lb`` entry, the criteria of the matched route are used, so an entry cannot be used + // to remove the criteria that the matched route configures. An entry whose only property is a + // ``metadata_match`` without an ``envoy.lb`` entry therefore replaces nothing and is rejected. + config.core.v3.Metadata metadata_match = 2; + + // Request mirroring policies replacing the request mirroring policies of the matched route. If + // not specified, the request mirroring policies of the matched route are used, so an entry cannot + // be used to turn off mirroring that the matched route configures. Statically named mirror + // clusters are checked against the cluster manager when :ref:`validate_clusters + // ` is enabled. + repeated config.route.v3.RouteAction.RequestMirrorPolicy request_mirror_policies = 3; + + // Hash policy replacing the hash policy of the matched route, used when the upstream cluster + // employs a hashing load balancer. If not specified, the hash policy of the matched route is used, + // so an entry cannot be used to remove a hash policy that the matched route configures. A + // cluster-level hash policy and a load-balancer-level hash policy, when configured, take precedence + // over this route-level policy. + repeated config.route.v3.RouteAction.HashPolicy hash_policy = 4; +} + +// Configuration for the Dynamic Modules Cluster Specifier. This cluster specifier allows loading +// shared object files via ``dlopen`` to select the upstream cluster for a request, and to replace +// the timeout, idle timeout, priority, request body buffer limit, cluster not found response code, +// hash policy, retry policy, metadata match criteria and request mirroring policies of the matched +// route. +// +// A module can be loaded by multiple cluster specifiers. It is loaded only once and shared across +// multiple cluster specifier instances. The module is invoked while the route is being +// resolved, so the selection is visible to the router without clearing the route cache. It is +// invoked again whenever a filter refreshes the route cluster, or a retry re-selects it when +// :ref:`refresh_cluster_on_retry +// ` is set, so the module +// must be able to produce a decision from the request headers and the stream info alone. +message DynamicModuleClusterSpecifier { + // Specifies the shared-object level configuration. This field is required. + // + // .. note:: + // This extension loads the module while the cluster specifier is configured, so it cannot wait + // for an asynchronous fetch. A remote :ref:`module + // ` is therefore + // accepted only when the module is already cached on disk, and is otherwise rejected. Setting + // :ref:`nack_on_cache_miss + // ` to + // ``true`` makes the rejection start a background fetch so that a later update succeeds. Prefer + // ``name`` or a local data source. + envoy.extensions.dynamic_modules.v3.DynamicModuleConfig dynamic_module_config = 1 + [(validate.rules).message = {required: true}]; + + // The name for this cluster specifier configuration. If not specified, defaults to an empty + // string. + // + // This can be used to distinguish between different cluster specifier implementations inside a + // dynamic module. When Envoy receives this configuration, it passes the ``specifier_name`` to the + // dynamic module's cluster specifier config init function together with the ``specifier_config``. + // That way a module can decide which in-module implementation to use based on the name at load + // time. + string specifier_name = 2; + + // The configuration for the cluster specifier chosen by ``specifier_name``. If not specified, an + // empty configuration is passed to the module. + // + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. + // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly without + // the wrapper. + // + // .. code-block:: yaml + // + // # Passing a JSON struct configuration + // specifier_config: + // "@type": "type.googleapis.com/google.protobuf.Struct" + // value: + // cluster_name_prefix: shard- + // + // # Passing a simple string configuration + // specifier_config: + // "@type": "type.googleapis.com/google.protobuf.StringValue" + // value: "shard-" + // + google.protobuf.Any specifier_config = 3; + + // Route action overrides that the module may select by name for a request. If not specified, the + // module can only select the cluster, the timeout, the idle timeout, the priority, the request + // body buffer limit and the cluster not found response code. + map route_action_overrides = 4 + [(validate.rules).map = {keys {string {min_len: 1}}}]; +} diff --git a/api/src/main/proto/envoy/extensions/router/cluster_specifiers/priority_group/v3/priority_group.proto b/api/src/main/proto/envoy/extensions/router/cluster_specifiers/priority_group/v3/priority_group.proto new file mode 100644 index 000000000..8f0a774c8 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/router/cluster_specifiers/priority_group/v3/priority_group.proto @@ -0,0 +1,193 @@ +syntax = "proto3"; + +package envoy.extensions.router.cluster_specifiers.priority_group.v3; + +import "google/protobuf/wrappers.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.router.cluster_specifiers.priority_group.v3"; +option java_outer_classname = "PriorityGroupProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/router/cluster_specifiers/priority_group/v3;priority_groupv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Priority Group Based Cluster Specifier] +// [#extension: envoy.router.cluster_specifier_plugin.priority_group] + +// A weighted cluster of a :ref:`priority group +// `. +message ClusterWeight { + // Name of the upstream cluster. + string cluster_name = 1 [(validate.rules).string = {min_len: 1}]; + + // Weight of the cluster relative to the other clusters of the same group. + google.protobuf.UInt32Value weight = 2 + [(validate.rules).uint32 = {gte: 1}, (validate.rules).message = {required: true}]; +} + +// A named group of weighted clusters. All the clusters of a group are considered to have the +// same priority and the target cluster is selected from the group based on the weights. +message PriorityGroup { + // Name of the group. The name is used to reference the group from the :ref:`override metadata + // ` + // and should be unique across all the groups of the same cluster specifier. If multiple groups + // share the same name, then the first one of them is used when the group is referenced by name. + string name = 1 [(validate.rules).string = {min_len: 1}]; + + // The candidate clusters of this group. + repeated ClusterWeight clusters = 2 [(validate.rules).repeated = {min_items: 1}]; +} + +// Cluster specifier plugin that selects a :ref:`priority group +// ` based +// on the attempt of the request first, and then selects a cluster from the selected group based +// on the weights of the clusters. +// +// The group is selected by the attempt count of the request: the initial attempt uses the first +// group of the list, the first retry uses the second group, and so on. If the attempt count +// exceeds the number of the available groups, then the last group of the list is used for all +// the remaining attempts. +// +// This plugin must be used together with the :ref:`refresh cluster on retry +// ` option of the retry +// policy to ensure the reselecting of the cluster on every attempt. +// +// See the :ref:`cluster specifier documentation +// ` for more details. +// +// Example: +// +// .. validated-code-block:: yaml +// :type-name: envoy.extensions.router.cluster_specifiers.priority_group.v3.PriorityGroupClusterSpecifier +// +// priority_groups: +// - name: local +// clusters: +// - cluster_name: local_primary +// weight: 80 +// - cluster_name: local_secondary +// weight: 20 +// - name: remote +// clusters: +// - cluster_name: remote_primary +// weight: 100 +// +// With the configuration above, the initial attempt will be routed to ``local_primary`` or +// ``local_secondary`` (80/20), and the first retry and every attempt after it will be routed to +// ``remote_primary``. +// +message PriorityGroupClusterSpecifier { + // The list of the priority groups. The order of the groups is the default selection order that + // is used when the :ref:`override metadata + // ` + // is not configured or not available in the request. + repeated PriorityGroup priority_groups = 1 [(validate.rules).repeated = {min_items: 1}]; + + // Optional dynamic metadata namespace that is used to override the priority groups on a + // per-request basis. If this is configured and the dynamic metadata of the request has a value + // under this namespace, then the priority groups of that value replace the configured + // :ref:`priority_groups + // ` + // for the request. + // + // The value of the namespace is read from the :ref:`typed dynamic metadata + // ` first, where it must be a + // :ref:`PriorityGroupsOverride + // ` + // message. If the namespace is not present there, then it is read from the :ref:`untyped + // dynamic metadata `, where it must + // be a struct with the same shape as the ``PriorityGroupsOverride`` message. + // + // The group of the current attempt is read from the overriding list in the same way as from the + // configured list: the initial attempt uses the first group, the first retry uses the second + // group, and so on, and the last group is used once the attempts go past the end of the list. + // + // An overriding group whose :ref:`clusters + // ` + // are set replaces the clusters and the weights of the group for the request. Note these + // clusters are not validated when the configuration is loaded and the request fails with a + // ``no cluster`` response if the selected cluster does not exist. An overriding group whose + // clusters are omitted or empty instead selects the configured priority group with the same + // :ref:`name + // ` + // and uses the configured clusters and weights of that group. + // + // The dynamic metadata is typically set by a filter that runs before the router filter, for + // example the :ref:`Lua filter ` or the :ref:`external processing + // filter `. + // + // .. note:: + // The route, and with it the cluster of the initial attempt, is resolved before the HTTP + // filter chain runs, so the filter that sets the metadata must also clear the route cache. + // + // Example of a matching untyped dynamic metadata value: + // + // .. code-block:: yaml + // + // envoy.my_filter: + // priority_groups: + // - name: remote + // clusters: + // - cluster_name: remote_primary + // weight: 20 + // - cluster_name: remote_secondary + // weight: 80 + // - name: local + // + // With the metadata value above, the initial attempt uses the group ``remote`` with the clusters + // and the weights of the metadata, and the first retry uses the configured group ``local`` with + // its configured clusters and weights. + // + // If the metadata namespace is missing, cannot be parsed as a ``PriorityGroupsOverride`` + // message, holds no group at all, or the group of the current attempt is not a valid override, + // then the configured ``priority_groups`` are used instead. + string override_metadata_namespace = 2; + + // The source of the random value that is used to select the target cluster of the selected + // priority group based on the cluster weights. If this is not configured, the internally + // generated random value of the request is used. The random value is only computed once for a + // request and the same value is reused for all the attempts of the request. + oneof random_value_specifier { + // Specifies the header name that is used to look up the random value passed in the request header. + // This is used to ensure consistent cluster picking across multiple proxy levels for weighted traffic. + // If header is not present or invalid, Envoy will fall back to use the internally generated random value. + // This header is expected to be single-valued header as we only want to have one selected value throughout + // the process for the consistency. And the value is a unsigned number between 0 and UINT64_MAX. + string header_name = 3 + [(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME strict: false}]; + + // When set to true, the :ref:`hash policies + // ` of the route will be used to + // generate the random value for weighted cluster selection. + // This could ensure consistent cluster picking across multiple proxy levels for weighted traffic. + // If the route has no hash policy or the hash policies can not generate a hash for the request, + // Envoy will fall back to use the internally generated random value. + google.protobuf.BoolValue use_hash_policy = 4; + } +} + +// The value of the :ref:`override metadata +// ` +// that replaces the configured :ref:`priority_groups +// ` +// for a single request. +// +// This message is never part of the cluster specifier configuration, so it is not checked by the +// proto validation rules. A value that cannot be used, or a single group of it that cannot be +// used, is ignored and the configured priority groups are used instead. +message PriorityGroupsOverride { + // The ordered list of the overriding priority groups. The initial attempt of the request uses + // the first group, the first retry uses the second group, and so on. Once the attempts go past + // the end of the list, the last group is used for all the remaining attempts. + // + // Unlike a configured :ref:`priority group + // `, an + // overriding group may omit its :ref:`clusters + // ` + // to reuse the clusters and the weights of the configured group with the same :ref:`name + // `. + // An empty list means that there is no override at all. + repeated PriorityGroup priority_groups = 1; +} diff --git a/api/src/main/proto/envoy/extensions/router/route_specifiers/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/router/route_specifiers/dynamic_modules/v3/dynamic_modules.proto new file mode 100644 index 000000000..d4897ec9d --- /dev/null +++ b/api/src/main/proto/envoy/extensions/router/route_specifiers/dynamic_modules/v3/dynamic_modules.proto @@ -0,0 +1,218 @@ +syntax = "proto3"; + +package envoy.extensions.router.route_specifiers.dynamic_modules.v3; + +import "envoy/config/core/v3/base.proto"; +import "envoy/config/route/v3/route_components.proto"; +import "envoy/extensions/dynamic_modules/v3/dynamic_modules.proto"; +import "envoy/type/matcher/v3/regex.proto"; + +import "google/protobuf/any.proto"; +import "google/protobuf/wrappers.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.router.route_specifiers.dynamic_modules.v3"; +option java_outer_classname = "DynamicModulesProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/router/route_specifiers/dynamic_modules/v3;dynamic_modulesv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Dynamic modules route specifier] +// +// A :ref:`route specifier ` implemented by a +// :ref:`dynamic module `. For each request the module keeps the +// route that route matching resolved, refines it, replaces it with one of the route templates +// declared here, drops it, or lets route matching carry on with the next route. Envoy builds every +// route from validated configuration, so a module can never produce a malformed route. +// +// See :ref:`the dynamic modules route specifier +// ` for more details. +// [#extension: envoy.router.route_specifiers.dynamic_modules] + +// What Envoy does when the decision of the module cannot be honored. +// +// This covers a module that reports an error, which is what the SDK does when the module panics, +// a decision or a status Envoy does not know, a template selection that names an identifier that +// is not declared, a template whose ``match`` does not hold for the request, an override recorded +// without a template while route matching resolved no route, route entry overrides recorded for a +// direct response, and route metadata a typed metadata factory rejects. +enum FailurePolicy { + // Must be set explicitly. + FAILURE_POLICY_UNSPECIFIED = 0; + + // Use the route the specifier was given, unchanged, and carry on with the chain. This keeps the + // routing of the route table the module replaces in effect while it is being rolled out. If the + // specifier was given no route, the request has no route. + PASS_THROUGH = 1; + + // Use no route, so the request is handled as if nothing had matched, and end the chain. Prefer + // this once the module owns the routing of the virtual host, so that a failure never falls back + // to the routes that are left. + NO_ROUTE = 2; + + // Skip the route the specifier was given and let route matching carry on with the next route, + // keeping the route table the module replaces in effect for the request. Prefer this for the + // catch all route that owns routing during a migration, so a module failure falls back to the + // route table rather than to the catch all route's own action. + CONTINUE_MATCHING = 3; +} + +// A named route the module may select for a request. +// +// A template is built and validated once, when the specifier is configured, so an invalid template +// is rejected at configuration load. It inherits from the virtual host and the route configuration +// the specifier is configured on, exactly like a configured route does. When the module selects a +// template, Envoy evaluates it against the request like a configured route: the +// :ref:`match ` must hold, otherwise the +// ``failure_policy`` applies, and the action is resolved the usual way, including +// :ref:`weighted_clusters ` and +// :ref:`cluster specifier plugins +// `. +message RouteTemplate { + // The identifier the module selects this template with. Must be unique within the specifier. + string template_id = 1 [(validate.rules).string = {min_len: 1}]; + + // The route. ``route_specifiers`` must be empty, since a template is not run through the + // specifier chains. + config.route.v3.Route route = 2 [(validate.rules).message = {required: true}]; +} + +// Route properties the module may select for a request. +// +// These properties are built from other extensions, so they are declared here and built once at +// configuration load rather than constructed on the request path. An entry that replaces no +// property is rejected. A property an entry leaves unset keeps the value of the route the decision +// produced, so an entry can never remove a property that route configures. +// [#next-free-field: 12] +message RouteOverride { + // The identifier the module selects this override with. Must be unique within the specifier. + string override_id = 1 [(validate.rules).string = {min_len: 1}]; + + // Retry policy replacing the retry policy of the produced route. + config.route.v3.RetryPolicy retry_policy = 2; + + // Metadata match criteria replacing those of the produced route, used by subset load balancing. + // Only the ``envoy.lb`` entry of :ref:`filter_metadata + // ` is used, matching the behavior of + // :ref:`RouteAction.metadata_match + // `. An entry whose only property + // is a ``metadata_match`` without an ``envoy.lb`` entry replaces nothing and is rejected. + config.core.v3.Metadata metadata_match = 3; + + // Request mirroring policies replacing those of the produced route. Statically named mirror + // clusters are checked against the cluster manager when ``validate_clusters`` is enabled. + repeated config.route.v3.RouteAction.RequestMirrorPolicy request_mirror_policies = 4; + + // Hash policy replacing the hash policy of the produced route, used when the upstream cluster + // employs a hashing load balancer. A cluster level and a load balancer level hash policy, when + // configured, take precedence over this route level policy. + repeated config.route.v3.RouteAction.HashPolicy hash_policy = 5; + + // Hedge policy replacing the hedge policy of the produced route. + config.route.v3.HedgePolicy hedge_policy = 6; + + // Rate limits replacing the rate limits of the produced route. + repeated config.route.v3.RateLimit rate_limits = 7; + + // CORS policy replacing the CORS policy of the produced route. The CORS filter reads it only when + // CORS is not configured through per filter configuration. + config.route.v3.CorsPolicy cors = 8; + + // Regex rewrite of the request path, replacing the path the produced route sends upstream, + // unless the module records a path of its own, which wins. The + // pattern is compiled once when the specifier is configured. It applies to the path without the + // query string, which is preserved, and the result is capped at + // :ref:`max_rewritten_path_bytes + // `. + type.matcher.v3.RegexMatchAndSubstitute regex_rewrite = 9; + + // Tracing configuration replacing the tracing settings of the produced route, overriding the + // connection manager defaults for the request. This is a route level property, so it applies to + // a direct response or a redirect route as well as a route entry. + config.route.v3.Tracing tracing = 10; + + // Metadata layered onto the metadata of the produced route, per namespace, so consumers such as + // the rate limit ROUTE_ENTRY action, ext_authz and the METADATA(ROUTE) formatter observe it. + // Metadata the module records itself layers on top of it. It is a route level property. An + // empty message layers nothing. + config.core.v3.Metadata metadata = 11; +} + +// Configuration for the dynamic modules route specifier. +// [#next-free-field: 12] +message DynamicModuleRouteSpecifier { + // Specifies the shared object level configuration. This field is required. + // + // .. note:: + // This extension loads the module while the route configuration is built, so it cannot wait + // for an asynchronous fetch. A remote :ref:`module + // ` is therefore + // accepted only when the module is already cached on disk, and is otherwise rejected. Setting + // :ref:`nack_on_cache_miss + // ` to + // ``true`` makes the rejection start a background fetch so that a later update succeeds. Prefer + // ``name`` or a local data source. + envoy.extensions.dynamic_modules.v3.DynamicModuleConfig dynamic_module_config = 1 + [(validate.rules).message = {required: true}]; + + // The name for this route specifier configuration, used to select an implementation within the + // module. If not specified, defaults to an empty string. + string specifier_name = 2; + + // The configuration for the route specifier chosen by ``specifier_name``. If not specified, + // defaults to an empty configuration. + google.protobuf.Any specifier_config = 3; + + // Prefix for the statistics of this specifier, emitted as + // ``.route_specifier..*``, where ``metrics_namespace`` is the + // :ref:`metrics_namespace + // ` + // of the module. Specifiers that share a metrics namespace and prefix share counters, so keep + // the prefix unique within that namespace. + string stat_prefix = 4 [(validate.rules).string = {min_len: 1}]; + + // The route templates the module may select by ``template_id``, each replacing the resolved + // route with a route built from configuration. The ``template_id`` values must be unique. + repeated RouteTemplate route_templates = 5; + + // The route overrides the module may select by ``override_id``, each overlaying its properties + // onto the produced route. The ``override_id`` values must be unique. + repeated RouteOverride route_overrides = 6; + + // Fraction of requests the module is invoked for. A request outside the fraction is passed + // through untouched and counted in ``runtime_skipped``. The stable random value of the request is + // used, so the choice holds when the route of a request is recomputed. If not specified, + // defaults to every request. + // + // .. attention:: + // A request outside the fraction is routed by ``routes`` or ``matcher`` alone, so a fraction + // below 100% is only safe, as a canary or as an emergency switch with the runtime key set to + // ``0``, while the route table the module replaces is still complete. Once that table has been + // shrunk, lowering the fraction turns the affected requests into 404s or routes them wrongly, and + // the way back is a route configuration rollback that restores the table. + config.core.v3.RuntimeFractionalPercent runtime_fraction = 7; + + // What Envoy does when the decision of the module cannot be honored. Must be set explicitly. + FailurePolicy failure_policy = 8 [(validate.rules).enum = {defined_only: true}]; + + // Whether the clusters the route templates and the route overrides name are checked + // against the cluster manager while the specifier is configured. If not specified, defaults to + // ``false``, because the clusters a route names may be delivered after the route configuration + // that references them. An unknown cluster then fails the request with the + // ``cluster_not_found_response_code`` of the route instead. + google.protobuf.BoolValue validate_clusters = 9; + + // The maximum length of a request path a module rewrite may produce, covering the full ``:path`` + // value including the query string. A rewrite whose result would exceed it is rejected. If not + // specified, defaults to 65536. + google.protobuf.UInt32Value max_rewritten_path_bytes = 10 [(validate.rules).uint32 = {gt: 0}]; + + // An opaque identifier the module reads with ``get_config_specifier_instance_id``, so that two + // specifier instances sharing one module can tell the routes they build apart, for example by + // writing it into the route metadata they mark their routes with. It is documentation and + // convenience for the module and Envoy enforces nothing about it. If not specified, defaults to + // an empty string. + string specifier_instance_id = 11 [(validate.rules).string = {max_len: 256}]; +} diff --git a/api/src/main/proto/envoy/extensions/stat_sinks/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/stat_sinks/dynamic_modules/v3/dynamic_modules.proto index 2f49626dd..53f00212f 100644 --- a/api/src/main/proto/envoy/extensions/stat_sinks/dynamic_modules/v3/dynamic_modules.proto +++ b/api/src/main/proto/envoy/extensions/stat_sinks/dynamic_modules/v3/dynamic_modules.proto @@ -41,7 +41,8 @@ message DynamicModuleStatsSink { // The configuration for the sink chosen by ``sink_name``. If not specified, an empty // configuration is passed to the module. // - // ``google.protobuf.Struct`` is serialized as JSON before passing it to the module. + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly // without the wrapper. // diff --git a/api/src/main/proto/envoy/extensions/stat_sinks/graphite_statsd/v3/graphite_statsd.proto b/api/src/main/proto/envoy/extensions/stat_sinks/graphite_statsd/v3/graphite_statsd.proto index 7d538cf35..a42f847b9 100644 --- a/api/src/main/proto/envoy/extensions/stat_sinks/graphite_statsd/v3/graphite_statsd.proto +++ b/api/src/main/proto/envoy/extensions/stat_sinks/graphite_statsd/v3/graphite_statsd.proto @@ -22,6 +22,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // `. // [#extension: envoy.stat_sinks.graphite_statsd] +// [#next-free-field: 6] message GraphiteStatsdSink { oneof statsd_specifier { option (validate.required) = true; @@ -42,4 +43,10 @@ message GraphiteStatsdSink { // // Note that this value may not be respected if smaller than a single metric. google.protobuf.UInt64Value max_bytes_per_datagram = 4 [(validate.rules).uint64 = {gt: 0}]; + + // If true, histogram samples are scaled to milliseconds according to the histogram's unit + // before being reported as timers. See :ref:`StatsdSink's scale_histogram_units_to_milliseconds + // field ` + // for more details. + bool scale_histogram_units_to_milliseconds = 5; } diff --git a/api/src/main/proto/envoy/extensions/tracers/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/tracers/dynamic_modules/v3/dynamic_modules.proto index 2c1d4cff1..f0a4fece1 100644 --- a/api/src/main/proto/envoy/extensions/tracers/dynamic_modules/v3/dynamic_modules.proto +++ b/api/src/main/proto/envoy/extensions/tracers/dynamic_modules/v3/dynamic_modules.proto @@ -49,7 +49,8 @@ message DynamicModuleTracer { // ``tracer_name``, the module can decide which in-module tracer implementation to use and // fine-tune the behavior of the tracer. // - // ``google.protobuf.Struct`` is serialized as JSON before passing it to the module. + // ``google.protobuf.Struct`` and the ``value`` field of ``xds.type.v3.TypedStruct`` are + // serialized as JSON before passing them to the module. // ``google.protobuf.BytesValue`` and ``google.protobuf.StringValue`` are passed directly // without the wrapper. // diff --git a/api/src/main/proto/envoy/extensions/transport_sockets/quic/v3/quic_transport.proto b/api/src/main/proto/envoy/extensions/transport_sockets/quic/v3/quic_transport.proto index 652e37ed2..ae1e73cf5 100644 --- a/api/src/main/proto/envoy/extensions/transport_sockets/quic/v3/quic_transport.proto +++ b/api/src/main/proto/envoy/extensions/transport_sockets/quic/v3/quic_transport.proto @@ -24,12 +24,25 @@ message QuicDownstreamTransport { tls.v3.DownstreamTlsContext downstream_tls_context = 1 [(validate.rules).message = {required: true}]; - // If false, QUIC will tell TLS to reject any early data and to stop issuing 0-RTT credentials with resumption session tickets. This will prevent clients from sending 0-RTT requests. - // Default to true. + // If false, QUIC will tell TLS to reject any early data and to stop issuing 0-RTT credentials + // with resumption session tickets. This will prevent clients from sending 0-RTT requests. + // Defaults to true, except when a client certificate validation context is configured, in which + // case it defaults to false. Early data requires resumption, so it cannot be enabled unless + // :ref:`enable_resumption + // ` + // is also true. google.protobuf.BoolValue enable_early_data = 2; // If false, TLS session tickets are not issued and accepted by QUIC. - // Default to true. + // Defaults to true, except when a client certificate validation context is configured, in which + // case it defaults to false. QUIC does not re-validate the client certificate when a session is + // resumed. A resumed connection reuses the certificate verdict of the original handshake until the + // ticket expires, so certificate revocation or expiry and validation context changes are not + // rechecked. Setting this to true on a filter chain that validates a client certificate opts into + // that trade-off in exchange for cheaper handshakes. Resumption also requires + // :ref:`disable_stateless_session_resumption + // ` + // to be false, because that field controls the underlying TLS session tickets. google.protobuf.BoolValue enable_resumption = 3; } diff --git a/api/src/main/proto/envoy/extensions/transport_sockets/tls/handshakers/dynamic_modules/v3/dynamic_modules.proto b/api/src/main/proto/envoy/extensions/transport_sockets/tls/handshakers/dynamic_modules/v3/dynamic_modules.proto new file mode 100644 index 000000000..01530d019 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/transport_sockets/tls/handshakers/dynamic_modules/v3/dynamic_modules.proto @@ -0,0 +1,49 @@ +syntax = "proto3"; + +package envoy.extensions.transport_sockets.tls.handshakers.dynamic_modules.v3; + +import "envoy/extensions/dynamic_modules/v3/dynamic_modules.proto"; + +import "google/protobuf/any.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.transport_sockets.tls.handshakers.dynamic_modules.v3"; +option java_outer_classname = "DynamicModulesProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/handshakers/dynamic_modules/v3;dynamic_modulesv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Dynamic Module TLS Handshaker] +// [#extension: envoy.tls.handshakers.dynamic_modules] + +// Configuration for the dynamic module TLS handshaker. +// +// Example: +// +// .. validated-code-block:: yaml +// :type-name: envoy.extensions.transport_sockets.tls.v3.CommonTlsContext +// +// custom_handshaker: +// name: envoy.tls.handshakers.dynamic_modules +// typed_config: +// "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.handshakers.dynamic_modules.v3.DynamicModuleTlsHandshaker +// dynamic_module_config: +// name: my_module +// handshaker_name: my_handshaker +// +message DynamicModuleTlsHandshaker { + // Dynamic module configuration. See :ref:`dynamic module configuration + // ` for details. + envoy.extensions.dynamic_modules.v3.DynamicModuleConfig dynamic_module_config = 1 + [(validate.rules).message = {required: true}]; + + // The name of the handshaker implementation in the dynamic module. + // This is passed to the module's ``envoy_dynamic_module_on_tls_handshaker_config_new`` function. + string handshaker_name = 2 [(validate.rules).string = {min_len: 1}]; + + // Optional configuration for the handshaker. This is passed as bytes to the dynamic module. + // If not specified, no configuration bytes are passed to the module. + google.protobuf.Any handshaker_config = 3; +} diff --git a/api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/common.proto b/api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/common.proto index 3a3b753a0..f8facd683 100644 --- a/api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/common.proto +++ b/api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/common.proto @@ -242,7 +242,7 @@ message PrivateKeyProvider { bool fallback = 4; } -// [#next-free-field: 9] +// [#next-free-field: 10] message TlsCertificate { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.auth.TlsCertificate"; @@ -309,6 +309,26 @@ message TlsCertificate { // [#not-implemented-hide:] repeated config.core.v3.DataSource signed_certificate_timestamp = 5; + + // Optional per-certificate TLS parameters. When set on a server certificate, any specified + // fields override the corresponding context-level + // :ref:`tls_params ` + // for that certificate during the TLS handshake; unset fields continue to use the context-level + // values. This allows different cipher suites, ECDH curves, protocol versions, signature + // algorithms, or compliance policies per certificate. + // + // These parameters do not affect certificate selection, which continues to be based only on SNI, + // the client's ECDSA capability, and OCSP capability. They are applied after a certificate has + // been selected. For a multi-certificate configuration this means each certificate's parameters + // must be compatible with the clients that select it: if the selected certificate's parameters + // leave nothing in common with the client, the handshake fails and no other certificate is tried. + // + // Note: because these are overrides rather than constraints, a certificate-level + // ``tls_minimum_protocol_version`` can lower the floor set by the context-level + // ``tls_params``, weakening the listener's overall TLS security policy. + // Setting this on a client certificate is not supported and is ignored. + // This field has no effect on QUIC/HTTP3 downstream connections. + TlsParameters tls_params = 9; } message TlsSessionTicketKeys { diff --git a/api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/tls.proto b/api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/tls.proto index 648dd5b56..60d0250b0 100644 --- a/api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/tls.proto +++ b/api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/tls.proto @@ -270,7 +270,8 @@ message CommonTlsContext { // TLS protocol versions, cipher suites etc. TlsParameters tls_params = 1; - // Only a single TLS certificate is supported in client contexts. In server contexts, + // Only a single TLS certificate is supported in client contexts unless + // ``custom_tls_certificate_selector`` is explicitly defined with ``max_session_keys`` set to 0. In server contexts, // :ref:`Multiple TLS certificates ` can be associated with the // same context to allow both RSA and ECDSA certificates and support SNI-based selection. // @@ -362,6 +363,7 @@ message CommonTlsContext { // Custom TLS handshaker. If empty, defaults to native TLS handshaking // behavior. + // [#extension-category: envoy.tls_handshakers] config.core.v3.TypedExtensionConfig custom_handshaker = 13; // TLS key log configuration diff --git a/api/src/main/proto/envoy/extensions/upstreams/http/v3/http_protocol_options.proto b/api/src/main/proto/envoy/extensions/upstreams/http/v3/http_protocol_options.proto index 03f0158ed..6b53f9daa 100644 --- a/api/src/main/proto/envoy/extensions/upstreams/http/v3/http_protocol_options.proto +++ b/api/src/main/proto/envoy/extensions/upstreams/http/v3/http_protocol_options.proto @@ -73,9 +73,6 @@ message HttpProtocolOptions { config.core.v3.Http2ProtocolOptions http2_protocol_options = 2; - // .. warning:: - // QUIC upstream support is currently not ready for internet use. - // Please see :ref:`here ` for details. config.core.v3.Http3ProtocolOptions http3_protocol_options = 3; } } @@ -90,9 +87,6 @@ message HttpProtocolOptions { config.core.v3.Http2ProtocolOptions http2_protocol_options = 2; - // .. warning:: - // QUIC upstream support is currently not ready for internet use. - // Please see :ref:`here ` for details. config.core.v3.Http3ProtocolOptions http3_protocol_options = 3; } @@ -111,14 +105,10 @@ message HttpProtocolOptions { config.core.v3.Http2ProtocolOptions http2_protocol_options = 2; // Unlike HTTP/1 and HTTP/2, HTTP/3 will not be configured unless it is - // present, and (soon) only if there is an indication of server side + // present, and only if there is an indication of server side // support. // See :ref:`here ` for more information on // when HTTP/3 will be used, and when Envoy will fail over to TCP. - // - // .. warning:: - // QUIC upstream support is currently not ready for internet use. - // Please see :ref:`here ` for details. config.core.v3.Http3ProtocolOptions http3_protocol_options = 3; // The presence of alternate protocols cache options causes the use of the diff --git a/api/src/main/proto/envoy/extensions/wasm/v3/wasm.proto b/api/src/main/proto/envoy/extensions/wasm/v3/wasm.proto index e8fea6725..0bc96ceca 100644 --- a/api/src/main/proto/envoy/extensions/wasm/v3/wasm.proto +++ b/api/src/main/proto/envoy/extensions/wasm/v3/wasm.proto @@ -71,7 +71,7 @@ message SanitizationConfig { } // Configuration for a Wasm VM. -// [#next-free-field: 8] +// [#next-free-field: 9] message VmConfig { // An ID which will be used along with a hash of the wasm code (or the name of the registered Null // VM plugin) to determine which VM will be used for the plugin. All plugins which use the same @@ -137,6 +137,12 @@ message VmConfig { // .. warning:: // Envoy rejects the configuration if there's conflict of key space. EnvironmentVariables environment_variables = 7; + + // Configuration for restricting Proxy-Wasm capabilities available to modules. + // + // The restrictions are applied when the VM is created and are shared by every plugin running in + // that VM, so they are a property of the VM rather than of an individual plugin. + CapabilityRestrictionConfig capability_restriction_config = 8; } message EnvironmentVariables { @@ -192,7 +198,14 @@ message PluginConfig { ReloadConfig reload_config = 8; // Configuration for restricting Proxy-Wasm capabilities available to modules. - CapabilityRestrictionConfig capability_restriction_config = 6; + // + // This field is deprecated in favor of the :ref:`vm_config.capability_restriction_config + // ` field, because + // the restrictions are applied to the Wasm VM and are therefore shared by every plugin running in + // it. If this field is set and ``vm_config.capability_restriction_config`` is not, this field is + // used to populate it. + CapabilityRestrictionConfig capability_restriction_config = 6 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // Whether or not to allow plugin onRequestHeaders and onResponseHeaders callbacks to return // FilterHeadersStatus::StopIteration. diff --git a/api/src/main/proto/envoy/extensions/watchdog/backtrace_action/v3/backtrace_action.proto b/api/src/main/proto/envoy/extensions/watchdog/backtrace_action/v3/backtrace_action.proto new file mode 100644 index 000000000..e1c957371 --- /dev/null +++ b/api/src/main/proto/envoy/extensions/watchdog/backtrace_action/v3/backtrace_action.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; + +package envoy.extensions.watchdog.backtrace_action.v3; + +import "google/protobuf/duration.proto"; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.watchdog.backtrace_action.v3"; +option java_outer_classname = "BacktraceActionProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/watchdog/backtrace_action/v3;backtrace_actionv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Watchdog Action that logs backtraces.] +// [#extension: envoy.watchdog.backtrace_action] + +// Configuration for the backtrace watchdog action. +// +// This action is currently only supported on Linux. +message BacktraceActionConfig { + // Minimum time between backtrace logs per thread. Defaults to 10 seconds if not set. + // Set to 0 to disable the cooldown and log a backtrace on every watchdog event. + google.protobuf.Duration cooldown_duration = 1; +} diff --git a/api/src/main/proto/envoy/service/auth/v3/external_auth.proto b/api/src/main/proto/envoy/service/auth/v3/external_auth.proto index 520a4ff4f..d612d0cb7 100644 --- a/api/src/main/proto/envoy/service/auth/v3/external_auth.proto +++ b/api/src/main/proto/envoy/service/auth/v3/external_auth.proto @@ -52,6 +52,8 @@ message DeniedHttpResponse { // This field allows the authorization service to send HTTP response headers // to the downstream client. Note that the :ref:`append field in HeaderValueOption ` defaults to // false when used in this message. + // The :ref:`keep_empty_value field in HeaderValueOption ` + // is not supported. repeated config.core.v3.HeaderValueOption headers = 2; // This field allows the authorization service to send a response body data @@ -72,6 +74,8 @@ message OkHttpResponse { // the filter will append the correspondent header value to the matched request header. // By leaving ``append`` as false, the filter will either add a new header, or override an existing // one if there is a match. + // The :ref:`keep_empty_value field in HeaderValueOption ` + // is not supported. repeated config.core.v3.HeaderValueOption headers = 2; // HTTP entity headers to remove from the original request before dispatching @@ -101,6 +105,8 @@ message OkHttpResponse { // This field allows the authorization service to send HTTP response headers // to the downstream client on success. Note that the :ref:`append field in HeaderValueOption ` // defaults to false when used in this message. + // The :ref:`keep_empty_value field in HeaderValueOption ` + // is not supported. repeated config.core.v3.HeaderValueOption response_headers_to_add = 6; // This field allows the authorization service to set (and overwrite) query diff --git a/api/src/main/proto/envoy/service/ext_proc/v3/external_processor.proto b/api/src/main/proto/envoy/service/ext_proc/v3/external_processor.proto index 3ba9d028e..38900bd17 100644 --- a/api/src/main/proto/envoy/service/ext_proc/v3/external_processor.proto +++ b/api/src/main/proto/envoy/service/ext_proc/v3/external_processor.proto @@ -6,6 +6,7 @@ import "envoy/config/core/v3/base.proto"; import "envoy/extensions/filters/http/ext_proc/v3/processing_mode.proto"; import "envoy/type/v3/http_status.proto"; +import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/struct.proto"; @@ -79,8 +80,66 @@ message ProtocolConfiguration { // This represents the different types of messages that the data plane can send // to an external processing server. -// [#next-free-field: 12] +// [#next-free-field: 14] message ProcessingRequest { + // Initial flow control window sizes for ``FULL_DUPLEX_STREAMED`` and + // ``GRPC`` body send modes. + // + // A sender starts with this amount of flow control window. Whenever + // it sends body data, it must decrement its flow control window by + // the number of bytes that it has sent. When its flow control + // window is less than or equal to the amount of body data it wishes + // to send, it may not send until it receives a window update causing + // its flow control window to be large enough. + // + // However, note that in ``GRPC`` body send mode, whenever the flow + // control window is greater than zero, a sender may send a single + // message, even if the size of that message exceeds the available flow + // control window. At that point, the flow control window will be negative + // and the sender must not send the next message until it becomes positive. + // + // Note that the initial size for the to-sidestream windows are set by + // the sender, not the receiver. This is because each sidestream may be + // routed to a different ext_proc server instance, but there is no + // connection-level handshake to set a default for that server + // instance, so the only alternative here would be to have the + // ext_proc server instance set this on a per-stream basis, which + // would require an additional round-trip and therefore hurt latency. + // This unfortunately means that the ext_proc server instance has a + // bit less control: as soon as it receives these initial values, it can + // immediately send a window update that reduces the window, but it + // must be prepared to handle any data that the sender has already sent. + // The initial sizes for the to-sidestream windows are generally + // expected to be in the range of 32K to 64K. + // + // [#not-implemented-hide:] + message FlowControlInit { + // Downstream-to-sidestream initial window size. + int64 initial_window_downstream_to_sidestream = 1; + + // Sidestream-to-upstream initial window size. + int64 initial_window_sidestream_to_upstream = 2; + + // Upstream-to-sidestream initial window size. + int64 initial_window_upstream_to_sidestream = 3; + + // Sidestream-to-downstream initial window size. + int64 initial_window_sidestream_to_downstream = 4; + } + + // Flow control window update. Values may be positive or negative. The + // sender must immediately add these values to its flow control window, + // which governs how much data can be sent. + // + // [#not-implemented-hide:] + message ClientWindowUpdate { + // Window update for sidestream-to-upstream. + int64 window_increment_sidestream_to_upstream = 1; + + // Window update for sidestream-to-downstream. + int64 window_increment_sidestream_to_downstream = 2; + } + reserved 1; reserved "async_mode"; @@ -89,8 +148,6 @@ message ProcessingRequest { // ones are set for a particular HTTP request/response depend on the // processing mode. oneof request { - option (validate.required) = true; - // Information about the HTTP request headers, as well as peer info and additional // properties. Unless ``observability_mode`` is ``true``, the server must send back a // ``HeaderResponse`` message, an ``ImmediateResponse`` message, or close the stream. @@ -148,6 +205,32 @@ message ProcessingRequest { // Specify the filter protocol configurations to be sent to the server. // ``protocol_config`` is only encoded in the first ``ProcessingRequest`` message from the client to the server. ProtocolConfiguration protocol_config = 11; + + // Flow control initialization for ``FULL_DUPLEX_STREAMED`` and + // ``GRPC`` body send modes. + // + // Must be set in the initial message on the stream. Not used in + // subsequent messages. + // + // [#not-implemented-hide:] + FlowControlInit flow_control_init = 12; + + // Flow control updates for ``FULL_DUPLEX_STREAMED`` and ``GRPC`` body + // send modes. + // + // This message may be included in a request message that also + // populates one of the fields in the ``request`` oneof above, or it + // may be sent in a request message that does not set the + // ``request`` oneof. + // + // In ``FULL_DUPLEX_STREAMED`` body send mode, for backward + // compatibility with data planes that do not yet support flow control, + // the data plane must not send a message containing only this field + // (i.e., not setting the ``request`` oneof) unless the ext_proc server + // has sent a window update, thus indicating that it supports flow control. + // + // [#not-implemented-hide:] + ClientWindowUpdate client_window_update = 13; } // This represents the different types of messages the server may send back to the data plane @@ -159,12 +242,23 @@ message ProcessingRequest { // the server must send back exactly one ``ProcessingResponse`` message. // * If it is set to ``FULL_DUPLEX_STREAMED``, the server must follow the API defined // for this mode to send the ``ProcessingResponse`` messages. -// [#next-free-field: 13] +// [#next-free-field: 17] message ProcessingResponse { + // Flow control window update. Values may be positive or negative. The + // sender must immediately add these values to its flow control window, + // which governs how much data can be sent. + // + // [#not-implemented-hide:] + message ServerWindowUpdate { + // Window update for downstream-to-sidestream. + int64 window_increment_downstream_to_sidestream = 1; + + // Window update for upstream-to-sidestream. + int64 window_increment_upstream_to_sidestream = 2; + } + // The response type that is sent by the server. oneof response { - option (validate.required) = true; - // The server must send back this message in response to a message with the // ``request_headers`` field set. HeadersResponse request_headers = 1; @@ -220,31 +314,139 @@ message ProcessingResponse { // field name(s) of the struct. google.protobuf.Struct dynamic_metadata = 8; + // Optional typed metadata that will be emitted as dynamic metadata to be consumed by + // following filters. This metadata will be placed in the namespace(s) specified by the + // keys of the map. + // + // Typed dynamic metadata should be preferred over untyped dynamic metadata (``dynamic_metadata``) + // because it is more efficient and more type-safe. + map typed_dynamic_metadata = 13; + // Override how parts of the HTTP request and response are processed for the duration of this // particular request/response only. Servers may use this to intelligently control how requests // are processed based on the headers and other metadata that they see. // - // This field is only applicable when servers are responding to the header requests. If it is set - // in the response to the body or trailer requests, it will be ignored by the data plane. + // If set in a response to body or trailer requests, it will be ignored by the data plane. // It is also ignored by the data plane when the ext_proc filter config // :ref:`allow_mode_override ` // is set to ``false``, or // :ref:`send_body_without_waiting_for_header_response ` // is set to ``true``. + // + // ``mode_override`` can be sent in the following scenarios: + // + // 1. Included in a header response: + // The server can set this field when responding to request or response headers, i.e., + // alongside a ``request_headers`` or ``response_headers`` response. + // + // 2. Standalone ``mode_override`` response: + // After receiving a ``ProcessingRequest`` for request headers, the server can send a + // standalone ``mode_override`` response (i.e., a ``ProcessingResponse`` with only + // ``mode_override`` populated and no ``response`` case set) before sending the + // ``request_headers`` response. Subsequent messages will adhere to this new mode. + // + // .. note:: + // Processing mode changes in a standalone ``mode_override`` have the following constraints: + // + // * For request path: Only supports transitioning the request body processing mode from + // ``NONE`` or ``STREAMED`` to ``FULL_DUPLEX_STREAMED``. Additionally, the request + // trailer mode must be set to ``SEND``, which is required by ``FULL_DUPLEX_STREAMED`` + // mode. Responses that do not meet these constraints are treated as spurious and rejected. + // * For Response path: There are no restrictions on processing mode changes. + // envoy.extensions.filters.http.ext_proc.v3.ProcessingMode mode_override = 9; // [#not-implemented-hide:] - // Used only in ``FULL_DUPLEX_STREAMED`` and ``GRPC`` body send modes. - // Instructs the data plane to stop sending body data and to send a - // half-close on the ext_proc stream. The ext_proc server should then echo - // back all subsequent body contents as-is until it sees the client's - // half-close, at which point the ext_proc server can terminate the stream - // with an OK status. This provides a safe way for the ext_proc server - // to indicate that it does not need to see the rest of the stream; - // without this, the ext_proc server could not terminate the stream - // early, because it would wind up dropping any body contents that the - // client had already sent before it saw the ext_proc stream termination. - bool request_drain = 12; + // Deprecated and not implemented. This field has been replaced with + // the request_drain_requests and request_drain_responses fields. + bool request_drain = 12 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; + + // [#not-implemented-hide:] + // Initiates a drain of request body data. Used only in + // ``FULL_DUPLEX_STREAMED`` and ``GRPC`` body send modes. + // + // The expected sequence for a drain is as follows: + // + // 1. The ext_proc server sends a message to the data plane with this + // field set to true. + // 2. The data plane pauses reading from the downstream client, applying + // any necessary flow control push-back. + // 3. The data plane sends a + // :ref:`request_body ` + // with the + // :ref:`drain_complete ` + // field set to true. + // 4. The ext_proc server continues processing all subsequent request body + // chunks until it sees the body chunk with the + // :ref:`drain_complete ` + // field set to true. When sending back its response to that last body + // chunk, the ext_proc server will set the + // :ref:`drain_complete ` + // field to true to let the data plane know that it has finished draining. + // 5. When the data plane sees the response with the + // :ref:`drain_complete ` + // field set to true, it will resume reading from the downstream + // client, passing all data directly to the upstream server, + // without going through the ext_proc sidestream. + // + // This procedure provides a safe way for the ext_proc server to indicate + // that it does not need to see the rest of the request body. + // + // Note that if the data plane is sending request body data and the + // ext_proc server wants to terminate the stream with an OK status, it + // must perform this drain before doing so. + // + // Note that the data plane may have either sent a body chunk with + // :ref:`end_of_stream ` + // set to true or may have sent trailers before it received the drain + // request from the ext_proc server. In these cases, the data plane will + // ignore the drain request, and the ext_proc will consider the drain + // complete when it sees the end-of-stream or trailers. + bool request_drain_requests = 15; + + // [#not-implemented-hide:] + // Initiates a drain of response body data. Used only in + // ``FULL_DUPLEX_STREAMED`` and ``GRPC`` body send modes. + // + // The expected sequence for a drain is as follows: + // + // 1. The ext_proc server sends a message to the data plane with this + // field set to true. + // 2. The data plane pauses reading from the upstream server, applying + // any necessary flow control push-back. + // 3. The data plane sends a + // :ref:`response_body ` + // with the + // :ref:`drain_complete ` + // field set to true. + // 4. The ext_proc server continues processing all subsequent response body + // chunks until it sees the body chunk with the + // :ref:`drain_complete ` + // field set to true. When sending back its response to that last body + // chunk, the ext_proc server will set the + // :ref:`drain_complete ` + // field to true to let the data plane know that it has finished draining. + // 5. When the data plane sees the response with the + // :ref:`drain_complete ` + // field set to true, it will resume reading from the upstream + // server, passing all data directly to the downstream client, + // without going through the ext_proc sidestream. + // + // This procedure provides a safe way for the ext_proc server to indicate + // that it does not need to see the rest of the response body. + // + // Note that if the data plane is sending response body data and the + // ext_proc server wants to terminate the stream with an OK status, it + // must perform this drain before doing so. + // + // Note that the data plane may have either sent a body chunk with + // :ref:`end_of_stream ` + // set to true or may have sent trailers before it received the drain + // request from the ext_proc server. In these cases, the data plane will + // ignore the drain request, and the ext_proc will consider the drain + // complete when it sees the end-of-stream or trailers. + bool request_drain_responses = 16; // When the ext_proc server receives a request message and needs more time to process it, it // sends back a ``ProcessingResponse`` message with a new timeout value. When the data plane @@ -259,6 +461,29 @@ message ProcessingResponse { // Such a message can be sent at most once in a particular data plane ext_proc filter processing // state. To enable this API, ``max_message_timeout`` must be set to a value >= 1ms. google.protobuf.Duration override_message_timeout = 10; + + // Flow control updates for ``FULL_DUPLEX_STREAMED`` and ``GRPC`` body + // send modes. + // + // This message may be included in a response message that also + // populates one of the fields in the ``response`` oneof above, or it + // may be sent in a response message that does not set the + // ``response`` oneof. + // + // In ``FULL_DUPLEX_STREAMED`` body send mode, for backward + // compatibility with data planes that do not yet support flow control, + // the ext_proc server must not set this field unless the data plane + // sent initial window sizes in its initial message on the stream. + // Conversely, if the data plane did send initial window sizes in its + // initial message on the stream, the ext_proc server must send a + // window update immediately to let the data plane know that it also + // supports flow control. If the ext_proc server is sending a message + // immediately anyway (e.g., for a header or body chunk), it can include + // this field in that same message; otherwise, the ext_proc server must + // send a message containing only this field. + // + // [#not-implemented-hide:] + ServerWindowUpdate server_window_update = 14; } // The following are messages that are sent to the server. @@ -283,6 +508,7 @@ message HttpHeaders { // This message is sent to the external server when the HTTP request and response bodies are // received. +// [#next-free-field: 6] message HttpBody { // The contents of the body in the HTTP request/response. Note that in streaming mode multiple // ``HttpBody`` messages may be sent. @@ -295,16 +521,31 @@ message HttpBody { // will be sent for the current request/response. bool end_of_stream = 2; - // This field is used in ``GRPC`` body send mode when ``end_of_stream`` is ``true`` and ``body`` - // is empty. Those values would normally indicate an empty message on the stream with the - // end-of-stream bit set. However, if the half-close happens after the last message on the stream - // was already sent, then this field will be ``true`` to indicate an end-of-stream with *no* - // message (as opposed to an empty message). + // This field is used only in ``GRPC`` body send mode. It is not used in any other body send + // mode. + // + // This field is used only when ``end_of_stream`` is true and ``body`` is empty. + // Normally, in ``GRPC`` body send mode, an empty ``body`` field indicates an empty message on + // the gRPC stream. However, it is possible that the gRPC client sends a half-close without + // actually sending a message on the stream, so we need a way to differentiate between + // an empty message being sent and no message being sent. If this field is true, then it + // indicates that no message has been sent; if it is false, then it indicates that an empty + // message has been sent. + // [#not-implemented-hide:] bool end_of_stream_without_message = 3; // This field is used in ``GRPC`` body send mode to indicate whether the message is compressed. // This will never be set to ``true`` by gRPC but may be set to ``true`` by a proxy like Envoy. bool grpc_message_compressed = 4; + + // [#not-implemented-hide:] + // In ``FULL_DUPLEX_STREAMED`` or ``GRPC`` body send modes, if the + // data plane has seen the + // :ref:`request_drain_requests ` + // or :ref:`request_drain_responses ` + // field, it will populate this field to indicate that it has finished + // sending data to the ext_proc server. + bool drain_complete = 5; } // This message is sent to the external server when the HTTP request and @@ -457,6 +698,10 @@ message HeaderMutation { // ``:authority``, ``:scheme``, or ``host`` headers will be ignored. // The header value is encoded in the // :ref:`raw_value ` field. + // Note that the :ref:`append field in HeaderValueOption ` + // defaults to false when used in this message. + // The :ref:`keep_empty_value field in HeaderValueOption ` + // is not supported. repeated config.core.v3.HeaderValueOption set_headers = 1; // Remove these HTTP headers. Attempts to remove system headers -- @@ -465,6 +710,7 @@ message HeaderMutation { } // The body response message corresponding to ``FULL_DUPLEX_STREAMED`` or ``GRPC`` body modes. +// [#next-free-field: 6] message StreamedBodyResponse { // In ``FULL_DUPLEX_STREAMED`` body send mode, contains the body response chunk that will be // passed to the upstream/downstream by the data plane. In ``GRPC`` body send mode, contains @@ -480,16 +726,35 @@ message StreamedBodyResponse { // messages sent by the client application. bool end_of_stream = 2; - // This field is used in ``GRPC`` body send mode when ``end_of_stream`` is ``true`` and ``body`` - // is empty. Those values would normally indicate an empty message on the stream with the - // end-of-stream bit set. However, if the half-close happens after the last message on the stream - // was already sent, then this field will be ``true`` to indicate an end-of-stream with *no* - // message (as opposed to an empty message). + // This field is used only in ``GRPC`` body send mode. It is not used in any other body send + // mode. + // + // This field is used only when ``end_of_stream`` is true and ``body`` is empty. + // Normally, in ``GRPC`` body send mode, an empty ``body`` field indicates an empty message on + // the gRPC stream. However, it is possible that the gRPC client sends a half-close without + // actually sending a message on the stream, so we need a way to differentiate between + // an empty message being sent and no message being sent. If this field is true, then it + // indicates that no message has been sent; if it is false, then it indicates that an empty + // message has been sent. + // [#not-implemented-hide:] bool end_of_stream_without_message = 3; // This field is used in ``GRPC`` body send mode to indicate whether the message is compressed. // This will never be set to ``true`` by gRPC but may be set to ``true`` by a proxy like Envoy. bool grpc_message_compressed = 4; + + // [#not-implemented-hide:] + // In ``FULL_DUPLEX_STREAMED`` or ``GRPC`` body send modes, if the + // ext_proc server has seen the + // :ref:`drain_complete ` + // field, it will populate this field to indicate that it has finished + // sending data back to the data plane. + // + // If the data plane receives a message with this field set to true + // before it has sent a drain-complete message to the ext_proc server, + // the data plane will treat that as if the ext_proc stream has failed + // with a non-OK status. + bool drain_complete = 5; } // This message specifies the body mutation the server sends to the data plane. diff --git a/api/src/main/proto/envoy/service/network_ext_proc/v3/network_external_processor.proto b/api/src/main/proto/envoy/service/network_ext_proc/v3/network_external_processor.proto index e2cb83131..76dffcda4 100644 --- a/api/src/main/proto/envoy/service/network_ext_proc/v3/network_external_processor.proto +++ b/api/src/main/proto/envoy/service/network_ext_proc/v3/network_external_processor.proto @@ -71,7 +71,7 @@ message Data { // ProcessingRequest contains data sent from Envoy to the external processing server. // Each request contains either read data (from client) or write data (to client) -// along with optional metadata. +// along with optional metadata and attributes. message ProcessingRequest { // ReadData contains the network data intercepted in the request path (client to server). // This is sent to the external processor when data arrives from the downstream client. @@ -90,6 +90,11 @@ message ProcessingRequest { // The metadata is not automatically propagated from request to response. // The external processor must include any needed metadata in its response. config.core.v3.Metadata metadata = 3; + + // The values of properties selected by the ``connection_attributes`` + // list in the configuration. Each entry in the list is populated + // from the standard :ref:`attributes ` supported in the data plane. + map attributes = 4; } // ProcessingResponse contains the response from the external processing server to Envoy. diff --git a/api/src/main/proto/envoy/service/rate_limit_quota/v3/rlqs.proto b/api/src/main/proto/envoy/service/rate_limit_quota/v3/rlqs.proto index b8fa2cd89..cb65948f6 100644 --- a/api/src/main/proto/envoy/service/rate_limit_quota/v3/rlqs.proto +++ b/api/src/main/proto/envoy/service/rate_limit_quota/v3/rlqs.proto @@ -6,8 +6,6 @@ import "envoy/type/v3/ratelimit_strategy.proto"; import "google/protobuf/duration.proto"; -import "xds/annotations/v3/status.proto"; - import "udpa/annotations/status.proto"; import "validate/validate.proto"; @@ -16,7 +14,6 @@ option java_outer_classname = "RlqsProto"; option java_multiple_files = true; option go_package = "github.com/envoyproxy/go-control-plane/envoy/service/rate_limit_quota/v3;rate_limit_quotav3"; option (udpa.annotations.file_status).package_version_status = ACTIVE; -option (xds.annotations.v3.file_status).work_in_progress = true; // [#protodoc-title: Rate Limit Quota Service (RLQS)] diff --git a/api/src/main/proto/envoy/service/ratelimit/v3/rls.proto b/api/src/main/proto/envoy/service/ratelimit/v3/rls.proto index 8399255fe..8f2d080a8 100644 --- a/api/src/main/proto/envoy/service/ratelimit/v3/rls.proto +++ b/api/src/main/proto/envoy/service/ratelimit/v3/rls.proto @@ -8,6 +8,7 @@ import "envoy/extensions/common/ratelimit/v3/ratelimit.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; @@ -112,6 +113,10 @@ message RateLimitResponse { // The unit of time. Unit unit = 2; + + // The number of units in the rate limit period. For example, a value of ``10`` with a unit + // of ``MINUTE`` specifies a 10-minute rate limit period. If not specified, defaults to ``1``. + google.protobuf.UInt32Value unit_multiplier = 4 [(validate.rules).uint32 = {gt: 0}]; } // Cacheable quota for responses. diff --git a/api/src/main/proto/envoy/type/ai/v3/llm_protocol.proto b/api/src/main/proto/envoy/type/ai/v3/llm_protocol.proto new file mode 100644 index 000000000..46d2949e8 --- /dev/null +++ b/api/src/main/proto/envoy/type/ai/v3/llm_protocol.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +package envoy.type.ai.v3; + +import "xds/annotations/v3/status.proto"; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.type.ai.v3"; +option java_outer_classname = "LlmProtocolProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/type/ai/v3;aiv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; +option (xds.annotations.v3.file_status).work_in_progress = true; + +// [#protodoc-title: LLM protocol] + +// Identifies the AI API contract spoken on the wire. +// +// This names request/response schemas and streaming event semantics, not the +// organization operating the backend: OpenAI, Azure OpenAI, vLLM, and any +// other OpenAI-compatible backend all speak ``OPENAI_CHAT_COMPLETIONS``. +// Provider identity, when needed, must come from configuration or routing +// metadata. +// +// Response framing is separate: JSON, SSE, and streamed JSON-array variants +// of the same API share one ``LLMProtocol`` value. +enum LLMProtocol { + LLM_PROTOCOL_UNSPECIFIED = 0; + + // OpenAI-compatible ``/v1/chat/completions`` API. + OPENAI_CHAT_COMPLETIONS = 1; + + // OpenAI-compatible ``/v1/responses`` API. + OPENAI_RESPONSES = 2; + + // Anthropic-compatible ``/v1/messages`` API. + ANTHROPIC_MESSAGES = 3; + + // Gemini ``generateContent`` / ``streamGenerateContent`` APIs. + GEMINI_GENERATE_CONTENT = 4; +} diff --git a/api/src/main/proto/envoy/type/metadata/v3/metadata.proto b/api/src/main/proto/envoy/type/metadata/v3/metadata.proto index d131635bf..2a6192924 100644 --- a/api/src/main/proto/envoy/type/metadata/v3/metadata.proto +++ b/api/src/main/proto/envoy/type/metadata/v3/metadata.proto @@ -41,7 +41,8 @@ message MetadataKey { option (udpa.annotations.versioning).previous_message_type = "envoy.type.metadata.v2.MetadataKey"; // Specifies a segment in a path for retrieving values from Metadata. - // Currently, only key-based segments (field names) are supported. + // Supports both key-based segments (field names in a Struct) and index-based + // segments (element access in a ListValue). message PathSegment { option (udpa.annotations.versioning).previous_message_type = "envoy.type.metadata.v2.MetadataKey.PathSegment"; @@ -51,6 +52,9 @@ message MetadataKey { // If specified, use this key to retrieve the value in a Struct. string key = 1 [(validate.rules).string = {min_len: 1}]; + + // If specified, use this index to retrieve a value from a ListValue. + uint32 index = 2; } } @@ -60,12 +64,12 @@ message MetadataKey { // The path used to retrieve a specific Value from the Struct. // This can be either a prefix or a full path, depending on the use case. - // For example, ``[prop, xyz]`` would retrieve a struct or ``[prop, foo]`` would retrieve a string - // in the example above. + // For example, ``[{key: prop}, {key: xyz}]`` would retrieve a struct or ``[{key: prop}, {key: foo}]`` + // would retrieve a string in the example above. // - // .. note:: - // Since only key-type segments are supported, a path cannot specify a list - // unless the list is the last segment. + // Path segments support both struct field access (via ``key``) and list element access (via ``index``). + // For example, to access the first element of a list at ``envoy.filters.http.grpc_field_extraction.tenant_id``, + // use ``path: [{key: tenant_id}, {index: 0}]``. repeated PathSegment path = 2 [(validate.rules).repeated = {min_items: 1}]; } diff --git a/api/src/main/proto/envoy/type/tracing/v3/custom_tag.proto b/api/src/main/proto/envoy/type/tracing/v3/custom_tag.proto index cdb42a435..f89dca111 100644 --- a/api/src/main/proto/envoy/type/tracing/v3/custom_tag.proto +++ b/api/src/main/proto/envoy/type/tracing/v3/custom_tag.proto @@ -17,10 +17,44 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // [#protodoc-title: Custom Tag] // Describes custom tags for the active span. -// [#next-free-field: 7] +// [#next-free-field: 8] message CustomTag { option (udpa.annotations.versioning).previous_message_type = "envoy.type.tracing.v2.CustomTag"; + // Specifies how the resolved tag value should be typed on tracers that support + // typed span attributes (e.g. OpenTelemetry). The integer and floating-point + // cases are declared explicitly so the emitted attribute type is deterministic + // rather than inferred from the value. + enum ValueType { + // The value type is not set. Behaves like ``STRING``; the distinct default + // value lets consumers tell an unset ``value_type`` apart from an explicit + // ``STRING``. + UNSPECIFIED = 0; + + // Emit the tag value as a string. + STRING = 1; + + // Coerce the resolved tag value to a signed 64-bit integer. Tracers that + // support typed span attributes emit it as a native integer attribute (for + // OpenTelemetry, an OTLP ``int_value``). If the value does not parse as an + // integer, or the tracer has no typed-attribute support, it falls back to a + // string tag. + INT = 2; + + // Coerce the resolved tag value to a double. Tracers that support typed span + // attributes emit it as a native floating-point attribute (for OpenTelemetry, + // an OTLP ``double_value``). If the value does not parse as a double, or the + // tracer has no typed-attribute support, it falls back to a string tag. + DOUBLE = 3; + + // Coerce the resolved tag value to a boolean. Tracers that support typed span + // attributes emit it as a native boolean attribute (for OpenTelemetry, an OTLP + // ``bool_value``). Accepts the usual boolean spellings (``true``/``false``, + // ``1``/``0``, etc.). If the value does not parse as a boolean, or the tracer + // has no typed-attribute support, it falls back to a string tag. + BOOL = 4; + } + // Literal type custom tag with static value for the tag value. message Literal { option (udpa.annotations.versioning).previous_message_type = @@ -106,4 +140,11 @@ message CustomTag { // unknown specifier values are replaced with the empty string instead of ``-``. string value = 6; } + + // The value's type. When unset (``UNSPECIFIED``) or ``STRING`` the tag keeps the + // preexisting string behavior. When set to ``INT``, ``DOUBLE`` or ``BOOL``, tracers + // that support typed span attributes (e.g. OpenTelemetry) emit the tag as an + // integer, floating-point or boolean attribute instead of a string. Applies to + // every custom tag type. + ValueType value_type = 7 [(validate.rules).enum = {defined_only: true}]; } diff --git a/api/src/main/proto/envoy/type/v3/http.proto b/api/src/main/proto/envoy/type/v3/http.proto index a1a5a04fc..c53c2be3e 100644 --- a/api/src/main/proto/envoy/type/v3/http.proto +++ b/api/src/main/proto/envoy/type/v3/http.proto @@ -14,11 +14,6 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; enum CodecClientType { HTTP1 = 0; - HTTP2 = 1; - - // [#not-implemented-hide:] QUIC implementation is not production ready yet. Use this enum with - // caution to prevent accidental execution of QUIC code. I.e. `!= HTTP2` is no longer sufficient - // to distinguish HTTP1 and HTTP2 traffic. HTTP3 = 2; } diff --git a/api/src/main/proto/google/api/annotations.proto b/api/src/main/proto/google/api/annotations.proto index 84c48164a..417edd8fa 100644 --- a/api/src/main/proto/google/api/annotations.proto +++ b/api/src/main/proto/google/api/annotations.proto @@ -1,4 +1,4 @@ -// Copyright 2024 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/api/src/main/proto/google/api/expr/v1alpha1/checked.proto b/api/src/main/proto/google/api/expr/v1alpha1/checked.proto index c68493485..ffdbee5fa 100644 --- a/api/src/main/proto/google/api/expr/v1alpha1/checked.proto +++ b/api/src/main/proto/google/api/expr/v1alpha1/checked.proto @@ -1,4 +1,4 @@ -// Copyright 2024 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/api/src/main/proto/google/api/expr/v1alpha1/syntax.proto b/api/src/main/proto/google/api/expr/v1alpha1/syntax.proto index 7b6668db1..b0cdd4d44 100644 --- a/api/src/main/proto/google/api/expr/v1alpha1/syntax.proto +++ b/api/src/main/proto/google/api/expr/v1alpha1/syntax.proto @@ -1,4 +1,4 @@ -// Copyright 2024 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/api/src/main/proto/google/api/http.proto b/api/src/main/proto/google/api/http.proto index e3270371d..57621b537 100644 --- a/api/src/main/proto/google/api/http.proto +++ b/api/src/main/proto/google/api/http.proto @@ -1,4 +1,4 @@ -// Copyright 2024 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ syntax = "proto3"; package google.api; -option cc_enable_arenas = true; option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; option java_multiple_files = true; option java_outer_classname = "HttpProto"; diff --git a/api/src/main/proto/google/rpc/status.proto b/api/src/main/proto/google/rpc/status.proto index 90b70ddf9..dc14c9438 100644 --- a/api/src/main/proto/google/rpc/status.proto +++ b/api/src/main/proto/google/rpc/status.proto @@ -1,4 +1,4 @@ -// Copyright 2024 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/server/src/test/java/io/envoyproxy/controlplane/server/EnvoyContainer.java b/server/src/test/java/io/envoyproxy/controlplane/server/EnvoyContainer.java index b36c7a83e..99f8fdb16 100644 --- a/server/src/test/java/io/envoyproxy/controlplane/server/EnvoyContainer.java +++ b/server/src/test/java/io/envoyproxy/controlplane/server/EnvoyContainer.java @@ -24,7 +24,7 @@ class EnvoyContainer extends GenericContainer { EnvoyContainer(String config, Supplier controlPlanePortSupplier) { // this version is changed automatically by /tools/update-sha.sh:57 // if you change it make sure to reflect changes there - super("envoyproxy/envoy:v1.39.4"); + super("envoyproxy/envoy:v1.40.2"); this.config = config; this.controlPlanePortSupplier = controlPlanePortSupplier; } diff --git a/tools/API_SHAS b/tools/API_SHAS index f21b4e8ea..c018f25f0 100644 --- a/tools/API_SHAS +++ b/tools/API_SHAS @@ -1,12 +1,12 @@ # Update the versions here and run update-api.sh # envoy (source: SHA from https://github.com/envoyproxy/envoy) -ENVOY_SHA="72315c132d462e5126e492ab2a71057565dbc87a" +ENVOY_SHA="b2d89e0ae53916f28770771fbdd49c5c99c5c5a2" -# dependencies (source: https://github.com/envoyproxy/envoy/blob/72315c132d462e5126e492ab2a71057565dbc87a/api/bazel/repository_locations.bzl) -GOOGLEAPIS_SHA="fd52b5754b2b268bc3a22a10f29844f206abb327" # -PGV_VERSION="1.3.3" # -PROMETHEUS_SHA="0.6.2" # -OPENTELEMETRY_VERSION="1.10.0" # -CEL_VERSION="0.25.1" # -XDS_SHA="8bfbf64dc13ee1a570be4fbdcfccbdd8532463f0" # +# dependencies (source: https://github.com/envoyproxy/envoy/blob/b2d89e0ae53916f28770771fbdd49c5c99c5c5a2/api/MODULE.bazel.lock) +GOOGLEAPIS_SHA="2193a2bfcecb92b92aad7a4d81baa428cafd7dfd" +PGV_VERSION="1.3.3" +PROMETHEUS_SHA="0.6.2" +OPENTELEMETRY_VERSION="1.10.0" # Pinned for API compatibility. +CEL_VERSION="0.25.1" # Pinned for API compatibility. +XDS_SHA="ee656c7534f5d7dc23d44dd611689568f72017a6" diff --git a/tools/envoy_release b/tools/envoy_release index 64110c405..ae892d8a6 100644 --- a/tools/envoy_release +++ b/tools/envoy_release @@ -1 +1 @@ -v1.39.4 +v1.40.2