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

Update metrics: appsec.waf.requests #8353

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ public void onDataAvailable(
if (!reqCtx.isAdditiveClosed()) {
log.error("Error calling WAF", e);
}
WafMetricCollector.get().wafRequestError();
return;
} finally {
if (log.isDebugEnabled()) {
Expand Down Expand Up @@ -489,27 +490,33 @@ public void onDataAvailable(
}
} else {
log.info("Ignoring action with type {}", actionInfo.type);
WafMetricCollector.get().wafRequestBlockFailure();
}
}
Collection<AppSecEvent> events = buildEvents(resultWithData);

if (!events.isEmpty() && !reqCtx.isThrottled(rateLimiter)) {
AgentSpan activeSpan = AgentTracer.get().activeSpan();
if (activeSpan != null) {
log.debug("Setting force-keep tag on the current span");
// Keep event related span, because it could be ignored in case of
// reduced datadog sampling rate.
activeSpan.getLocalRootSpan().setTag(Tags.ASM_KEEP, true);
// If APM is disabled, inform downstream services that the current
// distributed trace contains at least one ASM event and must inherit
// the given force-keep priority
activeSpan.getLocalRootSpan().setTag(Tags.PROPAGATED_APPSEC, true);
if (!events.isEmpty()) {
if (!reqCtx.isThrottled(rateLimiter)) {
AgentSpan activeSpan = AgentTracer.get().activeSpan();
if (activeSpan != null) {
log.debug("Setting force-keep tag on the current span");
// Keep event related span, because it could be ignored in case of
// reduced datadog sampling rate.
activeSpan.getLocalRootSpan().setTag(Tags.ASM_KEEP, true);
// If APM is disabled, inform downstream services that the current
// distributed trace contains at least one ASM event and must inherit
// the given force-keep priority
activeSpan.getLocalRootSpan().setTag(Tags.PROPAGATED_APPSEC, true);
} else {
// If active span is not available the ASK_KEEP tag will be set in the GatewayBridge
// when the request ends
log.debug("There is no active span available");
}
reqCtx.reportEvents(events);
} else {
// If active span is not available the ASK_KEEP tag will be set in the GatewayBridge
// when the request ends
log.debug("There is no active span available");
log.debug("Rate limited WAF events");
WafMetricCollector.get().wafRequestRateLimited();
}
reqCtx.reportEvents(events);
}

if (flow.isBlocking()) {
Expand Down Expand Up @@ -543,6 +550,7 @@ private Flow.Action.RequestBlockingAction createBlockRequestAction(ActionInfo ac
return new Flow.Action.RequestBlockingAction(statusCode, blockingContentType);
} catch (RuntimeException cce) {
log.warn("Invalid blocking action data", cce);
WafMetricCollector.get().wafRequestBlockFailure();
return null;
}
}
Expand All @@ -568,6 +576,7 @@ private Flow.Action.RequestBlockingAction createRedirectRequestAction(ActionInfo
return Flow.Action.RequestBlockingAction.forRedirect(statusCode, location);
} catch (RuntimeException cce) {
log.warn("Invalid blocking action data", cce);
WafMetricCollector.get().wafRequestBlockFailure();
return null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ private WafMetricCollector() {
private static final AtomicRequestCounter wafTriggeredRequestCounter = new AtomicRequestCounter();
private static final AtomicRequestCounter wafBlockedRequestCounter = new AtomicRequestCounter();
private static final AtomicRequestCounter wafTimeoutRequestCounter = new AtomicRequestCounter();
private static final AtomicRequestCounter wafErrorRequestCounter = new AtomicRequestCounter();
private static final AtomicRequestCounter wafRateLimitedRequestCounter =
new AtomicRequestCounter();
private static final AtomicRequestCounter wafBlockFailureRequestCounter =
new AtomicRequestCounter();
private static final AtomicLongArray raspRuleEvalCounter =
new AtomicLongArray(RuleType.getNumValues());
private static final AtomicLongArray raspRuleMatchCounter =
Expand Down Expand Up @@ -92,6 +97,18 @@ public void wafRequestTimeout() {
wafTimeoutRequestCounter.increment();
}

public void wafRequestError() {
wafErrorRequestCounter.increment();
}

public void wafRequestRateLimited() {
wafRateLimitedRequestCounter.increment();
}

public void wafRequestBlockFailure() {
wafBlockFailureRequestCounter.increment();
}

public void raspRuleEval(final RuleType ruleType) {
raspRuleEvalCounter.incrementAndGet(ruleType.ordinal());
}
Expand Down Expand Up @@ -127,6 +144,9 @@ public Collection<WafMetric> drain() {

@Override
public void prepareMetrics() {
final boolean isRateLimited = wafRateLimitedRequestCounter.getAndReset() > 0;
final boolean isBlockFailure = wafBlockFailureRequestCounter.getAndReset() > 0;

// Requests
if (wafRequestCounter.get() > 0) {
if (!rawMetricsQueue.offer(
Expand All @@ -136,7 +156,10 @@ public void prepareMetrics() {
WafMetricCollector.rulesVersion,
false,
false,
false))) {
false,
false,
isBlockFailure,
isRateLimited))) {
return;
}
}
Expand All @@ -150,7 +173,10 @@ public void prepareMetrics() {
WafMetricCollector.rulesVersion,
true,
false,
false))) {
false,
false,
isBlockFailure,
isRateLimited))) {
return;
}
}
Expand All @@ -164,7 +190,10 @@ public void prepareMetrics() {
WafMetricCollector.rulesVersion,
true,
true,
false))) {
false,
false,
false,
isRateLimited))) {
return;
}
}
Expand All @@ -178,7 +207,27 @@ public void prepareMetrics() {
WafMetricCollector.rulesVersion,
false,
false,
true))) {
false,
true,
false,
isRateLimited))) {
return;
}
}

