Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tag AppSec on Rack top-level span #2858

Merged
merged 12 commits into from
Jun 1, 2023
Merged

Conversation

lloeki
Copy link
Contributor

@lloeki lloeki commented May 17, 2023

What does this PR do?
Tag AppSec on Rack top-level span

Motivation
AppSec discovers service name based on top-level span. Tagging at trace level results in tags on the trace root span, which is usually Rack's top-level span.

When request queuing is enabeld, though, a synthetic span is added in front, representing a service outside the application. This tag then gets mistakenly tagged with AppSec information, resulting in much confusion.

The situation gets even trickier with partial flushing, as partially flushed spans may receive a trace tag.

Ensuring we tag the proper span should solve both issues.

Additional Notes

Starting this PR as draft since I am still figuring out how to handle Datadog::Kit tagging in a backward compatible manner.

How to test the change?

Add request_queuing: true to Rack or Rails tracing integration, then:

curl -vvv -H 'User-Agent: Arachni/v2' -H "X-Request-Start: $(ruby -e 'puts "%d" % (Time.now.to_f * 1000)')" -H "X-Queue-Start: $(ruby -e 'puts "%d" % (Time.now.to_f * 1000)')" 'http://user:pass@127.0.0.1:9292/'

@github-actions github-actions bot added appsec Application Security monitoring product integrations Involves tracing integrations labels May 17, 2023
@lloeki lloeki force-pushed the attach-appec-to-toplevel-span branch from 2c7d1e1 to fcc90d2 Compare May 17, 2023 11:13
@lloeki lloeki force-pushed the attach-appec-to-toplevel-span branch 2 times, most recently from 277d339 to 9b73c08 Compare May 25, 2023 13:47
Comment on lines 28 to 38
if (appsec_scope = Datadog::AppSec.active_scope)
trace = appsec_scope.trace
span = appsec_scope.span
end

trace ||= Datadog::Tracing.active_trace
span ||= trace.active_span || Datadog::Tracing.active_span

if trace.trace_id != span.trace_id
raise ArgumentError, "span #{span.span_id} does not belong to trace #{trace.trace_id}"
end
Copy link
Member

@GustavoCaso GustavoCaso May 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably extract this to a separate helper method within appsec 😄

Copy link
Contributor Author

@lloeki lloeki Jun 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I went for the quick fix route here, as I find it awkward currently to hide that code behind the wrong abstraction.

Let's address this later and get the release done.

Comment on lines 100 to 102
def active_scope(env)
env['datadog.appsec.scope']
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this one line methods no very useful, since it requires the reader to check what the method is actually doing. In this case checking the env['datadog.appsec.scope'] is more readable in line 39 in my opinion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Let's address this later and get the release done.

AppSec discovers service name based on top-level span. Tagging at trace
level results in tags on the trace root span, which is usually Rack's
top-level span.

When request queuing is enabeld, though, a synthetic span is added in
front, representing a service outside the application. This tag then
gets mistakenly tagged with AppSec information, resulting in much
confusion.

The situation gets even trickier with partial flushing, as partially
flushed spans may receive a trace tag.

Ensuring we tag the proper span should solve both issues.
- Create a AppSec::Scope concept to capture toplevel references
- Extract context management out of Processor to the more general Scope class
- Propagate Scope instead of Context through Rack
- Refactor Processor::Context users to find context through Scope instead
@lloeki lloeki force-pushed the attach-appec-to-toplevel-span branch from 07898dc to 3a16237 Compare May 26, 2023 11:39
@lloeki lloeki force-pushed the attach-appec-to-toplevel-span branch from 3a16237 to 114b7a0 Compare May 26, 2023 12:24
trace ||= Datadog::Tracing.active_trace
span ||= trace.active_span || Datadog::Tracing.active_span

raise ArgumentError, "span #{span.span_id} does not belong to trace #{trace.id}" if trace.id != span.trace_id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we raise or log an message letting the user that they have done something odd?

Copy link
Contributor Author

@lloeki lloeki Jun 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with the active scope (prev. active context) sanity checks, this should not happen, ever. If we swallow it we'll never be aware.

Practically since we now use the AppSec scope as an override, it can only happen if a user forcefully passes both trace and span args outside an AppSec scope. In that case they made a mistake and will want to be aware immediately.

@lloeki lloeki force-pushed the attach-appec-to-toplevel-span branch from 41edde7 to 3080fb7 Compare May 30, 2023 13:12
@GustavoCaso GustavoCaso force-pushed the attach-appec-to-toplevel-span branch from d5a3357 to 3bdd5c6 Compare May 31, 2023 08:28
@codecov-commenter
Copy link

Codecov Report

Merging #2858 (3bdd5c6) into master (df8612f) will increase coverage by 0.01%.
The diff coverage is n/a.

@@            Coverage Diff             @@
##           master    #2858      +/-   ##
==========================================
+ Coverage   98.09%   98.10%   +0.01%     
==========================================
  Files        1269     1266       -3     
  Lines       69969    69990      +21     
  Branches     3161     3172      +11     
==========================================
+ Hits        68633    68662      +29     
+ Misses       1336     1328       -8     

see 42 files with indirect coverage changes

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@@ -17,7 +17,7 @@ def initialize(app, opt = {})
end

def call(env)
context = env['datadog.waf.context']
context = env['datadog.appsec.scope']
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @GustavoCaso !

@lloeki lloeki marked this pull request as ready for review June 1, 2023 10:11
@lloeki lloeki requested a review from a team June 1, 2023 10:11
Copy link
Member

@GustavoCaso GustavoCaso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@GustavoCaso GustavoCaso merged commit 80c3573 into master Jun 1, 2023
@GustavoCaso GustavoCaso deleted the attach-appec-to-toplevel-span branch June 1, 2023 14:10
@github-actions github-actions bot added this to the 1.12.0 milestone Jun 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
appsec Application Security monitoring product integrations Involves tracing integrations
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants