Skip to content

Commit d51e7c5

Browse files
authored
Merge branch 'master' into change-system-tests-workflow-run-conditions
2 parents c51fb57 + e3cec5f commit d51e7c5

File tree

10 files changed

+212
-7
lines changed

10 files changed

+212
-7
lines changed

.gitlab/prepare-oci-package.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
set -e
44

5+
if [ "$OS" != "linux" ]; then
6+
echo "Only linux packages are supported. Exiting"
7+
exit 0
8+
fi
9+
510
mkdir sources
611

712
cp ../lib-injection/host_inject.rb sources

lib/datadog/appsec/context.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,12 @@ def run_waf(persistent_data, ephemeral_data, timeout = WAF::LibDDWAF::DDWAF_RUN_
4646
result
4747
end
4848

49-
def run_rasp(_type, persistent_data, ephemeral_data, timeout = WAF::LibDDWAF::DDWAF_RUN_TIMEOUT)
49+
def run_rasp(type, persistent_data, ephemeral_data, timeout = WAF::LibDDWAF::DDWAF_RUN_TIMEOUT)
5050
result = @waf_runner.run(persistent_data, ephemeral_data, timeout)
5151

52+
Metrics::Telemetry.report_rasp(type, result)
5253
@metrics.record_rasp(result)
54+
5355
result
5456
end
5557

lib/datadog/appsec/ext.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@
33
module Datadog
44
module AppSec
55
module Ext
6-
RASP_SQLI = :sql_injection
6+
RASP_SQLI = 'sql_injection'
7+
RASP_LFI = 'lfi'
8+
RASP_SSRF = 'ssrf'
9+
710
INTERRUPT = :datadog_appsec_interrupt
811
CONTEXT_KEY = 'datadog.appsec.context'
912
ACTIVE_CONTEXT_KEY = :datadog_appsec_active_context
1013

1114
TAG_APPSEC_ENABLED = '_dd.appsec.enabled'
1215
TAG_APM_ENABLED = '_dd.apm.enabled'
1316
TAG_DISTRIBUTED_APPSEC_EVENT = '_dd.p.appsec'
17+
18+
TELEMETRY_METRICS_NAMESPACE = 'appsec'
1419
end
1520
end
1621
end

lib/datadog/appsec/metrics.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ module Metrics
1010

1111
require_relative 'metrics/collector'
1212
require_relative 'metrics/exporter'
13+
require_relative 'metrics/telemetry'
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

sig/datadog/appsec/context.rbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ module Datadog
3333

3434
def run_waf: (input_data persistent_data, input_data ephemeral_data, ?Integer timeout) -> SecurityEngine::result
3535

36-
def run_rasp: (::Symbol _type, input_data persistent_data, input_data ephemeral_data, ?Integer timeout) -> SecurityEngine::result
36+
def run_rasp: (Ext::rasp_rule_type type, input_data persistent_data, input_data ephemeral_data, ?Integer timeout) -> SecurityEngine::result
3737

3838
def export_metrics: () -> void
3939

sig/datadog/appsec/ext.rbs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
11
module Datadog
22
module AppSec
33
module Ext
4-
RASP_SQLI: ::Symbol
4+
type rasp_rule_type = ::String
5+
6+
RASP_SQLI: ::String
7+
8+
RASP_LFI: ::String
9+
10+
RASP_SSRF: ::String
11+
512
INTERRUPT: ::Symbol
13+
614
CONTEXT_KEY: ::String
15+
716
ACTIVE_CONTEXT_KEY: ::Symbol
817

918
TAG_APPSEC_ENABLED: ::String
19+
1020
TAG_APM_ENABLED: ::String
21+
1122
TAG_DISTRIBUTED_APPSEC_EVENT: ::String
23+
24+
TELEMETRY_METRICS_NAMESPACE: ::String
1225
end
1326
end
1427
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module Datadog
2+
module AppSec
3+
module Metrics
4+
module Telemetry
5+
def self?.report_rasp: (Ext::rasp_rule_type type, SecurityEngine::result result) -> void
6+
end
7+
end
8+
end
9+
end

spec/datadog/appsec/context_spec.rb

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
'server.request.headers.no_cookies' => { 'user-agent' => 'Nessus SOAP' }
8989
}
9090

91-
Array.new(3) { context.run_waf(persistent_data, {}, 10_000) }
91+
Array.new(3) { context.run_waf(persistent_data, {}, 1_000_000) }
9292
end
9393

9494
it 'returns a single match and rest is ok' do
@@ -110,8 +110,8 @@
110110
}
111111

112112
[
113-
context.run_waf(persistent_data_1, {}, 10_000),
114-
context.run_waf(persistent_data_2, {}, 10_000),
113+
context.run_waf(persistent_data_1, {}, 1_000_000),
114+
context.run_waf(persistent_data_2, {}, 1_000_000),
115115
]
116116
end
117117

@@ -126,6 +126,57 @@
126126
end
127127
end
128128

