Skip to content

Commit 20e87ca

Browse files
authored
chore(asm): standalone asm propagation (#9482)
## Description: ASM: adds Standalone ASM distributed propagation changes as described in "RFC: Standalone ASM billing V2". For the full picture of this feature, see: #9211 , #9444 and #9445 See also System Tests related changes: DataDog/system-tests#2522 ## Details: The main change is that if ASM Standalone is enabled, propagation of distributed spans would reset (from upstream) unless they are part of a distributed span where there are AppSec events (signaled through the propagation tag _dd.p.appsec: 1). It will also cut propagation downstream if there are no appsec events in the current or upstream spans. Notice that AppSec events trigger a force keep, and that takes precedence over the received propagation in this PR. Also notice that most tests start by creating a first span without an appsec event. This is due to the fact that ASM Standalone needs to maintain a minimum rate of 1 trace per minute regardless of upstream propagation or appsec events present, so that way we are not affected by that rate in the test. ## Checklist - [x] Change(s) are motivated and described in the PR description - [x] Testing strategy is described if automated tests are not included in the PR - [x] Risks are described (performance impact, potential for breakage, maintainability) - [x] Change is maintainable (easy to change, telemetry, documentation) - [x] [Library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) are followed or label `changelog/no-changelog` is set - [x] Documentation is included (in-code, generated user docs, [public corp docs](https://github.com/DataDog/documentation/)) - [x] Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) - [x] If this PR changes the public interface, I've notified `@DataDog/apm-tees`. ## Reviewer Checklist - [x] Title is accurate - [x] All changes are related to the pull request's stated goal - [x] Description motivates each change - [x] Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes - [x] Testing strategy adequately addresses listed risks - [x] Change is maintainable (easy to change, telemetry, documentation) - [x] Release note makes sense to a user of the library - [x] Author has acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment - [x] Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)
1 parent b0fdb1e commit 20e87ca

File tree

5 files changed

+353
-1
lines changed

5 files changed

+353
-1
lines changed

ddtrace/_trace/tracer.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from ddtrace._trace.processor import TraceTagsProcessor
2828
from ddtrace._trace.provider import DefaultContextProvider
2929
from ddtrace._trace.span import Span
30+
from ddtrace.appsec._constants import APPSEC
3031
from ddtrace.constants import ENV_KEY
3132
from ddtrace.constants import HOSTNAME_KEY
3233
from ddtrace.constants import PID
@@ -796,7 +797,9 @@ def _start_span(
796797
if span._local_root is None:
797798
span._local_root = span
798799
for k, v in _get_metas_to_propagate(context):
799-
if k != SAMPLING_DECISION_TRACE_TAG_KEY:
800+
# We do not want to propagate AppSec propagation headers
801+
# to children spans, only across distributed spans
802+
if k not in (SAMPLING_DECISION_TRACE_TAG_KEY, APPSEC.PROPAGATION_HEADER):
800803
span._meta[k] = v
801804
else:
802805
# this is the root span of a new trace

ddtrace/appsec/_trace_utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def _asm_manual_keep(span: Span) -> None:
2929

3030
# set Security propagation tag
3131
span.set_tag_str(APPSEC.PROPAGATION_HEADER, "1")
32+
span.context._meta[APPSEC.PROPAGATION_HEADER] = "1"
3233

3334

3435
def _track_user_login_common(

ddtrace/propagation/http.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
from ddtrace._trace.span import _get_64_highest_order_bits_as_hex
2626
from ddtrace._trace.span import _get_64_lowest_order_bits_as_int
2727
from ddtrace._trace.span import _MetaDictType
28+
from ddtrace.appsec._constants import APPSEC
29+
from ddtrace.settings.asm import config as asm_config
2830

2931
from ..constants import AUTO_KEEP
3032
from ..constants import AUTO_REJECT
@@ -230,6 +232,11 @@ def _inject(span_context, headers):
230232
log.debug("tried to inject invalid context %r", span_context)
231233
return
232234

235+
# When in appsec standalone mode, only distributed traces with the `_dd.p.appsec` tag
236+
# are propagated. If the tag is not present, we should not propagate downstream.
237+
if asm_config._appsec_standalone_enabled and (APPSEC.PROPAGATION_HEADER not in span_context._meta):
238+
return
239+
233240
if span_context.trace_id > _MAX_UINT_64BITS:
234241
# set lower order 64 bits in `x-datadog-trace-id` header. For backwards compatibility these
235242
# bits should be converted to a base 10 integer.
@@ -343,6 +350,16 @@ def _extract(headers):
343350
if meta:
344351
meta = validate_sampling_decision(meta)
345352

353+
if asm_config._appsec_standalone_enabled:
354+
# When in appsec standalone mode, only distributed traces with the `_dd.p.appsec` tag
355+
# are propagated downstream, however we need 1 trace per minute sent to the backend, so
356+
# we unset sampling priority so the rate limiter decides.
357+
if not meta or APPSEC.PROPAGATION_HEADER not in meta:
358+
sampling_priority = None
359+
# If the trace has appsec propagation tag, the default priority is user keep
360+
elif meta and APPSEC.PROPAGATION_HEADER in meta:
361+
sampling_priority = 2 # type: ignore[assignment]
362+
346363
return Context(
347364
# DEV: Do not allow `0` for trace id or span id, use None instead
348365
trace_id=trace_id or None,

ddtrace/settings/asm.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ class ASMConfig(Env):
107107
# for tests purposes
108108
_asm_config_keys = [
109109
"_asm_enabled",
110+
"_appsec_standalone_enabled",
110111
"_iast_enabled",
111112
"_ep_enabled",
112113
"_use_metastruct_for_triggers",

0 commit comments

Comments
 (0)