Skip to content

Commit f5875d2

Browse files
authored
akamai: handle input leniently (elastic#10158)
Also remove all redundant null-safe operators.
1 parent ef1282e commit f5875d2

File tree

3 files changed

+128
-43
lines changed

3 files changed

+128
-43
lines changed

packages/akamai/changelog.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
# newer versions go on top
2+
- version: "2.26.0"
3+
changes:
4+
- description: Handle input leniently.
5+
type: enhancement
6+
link: https://github.com/elastic/integrations/pull/10158
7+
- description: Improve efficiency of script processing.
8+
type: enhancement
9+
link: https://github.com/elastic/integrations/pull/10158
10+
- description: Fix handling of missing fields.
11+
type: bugfix
12+
link: https://github.com/elastic/integrations/pull/10158
213
- version: "2.25.4"
314
changes:
415
- description: Remove experimental/beta status warnings.

packages/akamai/data_stream/siem/elasticsearch/ingest_pipeline/default.yml

Lines changed: 116 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ processors:
1313
field: event.original
1414
target_field: json
1515
- drop:
16-
if: 'ctx?.json?.offset != null'
16+
if: ctx.json.offset != null
1717
- set:
1818
field: observer.vendor
1919
value: akamai
@@ -26,9 +26,12 @@ processors:
2626
- UNIX
2727
timezone: UTC
2828
target_field: "@timestamp"
29+
# 500s do not include a timestamp.
30+
if: ctx.json.httpMessage?.start != null
2931
- set:
3032
field: "event.start"
3133
copy_from: "@timestamp"
34+
ignore_empty_value: true
3235
- rename:
3336
field: json.httpMessage.status
3437
target_field: http.response.status_code
@@ -71,11 +74,22 @@ processors:
7174
field: json.httpMessage.path
7275
target_field: url.path
7376
ignore_missing: true
77+
on_failure:
78+
# We see some illegal character, if we can't decode, at least give the data that exists.
79+
- set:
80+
field: url.path
81+
copy_from: json.httpMessage.path
7482
- urldecode:
7583
tag: urldecode_httpMessage_query
7684
field: json.httpMessage.query
7785
target_field: url.query
7886
ignore_missing: true
87+
on_failure:
88+
# Assume a failure is due to the query already being decoded.
89+
- rename:
90+
field: json.httpMessage.query
91+
target_field: url.query
92+
ignore_failure: true
7993
- rename:
8094
field: json.httpMessage.port
8195
target_field: url.port
@@ -89,7 +103,7 @@ processors:
89103
field: json.httpMessage.responseHeaders
90104
ignore_missing: true
91105
- kv:
92-
if: ctx.json?.httpMessage?.responseHeaders != ""
106+
if: ctx.json.httpMessage?.responseHeaders != ""
93107
tag: kv_httpMessage_responseHeaders
94108
field: json.httpMessage.responseHeaders
95109
target_field: akamai.siem.response.headers
@@ -101,7 +115,7 @@ processors:
101115
field: json.httpMessage.requestHeaders
102116
ignore_missing: true
103117
- kv:
104-
if: ctx.json?.httpMessage?.requestHeaders != ""
118+
if: ctx.json.httpMessage?.requestHeaders != ""
105119
tag: kv_httpMessage_requestHeaders
106120
field: json.httpMessage.requestHeaders
107121
target_field: akamai.siem.request.headers
@@ -112,21 +126,24 @@ processors:
112126
lang: painless
113127
description: This script builds the `url.full` field out of the available `url.*` parts.
114128
source: |
115-
def full = "";
116-
if(ctx.url.scheme != null && ctx.url.scheme != "") {
117-
full += ctx.url.scheme+"://";
129+
String full = '';
130+
if (ctx.url?.scheme != null && ctx.url.scheme != "") {
131+
full += ctx.url.scheme+"://";
118132
}
119-
if(ctx.url.domain != null && ctx.url.domain != "") {
120-
full += ctx.url.domain;
133+
if (ctx.url?.domain != null && ctx.url.domain != "") {
134+
full += ctx.url.domain;
121135
}
122-
if(ctx.json.httpMessage.path != null && ctx.json.httpMessage.path != "") {
123-
full += ctx.json.httpMessage.path;
136+
if (ctx.json.httpMessage?.path != null && ctx.json.httpMessage.path != "") {
137+
full += ctx.json.httpMessage.path;
124138
}
125-
if(ctx.json.httpMessage.query != null && ctx.json.httpMessage.query != "") {
126-
full += "?"+ctx.json.httpMessage.query;
139+
if (ctx.json.httpMessage?.query != null && ctx.json.httpMessage.query != "") {
140+
full += "?"+ctx.json.httpMessage.query;
127141
}
128-
if(full != "") {
129-
ctx.url.full = full
142+
if (full != "") {
143+
if (ctx.url == null) {
144+
ctx.url = [:];
145+
}
146+
ctx.url.full = full
130147
}
131148
- dissect:
132149
field: json.httpMessage.protocol
@@ -138,7 +155,7 @@ processors:
138155
- set:
139156
field: network.transport
140157
value: tcp
141-
if: ctx?.network?.protocol != null && ctx?.network?.protocol == 'http'
158+
if: ctx.network?.protocol != null && ctx.network.protocol == 'http'
142159
- dissect:
143160
field: json.httpMessage.tls
144161
pattern: "%{tls.version_protocol}v%{tls.version}"
@@ -165,17 +182,17 @@ processors:
165182
field: json.geo.country
166183
target_field: source.geo.country_iso_code
167184
ignore_missing: true
168-
if: ctx?.source?.geo?.country_iso_code == null
185+
if: ctx.source?.geo?.country_iso_code == null
169186
- set:
170187
field: source.geo.region_iso_code
171188
value: "{{{json.geo.country}}}-{{{json.geo.regionCode}}}"
172189
ignore_empty_value: true
173-
if: ctx?.source?.geo?.region_iso_code == null
190+
if: ctx.source?.geo?.region_iso_code == null
174191
- rename:
175192
field: json.geo.city
176193
target_field: source.geo.city_name
177194
ignore_missing: true
178-
if: ctx?.source?.geo?.city_name == null
195+
if: ctx.source?.geo?.city_name == null
179196
- geoip:
180197
database_file: GeoLite2-ASN.mmdb
181198
field: source.ip
@@ -193,7 +210,7 @@ processors:
193210
target_field: source.as.number
194211
type: long
195212
ignore_missing: true
196-
if: ctx?.source?.as?.number == null
213+
if: ctx.source?.as?.number == null
197214
- rename:
198215
field: source.as.organization_name
199216
target_field: source.as.organization.name
@@ -209,6 +226,7 @@ processors:
209226
target_field: json.attackData.ruleActions
210227
separator: ';'
211228
preserve_trailing: true
229+
ignore_missing: true
212230
- urldecode:
213231
tag: urldecode_attackData_ruleData
214232
field: json.attackData.ruleData
@@ -219,6 +237,7 @@ processors:
219237
target_field: json.attackData.ruleData
220238
separator: ';'
221239
preserve_trailing: true
240+
ignore_missing: true
222241
- urldecode:
223242
tag: urldecode_attackData_ruleMessages
224243
field: json.attackData.ruleMessages
@@ -229,6 +248,7 @@ processors:
229248
target_field: json.attackData.ruleMessages
230249
separator: ';'
231250
preserve_trailing: true
251+
ignore_missing: true
232252
- urldecode:
233253
tag: urldecode_attackData_ruleSelectors
234254
field: json.attackData.ruleSelectors
@@ -239,6 +259,7 @@ processors:
239259
target_field: json.attackData.ruleSelectors
240260
separator: ';'
241261
preserve_trailing: true
262+
ignore_missing: true
242263
- urldecode:
243264
tag: urldecode_attackData_ruleTags
244265
field: json.attackData.ruleTags
@@ -249,6 +270,7 @@ processors:
249270
target_field: json.attackData.ruleTags
250271
separator: ';'
251272
preserve_trailing: true
273+
ignore_missing: true
252274
- urldecode:
253275
tag: urldecode_attackData_ruleVersions
254276
field: json.attackData.ruleVersions
@@ -259,6 +281,7 @@ processors:
259281
target_field: json.attackData.ruleVersions
260282
separator: ';'
261283
preserve_trailing: true
284+
ignore_missing: true
262285
- urldecode:
263286
tag: urldecode_attackData_rules
264287
field: json.attackData.rules
@@ -269,30 +292,53 @@ processors:
269292
target_field: json.attackData.rules
270293
separator: ';'
271294
preserve_trailing: true
295+
ignore_missing: true
272296
- script:
273297
lang: painless
274298
description: Base64 Decode the json.attackData.rule* fields
275299
tag: script_base64_decode_attackData_rule
300+
params:
301+
items:
302+
- rules
303+
- ruleActions
304+
- ruleData
305+
- ruleMessages
306+
- ruleTags
307+
- ruleSelectors
308+
- ruleVersions
309+
if: ctx.json.attackData?.rules instanceof List
276310
source: |
277-
ArrayList items = new ArrayList(["rules", "ruleActions", "ruleData", "ruleMessages", "ruleTags", "ruleSelectors", "ruleVersions"]);
278311
ArrayList rules_array = new ArrayList();
279312
ArrayList rule_actions = new ArrayList();
280313
ArrayList rule_tags = new ArrayList();
281314
for (def i = 0; i < ctx.json.attackData.rules.length; i++) {
282-
HashMap map = new HashMap();
283-
for (def j = 0; j < items.length; j++) {
284-
String key = items[j];
285-
if (i < ctx.json.attackData[key].length ) {
286-
String value = ctx.json.attackData[key][i].replace(" ", "").decodeBase64();
287-
map.put(key, value);
288-
if (key == "ruleTags") {
289-
rule_tags.add(value.toLowerCase());
290-
} else if (key == "ruleActions") {
291-
rule_actions.add(value.toLowerCase());
292-
}
315+
HashMap map = new HashMap();
316+
for (String key: params.items) {
317+
if (i < ctx.json.attackData[key].length) {
318+
String data = ctx.json.attackData[key][i].replace(" ", "");
319+
try {
320+
String value = data.decodeBase64();
321+
map.put(key, value);
322+
if (key == "ruleTags") {
323+
rule_tags.add(value.toLowerCase());
324+
} else if (key == "ruleActions") {
325+
rule_actions.add(value.toLowerCase());
326+
}
327+
}
328+
catch (Exception e) {
329+
if (data.length() > 10) {
330+
data = data.substring(0,10)+"..."
331+
}
332+
String error = e.toString();
333+
if (error.startsWith("java.lang.IllegalArgumentException: ")) {
334+
error = error.substring("java.lang.IllegalArgumentException: ".length());
293335
}
336+
String warning = "failed to decode base64 data: " + error + ": " + data;
337+
map.put(key, warning);
338+
}
294339
}
295-
rules_array.add(map);
340+
}
341+
rules_array.add(map);
296342
}
297343
ctx.akamai.siem.rules = rules_array;
298344
ctx._rule_actions = rule_actions;
@@ -393,36 +439,64 @@ processors:
393439
field: json.userRiskData.score
394440
target_field: akamai.siem.user_risk.score
395441
type: long
442+
if: ctx.json.userRiskData?.score != null && ctx.json.userRiskData.score != ''
396443
ignore_missing: true
397444
- convert:
398445
field: json.userRiskData.allow
399446
target_field: akamai.siem.user_risk.allow
400447
type: long
401448
ignore_missing: true
402449
- kv:
403-
if: ctx.json?.userRiskData?.risk != ""
450+
if: ctx.json.userRiskData?.risk != ""
404451
tag: kv_userRiskData_risk
405452
field: json.userRiskData.risk
406453
target_field: akamai.siem.user_risk.risk
407454
field_split: '\|'
408455
value_split: ':'
409456
ignore_missing: true
410457
- kv:
411-
if: ctx.json?.userRiskData?.trust != ""
458+
if: ctx.json.userRiskData?.trust != ""
412459
tag: kv_userRiskData_trust
413460
field: json.userRiskData.trust
414461
target_field: akamai.siem.user_risk.trust
415462
field_split: '\|'
416463
value_split: ':'
417464
ignore_missing: true
418-
- kv:
419-
if: ctx.json?.userRiskData?.general != ""
420-
tag: kv_userRiskData_general
421-
field: json.userRiskData.general
422-
target_field: akamai.siem.user_risk.general
423-
field_split: '\|'
424-
value_split: ':'
425-
ignore_missing: true
465+
- script:
466+
description: Process key-value pairs, preserving keys without values.
467+
lang: painless
468+
tag: script_userRiskData_general
469+
if: ctx.json.userRiskData?.general instanceof String && ctx.json.userRiskData.general != ""
470+
source: |
471+
String text = ctx.json.userRiskData.general.trim();
472+
if (text != "") {
473+
def m = new HashMap();
474+
for (String f: /\|/.split(text)) {
475+
if (f == "") {
476+
continue;
477+
}
478+
int idx = f.indexOf(':');
479+
if (idx == -1) {
480+
m.put(f, "-"); // Include a non-empty string to prevent the field being removed.
481+
continue;
482+
}
483+
String k = f.substring(0, idx);
484+
String v = f.substring(idx+1);
485+
m.put(k, v);
486+
}
487+
if (m.size() > 0) {
488+
if (ctx.akamai == null) {
489+
ctx.akamai = new HashMap();
490+
}
491+
if (ctx.akamai.siem == null) {
492+
ctx.akamai.siem = new HashMap();
493+
}
494+
if (ctx.akamai.siem.user_risk == null) {
495+
ctx.akamai.siem.user_risk = new HashMap();
496+
}
497+
ctx.akamai.siem.user_risk.general = m;
498+
}
499+
}
426500
##
427501
- append:
428502
field: related.ip

packages/akamai/manifest.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: akamai
22
title: Akamai
3-
version: "2.25.4"
3+
version: "2.26.0"
44
description: Collect logs from Akamai with Elastic Agent.
55
type: integration
66
format_version: "3.0.2"

0 commit comments

Comments
 (0)