datadog 2.15.0 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +46 -2
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +3 -0
- data/ext/datadog_profiling_native_extension/heap_recorder.c +8 -1
- data/ext/libdatadog_api/crashtracker.c +1 -9
- data/ext/libdatadog_api/crashtracker.h +5 -0
- data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
- data/ext/libdatadog_api/datadog_ruby_common.h +7 -0
- data/ext/libdatadog_api/init.c +15 -0
- data/ext/libdatadog_api/library_config.c +122 -0
- data/ext/libdatadog_api/library_config.h +19 -0
- data/ext/libdatadog_api/process_discovery.c +117 -0
- data/ext/libdatadog_api/process_discovery.h +5 -0
- data/lib/datadog/appsec/actions_handler.rb +3 -2
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +1344 -0
- data/lib/datadog/appsec/assets/waf_rules/strict.json +1344 -0
- data/lib/datadog/appsec/autoload.rb +1 -1
- data/lib/datadog/appsec/component.rb +11 -4
- data/lib/datadog/appsec/configuration/settings.rb +31 -18
- data/lib/datadog/appsec/context.rb +1 -1
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +10 -12
- data/lib/datadog/appsec/contrib/active_record/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +22 -22
- data/lib/datadog/appsec/contrib/devise/data_extractor.rb +2 -3
- data/lib/datadog/appsec/contrib/devise/ext.rb +1 -0
- data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/patcher.rb +3 -5
- data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +17 -4
- data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +9 -10
- data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +8 -9
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +8 -9
- data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +22 -32
- data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +16 -16
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +11 -13
- data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/patcher.rb +21 -21
- data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +10 -11
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +17 -23
- data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
- data/lib/datadog/appsec/event.rb +85 -95
- data/lib/datadog/appsec/instrumentation/gateway/argument.rb +5 -2
- data/lib/datadog/appsec/metrics/telemetry.rb +1 -1
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +42 -12
- data/lib/datadog/appsec/processor/rule_loader.rb +26 -28
- data/lib/datadog/appsec/processor/rule_merger.rb +5 -5
- data/lib/datadog/appsec/processor.rb +1 -1
- data/lib/datadog/appsec/remote.rb +14 -13
- data/lib/datadog/appsec/response.rb +6 -6
- data/lib/datadog/appsec/security_engine/runner.rb +1 -1
- data/lib/datadog/appsec/security_event.rb +39 -0
- data/lib/datadog/appsec.rb +1 -1
- data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
- data/lib/datadog/core/configuration/components.rb +19 -10
- data/lib/datadog/core/configuration/option.rb +61 -25
- data/lib/datadog/core/configuration/settings.rb +10 -0
- data/lib/datadog/core/configuration/stable_config.rb +23 -0
- data/lib/datadog/core/configuration.rb +24 -0
- data/lib/datadog/core/crashtracking/component.rb +1 -9
- data/lib/datadog/core/environment/git.rb +1 -0
- data/lib/datadog/core/environment/variable_helpers.rb +1 -1
- data/lib/datadog/core/metrics/client.rb +8 -7
- data/lib/datadog/core/process_discovery.rb +32 -0
- data/lib/datadog/core/remote/client.rb +7 -0
- data/lib/datadog/core/runtime/metrics.rb +1 -1
- data/lib/datadog/core/telemetry/component.rb +60 -50
- data/lib/datadog/core/telemetry/emitter.rb +17 -11
- data/lib/datadog/core/telemetry/event.rb +7 -4
- data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
- data/lib/datadog/core/telemetry/request.rb +3 -3
- data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
- data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
- data/lib/datadog/core/telemetry/transport/http.rb +63 -0
- data/lib/datadog/core/telemetry/transport/telemetry.rb +52 -0
- data/lib/datadog/core/telemetry/worker.rb +45 -0
- data/lib/datadog/core/utils/time.rb +12 -0
- data/lib/datadog/core/workers/async.rb +20 -2
- data/lib/datadog/core/workers/interval_loop.rb +12 -1
- data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
- data/lib/datadog/core.rb +8 -0
- data/lib/datadog/di/boot.rb +34 -0
- data/lib/datadog/di/remote.rb +2 -0
- data/lib/datadog/di.rb +5 -32
- data/lib/datadog/error_tracking/collector.rb +87 -0
- data/lib/datadog/error_tracking/component.rb +167 -0
- data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
- data/lib/datadog/error_tracking/configuration.rb +11 -0
- data/lib/datadog/error_tracking/ext.rb +18 -0
- data/lib/datadog/error_tracking/extensions.rb +16 -0
- data/lib/datadog/error_tracking/filters.rb +77 -0
- data/lib/datadog/error_tracking.rb +18 -0
- data/lib/datadog/kit/identity.rb +1 -1
- data/lib/datadog/profiling/exporter.rb +1 -1
- data/lib/datadog/tracing/analytics.rb +1 -1
- data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +2 -0
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
- data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
- data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
- data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
- data/lib/datadog/tracing/distributed/datadog.rb +2 -2
- data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
- data/lib/datadog/tracing/span_operation.rb +38 -14
- data/lib/datadog/tracing/trace_operation.rb +15 -7
- data/lib/datadog/tracing/tracer.rb +7 -3
- data/lib/datadog/tracing/utils.rb +1 -1
- data/lib/datadog/version.rb +1 -1
- data/lib/datadog.rb +2 -3
- metadata +34 -8
- data/lib/datadog/core/telemetry/http/env.rb +0 -20
- data/lib/datadog/core/telemetry/http/ext.rb +0 -28
- data/lib/datadog/core/telemetry/http/response.rb +0 -70
- data/lib/datadog/core/telemetry/http/transport.rb +0 -90
@@ -4,9 +4,12 @@ require 'json'
|
|
4
4
|
|
5
5
|
require_relative 'gateway/request'
|
6
6
|
require_relative 'gateway/response'
|
7
|
-
|
8
|
-
require_relative '../../
|
7
|
+
|
8
|
+
require_relative '../../event'
|
9
9
|
require_relative '../../response'
|
10
|
+
require_relative '../../processor'
|
11
|
+
require_relative '../../security_event'
|
12
|
+
require_relative '../../instrumentation/gateway'
|
10
13
|
|
11
14
|
require_relative '../../../tracing/client_ip'
|
12
15
|
require_relative '../../../tracing/contrib/rack/header_collection'
|
@@ -36,7 +39,7 @@ module Datadog
|
|
36
39
|
@rack_headers = {}
|
37
40
|
end
|
38
41
|
|
39
|
-
# rubocop:disable Metrics/
|
42
|
+
# rubocop:disable Metrics/MethodLength
|
40
43
|
def call(env)
|
41
44
|
return @app.call(env) unless Datadog::AppSec.enabled?
|
42
45
|
|
@@ -97,20 +100,13 @@ module Datadog
|
|
97
100
|
http_response = AppSec::Response.from_interrupt_params(interrupt_params, env['HTTP_ACCEPT']).to_rack
|
98
101
|
end
|
99
102
|
|
100
|
-
if AppSec.
|
101
|
-
ctx.events
|
102
|
-
trace: ctx.trace,
|
103
|
-
|
104
|
-
waf_result: ctx.extract_schema,
|
105
|
-
}
|
106
|
-
end
|
107
|
-
|
108
|
-
ctx.events.each do |e|
|
109
|
-
e[:response] ||= gateway_response
|
110
|
-
e[:request] ||= gateway_request
|
103
|
+
if AppSec.perform_api_security_check?
|
104
|
+
ctx.events.push(
|
105
|
+
AppSec::SecurityEvent.new(ctx.extract_schema, trace: ctx.trace, span: ctx.span)
|
106
|
+
)
|
111
107
|
end
|
112
108
|
|
113
|
-
AppSec::Event.record(ctx
|
109
|
+
AppSec::Event.record(ctx, request: gateway_request, response: gateway_response)
|
114
110
|
|
115
111
|
http_response
|
116
112
|
ensure
|
@@ -119,7 +115,7 @@ module Datadog
|
|
119
115
|
Datadog::AppSec::Context.deactivate
|
120
116
|
end
|
121
117
|
end
|
122
|
-
# rubocop:enable Metrics/
|
118
|
+
# rubocop:enable Metrics/MethodLength
|
123
119
|
|
124
120
|
private
|
125
121
|
|
@@ -143,6 +139,7 @@ module Datadog
|
|
143
139
|
Datadog::Tracing.active_span
|
144
140
|
end
|
145
141
|
|
142
|
+
# standard:disable Metrics/MethodLength
|
146
143
|
def add_appsec_tags(processor, context)
|
147
144
|
span = context.span
|
148
145
|
trace = context.trace
|
@@ -177,7 +174,9 @@ module Datadog
|
|
177
174
|
end
|
178
175
|
end
|
179
176
|
end
|
177
|
+
# standard:enable Metrics/MethodLength
|
180
178
|
|
179
|
+
# standard:disable Metrics/MethodLength
|
181
180
|
def add_request_tags(context, env)
|
182
181
|
span = context.span
|
183
182
|
|
@@ -200,6 +199,7 @@ module Datadog
|
|
200
199
|
)
|
201
200
|
end
|
202
201
|
end
|
202
|
+
# standard:enable Metrics/MethodLength
|
203
203
|
|
204
204
|
def to_rack_header(header)
|
205
205
|
@rack_headers[header] ||= Datadog::Tracing::Contrib::Rack::Header.to_rack_header(header)
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../../../instrumentation/gateway'
|
4
3
|
require_relative '../../../event'
|
4
|
+
require_relative '../../../security_event'
|
5
|
+
require_relative '../../../instrumentation/gateway'
|
5
6
|
|
6
7
|
module Datadog
|
7
8
|
module AppSec
|
@@ -19,7 +20,7 @@ module Datadog
|
|
19
20
|
|
20
21
|
def watch_request_action(gateway = Instrumentation.gateway)
|
21
22
|
gateway.watch('rails.request.action', :appsec) do |stack, gateway_request|
|
22
|
-
context = gateway_request.env[
|
23
|
+
context = gateway_request.env[AppSec::Ext::CONTEXT_KEY]
|
23
24
|
|
24
25
|
persistent_data = {
|
25
26
|
'server.request.body' => gateway_request.parsed_body,
|
@@ -28,18 +29,15 @@ module Datadog
|
|
28
29
|
|
29
30
|
result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
|
30
31
|
|
31
|
-
if result.match?
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
trace: context.trace,
|
37
|
-
span: context.span,
|
38
|
-
request: gateway_request,
|
39
|
-
actions: result.actions
|
40
|
-
}
|
32
|
+
if result.match? || !result.derivatives.empty?
|
33
|
+
context.events.push(
|
34
|
+
AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
|
35
|
+
)
|
36
|
+
end
|
41
37
|
|
42
|
-
|
38
|
+
if result.match?
|
39
|
+
AppSec::Event.tag_and_keep!(context, result)
|
40
|
+
AppSec::ActionsHandler.handle(result.actions)
|
43
41
|
end
|
44
42
|
|
45
43
|
stack.call(gateway_request.request)
|
@@ -96,27 +96,27 @@ module Datadog
|
|
96
96
|
# find tracer middleware reference in Rails::Configuration::MiddlewareStackProxy
|
97
97
|
app.middleware.instance_variable_get(:@operations).each do |operation|
|
98
98
|
args = case operation
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
99
|
+
when Array
|
100
|
+
# rails 5.2
|
101
|
+
_op, args = operation
|
102
|
+
args
|
103
|
+
when Proc
|
104
|
+
if operation.binding.local_variables.include?(:args)
|
105
|
+
# rails 6.0, 6.1
|
106
|
+
operation.binding.local_variable_get(:args)
|
107
|
+
else
|
108
|
+
# rails 7.0 uses ... to pass args
|
109
|
+
args_getter = Class.new do
|
110
|
+
def method_missing(_op, *args) # standard:disable Style/MissingRespondToMissing
|
111
|
+
args
|
112
|
+
end
|
113
|
+
end.new
|
114
|
+
operation.call(args_getter)
|
115
|
+
end
|
116
|
+
else
|
117
|
+
# unknown, pass through
|
118
|
+
[]
|
119
|
+
end
|
120
120
|
|
121
121
|
found = true if args.include?(middleware)
|
122
122
|
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# rubocop:disable Naming/FileName
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require_relative '../../event'
|
5
|
+
require_relative '../../security_event'
|
6
|
+
|
4
7
|
module Datadog
|
5
8
|
module AppSec
|
6
9
|
module Contrib
|
@@ -12,24 +15,20 @@ module Datadog
|
|
12
15
|
|
13
16
|
context = AppSec.active_context
|
14
17
|
|
15
|
-
ephemeral_data = {
|
18
|
+
ephemeral_data = {'server.io.net.url' => url}
|
16
19
|
result = context.run_rasp(Ext::RASP_SSRF, {}, ephemeral_data, Datadog.configuration.appsec.waf_timeout)
|
17
20
|
|
18
21
|
if result.match?
|
19
|
-
|
22
|
+
AppSec::Event.tag_and_keep!(context, result)
|
20
23
|
|
21
|
-
context.events
|
22
|
-
|
23
|
-
|
24
|
-
span: context.span,
|
25
|
-
request_url: url,
|
26
|
-
actions: result.actions
|
27
|
-
}
|
24
|
+
context.events.push(
|
25
|
+
AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
|
26
|
+
)
|
28
27
|
|
29
|
-
ActionsHandler.handle(result.actions)
|
28
|
+
AppSec::ActionsHandler.handle(result.actions)
|
30
29
|
end
|
31
30
|
|
32
|
-
super
|
31
|
+
super
|
33
32
|
end
|
34
33
|
end
|
35
34
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../../../instrumentation/gateway'
|
4
3
|
require_relative '../../../event'
|
4
|
+
require_relative '../../../security_event'
|
5
|
+
require_relative '../../../instrumentation/gateway'
|
5
6
|
|
6
7
|
module Datadog
|
7
8
|
module AppSec
|
@@ -20,7 +21,7 @@ module Datadog
|
|
20
21
|
|
21
22
|
def watch_request_dispatch(gateway = Instrumentation.gateway)
|
22
23
|
gateway.watch('sinatra.request.dispatch', :appsec) do |stack, gateway_request|
|
23
|
-
context = gateway_request.env[
|
24
|
+
context = gateway_request.env[AppSec::Ext::CONTEXT_KEY]
|
24
25
|
|
25
26
|
persistent_data = {
|
26
27
|
'server.request.body' => gateway_request.form_hash
|
@@ -28,18 +29,15 @@ module Datadog
|
|
28
29
|
|
29
30
|
result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
|
30
31
|
|
31
|
-
if result.match?
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
trace: context.trace,
|
37
|
-
span: context.span,
|
38
|
-
request: gateway_request,
|
39
|
-
actions: result.actions
|
40
|
-
}
|
32
|
+
if result.match? || !result.derivatives.empty?
|
33
|
+
context.events.push(
|
34
|
+
AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
|
35
|
+
)
|
36
|
+
end
|
41
37
|
|
42
|
-
|
38
|
+
if result.match?
|
39
|
+
AppSec::Event.tag_and_keep!(context, result)
|
40
|
+
AppSec::ActionsHandler.handle(result.actions)
|
43
41
|
end
|
44
42
|
|
45
43
|
stack.call(gateway_request.request)
|
@@ -48,7 +46,7 @@ module Datadog
|
|
48
46
|
|
49
47
|
def watch_request_routed(gateway = Instrumentation.gateway)
|
50
48
|
gateway.watch('sinatra.request.routed', :appsec) do |stack, (gateway_request, gateway_route_params)|
|
51
|
-
context = gateway_request.env[
|
49
|
+
context = gateway_request.env[AppSec::Ext::CONTEXT_KEY]
|
52
50
|
|
53
51
|
persistent_data = {
|
54
52
|
'server.request.path_params' => gateway_route_params.params
|
@@ -57,17 +55,13 @@ module Datadog
|
|
57
55
|
result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
|
58
56
|
|
59
57
|
if result.match?
|
60
|
-
|
58
|
+
AppSec::Event.tag_and_keep!(context, result)
|
61
59
|
|
62
|
-
context.events
|
63
|
-
|
64
|
-
|
65
|
-
span: context.span,
|
66
|
-
request: gateway_request,
|
67
|
-
actions: result.actions
|
68
|
-
}
|
60
|
+
context.events.push(
|
61
|
+
AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
|
62
|
+
)
|
69
63
|
|
70
|
-
|
64
|
+
AppSec::ActionsHandler.handle(result.actions)
|
71
65
|
end
|
72
66
|
|
73
67
|
stack.call(gateway_request.request)
|
data/lib/datadog/appsec/event.rb
CHANGED
@@ -11,96 +11,106 @@ module Datadog
|
|
11
11
|
DERIVATIVE_SCHEMA_KEY_PREFIX = '_dd.appsec.s.'
|
12
12
|
DERIVATIVE_SCHEMA_MAX_COMPRESSED_SIZE = 25000
|
13
13
|
ALLOWED_REQUEST_HEADERS = %w[
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
].
|
14
|
+
x-forwarded-for
|
15
|
+
x-client-ip
|
16
|
+
x-real-ip
|
17
|
+
x-forwarded
|
18
|
+
x-cluster-client-ip
|
19
|
+
forwarded-for
|
20
|
+
forwarded
|
21
|
+
via
|
22
|
+
true-client-ip
|
23
|
+
content-length
|
24
|
+
content-type
|
25
|
+
content-encoding
|
26
|
+
content-language
|
27
|
+
host
|
28
|
+
user-agent
|
29
|
+
accept
|
30
|
+
accept-encoding
|
31
|
+
accept-language
|
32
|
+
].freeze
|
33
33
|
|
34
34
|
ALLOWED_RESPONSE_HEADERS = %w[
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
].
|
40
|
-
|
41
|
-
# Record events for a trace
|
42
|
-
#
|
43
|
-
# This is expected to be called only once per trace for the rate limiter
|
44
|
-
# to properly apply
|
35
|
+
content-length
|
36
|
+
content-type
|
37
|
+
content-encoding
|
38
|
+
content-language
|
39
|
+
].freeze
|
40
|
+
|
45
41
|
class << self
|
46
|
-
def
|
47
|
-
#
|
48
|
-
|
42
|
+
def tag_and_keep!(context, waf_result)
|
43
|
+
# We want to keep the trace in case of security event
|
44
|
+
context.trace&.keep!
|
49
45
|
|
50
|
-
|
51
|
-
|
46
|
+
if context.span
|
47
|
+
if waf_result.actions.key?('block_request') || waf_result.actions.key?('redirect_request')
|
48
|
+
context.span.set_tag('appsec.blocked', 'true')
|
49
|
+
end
|
50
|
+
|
51
|
+
context.span.set_tag('appsec.event', 'true')
|
52
52
|
end
|
53
|
+
|
54
|
+
add_distributed_tags(context.trace)
|
53
55
|
end
|
54
56
|
|
55
|
-
def
|
56
|
-
events.
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
def record(context, request: nil, response: nil)
|
58
|
+
return if context.events.empty? || context.span.nil?
|
59
|
+
|
60
|
+
Datadog::AppSec::RateLimiter.thread_local.limit do
|
61
|
+
context.events.group_by(&:trace).each do |trace, event_group|
|
62
|
+
unless trace
|
63
|
+
next Datadog.logger.debug do
|
64
|
+
"AppSec: Cannot record event group with #{event_group.count} events because it has no trace"
|
65
|
+
end
|
66
|
+
end
|
61
67
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
Datadog::Tracing::Sampling::Ext::Decision::ASM
|
66
|
-
)
|
68
|
+
if event_group.any? { |event| event.attack? || event.schema? }
|
69
|
+
trace.keep!
|
70
|
+
trace[Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER] = Tracing::Sampling::Ext::Decision::ASM
|
67
71
|
|
68
|
-
|
69
|
-
|
72
|
+
context.span['_dd.origin'] = 'appsec'
|
73
|
+
context.span.set_tags(request_tags(request)) if request
|
74
|
+
context.span.set_tags(response_tags(response)) if response
|
75
|
+
end
|
70
76
|
|
71
|
-
|
72
|
-
service_entry_tags.each do |key, value|
|
73
|
-
span.set_tag(key, value)
|
77
|
+
context.span.set_tags(waf_tags(event_group))
|
74
78
|
end
|
75
79
|
end
|
76
80
|
end
|
77
81
|
|
78
|
-
|
79
|
-
waf_events = []
|
80
|
-
entry_tags = event_group.each_with_object({ '_dd.origin' => 'appsec' }) do |event, tags|
|
81
|
-
# TODO: assume HTTP request context for now
|
82
|
-
if (request = event[:request])
|
83
|
-
request.headers.each do |header, value|
|
84
|
-
tags["http.request.headers.#{header}"] = value if ALLOWED_REQUEST_HEADERS.include?(header.downcase)
|
85
|
-
end
|
82
|
+
private
|
86
83
|
|
87
|
-
|
88
|
-
|
89
|
-
tags['network.client.ip'] = request.remote_addr
|
90
|
-
end
|
84
|
+
def request_tags(request)
|
85
|
+
tags = {}
|
91
86
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
87
|
+
tags['http.host'] = request.host if request.host
|
88
|
+
tags['http.useragent'] = request.user_agent if request.user_agent
|
89
|
+
tags['network.client.ip'] = request.remote_addr if request.remote_addr
|
90
|
+
|
91
|
+
request.headers.each_with_object(tags) do |(name, value), memo|
|
92
|
+
next unless ALLOWED_REQUEST_HEADERS.include?(name)
|
93
|
+
|
94
|
+
memo["http.request.headers.#{name}"] = value
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def response_tags(response)
|
99
|
+
response.headers.each_with_object({}) do |(name, value), memo|
|
100
|
+
next unless ALLOWED_RESPONSE_HEADERS.include?(name)
|
101
|
+
|
102
|
+
memo["http.response.headers.#{name}"] = value
|
103
|
+
end
|
104
|
+
end
|
97
105
|
|
98
|
-
|
99
|
-
|
100
|
-
waf_events += waf_result.events
|
106
|
+
def waf_tags(security_events)
|
107
|
+
triggers = []
|
101
108
|
|
102
|
-
|
103
|
-
|
109
|
+
tags = security_events.each_with_object({}) do |security_event, memo|
|
110
|
+
triggers.concat(security_event.waf_result.events)
|
111
|
+
|
112
|
+
security_event.waf_result.derivatives.each do |key, value|
|
113
|
+
next memo[key] = value unless key.start_with?(DERIVATIVE_SCHEMA_KEY_PREFIX)
|
104
114
|
|
105
115
|
value = CompressedJson.dump(value)
|
106
116
|
next if value.nil?
|
@@ -110,34 +120,14 @@ module Datadog
|
|
110
120
|
next
|
111
121
|
end
|
112
122
|
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
tags
|
117
|
-
end
|
118
|
-
|
119
|
-
appsec_events = json_parse({ triggers: waf_events })
|
120
|
-
entry_tags['_dd.appsec.json'] = appsec_events if appsec_events
|
121
|
-
entry_tags
|
122
|
-
end
|
123
|
-
|
124
|
-
def tag_and_keep!(context, waf_result)
|
125
|
-
# We want to keep the trace in case of security event
|
126
|
-
context.trace.keep! if context.trace
|
127
|
-
|
128
|
-
if context.span
|
129
|
-
if waf_result.actions.key?('block_request') || waf_result.actions.key?('redirect_request')
|
130
|
-
context.span.set_tag('appsec.blocked', 'true')
|
123
|
+
memo[key] = value
|
131
124
|
end
|
132
|
-
|
133
|
-
context.span.set_tag('appsec.event', 'true')
|
134
125
|
end
|
135
126
|
|
136
|
-
|
127
|
+
tags['_dd.appsec.json'] = json_parse({triggers: triggers}) unless triggers.empty?
|
128
|
+
tags
|
137
129
|
end
|
138
130
|
|
139
|
-
private
|
140
|
-
|
141
131
|
# NOTE: Handling of Encoding::UndefinedConversionError is added as a quick fix to
|
142
132
|
# the issue between Ruby encoded strings and libddwaf produced events and now
|
143
133
|
# is under investigation.
|
@@ -8,14 +8,17 @@ module Datadog
|
|
8
8
|
class Argument; end # rubocop:disable Lint/EmptyClass
|
9
9
|
|
10
10
|
# Gateway User argument
|
11
|
+
# NOTE: This class is a subject of elimination and will be removed when
|
12
|
+
# the event system is refactored.
|
11
13
|
class User < Argument
|
12
|
-
attr_reader :id, :login
|
14
|
+
attr_reader :id, :login, :session_id
|
13
15
|
|
14
|
-
def initialize(id, login)
|
16
|
+
def initialize(id, login = nil, session_id = nil)
|
15
17
|
super()
|
16
18
|
|
17
19
|
@id = id
|
18
20
|
@login = login
|
21
|
+
@session_id = session_id
|
19
22
|
end
|
20
23
|
end
|
21
24
|
end
|
@@ -10,7 +10,7 @@ module Datadog
|
|
10
10
|
def report_rasp(type, result)
|
11
11
|
return if result.is_a?(SecurityEngine::Result::Error)
|
12
12
|
|
13
|
-
tags = {
|
13
|
+
tags = {rule_type: type, waf_version: Datadog::AppSec::WAF::VERSION::BASE_STRING}
|
14
14
|
namespace = Ext::TELEMETRY_METRICS_NAMESPACE
|
15
15
|
|
16
16
|
AppSec.telemetry.inc(namespace, 'rasp.rule.eval', 1, tags: tags)
|