#[non_exhaustive]pub enum InboundTracePolicy {
Continue,
Restart,
Drop,
}Expand description
What this deployment does with a traceparent an unauthenticated peer
sent it.
§The threat this exists for
The inbound trace is joined while the request’s CallContext is built,
which runs before the interceptor chain — and the interceptor chain is
where authentication happens. So on a public endpoint the peer choosing
the trace-id and the sampling bit is, at that moment, anonymous.
W3C Trace Context §7.2 “Denial of
Service” names
exactly this: “When distributed tracing is enabled on a service with a
public API and naively continues any trace with the sampled flag set, a
malicious attacker could overwhelm an application with tracing overhead,
forge trace-id collisions that make monitoring data unusable, or run up
your tracing bill with your SaaS tracing vendor.” Its own suggested
remedy is “different tracing behavior for authenticated and
unauthenticated requests”.
§3.4 names the mutation that implements it: “Restart trace: All properties (trace-id, parent-id, trace-flags) are regenerated. This mutation is used in services that are defined as a front gate into secure networks and eliminates a potential denial-of-service attack surface. Vendors SHOULD clean up tracestate collection on traceparent restart.”
Set per handler with
RequestHandlerBuilder::with_inbound_trace_policy,
so a process serving both a public front gate and an internal endpoint can
hold a different policy on each.
§Why Continue is still the default
A2A’s premise is a mesh of agents delegating to one another, and one trace id surviving every hop is the only thing that makes such a chain readable. Restarting by default would sever every chain to protect the deployments that are front gates, which are the minority. A front gate opts in.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Continue
Join the peer’s trace: same trace-id, a fresh span. The right answer
inside a trusted mesh, and the historical behaviour.
Restart
Restart the trace, per §3.4: mint a new trace-id and parent-id,
reset trace-flags, and drop tracestate — the peer controls none of
it. The request still carries a trace, so this hop and everything
below it remain correlated; what is severed is the attacker’s ability
to choose the identifier or the sampling decision.
Drop
Refuse to trace an untrusted request at all. Cheaper than
Restart — nothing is minted and nothing is
recorded — and appropriate where the tracing bill, not the trace tree,
is the thing being protected.
Trait Implementations§
Source§impl Clone for InboundTracePolicy
impl Clone for InboundTracePolicy
Source§fn clone(&self) -> InboundTracePolicy
fn clone(&self) -> InboundTracePolicy
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for InboundTracePolicy
Source§impl Debug for InboundTracePolicy
impl Debug for InboundTracePolicy
Source§impl Default for InboundTracePolicy
impl Default for InboundTracePolicy
Source§fn default() -> InboundTracePolicy
fn default() -> InboundTracePolicy
impl Eq for InboundTracePolicy
Source§impl PartialEq for InboundTracePolicy
impl PartialEq for InboundTracePolicy
impl StructuralPartialEq for InboundTracePolicy
Auto Trait Implementations§
impl Freeze for InboundTracePolicy
impl RefUnwindSafe for InboundTracePolicy
impl Send for InboundTracePolicy
impl Sync for InboundTracePolicy
impl Unpin for InboundTracePolicy
impl UnsafeUnpin for InboundTracePolicy
impl UnwindSafe for InboundTracePolicy
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
Source§fn with_current_context(self) -> WithContext<Self> ⓘ
fn with_current_context(self) -> WithContext<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request