129+
describe '#run_rasp' do
130+
context 'when a matching run was made' do
131+
before { allow(Datadog::AppSec).to receive(:telemetry).and_return(telemetry) }
132+
133+
let(:persistent_data) do
134+
{ 'server.request.query' => { 'q' => "1' OR 1=1;" } }
135+
end
136+
let(:ephemeral_data) do
137+
{
138+
'server.db.statement' => "SELECT * FROM users WHERE name = '1' OR 1=1;",
139+
'server.db.system' => 'mysql'
140+
}
141+
end
142+
143+
it 'sends telemetry metrics' do
144+
expect(telemetry).to receive(:inc)
145+
.with('appsec', anything, kind_of(Integer), anything)
146+
.at_least(:once)
147+
148+
context.run_rasp('sqli', persistent_data, ephemeral_data, 1_000_000)
149+
end
150+
end
151+
152+
context 'when a run was a failure' do
153+
before do
154+
allow(Datadog::AppSec).to receive(:telemetry).and_return(telemetry)
155+
allow_any_instance_of(Datadog::AppSec::SecurityEngine::Runner).to receive(:run)
156+
.and_return(run_result)
157+
end
158+
159+
let(:run_result) do
160+
Datadog::AppSec::SecurityEngine::Result::Error.new(duration_ext_ns: 0)
161+
end
162+
let(:persistent_data) do
163+
{ 'server.request.query' => { 'q' => "1' OR 1=1;" } }
164+
end
165+
let(:ephemeral_data) do
166+
{
167+
'server.db.statement' => "SELECT * FROM users WHERE name = '1' OR 1=1;",
168+
'server.db.system' => 'mysql'
169+
}
170+
end
171+
172+
it 'sends telemetry metrics' do
173+
expect(telemetry).not_to receive(:inc)
174+
175+
context.run_rasp('sqli', persistent_data, ephemeral_data, 1_000_000)
176+
end
177+
end
178+
end
179+
129180
describe '#extract_schema' do
130181
it 'calls the waf runner with specific addresses' do
131182
expect_any_instance_of(Datadog::AppSec::SecurityEngine::Runner).to receive(:run)
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# frozen_string_literal: true
2+
3+
require 'datadog/appsec/spec_helper'
4+
5+
RSpec.describe Datadog::AppSec::Metrics::Telemetry do
6+
before do
7+
stub_const('Datadog::AppSec::Ext::TELEMETRY_METRICS_NAMESPACE', 'specsec')
8+
stub_const('Datadog::AppSec::WAF::VERSION::BASE_STRING', '1.42.99')
9+
10+
allow(Datadog::AppSec).to receive(:telemetry).and_return(telemetry)
11+
end
12+
13+
let(:telemetry) { instance_double(Datadog::Core::Telemetry::Component) }
14+
15+
describe '.report_rasp' do
16+
context 'when reporting a match run result' do
17+
let(:run_result) do
18+
Datadog::AppSec::SecurityEngine::Result::Match.new(
19+
events: [], actions: {}, derivatives: {}, timeout: false, duration_ns: 0, duration_ext_ns: 0
20+
)
21+
end
22+
23+
it 'does not set WAF metrics on the span' do
24+
expect(telemetry).to receive(:inc)
25+
.with('specsec', 'rasp.rule.eval', 1, tags: { rule_type: 'my-type', waf_version: '1.42.99' })
26+
expect(telemetry).to receive(:inc)
27+
.with('specsec', 'rasp.rule.match', 1, tags: { rule_type: 'my-type', waf_version: '1.42.99' })
28+
29+
described_class.report_rasp('my-type', run_result)
30+
end
31+
end
32+
33+
context 'when reporting a match run result with timeout' do
34+
let(:run_result) do
35+
Datadog::AppSec::SecurityEngine::Result::Match.new(
36+
events: [], actions: {}, derivatives: {}, timeout: true, duration_ns: 0, duration_ext_ns: 0
37+
)
38+
end
39+
40+
it 'does not set WAF metrics on the span' do
41+
expect(telemetry).to receive(:inc)
42+
.with('specsec', 'rasp.rule.eval', 1, tags: { rule_type: 'my-type', waf_version: '1.42.99' })
43+
expect(telemetry).to receive(:inc)
44+
.with('specsec', 'rasp.rule.match', 1, tags: { rule_type: 'my-type', waf_version: '1.42.99' })
45+
expect(telemetry).to receive(:inc)
46+
.with('specsec', 'rasp.timeout', 1, tags: { rule_type: 'my-type', waf_version: '1.42.99' })
47+
48+
described_class.report_rasp('my-type', run_result)
49+
end
50+
end
51+
52+
context 'when reporting a ok run result' do
53+
let(:run_result) do
54+
Datadog::AppSec::SecurityEngine::Result::Ok.new(
55+
events: [], actions: {}, derivatives: {}, timeout: false, duration_ns: 0, duration_ext_ns: 0
56+
)
57+
end
58+
59+
it 'does not set WAF metrics on the span' do
60+
expect(telemetry).to receive(:inc)
61+
.with('specsec', 'rasp.rule.eval', 1, tags: { rule_type: 'my-type', waf_version: '1.42.99' })
62+
63+
described_class.report_rasp('my-type', run_result)
64+
end
65+
end
66+
67+
context 'when reporting a ok run result with timeout' do
68+
let(:run_result) do
69+
Datadog::AppSec::SecurityEngine::Result::Ok.new(
70+
events: [], actions: {}, derivatives: {}, timeout: true, duration_ns: 0, duration_ext_ns: 0
71+
)
72+
end
73+
74+
it 'does not set WAF metrics on the span' do
75+
expect(telemetry).to receive(:inc)
76+
.with('specsec', 'rasp.rule.eval', 1, tags: { rule_type: 'my-type', waf_version: '1.42.99' })
77+
expect(telemetry).to receive(:inc)
78+
.with('specsec', 'rasp.timeout', 1, tags: { rule_type: 'my-type', waf_version: '1.42.99' })
79+
80+
described_class.report_rasp('my-type', run_result)
81+
end
82+
end
83+
84+
context 'when reporting a error run result' do
85+
let(:run_result) do
86+
Datadog::AppSec::SecurityEngine::Result::Error.new(duration_ext_ns: 0)
87+
end
88+
89+
it 'does not set WAF metrics on the span' do
90+
expect(telemetry).not_to receive(:inc)
91+
92+
described_class.report_rasp('my-type', run_result)
93+
end
94+
end
95+
end
96+
end

0 commit comments

Comments
 (0)