reverse_tunnel: add access logging support for initiator bootstrap extension (#44326)
commit f3ad716 ↗ · envoyproxy/envoy · · committed Jun 11, 2026 · +434−30 · base aa35acd6e4a9
Agent prompt
what a new run launched now would send
The reverse tunnel initiator (downstream bootstrap extension) currently has no access logging. Operators only get stats counters and debug ENVOY_LOG traces, which are not suitable for production monitoring or auditing of when reverse tunnels are established, when handshakes fail, or when connections close.
Add configurable access logging to the initiator bootstrap extension so operators get structured visibility into reverse-tunnel lifecycle events.
Requirements a teammate would be expected to meet:
1. Extend the DownstreamReverseConnectionSocketInterface bootstrap config with an optional repeated access_log field (standard Envoy access log configs: file, stdout, gRPC, etc.).
2. Instantiate configured access loggers when the initiator extension is created.
3. Emit an access log entry at each of these lifecycle points on the initiator connection path:
- handshake_success — reverse tunnel handshake completed successfully
- handshake_failure — reverse tunnel handshake failed (include failure reason)
- connection_closed — an established reverse tunnel connection was torn down
4. Each log entry must expose reverse-tunnel metadata as dynamic metadata under the namespace envoy.reverse_tunnel.initiator, usable via %DYNAMIC_METADATA(envoy.reverse_tunnel.initiator:...)% format strings, with at least these string fields: event, node_id, cluster_id, tenant_id, upstream_cluster, host_address, connection_key, and error (error populated on handshake_failure; empty string otherwise; field still present on non-failure events). node_id / cluster_id / tenant_id come from the initiator’s src_* identity; upstream_cluster and host_address identify the target; connection_key correlates handshake and close for the same connection.
5. Follow the same approach used elsewhere in Envoy for non-HTTP access logging (e.g. TCP proxy): create an ephemeral StreamInfo per log entry, populate dynamic metadata, then call each configured logger. Emitting must be a no-op when no access logs are configured.
6. Cover the new behavior with unit tests (empty config, no-op emit, metadata contents including error and empty optional fields, multiple loggers, namespace).
7. Document initiator access logging and update the initiator example config to show a working access_log configuration.
Do not change unrelated reverse-tunnel behavior beyond what is needed for this observability feature.
Interface contract — the change must expose exactly this surface:
DownstreamReverseConnectionSocketInterface gains repeated config.accesslog.v3.AccessLog access_log = 4. ReverseTunnelInitiatorExtension must expose const AccessLog::InstanceSharedPtrVector& accessLogs() const and void emitAccessLog(TimeSource&, const std::string& event, const std::string& node_id, const std::string& cluster_id, const std::string& tenant_id, const std::string& upstream_cluster, const std::string& host_address, const std::string& connection_key, const std::string& error_message) that logs via StreamInfo dynamic metadata filter envoy.reverse_tunnel.initiator with string fields event, node_id, cluster_id, tenant_id, upstream_cluster, host_address, connection_key, error. Tests may inject mock loggers into the extension’s access_logs_ (friend/test hook).
Work only inside this repository checkout. Make the code change the task
describes, keeping the diff focused — no drive-by refactors.
When you are done, leave your changes committed or in the working tree;
they are collected automatically.
Stay on this snapshot checkout (`task/ycb_envoy_cf3ad7169047a`). Never checkout, pull, or rebase onto `main`. That branch is a README-only orphan.
Stay on this HEAD. Do not fetch another default branch. Push only on the Cursor-created `crazy-cursor/…` side branch from this HEAD.
Some past runs of this task were launched with a different prompt (the prompt template changed since, or those runs predate this benchmark's stored prompt). Each run persists the exact prompt it sent at launch — that per-launch record is the audit trail; this page shows only the current one.
Reference diff
The task commit's diff against its first parent — the judge's comparison target.