datadog 2.8.0 → 2.10.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 +62 -1
- data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +66 -56
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
- data/ext/datadog_profiling_native_extension/collectors_stack.c +7 -7
- data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +221 -127
- data/ext/datadog_profiling_native_extension/heap_recorder.c +50 -92
- data/ext/datadog_profiling_native_extension/heap_recorder.h +2 -2
- data/ext/datadog_profiling_native_extension/http_transport.c +4 -4
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +3 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -1
- data/ext/datadog_profiling_native_extension/profiling.c +10 -8
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
- data/ext/datadog_profiling_native_extension/stack_recorder.c +63 -76
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -2
- data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
- data/ext/libdatadog_api/crashtracker.c +3 -0
- data/lib/datadog/appsec/actions_handler.rb +27 -0
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
- data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
- data/lib/datadog/appsec/component.rb +14 -8
- data/lib/datadog/appsec/configuration/settings.rb +9 -0
- data/lib/datadog/appsec/context.rb +74 -0
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +12 -8
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +6 -6
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +4 -4
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +1 -7
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +20 -30
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +6 -6
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +67 -96
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +11 -11
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +6 -6
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +7 -7
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -60
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +23 -33
- data/lib/datadog/appsec/contrib/rails/patcher.rb +4 -14
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +7 -7
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +45 -65
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +5 -28
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +6 -6
- data/lib/datadog/appsec/event.rb +6 -6
- data/lib/datadog/appsec/ext.rb +8 -1
- data/lib/datadog/appsec/metrics/collector.rb +38 -0
- data/lib/datadog/appsec/metrics/exporter.rb +35 -0
- data/lib/datadog/appsec/metrics/telemetry.rb +23 -0
- data/lib/datadog/appsec/metrics.rb +13 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +23 -32
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +6 -6
- data/lib/datadog/appsec/processor/rule_loader.rb +0 -3
- data/lib/datadog/appsec/processor.rb +4 -3
- data/lib/datadog/appsec/response.rb +18 -80
- data/lib/datadog/appsec/security_engine/result.rb +67 -0
- data/lib/datadog/appsec/security_engine/runner.rb +88 -0
- data/lib/datadog/appsec/security_engine.rb +9 -0
- data/lib/datadog/appsec.rb +17 -8
- data/lib/datadog/auto_instrument.rb +3 -0
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +39 -11
- data/lib/datadog/core/configuration/components.rb +4 -2
- data/lib/datadog/core/configuration.rb +1 -1
- data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
- data/lib/datadog/core/crashtracking/component.rb +1 -3
- data/lib/datadog/core/telemetry/event.rb +87 -3
- data/lib/datadog/core/telemetry/logging.rb +2 -2
- data/lib/datadog/core/telemetry/metric.rb +22 -0
- data/lib/datadog/core/telemetry/worker.rb +33 -0
- data/lib/datadog/di/base.rb +115 -0
- data/lib/datadog/di/code_tracker.rb +7 -4
- data/lib/datadog/di/component.rb +19 -11
- data/lib/datadog/di/configuration/settings.rb +11 -1
- data/lib/datadog/di/contrib/railtie.rb +15 -0
- data/lib/datadog/di/contrib.rb +26 -0
- data/lib/datadog/di/error.rb +5 -0
- data/lib/datadog/di/instrumenter.rb +39 -18
- data/lib/datadog/di/{init.rb → preload.rb} +2 -4
- data/lib/datadog/di/probe_manager.rb +4 -4
- data/lib/datadog/di/probe_notification_builder.rb +22 -2
- data/lib/datadog/di/probe_notifier_worker.rb +5 -6
- data/lib/datadog/di/redactor.rb +0 -1
- data/lib/datadog/di/remote.rb +30 -9
- data/lib/datadog/di/transport.rb +2 -4
- data/lib/datadog/di.rb +5 -108
- data/lib/datadog/kit/appsec/events.rb +3 -3
- data/lib/datadog/kit/identity.rb +4 -4
- data/lib/datadog/profiling/component.rb +55 -53
- data/lib/datadog/profiling/http_transport.rb +1 -26
- data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
- data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/extensions.rb +15 -3
- data/lib/datadog/tracing/contrib/http/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
- data/lib/datadog/tracing/span.rb +12 -4
- data/lib/datadog/tracing/span_event.rb +123 -3
- data/lib/datadog/tracing/span_operation.rb +6 -0
- data/lib/datadog/tracing/transport/serializable_trace.rb +24 -6
- data/lib/datadog/version.rb +1 -1
- metadata +40 -17
- data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
- data/lib/datadog/appsec/processor/context.rb +0 -107
- data/lib/datadog/appsec/reactive/operation.rb +0 -68
- data/lib/datadog/appsec/scope.rb +0 -58
- data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
@@ -15,18 +15,18 @@ module Datadog
|
|
15
15
|
].freeze
|
16
16
|
private_constant :ADDRESSES
|
17
17
|
|
18
|
-
def self.publish(
|
18
|
+
def self.publish(engine, gateway_request)
|
19
19
|
catch(:block) do
|
20
20
|
# params have been parsed from the request body
|
21
|
-
|
22
|
-
|
21
|
+
engine.publish('rails.request.body', gateway_request.parsed_body)
|
22
|
+
engine.publish('rails.request.route_params', gateway_request.route_params)
|
23
23
|
|
24
24
|
nil
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
def self.subscribe(
|
29
|
-
|
28
|
+
def self.subscribe(engine, context)
|
29
|
+
engine.subscribe(*ADDRESSES) do |*values|
|
30
30
|
Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
|
31
31
|
body = values[0]
|
32
32
|
path_params = values[1]
|
@@ -37,9 +37,9 @@ module Datadog
|
|
37
37
|
}
|
38
38
|
|
39
39
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
40
|
-
result =
|
40
|
+
result = context.run_waf(persistent_data, {}, waf_timeout)
|
41
41
|
|
42
|
-
next
|
42
|
+
next unless result.match?
|
43
43
|
|
44
44
|
yield result
|
45
45
|
throw(:block, true) unless result.actions.empty?
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../../../instrumentation/gateway'
|
4
|
-
require_relative '../../../reactive/
|
4
|
+
require_relative '../../../reactive/engine'
|
5
5
|
require_relative '../../rack/reactive/request_body'
|
6
6
|
require_relative '../reactive/routed'
|
7
7
|
require_relative '../../../event'
|
@@ -23,85 +23,65 @@ module Datadog
|
|
23
23
|
|
24
24
|
def watch_request_dispatch(gateway = Instrumentation.gateway)
|
25
25
|
gateway.watch('sinatra.request.dispatch', :appsec) do |stack, gateway_request|
|
26
|
-
block = false
|
27
|
-
|
28
26
|
event = nil
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
27
|
+
context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
|
28
|
+
engine = AppSec::Reactive::Engine.new
|
29
|
+
|
30
|
+
Rack::Reactive::RequestBody.subscribe(engine, context) do |result|
|
31
|
+
if result.match?
|
32
|
+
# TODO: should this hash be an Event instance instead?
|
33
|
+
event = {
|
34
|
+
waf_result: result,
|
35
|
+
trace: context.trace,
|
36
|
+
span: context.span,
|
37
|
+
request: gateway_request,
|
38
|
+
actions: result.actions
|
39
|
+
}
|
40
|
+
|
41
|
+
# We want to keep the trace in case of security event
|
42
|
+
context.trace.keep! if context.trace
|
43
|
+
Datadog::AppSec::Event.tag_and_keep!(context, result)
|
44
|
+
context.events << event
|
45
|
+
|
46
|
+
Datadog::AppSec::ActionsHandler.handle(result.actions)
|
48
47
|
end
|
49
|
-
|
50
|
-
block = Rack::Reactive::RequestBody.publish(op, gateway_request)
|
51
48
|
end
|
52
49
|
|
53
|
-
|
54
|
-
|
55
|
-
ret, res = stack.call(gateway_request.request)
|
56
|
-
|
57
|
-
if event
|
58
|
-
res ||= []
|
59
|
-
res << [:monitor, event]
|
60
|
-
end
|
50
|
+
Rack::Reactive::RequestBody.publish(engine, gateway_request)
|
61
51
|
|
62
|
-
|
52
|
+
stack.call(gateway_request.request)
|
63
53
|
end
|
64
54
|
end
|
65
55
|
|
66
56
|
def watch_request_routed(gateway = Instrumentation.gateway)
|
67
57
|
gateway.watch('sinatra.request.routed', :appsec) do |stack, (gateway_request, gateway_route_params)|
|
68
|
-
block = false
|
69
|
-
|
70
58
|
event = nil
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
59
|
+
context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
|
60
|
+
engine = AppSec::Reactive::Engine.new
|
61
|
+
|
62
|
+
Sinatra::Reactive::Routed.subscribe(engine, context) do |result|
|
63
|
+
if result.match?
|
64
|
+
# TODO: should this hash be an Event instance instead?
|
65
|
+
event = {
|
66
|
+
waf_result: result,
|
67
|
+
trace: context.trace,
|
68
|
+
span: context.span,
|
69
|
+
request: gateway_request,
|
70
|
+
actions: result.actions
|
71
|
+
}
|
72
|
+
|
73
|
+
# We want to keep the trace in case of security event
|
74
|
+
context.trace.keep! if context.trace
|
75
|
+
Datadog::AppSec::Event.tag_and_keep!(context, result)
|
76
|
+
context.events << event
|
77
|
+
|
78
|
+
Datadog::AppSec::ActionsHandler.handle(result.actions)
|
90
79
|
end
|
91
|
-
|
92
|
-
block = Sinatra::Reactive::Routed.publish(op, [gateway_request, gateway_route_params])
|
93
80
|
end
|
94
81
|
|
95
|
-
|
96
|
-
|
97
|
-
ret, res = stack.call(gateway_request.request)
|
98
|
-
|
99
|
-
if event
|
100
|
-
res ||= []
|
101
|
-
res << [:monitor, event]
|
102
|
-
end
|
82
|
+
Sinatra::Reactive::Routed.publish(engine, [gateway_request, gateway_route_params])
|
103
83
|
|
104
|
-
|
84
|
+
stack.call(gateway_request.request)
|
105
85
|
end
|
106
86
|
end
|
107
87
|
end
|
@@ -6,7 +6,6 @@ require_relative '../patcher'
|
|
6
6
|
require_relative '../../response'
|
7
7
|
require_relative '../rack/request_middleware'
|
8
8
|
require_relative 'framework'
|
9
|
-
require_relative 'ext'
|
10
9
|
require_relative 'gateway/watcher'
|
11
10
|
require_relative 'gateway/route_params'
|
12
11
|
require_relative 'gateway/request'
|
@@ -54,7 +53,7 @@ module Datadog
|
|
54
53
|
def dispatch!
|
55
54
|
env = @request.env
|
56
55
|
|
57
|
-
context = env[Datadog::AppSec::Ext::
|
56
|
+
context = env[Datadog::AppSec::Ext::CONTEXT_KEY]
|
58
57
|
|
59
58
|
return super unless context
|
60
59
|
|
@@ -62,17 +61,8 @@ module Datadog
|
|
62
61
|
|
63
62
|
gateway_request = Gateway::Request.new(env)
|
64
63
|
|
65
|
-
request_return,
|
66
|
-
|
67
|
-
catch(Datadog::AppSec::Contrib::Sinatra::Ext::ROUTE_INTERRUPT) { super }
|
68
|
-
end
|
69
|
-
|
70
|
-
if request_response
|
71
|
-
blocked_event = request_response.find { |action, _options| action == :block }
|
72
|
-
if blocked_event
|
73
|
-
self.response = AppSec::Response.negotiate(env, blocked_event.last[:actions]).to_sinatra_response
|
74
|
-
request_return = nil
|
75
|
-
end
|
64
|
+
request_return, _gateway_request = Instrumentation.gateway.push('sinatra.request.dispatch', gateway_request) do
|
65
|
+
super
|
76
66
|
end
|
77
67
|
|
78
68
|
request_return
|
@@ -86,7 +76,7 @@ module Datadog
|
|
86
76
|
def process_route(*)
|
87
77
|
env = @request.env
|
88
78
|
|
89
|
-
context = env[Datadog::AppSec::Ext::
|
79
|
+
context = env[Datadog::AppSec::Ext::CONTEXT_KEY]
|
90
80
|
|
91
81
|
return super unless context
|
92
82
|
|
@@ -103,20 +93,7 @@ module Datadog
|
|
103
93
|
gateway_request = Gateway::Request.new(env)
|
104
94
|
gateway_route_params = Gateway::RouteParams.new(route_params)
|
105
95
|
|
106
|
-
|
107
|
-
'sinatra.request.routed',
|
108
|
-
[gateway_request, gateway_route_params]
|
109
|
-
)
|
110
|
-
|
111
|
-
if request_response
|
112
|
-
blocked_event = request_response.find { |action, _options| action == :block }
|
113
|
-
if blocked_event
|
114
|
-
self.response = AppSec::Response.negotiate(env, blocked_event.last[:actions]).to_sinatra_response
|
115
|
-
|
116
|
-
# interrupt request and return response to dispatch! for consistency
|
117
|
-
throw(Datadog::AppSec::Contrib::Sinatra::Ext::ROUTE_INTERRUPT, response)
|
118
|
-
end
|
119
|
-
end
|
96
|
+
Instrumentation.gateway.push('sinatra.request.routed', [gateway_request, gateway_route_params])
|
120
97
|
|
121
98
|
yield(*args)
|
122
99
|
end
|
@@ -12,18 +12,18 @@ module Datadog
|
|
12
12
|
].freeze
|
13
13
|
private_constant :ADDRESSES
|
14
14
|
|
15
|
-
def self.publish(
|
15
|
+
def self.publish(engine, data)
|
16
16
|
_request, route_params = data
|
17
17
|
|
18
18
|
catch(:block) do
|
19
|
-
|
19
|
+
engine.publish('sinatra.request.route_params', route_params.params)
|
20
20
|
|
21
21
|
nil
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.subscribe(
|
26
|
-
|
25
|
+
def self.subscribe(engine, context)
|
26
|
+
engine.subscribe(*ADDRESSES) do |*values|
|
27
27
|
Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
|
28
28
|
path_params = values[0]
|
29
29
|
|
@@ -32,9 +32,9 @@ module Datadog
|
|
32
32
|
}
|
33
33
|
|
34
34
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
35
|
-
result =
|
35
|
+
result = context.run_waf(persistent_data, {}, waf_timeout)
|
36
36
|
|
37
|
-
next
|
37
|
+
next unless result.match?
|
38
38
|
|
39
39
|
yield result
|
40
40
|
throw(:block, true) unless result.actions.empty?
|
data/lib/datadog/appsec/event.rb
CHANGED
@@ -137,16 +137,16 @@ module Datadog
|
|
137
137
|
end
|
138
138
|
# rubocop:enable Metrics/MethodLength
|
139
139
|
|
140
|
-
def tag_and_keep!(
|
140
|
+
def tag_and_keep!(context, waf_result)
|
141
141
|
# We want to keep the trace in case of security event
|
142
|
-
|
142
|
+
context.trace.keep! if context.trace
|
143
143
|
|
144
|
-
if
|
145
|
-
|
146
|
-
|
144
|
+
if context.span
|
145
|
+
context.span.set_tag('appsec.blocked', 'true') if waf_result.actions.key?('block_request')
|
146
|
+
context.span.set_tag('appsec.event', 'true')
|
147
147
|
end
|
148
148
|
|
149
|
-
add_distributed_tags(
|
149
|
+
add_distributed_tags(context.trace)
|
150
150
|
end
|
151
151
|
|
152
152
|
private
|
data/lib/datadog/appsec/ext.rb
CHANGED
@@ -3,12 +3,19 @@
|
|
3
3
|
module Datadog
|
4
4
|
module AppSec
|
5
5
|
module Ext
|
6
|
+
RASP_SQLI = 'sql_injection'
|
7
|
+
RASP_LFI = 'lfi'
|
8
|
+
RASP_SSRF = 'ssrf'
|
9
|
+
|
6
10
|
INTERRUPT = :datadog_appsec_interrupt
|
7
|
-
|
11
|
+
CONTEXT_KEY = 'datadog.appsec.context'
|
12
|
+
ACTIVE_CONTEXT_KEY = :datadog_appsec_active_context
|
8
13
|
|
9
14
|
TAG_APPSEC_ENABLED = '_dd.appsec.enabled'
|
10
15
|
TAG_APM_ENABLED = '_dd.apm.enabled'
|
11
16
|
TAG_DISTRIBUTED_APPSEC_EVENT = '_dd.p.appsec'
|
17
|
+
|
18
|
+
TELEMETRY_METRICS_NAMESPACE = 'appsec'
|
12
19
|
end
|
13
20
|
end
|
14
21
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module AppSec
|
5
|
+
module Metrics
|
6
|
+
# A class responsible for collecting WAF and RASP call metrics.
|
7
|
+
class Collector
|
8
|
+
Store = Struct.new(:evals, :timeouts, :duration_ns, :duration_ext_ns, keyword_init: true)
|
9
|
+
|
10
|
+
attr_reader :waf, :rasp
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@mutex = Mutex.new
|
14
|
+
@waf = Store.new(evals: 0, timeouts: 0, duration_ns: 0, duration_ext_ns: 0)
|
15
|
+
@rasp = Store.new(evals: 0, timeouts: 0, duration_ns: 0, duration_ext_ns: 0)
|
16
|
+
end
|
17
|
+
|
18
|
+
def record_waf(result)
|
19
|
+
@mutex.synchronize do
|
20
|
+
@waf.evals += 1
|
21
|
+
@waf.timeouts += 1 if result.timeout?
|
22
|
+
@waf.duration_ns += result.duration_ns
|
23
|
+
@waf.duration_ext_ns += result.duration_ext_ns
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def record_rasp(result)
|
28
|
+
@mutex.synchronize do
|
29
|
+
@rasp.evals += 1
|
30
|
+
@rasp.timeouts += 1 if result.timeout?
|
31
|
+
@rasp.duration_ns += result.duration_ns
|
32
|
+
@rasp.duration_ext_ns += result.duration_ext_ns
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module AppSec
|
5
|
+
module Metrics
|
6
|
+
# A class responsible for exporting WAF and RASP call metrics.
|
7
|
+
module Exporter
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def export_waf_metrics(metrics, span)
|
11
|
+
return if metrics.evals.zero?
|
12
|
+
|
13
|
+
span.set_tag('_dd.appsec.waf.timeouts', metrics.timeouts)
|
14
|
+
span.set_tag('_dd.appsec.waf.duration', convert_ns_to_us(metrics.duration_ns))
|
15
|
+
span.set_tag('_dd.appsec.waf.duration_ext', convert_ns_to_us(metrics.duration_ext_ns))
|
16
|
+
end
|
17
|
+
|
18
|
+
def export_rasp_metrics(metrics, span)
|
19
|
+
return if metrics.evals.zero?
|
20
|
+
|
21
|
+
span.set_tag('_dd.appsec.rasp.rule.eval', metrics.evals)
|
22
|
+
span.set_tag('_dd.appsec.rasp.timeout', 1) unless metrics.timeouts.zero?
|
23
|
+
span.set_tag('_dd.appsec.rasp.duration', convert_ns_to_us(metrics.duration_ns))
|
24
|
+
span.set_tag('_dd.appsec.rasp.duration_ext', convert_ns_to_us(metrics.duration_ext_ns))
|
25
|
+
end
|
26
|
+
|
27
|
+
# private
|
28
|
+
|
29
|
+
def convert_ns_to_us(value)
|
30
|
+
value / 1000.0
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module AppSec
|
5
|
+
module Metrics
|
6
|
+
# A class responsible for reporting WAF and RASP telemetry metrics.
|
7
|
+
module Telemetry
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def report_rasp(type, result)
|
11
|
+
return if result.is_a?(SecurityEngine::Result::Error)
|
12
|
+
|
13
|
+
tags = { rule_type: type, waf_version: Datadog::AppSec::WAF::VERSION::BASE_STRING }
|
14
|
+
namespace = Ext::TELEMETRY_METRICS_NAMESPACE
|
15
|
+
|
16
|
+
AppSec.telemetry.inc(namespace, 'rasp.rule.eval', 1, tags: tags)
|
17
|
+
AppSec.telemetry.inc(namespace, 'rasp.rule.match', 1, tags: tags) if result.match?
|
18
|
+
AppSec.telemetry.inc(namespace, 'rasp.timeout', 1, tags: tags) if result.timeout?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module AppSec
|
5
|
+
# This namespace contains classes related to metrics collection and exportation.
|
6
|
+
module Metrics
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require_relative 'metrics/collector'
|
12
|
+
require_relative 'metrics/exporter'
|
13
|
+
require_relative 'metrics/telemetry'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../../instrumentation/gateway'
|
4
|
-
require_relative '../../reactive/
|
4
|
+
require_relative '../../reactive/engine'
|
5
5
|
require_relative '../reactive/set_user'
|
6
6
|
|
7
7
|
module Datadog
|
@@ -19,42 +19,33 @@ module Datadog
|
|
19
19
|
|
20
20
|
def watch_user_id(gateway = Instrumentation.gateway)
|
21
21
|
gateway.watch('identity.set_user', :appsec) do |stack, user|
|
22
|
-
block = false
|
23
22
|
event = nil
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
23
|
+
context = Datadog::AppSec.active_context
|
24
|
+
engine = AppSec::Reactive::Engine.new
|
25
|
+
|
26
|
+
Monitor::Reactive::SetUser.subscribe(engine, context) do |result|
|
27
|
+
if result.match?
|
28
|
+
# TODO: should this hash be an Event instance instead?
|
29
|
+
event = {
|
30
|
+
waf_result: result,
|
31
|
+
trace: context.trace,
|
32
|
+
span: context.span,
|
33
|
+
user: user,
|
34
|
+
actions: result.actions
|
35
|
+
}
|
36
|
+
|
37
|
+
# We want to keep the trace in case of security event
|
38
|
+
context.trace.keep! if context.trace
|
39
|
+
Datadog::AppSec::Event.tag_and_keep!(context, result)
|
40
|
+
context.events << event
|
41
|
+
|
42
|
+
Datadog::AppSec::ActionsHandler.handle(result.actions)
|
43
43
|
end
|
44
|
-
|
45
|
-
block = Monitor::Reactive::SetUser.publish(op, user)
|
46
44
|
end
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
ret, res = stack.call(user)
|
51
|
-
|
52
|
-
if event
|
53
|
-
res ||= []
|
54
|
-
res << [:monitor, event]
|
55
|
-
end
|
46
|
+
Monitor::Reactive::SetUser.publish(engine, user)
|
56
47
|
|
57
|
-
|
48
|
+
stack.call(user)
|
58
49
|
end
|
59
50
|
end
|
60
51
|
end
|
@@ -11,16 +11,16 @@ module Datadog
|
|
11
11
|
].freeze
|
12
12
|
private_constant :ADDRESSES
|
13
13
|
|
14
|
-
def self.publish(
|
14
|
+
def self.publish(engine, user)
|
15
15
|
catch(:block) do
|
16
|
-
|
16
|
+
engine.publish('usr.id', user.id)
|
17
17
|
|
18
18
|
nil
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def self.subscribe(
|
23
|
-
|
22
|
+
def self.subscribe(engine, context)
|
23
|
+
engine.subscribe(*ADDRESSES) do |*values|
|
24
24
|
Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
|
25
25
|
|
26
26
|
user_id = values[0]
|
@@ -30,9 +30,9 @@ module Datadog
|
|
30
30
|
}
|
31
31
|
|
32
32
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
33
|
-
result =
|
33
|
+
result = context.run_waf(persistent_data, {}, waf_timeout)
|
34
34
|
|
35
|
-
next
|
35
|
+
next unless result.match?
|
36
36
|
|
37
37
|
yield result
|
38
38
|
throw(:block, true) unless result.actions.empty?
|
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'security_engine/runner'
|
4
4
|
|
5
5
|
module Datadog
|
6
6
|
module AppSec
|
7
7
|
# Processor integrates libddwaf into datadog/appsec
|
8
|
+
# NOTE: This class will be moved under AppSec::SecurityEngine namespace
|
8
9
|
class Processor
|
9
10
|
attr_reader :diagnostics, :addresses
|
10
11
|
|
@@ -29,8 +30,8 @@ module Datadog
|
|
29
30
|
@handle.finalize
|
30
31
|
end
|
31
32
|
|
32
|
-
def
|
33
|
-
|
33
|
+
def new_runner
|
34
|
+
SecurityEngine::Runner.new(@handle, telemetry: @telemetry)
|
34
35
|
end
|
35
36
|
|
36
37
|
private
|