// WAF error requests
if (wafErrorRequestCounter.get() > 0) {
if (!rawMetricsQueue.offer(
new WafRequestsRawMetric(
wafErrorRequestCounter.getAndReset(),
WafMetricCollector.wafVersion,
WafMetricCollector.rulesVersion,
false,
false,
true,
false,
false,
isRateLimited))) {
return;
}
}
Expand Down Expand Up @@ -307,15 +356,21 @@ public WafRequestsRawMetric(
final String rulesVersion,
final boolean triggered,
final boolean blocked,
final boolean wafTimeout) {
final boolean wafError,
final boolean wafTimeout,
final boolean blockFailure,
final boolean rateLimited) {
super(
"waf.requests",
counter,
"waf_version:" + wafVersion,
"event_rules_version:" + rulesVersion,
"rule_triggered:" + triggered,
"request_blocked:" + blocked,
"waf_timeout:" + wafTimeout);
"waf_error:" + wafError,
"waf_timeout:" + wafTimeout,
"block_failure:" + blockFailure,
"rate_limited:" + rateLimited);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class WafMetricCollectorTest extends DDSpecification {
WafMetricCollector.get().wafRequestTriggered()
WafMetricCollector.get().wafRequestBlocked()
WafMetricCollector.get().wafRequestTimeout()
WafMetricCollector.get().wafRequestError()
WafMetricCollector.get().wafRequestRateLimited()
WafMetricCollector.get().wafRequestBlockFailure()
WafMetricCollector.get().raspRuleEval(RuleType.SQL_INJECTION)
WafMetricCollector.get().raspRuleEval(RuleType.SQL_INJECTION)
WafMetricCollector.get().raspRuleMatch(RuleType.SQL_INJECTION)
Expand Down Expand Up @@ -69,7 +72,10 @@ class WafMetricCollectorTest extends DDSpecification {
'event_rules_version:rules.3',
'rule_triggered:false',
'request_blocked:false',
'waf_timeout:false'
'waf_error:false',
'waf_timeout:false',
'block_failure:true',
'rate_limited:true'
].toSet()

def requestTriggeredMetric = (WafMetricCollector.WafRequestsRawMetric)metrics[4]
Expand All @@ -81,7 +87,10 @@ class WafMetricCollectorTest extends DDSpecification {
'event_rules_version:rules.3',
'rule_triggered:true',
'request_blocked:false',
'waf_timeout:false'
'waf_error:false',
'waf_timeout:false',
'block_failure:true',
'rate_limited:true'
].toSet()


Expand All @@ -95,7 +104,10 @@ class WafMetricCollectorTest extends DDSpecification {
'event_rules_version:rules.3',
'rule_triggered:true',
'request_blocked:true',
'waf_timeout:false'
'waf_error:false',
'waf_timeout:false',
'block_failure:false',
'rate_limited:true'
].toSet()

def requestTimeoutMetric = (WafMetricCollector.WafRequestsRawMetric)metrics[6]
Expand All @@ -108,24 +120,43 @@ class WafMetricCollectorTest extends DDSpecification {
'event_rules_version:rules.3',
'rule_triggered:false',
'request_blocked:false',
'waf_timeout:true'
'waf_error:false',
'waf_timeout:true',
'block_failure:false',
'rate_limited:true'
].toSet()

def raspRuleEvalSqli = (WafMetricCollector.RaspRuleEval)metrics[7]
def requestWafErrorMetric = (WafMetricCollector.WafRequestsRawMetric)metrics[7]
requestWafErrorMetric.namespace == 'appsec'
requestWafErrorMetric.metricName == 'waf.requests'
requestWafErrorMetric.type == 'count'
requestWafErrorMetric.value == 1
requestWafErrorMetric.tags.toSet() == [
'waf_version:waf_ver1',
'event_rules_version:rules.3',
'rule_triggered:false',
'request_blocked:false',
'waf_error:true',
'waf_timeout:false',
'block_failure:false',
'rate_limited:true'
].toSet()

def raspRuleEvalSqli = (WafMetricCollector.RaspRuleEval)metrics[8]
raspRuleEvalSqli.type == 'count'
raspRuleEvalSqli.value == 3
raspRuleEvalSqli.namespace == 'appsec'
raspRuleEvalSqli.metricName == 'rasp.rule.eval'
raspRuleEvalSqli.tags.toSet() == ['rule_type:sql_injection', 'waf_version:waf_ver1'].toSet()

def raspRuleMatch = (WafMetricCollector.RaspRuleMatch)metrics[8]
def raspRuleMatch = (WafMetricCollector.RaspRuleMatch)metrics[9]
raspRuleMatch.type == 'count'
raspRuleMatch.value == 1
raspRuleMatch.namespace == 'appsec'
raspRuleMatch.metricName == 'rasp.rule.match'
raspRuleMatch.tags.toSet() == ['rule_type:sql_injection', 'waf_version:waf_ver1'].toSet()

def raspTimeout = (WafMetricCollector.RaspTimeout)metrics[9]
def raspTimeout = (WafMetricCollector.RaspTimeout)metrics[10]
raspTimeout.type == 'count'
raspTimeout.value == 1
raspTimeout.namespace == 'appsec'
Expand Down
Loading
Loading