Skip to content

Commit 935deec

Browse files
authored
[ASM] Standalone Billing (part 2: Propagation) (#5743)
## Summary of changes Part 2 of the implementation of [Standalone ASM billing](https://docs.google.com/document/d/12NBx-nD-IoQEMiCRnJXneq4Be7cbtSc6pJLOFUWTpNE/edit?pli=1#heading=h.hs091bhdmugz). Part 1 was #5565 This PR adds the propagated span tag `_dd.p.appsec: 1` allowing to propagate to downstream services the information that the current distributed trace is containing at least one ASM security event. ## Test coverage This fully pass the system tests for ASM Standalone.
1 parent 83dab2b commit 935deec

File tree

6 files changed

+33
-5
lines changed

6 files changed

+33
-5
lines changed

tracer/src/Datadog.Trace/AppSec/Security.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ internal void SetTraceSamplingPriority(Span span)
482482
else if (_rateLimiter?.Allowed(span) ?? false)
483483
{
484484
span.Context.TraceContext?.SetSamplingPriority(SamplingPriorityValues.UserKeep, SamplingMechanism.Asm);
485+
span.Context.TraceContext?.Tags.SetTag(Tags.Propagated.AppSec, "1");
485486
}
486487
}
487488

tracer/src/Datadog.Trace/Iast/IastModule.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ private static IastModuleResponse AddWebVulnerability(string? evidenceValue, Int
562562
{
563563
traceContext.IastRequestContext?.AddVulnerability(vulnerability);
564564
traceContext.SetSamplingPriority(SamplingPriorityValues.UserKeep, SamplingMechanism.Asm);
565+
traceContext.Tags.SetTag(Tags.Propagated.AppSec, "1");
565566

566567
return IastModuleResponse.Vulnerable;
567568
}
@@ -636,6 +637,8 @@ private static IastModuleResponse GetScope(string evidenceValue, IntegrationId i
636637
if (isRequest)
637638
{
638639
traceContext?.SetSamplingPriority(SamplingPriorityValues.UserKeep, SamplingMechanism.Asm);
640+
traceContext?.Tags.SetTag(Tags.Propagated.AppSec, "1");
641+
639642
traceContext?.IastRequestContext?.AddVulnerability(vulnerability);
640643
return IastModuleResponse.Vulnerable;
641644
}
@@ -691,6 +694,7 @@ private static IastModuleResponse AddVulnerabilityAsSingleSpan(Tracer tracer, In
691694
scope.Span.Type = SpanTypes.IastVulnerability;
692695
tracer.TracerManager.Telemetry.IntegrationGeneratedSpan(integrationId);
693696
scope.Span.Context.TraceContext?.SetSamplingPriority(SamplingPriorityValues.UserKeep, SamplingMechanism.Asm);
697+
scope.Span.Context.TraceContext?.Tags.SetTag(Tags.Propagated.AppSec, "1");
694698
return new IastModuleResponse(scope);
695699
}
696700

tracer/src/Datadog.Trace/Propagators/DatadogContextPropagator.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ public void Inject<TCarrier, TCarrierSetter>(SpanContext context, TCarrier carri
4343
}
4444

4545
var propagatedTagsHeader = context.PrepareTagsHeaderForPropagation();
46-
4746
if (!string.IsNullOrEmpty(propagatedTagsHeader))
4847
{
4948
carrierSetter.Set(carrier, HttpHeaderNames.PropagatedTags, propagatedTagsHeader!);

tracer/src/Datadog.Trace/Propagators/SpanContextPropagator.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ internal void Inject<TCarrier, TCarrierSetter>(SpanContext context, TCarrier car
115115
if (context == null!) { ThrowHelper.ThrowArgumentNullException(nameof(context)); }
116116
if (carrier == null) { ThrowHelper.ThrowArgumentNullException(nameof(carrier)); }
117117

118+
// If appsec standalone is enabled and appsec propagation is disabled (no ASM events) -> stop propagation
119+
if (context.TraceContext?.Tracer.Settings?.AppsecStandaloneEnabledInternal == true && context.TraceContext.Tags.GetTag(Tags.Propagated.AppSec) != "1")
120+
{
121+
return;
122+
}
123+
118124
// trigger a sampling decision if it hasn't happened yet
119125
_ = context.GetOrMakeSamplingDecision();
120126

tracer/src/Datadog.Trace/Tags.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,12 @@ internal static class Propagated
725725
/// lower-case hexadecimal string with no zero-padding or `0x` prefix.
726726
/// </summary>
727727
internal const string TraceIdUpper = "_dd.p.tid";
728+
729+
/// <summary>
730+
/// A boolean allowing the propagation to downstream services the information that the current distributed trace
731+
/// is containing at least one ASM security event, no matter its type (threats, business logic events, IAST, etc.).
732+
/// </summary>
733+
internal const string AppSec = "_dd.p.appsec";
728734
}
729735
}
730736
}

tracer/src/Datadog.Trace/Tracer.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -419,13 +419,25 @@ internal SpanContext CreateSpanContext(ISpanContext parent = null, string servic
419419

420420
if (traceContext == null)
421421
{
422-
// If parent is SpanContext but its TraceContext is null, then it was extracted from
423-
// propagation headers. Create a new TraceContext (this will start a new trace) and initialize
422+
var propagatedTags = parentSpanContext.PropagatedTags;
423+
var samplingPriority = parentSpanContext.SamplingPriority;
424+
425+
// When in appsec standalone mode, only distributed traces with the `_dd.p.appsec` tag
426+
// are propagated downstream, however we need 1 trace per minute sent to the backend, so
427+
// we unset sampling priority so the rate limiter decides.
428+
if (Settings?.AppsecStandaloneEnabledInternal == true)
429+
{
430+
// If the trace has appsec propagation tag, the default priority is user keep
431+
samplingPriority = propagatedTags?.GetTag(Tags.Propagated.AppSec) == "1" ? SamplingPriorityValues.UserKeep : null;
432+
}
433+
434+
// If parent is SpanContext but its TraceContext is null, then it was extracted from propagation headers.
435+
// Create a new TraceContext (this will start a new trace) and initialize
424436
// it with the propagated values (sampling priority, origin, tags, W3C trace state, etc).
425-
traceContext = new TraceContext(this, parentSpanContext.PropagatedTags);
437+
traceContext = new TraceContext(this, propagatedTags);
426438
TelemetryFactory.Metrics.RecordCountTraceSegmentCreated(MetricTags.TraceContinuation.Continued);
427439

428-
var samplingPriority = parentSpanContext.SamplingPriority ?? DistributedTracer.Instance.GetSamplingPriority();
440+
samplingPriority ??= DistributedTracer.Instance.GetSamplingPriority();
429441
traceContext.SetSamplingPriority(samplingPriority);
430442
traceContext.Origin = parentSpanContext.Origin;
431443
traceContext.AdditionalW3CTraceState = parentSpanContext.AdditionalW3CTraceState;

0 commit comments

Comments
 (0)