ddtrace 1.11.1 → 1.12.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +73 -1
- data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +6 -4
- data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +34 -16
- data/ext/ddtrace_profiling_native_extension/extconf.rb +19 -3
- data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +2 -2
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +38 -4
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +489 -133
- data/lib/datadog/appsec/assets/waf_rules/strict.json +2 -47
- data/lib/datadog/appsec/configuration/settings.rb +2 -10
- data/lib/datadog/appsec/configuration.rb +3 -9
- data/lib/datadog/appsec/contrib/rack/ext.rb +0 -1
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +17 -3
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +27 -45
- data/lib/datadog/appsec/contrib/rack/integration.rb +0 -5
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +7 -1
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +34 -26
- data/lib/datadog/appsec/contrib/rails/ext.rb +0 -1
- data/lib/datadog/appsec/contrib/rails/framework.rb +1 -13
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +9 -27
- data/lib/datadog/appsec/contrib/rails/integration.rb +0 -5
- data/lib/datadog/appsec/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -1
- data/lib/datadog/appsec/contrib/sinatra/framework.rb +1 -13
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +18 -36
- data/lib/datadog/appsec/contrib/sinatra/integration.rb +0 -5
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +5 -4
- data/lib/datadog/appsec/event.rb +37 -37
- data/lib/datadog/appsec/ext.rb +1 -0
- data/lib/datadog/appsec/extensions.rb +2 -6
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +9 -28
- data/lib/datadog/appsec/processor/rule_merger.rb +13 -7
- data/lib/datadog/appsec/processor.rb +0 -45
- data/lib/datadog/appsec/remote.rb +6 -0
- data/lib/datadog/appsec/response.rb +13 -9
- data/lib/datadog/appsec/scope.rb +61 -0
- data/lib/datadog/appsec.rb +6 -0
- data/lib/datadog/ci/ext/environment.rb +40 -4
- data/lib/datadog/core/configuration/settings.rb +74 -14
- data/lib/datadog/core/configuration.rb +5 -1
- data/lib/datadog/core/remote/client/capabilities.rb +1 -1
- data/lib/datadog/core/remote/client.rb +5 -1
- data/lib/datadog/core/telemetry/collector.rb +2 -1
- data/lib/datadog/core/telemetry/v1/dependency.rb +2 -1
- data/lib/datadog/kit/appsec/events.rb +58 -13
- data/lib/datadog/kit/identity.rb +29 -10
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +2 -0
- data/lib/datadog/profiling/component.rb +69 -29
- data/lib/datadog/profiling.rb +2 -1
- data/lib/datadog/tracing/buffer.rb +0 -1
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +9 -1
- data/lib/datadog/tracing/contrib/aws/ext.rb +11 -1
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +7 -0
- data/lib/datadog/tracing/contrib/aws/parsed_context.rb +4 -0
- data/lib/datadog/tracing/contrib/aws/service/base.rb +16 -0
- data/lib/datadog/tracing/contrib/aws/service/dynamodb.rb +22 -0
- data/lib/datadog/tracing/contrib/aws/service/eventbridge.rb +22 -0
- data/lib/datadog/tracing/contrib/aws/service/kinesis.rb +32 -0
- data/lib/datadog/tracing/contrib/aws/service/s3.rb +22 -0
- data/lib/datadog/tracing/contrib/aws/service/sns.rb +30 -0
- data/lib/datadog/tracing/contrib/aws/service/sqs.rb +27 -0
- data/lib/datadog/tracing/contrib/aws/service/states.rb +40 -0
- data/lib/datadog/tracing/contrib/aws/services.rb +18 -0
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +6 -1
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +5 -2
- data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +6 -1
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +4 -2
- data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +6 -1
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +5 -2
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +6 -1
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +5 -2
- data/lib/datadog/tracing/contrib/patcher.rb +0 -1
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +6 -1
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +5 -2
- data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +6 -1
- data/lib/datadog/tracing/contrib/presto/instrumentation.rb +4 -2
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +10 -2
- data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +9 -1
- data/lib/datadog/tracing/contrib/racecar/event.rb +3 -1
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +3 -1
- data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +6 -1
- data/lib/datadog/tracing/contrib/redis/tags.rb +4 -1
- data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +6 -1
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +4 -1
- data/lib/datadog/tracing/contrib/roda/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/sequel/database.rb +4 -1
- data/lib/datadog/tracing/contrib/sequel/dataset.rb +4 -1
- data/lib/datadog/tracing/contrib/sequel/utils.rb +4 -1
- data/lib/datadog/tracing/contrib/status_code_matcher.rb +0 -1
- data/lib/datadog/tracing/correlation.rb +0 -1
- data/lib/datadog/tracing/distributed/headers/ext.rb +1 -1
- data/lib/datadog/tracing/event.rb +0 -2
- data/lib/datadog/tracing/pipeline.rb +0 -2
- data/lib/datadog/tracing/runtime/metrics.rb +0 -2
- data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +0 -1
- data/lib/datadog/tracing/sampling/rate_sampler.rb +0 -2
- data/lib/datadog/tracing/sampling/rule.rb +0 -2
- data/lib/datadog/tracing/sampling/rule_sampler.rb +0 -2
- data/lib/datadog/tracing/span_operation.rb +0 -1
- data/lib/datadog/tracing/sync_writer.rb +0 -2
- data/lib/datadog/tracing/trace_operation.rb +0 -1
- data/lib/datadog/tracing/tracer.rb +0 -1
- data/lib/datadog/tracing/workers/trace_writer.rb +0 -1
- data/lib/datadog/tracing/workers.rb +0 -2
- data/lib/datadog/tracing/writer.rb +0 -2
- data/lib/ddtrace/version.rb +1 -1
- metadata +18 -19
- data/lib/datadog/appsec/contrib/configuration/settings.rb +0 -20
- data/lib/datadog/appsec/contrib/rack/configuration/settings.rb +0 -22
- data/lib/datadog/appsec/contrib/rails/configuration/settings.rb +0 -22
- data/lib/datadog/appsec/contrib/sinatra/configuration/settings.rb +0 -22
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": "2.2",
|
3
3
|
"metadata": {
|
4
|
-
"rules_version": "1.
|
4
|
+
"rules_version": "1.7.0"
|
5
5
|
},
|
6
6
|
"rules": [
|
7
7
|
{
|
@@ -24,96 +24,51 @@
|
|
24
24
|
}
|
25
25
|
],
|
26
26
|
"list": [
|
27
|
-
"",
|
28
27
|
"(hydra)",
|
29
|
-
".nasl",
|
30
28
|
"absinthe",
|
31
|
-
"advanced email extractor",
|
32
|
-
"arachni/",
|
33
29
|
"autogetcontent",
|
34
30
|
"bilbo",
|
35
31
|
"bfac",
|
36
|
-
"brutus",
|
37
|
-
"brutus/aet",
|
38
|
-
"bsqlbf",
|
39
|
-
"cgichk",
|
40
32
|
"cisco-torch",
|
41
|
-
"commix",
|
42
33
|
"core-project/1.0",
|
43
34
|
"crimscanner/",
|
44
35
|
"datacha0s",
|
45
|
-
"detectify",
|
46
|
-
"dirbuster",
|
47
36
|
"domino hunter",
|
48
37
|
"dotdotpwn",
|
49
38
|
"email extractor",
|
50
39
|
"fhscan core 1.",
|
51
40
|
"floodgate",
|
52
|
-
"fuzz faster u fool",
|
53
41
|
"f-secure radar",
|
54
42
|
"get-minimal",
|
55
|
-
"gobuster",
|
56
43
|
"gootkit auto-rooter scanner",
|
57
44
|
"grabber",
|
58
45
|
"grendel-scan",
|
59
|
-
"havij",
|
60
46
|
"inspath",
|
61
47
|
"internet ninja",
|
62
|
-
"jaascois",
|
63
|
-
"jorgee",
|
64
48
|
"masscan",
|
65
|
-
"metis",
|
66
49
|
"morfeus fucking scanner",
|
67
50
|
"mysqloit",
|
68
|
-
"n-stealth",
|
69
|
-
"nessus",
|
70
|
-
"netsparker",
|
71
|
-
"nikto",
|
72
|
-
"nmap nse",
|
73
|
-
"nmap scripting engine",
|
74
|
-
"nmap-nse",
|
75
|
-
"nsauditor",
|
76
|
-
"nuclei",
|
77
|
-
"openvas",
|
78
|
-
"pangolin",
|
79
|
-
"paros",
|
80
|
-
"pmafind",
|
81
51
|
"prog.customcrawler",
|
82
52
|
"qqgamehall",
|
83
|
-
"qualys was",
|
84
53
|
"s.t.a.l.k.e.r.",
|
85
|
-
"security scan",
|
86
54
|
"springenwerk",
|
87
55
|
"sql power injector",
|
88
|
-
"sqlmap",
|
89
|
-
"sqlninja",
|
90
56
|
"struts-pwn",
|
91
57
|
"sysscan",
|
92
58
|
"tbi-webscanner",
|
93
59
|
"teh forest lobster",
|
94
|
-
"this is an exploit",
|
95
60
|
"toata dragostea",
|
96
|
-
"toata dragostea mea pentru diavola",
|
97
61
|
"uil2pn",
|
98
62
|
"user-agent:",
|
99
63
|
"vega/",
|
100
64
|
"voideye",
|
101
|
-
"w3af.sf.net",
|
102
|
-
"w3af.sourceforge.net",
|
103
|
-
"w3af.org",
|
104
65
|
"webbandit",
|
105
|
-
"webinspect",
|
106
66
|
"webshag",
|
107
|
-
"webtrends security analyzer",
|
108
67
|
"webvulnscan",
|
109
|
-
"wfuzz",
|
110
68
|
"whatweb",
|
111
69
|
"whcc/",
|
112
70
|
"wordpress hash grabber",
|
113
|
-
"
|
114
|
-
"xmlrpc exploit",
|
115
|
-
"zgrab",
|
116
|
-
"zmeu"
|
71
|
+
"xmlrpc exploit"
|
117
72
|
]
|
118
73
|
},
|
119
74
|
"operator": "phrase_match"
|
@@ -116,7 +116,7 @@ module Datadog
|
|
116
116
|
}.freeze
|
117
117
|
|
118
118
|
# Struct constant whisker cast for Steep
|
119
|
-
Integration = _ = Struct.new(:integration
|
119
|
+
Integration = _ = Struct.new(:integration) # rubocop:disable Naming/ConstantName
|
120
120
|
|
121
121
|
def initialize
|
122
122
|
@integrations = []
|
@@ -181,14 +181,6 @@ module Datadog
|
|
181
181
|
_ = @options[:obfuscator_value_regex]
|
182
182
|
end
|
183
183
|
|
184
|
-
def [](integration_name)
|
185
|
-
integration = Datadog::AppSec::Contrib::Integration.registry[integration_name]
|
186
|
-
|
187
|
-
raise ArgumentError, "'#{integration_name}' is not a valid integration." unless integration
|
188
|
-
|
189
|
-
integration.options
|
190
|
-
end
|
191
|
-
|
192
184
|
def merge(dsl)
|
193
185
|
dsl.options.each do |k, v|
|
194
186
|
unless v.nil?
|
@@ -203,7 +195,7 @@ module Datadog
|
|
203
195
|
dsl.instruments.each do |instrument|
|
204
196
|
# TODO: error handling
|
205
197
|
registered_integration = Datadog::AppSec::Contrib::Integration.registry[instrument.name]
|
206
|
-
@integrations << Integration.new(registered_integration
|
198
|
+
@integrations << Integration.new(registered_integration)
|
207
199
|
|
208
200
|
# TODO: move to a separate apply step
|
209
201
|
klass = registered_integration.klass
|
@@ -15,7 +15,7 @@ module Datadog
|
|
15
15
|
# Configuration DSL implementation
|
16
16
|
class DSL
|
17
17
|
# Struct constant whisker cast for Steep
|
18
|
-
Instrument = _ = Struct.new(:name
|
18
|
+
Instrument = _ = Struct.new(:name) # rubocop:disable Naming/ConstantName
|
19
19
|
|
20
20
|
def initialize
|
21
21
|
@instruments = []
|
@@ -24,8 +24,8 @@ module Datadog
|
|
24
24
|
|
25
25
|
attr_reader :instruments, :options
|
26
26
|
|
27
|
-
def instrument(name
|
28
|
-
@instruments << Instrument.new(name
|
27
|
+
def instrument(name)
|
28
|
+
@instruments << Instrument.new(name)
|
29
29
|
end
|
30
30
|
|
31
31
|
def enabled=(value)
|
@@ -64,12 +64,6 @@ module Datadog
|
|
64
64
|
def obfuscator_value_regex=(value)
|
65
65
|
options[:obfuscator_value_regex] = value
|
66
66
|
end
|
67
|
-
|
68
|
-
def [](key)
|
69
|
-
found = @instruments.find { |e| e.name == key }
|
70
|
-
|
71
|
-
found.options if found
|
72
|
-
end
|
73
67
|
end
|
74
68
|
|
75
69
|
# class-level methods for Configuration
|
@@ -25,14 +25,20 @@ module Datadog
|
|
25
25
|
def query
|
26
26
|
# Downstream libddwaf expects keys and values to be extractable
|
27
27
|
# separately so we can't use [[k, v], ...]. We also want to allow
|
28
|
-
# duplicate keys, so we use
|
29
|
-
|
28
|
+
# duplicate keys, so we use {k => [v, ...], ...} instead, taking into
|
29
|
+
# account that {k => [v1, v2, ...], ...} is possible for duplicate keys.
|
30
|
+
request.query_string.split('&').each.with_object({}) do |e, hash|
|
30
31
|
k, v = e.split('=').map { |s| CGI.unescape(s) }
|
32
|
+
hash[k] ||= []
|
31
33
|
|
32
|
-
|
34
|
+
hash[k] << v
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
38
|
+
def method
|
39
|
+
request.request_method
|
40
|
+
end
|
41
|
+
|
36
42
|
def headers
|
37
43
|
request.env.each_with_object({}) do |(k, v), h|
|
38
44
|
h[k.gsub(/^HTTP_/, '').downcase.tr('_', '-')] = v if k =~ /^HTTP_/
|
@@ -47,6 +53,14 @@ module Datadog
|
|
47
53
|
request.url
|
48
54
|
end
|
49
55
|
|
56
|
+
def fullpath
|
57
|
+
request.fullpath
|
58
|
+
end
|
59
|
+
|
60
|
+
def path
|
61
|
+
request.path
|
62
|
+
end
|
63
|
+
|
50
64
|
def cookies
|
51
65
|
request.cookies
|
52
66
|
end
|
@@ -9,14 +9,14 @@ module Datadog
|
|
9
9
|
module Gateway
|
10
10
|
# Gateway Response argument.
|
11
11
|
class Response < Instrumentation::Gateway::Argument
|
12
|
-
attr_reader :body, :status, :headers, :
|
12
|
+
attr_reader :body, :status, :headers, :scope
|
13
13
|
|
14
|
-
def initialize(body, status, headers,
|
14
|
+
def initialize(body, status, headers, scope:)
|
15
15
|
super()
|
16
16
|
@body = body
|
17
17
|
@status = status
|
18
18
|
@headers = headers.each_with_object({}) { |(k, v), h| h[k.downcase] = v }
|
19
|
-
@
|
19
|
+
@scope = scope
|
20
20
|
end
|
21
21
|
|
22
22
|
def response
|
@@ -25,26 +25,26 @@ module Datadog
|
|
25
25
|
gateway.watch('rack.request', :appsec) do |stack, gateway_request|
|
26
26
|
block = false
|
27
27
|
event = nil
|
28
|
-
|
28
|
+
scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY]
|
29
29
|
|
30
30
|
AppSec::Reactive::Operation.new('rack.request') do |op|
|
31
|
-
|
32
|
-
span = active_span
|
33
|
-
|
34
|
-
Rack::Reactive::Request.subscribe(op, waf_context) do |result, _block|
|
31
|
+
Rack::Reactive::Request.subscribe(op, scope.processor_context) do |result, _block|
|
35
32
|
if result.status == :match
|
36
33
|
# TODO: should this hash be an Event instance instead?
|
37
34
|
event = {
|
38
35
|
waf_result: result,
|
39
|
-
trace: trace,
|
40
|
-
span:
|
36
|
+
trace: scope.trace,
|
37
|
+
span: scope.service_entry_span,
|
41
38
|
request: gateway_request,
|
42
39
|
actions: result.actions
|
43
40
|
}
|
44
41
|
|
45
|
-
|
42
|
+
if scope.service_entry_span
|
43
|
+
scope.service_entry_span.set_tag('appsec.blocked', 'true') if result.actions.include?('block')
|
44
|
+
scope.service_entry_span.set_tag('appsec.event', 'true')
|
45
|
+
end
|
46
46
|
|
47
|
-
|
47
|
+
scope.processor_context.events << event
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
@@ -68,26 +68,26 @@ module Datadog
|
|
68
68
|
gateway.watch('rack.response', :appsec) do |stack, gateway_response|
|
69
69
|
block = false
|
70
70
|
event = nil
|
71
|
-
|
71
|
+
scope = gateway_response.scope
|
72
72
|
|
73
73
|
AppSec::Reactive::Operation.new('rack.response') do |op|
|
74
|
-
|
75
|
-
span = active_span
|
76
|
-
|
77
|
-
Rack::Reactive::Response.subscribe(op, waf_context) do |result, _block|
|
74
|
+
Rack::Reactive::Response.subscribe(op, scope.processor_context) do |result, _block|
|
78
75
|
if result.status == :match
|
79
76
|
# TODO: should this hash be an Event instance instead?
|
80
77
|
event = {
|
81
78
|
waf_result: result,
|
82
|
-
trace: trace,
|
83
|
-
span:
|
79
|
+
trace: scope.trace,
|
80
|
+
span: scope.service_entry_span,
|
84
81
|
response: gateway_response,
|
85
82
|
actions: result.actions
|
86
83
|
}
|
87
84
|
|
88
|
-
|
85
|
+
if scope.service_entry_span
|
86
|
+
scope.service_entry_span.set_tag('appsec.blocked', 'true') if result.actions.include?('block')
|
87
|
+
scope.service_entry_span.set_tag('appsec.event', 'true')
|
88
|
+
end
|
89
89
|
|
90
|
-
|
90
|
+
scope.processor_context.events << event
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
@@ -111,26 +111,26 @@ module Datadog
|
|
111
111
|
gateway.watch('rack.request.body', :appsec) do |stack, gateway_request|
|
112
112
|
block = false
|
113
113
|
event = nil
|
114
|
-
|
114
|
+
scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY]
|
115
115
|
|
116
116
|
AppSec::Reactive::Operation.new('rack.request.body') do |op|
|
117
|
-
|
118
|
-
span = active_span
|
119
|
-
|
120
|
-
Rack::Reactive::RequestBody.subscribe(op, waf_context) do |result, _block|
|
117
|
+
Rack::Reactive::RequestBody.subscribe(op, scope.processor_context) do |result, _block|
|
121
118
|
if result.status == :match
|
122
119
|
# TODO: should this hash be an Event instance instead?
|
123
120
|
event = {
|
124
121
|
waf_result: result,
|
125
|
-
trace: trace,
|
126
|
-
span:
|
122
|
+
trace: scope.trace,
|
123
|
+
span: scope.service_entry_span,
|
127
124
|
request: gateway_request,
|
128
125
|
actions: result.actions
|
129
126
|
}
|
130
127
|
|
131
|
-
|
128
|
+
if scope.service_entry_span
|
129
|
+
scope.service_entry_span.set_tag('appsec.blocked', 'true') if result.actions.include?('block')
|
130
|
+
scope.service_entry_span.set_tag('appsec.event', 'true')
|
131
|
+
end
|
132
132
|
|
133
|
-
|
133
|
+
scope.processor_context.events << event
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
@@ -149,24 +149,6 @@ module Datadog
|
|
149
149
|
[ret, res]
|
150
150
|
end
|
151
151
|
end
|
152
|
-
|
153
|
-
private
|
154
|
-
|
155
|
-
def active_trace
|
156
|
-
# TODO: factor out tracing availability detection
|
157
|
-
|
158
|
-
return unless defined?(Datadog::Tracing)
|
159
|
-
|
160
|
-
Datadog::Tracing.active_trace
|
161
|
-
end
|
162
|
-
|
163
|
-
def active_span
|
164
|
-
# TODO: factor out tracing availability detection
|
165
|
-
|
166
|
-
return unless defined?(Datadog::Tracing)
|
167
|
-
|
168
|
-
Datadog::Tracing.active_span
|
169
|
-
end
|
170
152
|
end
|
171
153
|
end
|
172
154
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require_relative '../integration'
|
2
2
|
|
3
|
-
require_relative 'configuration/settings'
|
4
3
|
require_relative 'patcher'
|
5
4
|
require_relative 'request_middleware'
|
6
5
|
require_relative 'request_body_middleware'
|
@@ -33,10 +32,6 @@ module Datadog
|
|
33
32
|
false
|
34
33
|
end
|
35
34
|
|
36
|
-
def default_configuration
|
37
|
-
Configuration::Settings.new
|
38
|
-
end
|
39
|
-
|
40
35
|
def patcher
|
41
36
|
Patcher
|
42
37
|
end
|
@@ -13,6 +13,7 @@ module Datadog
|
|
13
13
|
'request.query',
|
14
14
|
'request.cookies',
|
15
15
|
'request.client_ip',
|
16
|
+
'server.request.method'
|
16
17
|
].freeze
|
17
18
|
private_constant :ADDRESSES
|
18
19
|
|
@@ -20,14 +21,16 @@ module Datadog
|
|
20
21
|
catch(:block) do
|
21
22
|
op.publish('request.query', gateway_request.query)
|
22
23
|
op.publish('request.headers', gateway_request.headers)
|
23
|
-
op.publish('request.uri.raw', gateway_request.
|
24
|
+
op.publish('request.uri.raw', gateway_request.fullpath)
|
24
25
|
op.publish('request.cookies', gateway_request.cookies)
|
25
26
|
op.publish('request.client_ip', gateway_request.client_ip)
|
27
|
+
op.publish('server.request.method', gateway_request.method)
|
26
28
|
|
27
29
|
nil
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
33
|
+
# rubocop:disable Metrics/MethodLength
|
31
34
|
def self.subscribe(op, waf_context)
|
32
35
|
op.subscribe(*ADDRESSES) do |*values|
|
33
36
|
Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
|
@@ -37,6 +40,7 @@ module Datadog
|
|
37
40
|
query = values[2]
|
38
41
|
cookies = values[3]
|
39
42
|
client_ip = values[4]
|
43
|
+
request_method = values[5]
|
40
44
|
|
41
45
|
waf_args = {
|
42
46
|
'server.request.cookies' => cookies,
|
@@ -45,6 +49,7 @@ module Datadog
|
|
45
49
|
'server.request.headers' => headers,
|
46
50
|
'server.request.headers.no_cookies' => headers_no_cookies,
|
47
51
|
'http.client_ip' => client_ip,
|
52
|
+
'server.request.method' => request_method,
|
48
53
|
}
|
49
54
|
|
50
55
|
waf_timeout = Datadog::AppSec.settings.waf_timeout
|
@@ -71,6 +76,7 @@ module Datadog
|
|
71
76
|
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
72
77
|
end
|
73
78
|
end
|
79
|
+
# rubocop:enable Metrics/MethodLength
|
74
80
|
end
|
75
81
|
end
|
76
82
|
end
|
@@ -2,7 +2,6 @@ require 'json'
|
|
2
2
|
|
3
3
|
require_relative 'gateway/request'
|
4
4
|
require_relative 'gateway/response'
|
5
|
-
require_relative '../../ext'
|
6
5
|
require_relative '../../instrumentation/gateway'
|
7
6
|
require_relative '../../processor'
|
8
7
|
require_relative '../../response'
|
@@ -23,7 +22,7 @@ module Datadog
|
|
23
22
|
@oneshot_tags_sent = false
|
24
23
|
end
|
25
24
|
|
26
|
-
# rubocop:disable Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity,Metrics/MethodLength
|
25
|
+
# rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity,Metrics/MethodLength
|
27
26
|
def call(env)
|
28
27
|
return @app.call(env) unless Datadog::AppSec.enabled?
|
29
28
|
|
@@ -31,14 +30,19 @@ module Datadog
|
|
31
30
|
|
32
31
|
processor = nil
|
33
32
|
ready = false
|
34
|
-
|
33
|
+
scope = nil
|
34
|
+
|
35
|
+
# For a given request, keep using the first Rack stack scope for
|
36
|
+
# nested apps. Don't set `context` local variable so that on popping
|
37
|
+
# out of this nested stack we don't finalize the parent's context
|
38
|
+
return @app.call(env) if active_scope(env)
|
35
39
|
|
36
40
|
Datadog::AppSec.reconfigure_lock do
|
37
41
|
processor = Datadog::AppSec.processor
|
38
42
|
|
39
43
|
if !processor.nil? && processor.ready?
|
40
|
-
|
41
|
-
env[
|
44
|
+
scope = Datadog::AppSec::Scope.activate_scope(active_trace, active_span, processor)
|
45
|
+
env[Datadog::AppSec::Ext::SCOPE_KEY] = scope
|
42
46
|
ready = true
|
43
47
|
end
|
44
48
|
end
|
@@ -49,7 +53,7 @@ module Datadog
|
|
49
53
|
|
50
54
|
gateway_request = Gateway::Request.new(env)
|
51
55
|
|
52
|
-
add_appsec_tags(processor,
|
56
|
+
add_appsec_tags(processor, scope.trace, scope.service_entry_span, env)
|
53
57
|
|
54
58
|
request_return, request_response = catch(::Datadog::AppSec::Ext::INTERRUPT) do
|
55
59
|
Instrumentation.gateway.push('rack.request', gateway_request) do
|
@@ -65,17 +69,17 @@ module Datadog
|
|
65
69
|
request_return[2],
|
66
70
|
request_return[0],
|
67
71
|
request_return[1],
|
68
|
-
|
72
|
+
scope: scope
|
69
73
|
)
|
70
74
|
|
71
75
|
_response_return, response_response = Instrumentation.gateway.push('rack.response', gateway_response)
|
72
76
|
|
73
|
-
|
77
|
+
scope.processor_context.events.each do |e|
|
74
78
|
e[:response] ||= gateway_response
|
75
79
|
e[:request] ||= gateway_request
|
76
80
|
end
|
77
81
|
|
78
|
-
AppSec::Event.record(*
|
82
|
+
AppSec::Event.record(scope.service_entry_span, *scope.processor_context.events)
|
79
83
|
|
80
84
|
if response_response && response_response.any? { |action, _event| action == :block }
|
81
85
|
request_return = AppSec::Response.negotiate(env).to_rack
|
@@ -83,15 +87,19 @@ module Datadog
|
|
83
87
|
|
84
88
|
request_return
|
85
89
|
ensure
|
86
|
-
if
|
87
|
-
add_waf_runtime_tags(
|
88
|
-
|
90
|
+
if scope
|
91
|
+
add_waf_runtime_tags(scope.service_entry_span, scope.processor_context)
|
92
|
+
Datadog::AppSec::Scope.deactivate_scope
|
89
93
|
end
|
90
94
|
end
|
91
|
-
# rubocop:enable Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity,Metrics/MethodLength
|
95
|
+
# rubocop:enable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity,Metrics/MethodLength
|
92
96
|
|
93
97
|
private
|
94
98
|
|
99
|
+
def active_scope(env)
|
100
|
+
env[Datadog::AppSec::Ext::SCOPE_KEY]
|
101
|
+
end
|
102
|
+
|
95
103
|
def active_trace
|
96
104
|
# TODO: factor out tracing availability detection
|
97
105
|
|
@@ -111,9 +119,9 @@ module Datadog
|
|
111
119
|
def add_appsec_tags(processor, trace, span, env)
|
112
120
|
return unless trace
|
113
121
|
|
114
|
-
|
115
|
-
|
116
|
-
|
122
|
+
span.set_tag('_dd.appsec.enabled', 1)
|
123
|
+
span.set_tag('_dd.runtime_family', 'ruby')
|
124
|
+
span.set_tag('_dd.appsec.waf.version', Datadog::AppSec::WAF::VERSION::BASE_STRING)
|
117
125
|
|
118
126
|
if span && span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP).nil?
|
119
127
|
request_header_collection = Datadog::Tracing::Contrib::Rack::Header::RequestHeaderCollection.new(env)
|
@@ -127,17 +135,17 @@ module Datadog
|
|
127
135
|
end
|
128
136
|
|
129
137
|
if processor.ruleset_info
|
130
|
-
|
138
|
+
span.set_tag('_dd.appsec.event_rules.version', processor.ruleset_info[:version])
|
131
139
|
|
132
140
|
unless @oneshot_tags_sent
|
133
141
|
# Small race condition, but it's inoccuous: worst case the tags
|
134
142
|
# are sent a couple of times more than expected
|
135
143
|
@oneshot_tags_sent = true
|
136
144
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
145
|
+
span.set_tag('_dd.appsec.event_rules.loaded', processor.ruleset_info[:loaded].to_f)
|
146
|
+
span.set_tag('_dd.appsec.event_rules.error_count', processor.ruleset_info[:failed].to_f)
|
147
|
+
span.set_tag('_dd.appsec.event_rules.errors', JSON.dump(processor.ruleset_info[:errors]))
|
148
|
+
span.set_tag('_dd.appsec.event_rules.addresses', JSON.dump(processor.addresses))
|
141
149
|
|
142
150
|
# Ensure these tags reach the backend
|
143
151
|
trace.keep!
|
@@ -149,15 +157,15 @@ module Datadog
|
|
149
157
|
end
|
150
158
|
end
|
151
159
|
|
152
|
-
def add_waf_runtime_tags(
|
153
|
-
return unless
|
160
|
+
def add_waf_runtime_tags(span, context)
|
161
|
+
return unless span
|
154
162
|
return unless context
|
155
163
|
|
156
|
-
|
164
|
+
span.set_tag('_dd.appsec.waf.timeouts', context.timeouts)
|
157
165
|
|
158
166
|
# these tags expect time in us
|
159
|
-
|
160
|
-
|
167
|
+
span.set_tag('_dd.appsec.waf.duration', context.time_ns / 1000.0)
|
168
|
+
span.set_tag('_dd.appsec.waf.duration_ext', context.time_ext_ns / 1000.0)
|
161
169
|
end
|
162
170
|
end
|
163
171
|
end
|
@@ -8,21 +8,9 @@ module Datadog
|
|
8
8
|
module Framework
|
9
9
|
def self.setup
|
10
10
|
Datadog::AppSec.configure do |datadog_config|
|
11
|
-
|
12
|
-
activate_rack!(datadog_config, rails_config)
|
11
|
+
datadog_config.instrument(:rack)
|
13
12
|
end
|
14
13
|
end
|
15
|
-
|
16
|
-
def self.config_with_defaults(datadog_config)
|
17
|
-
datadog_config[:rails]
|
18
|
-
end
|
19
|
-
|
20
|
-
# Apply relevant configuration from Sinatra to Rack
|
21
|
-
def self.activate_rack!(datadog_config, sinatra_config)
|
22
|
-
datadog_config.instrument(
|
23
|
-
:rack,
|
24
|
-
)
|
25
|
-
end
|
26
14
|
end
|
27
15
|
end
|
28
16
|
end
|