Skip to content

Commit 5e2e95f

Browse files
committed
sentinel_one: fix duplicate event ingestion in threat_event and application_risk
Add a time watermark (updatedAt__gte) to the threat_event CEL program so each interval only fetches threats updated since the last completed walk, rather than re-walking the entire catalog. The high-water mark is tracked in cursor.last_timestamp and seeded from a new initial_interval manifest variable on the first run. The default poll interval drops from 24h to 5m since the watermark eliminates full re-walks. Add fingerprint processors to both the threat_event and application_risk ingest pipelines so that re-emitted documents with the same id are rejected within a backing index rather than accumulating as duplicates.
1 parent 0137f93 commit 5e2e95f

10 files changed

Lines changed: 102 additions & 13 deletions

File tree

packages/sentinel_one/changelog.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
# newer versions go on top
2+
- version: "2.11.1"
3+
changes:
4+
- description: Add time watermark and fingerprint deduplication to the threat event data stream to prevent duplicate ingestion.
5+
type: bugfix
6+
link: https://github.com/elastic/integrations/pull/20211
7+
- description: Add fingerprint deduplication to the application risk data stream to prevent duplicate ingestion.
8+
type: bugfix
9+
link: https://github.com/elastic/integrations/pull/20211
210
- version: "2.11.0"
311
changes:
412
- description: |

packages/sentinel_one/data_stream/application_risk/elasticsearch/ingest_pipeline/default.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ processors:
2626
field: event.original
2727
tag: json_event_original
2828
target_field: json
29+
- fingerprint:
30+
tag: fingerprint_application_risk_dedup
31+
fields:
32+
- json.id
33+
- json.status
34+
target_field: _id
35+
ignore_missing: true
2936
- set:
3037
field: event.kind
3138
tag: set_event_kind

packages/sentinel_one/data_stream/threat_event/_dev/test/policy/test-all.expected

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,17 @@ inputs:
3333
state.url.trim_right("/") + "/web/api/v2.1/threats?" + {
3434
"skipCount": ["true"],
3535
"limit": [string(state.batch_size)],
36+
"sortBy": ["updatedAt"],
37+
"sortOrder": ["asc"],
38+
"updatedAt__gte": [
39+
state.?cursor.?list_updated_at_gte.orValue(
40+
state.?cursor.?last_timestamp.orValue(
41+
(now - duration(state.initial_interval)).format(time_layout.RFC3339)
42+
)
43+
)
44+
],
3645
?"siteIds": state.?site_ids.optMap(v, [string(v)]),
37-
?"cursor": state.?cursor.next_page.token.optMap(v, [v]),
46+
?"cursor": state.?cursor.?next_page.token.optMap(v, [v]),
3847
}.format_query()
3948
).with(
4049
{
@@ -51,6 +60,12 @@ inputs:
5160
?"token": (body.?pagination.nextCursor.orValue(null) != null) ? optional.of(body.pagination.nextCursor) : optional.none(),
5261
},
5362
"fetch_more": body.?pagination.nextCursor.orValue(null) != null,
63+
"list_updated_at_gte": state.?cursor.?list_updated_at_gte.orValue(
64+
state.?cursor.?last_timestamp.orValue(
65+
(now - duration(state.initial_interval)).format(time_layout.RFC3339)
66+
)
67+
),
68+
?"last_timestamp": state.?cursor.last_timestamp,
5469
},
5570
}
5671
)
@@ -69,7 +84,6 @@ inputs:
6984
},
7085
},
7186
"want_more": false,
72-
"cursor": {},
7387
}
7488
)
7589
)
@@ -119,6 +133,11 @@ inputs:
119133
?"token": has_more_events ? optional.of(body.pagination.nextCursor) : optional.none(),
120134
},
121135
"fetch_more": state.?cursor.fetch_more.orValue(false),
136+
"list_updated_at_gte": state.cursor.list_updated_at_gte,
137+
?"last_timestamp": has_more_events ?
138+
state.?cursor.last_timestamp
139+
:
140+
state.cursor.worklist.data[0].?threatInfo.updatedAt.or(state.?cursor.last_timestamp),
122141
},
123142
}
124143
)
@@ -145,7 +164,6 @@ inputs:
145164
{
146165
"events": [],
147166
"want_more": false,
148-
"cursor": {},
149167
}
150168
)
151169
)
@@ -242,6 +260,7 @@ inputs:
242260
state:
243261
api_token: ${SECRET_0}
244262
batch_size: 100
263+
initial_interval: 1h
245264
site_ids: "123"
246265
tags:
247266
- preserve_original_event

packages/sentinel_one/data_stream/threat_event/_dev/test/policy/test-all.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ vars:
8383
-----END PRIVATE KEY-----
8484
data_stream:
8585
vars:
86+
initial_interval: 1h
8687
interval: 30s
8788
batch_size: 100
8889
max_executions: 1000

packages/sentinel_one/data_stream/threat_event/_dev/test/policy/test-default.expected

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ inputs:
99
- config_version: 2
1010
data_stream:
1111
dataset: sentinel_one.threat_event
12-
interval: 24h
12+
interval: 5m
1313
max_executions: 1000
1414
program: |-
1515
(
@@ -22,8 +22,17 @@ inputs:
2222
state.url.trim_right("/") + "/web/api/v2.1/threats?" + {
2323
"skipCount": ["true"],
2424
"limit": [string(state.batch_size)],
25+
"sortBy": ["updatedAt"],
26+
"sortOrder": ["asc"],
27+
"updatedAt__gte": [
28+
state.?cursor.?list_updated_at_gte.orValue(
29+
state.?cursor.?last_timestamp.orValue(
30+
(now - duration(state.initial_interval)).format(time_layout.RFC3339)
31+
)
32+
)
33+
],
2534
?"siteIds": state.?site_ids.optMap(v, [string(v)]),
26-
?"cursor": state.?cursor.next_page.token.optMap(v, [v]),
35+
?"cursor": state.?cursor.?next_page.token.optMap(v, [v]),
2736
}.format_query()
2837
).with(
2938
{
@@ -40,6 +49,12 @@ inputs:
4049
?"token": (body.?pagination.nextCursor.orValue(null) != null) ? optional.of(body.pagination.nextCursor) : optional.none(),
4150
},
4251
"fetch_more": body.?pagination.nextCursor.orValue(null) != null,
52+
"list_updated_at_gte": state.?cursor.?list_updated_at_gte.orValue(
53+
state.?cursor.?last_timestamp.orValue(
54+
(now - duration(state.initial_interval)).format(time_layout.RFC3339)
55+
)
56+
),
57+
?"last_timestamp": state.?cursor.last_timestamp,
4358
},
4459
}
4560
)
@@ -58,7 +73,6 @@ inputs:
5873
},
5974
},
6075
"want_more": false,
61-
"cursor": {},
6276
}
6377
)
6478
)
@@ -108,6 +122,11 @@ inputs:
108122
?"token": has_more_events ? optional.of(body.pagination.nextCursor) : optional.none(),
109123
},
110124
"fetch_more": state.?cursor.fetch_more.orValue(false),
125+
"list_updated_at_gte": state.cursor.list_updated_at_gte,
126+
?"last_timestamp": has_more_events ?
127+
state.?cursor.last_timestamp
128+
:
129+
state.cursor.worklist.data[0].?threatInfo.updatedAt.or(state.?cursor.last_timestamp),
111130
},
112131
}
113132
)
@@ -134,7 +153,6 @@ inputs:
134153
{
135154
"events": [],
136155
"want_more": false,
137-
"cursor": {},
138156
}
139157
)
140158
)
@@ -152,6 +170,7 @@ inputs:
152170
state:
153171
api_token: ${SECRET_0}
154172
batch_size: 1000
173+
initial_interval: 24h
155174
tags:
156175
- forwarded
157176
- sentinel_one-threat_event

packages/sentinel_one/data_stream/threat_event/_dev/test/policy/test-default.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ vars:
33
api_token: test_api_token
44
data_stream:
55
vars:
6-
interval: 24h
6+
initial_interval: 24h
7+
interval: 5m
78
batch_size: 1000
89
max_executions: 1000
910
enable_request_tracer: false

packages/sentinel_one/data_stream/threat_event/agent/stream/cel.yml.hbs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ resource.url: {{url}}
1818
state:
1919
api_token: {{api_token}}
2020
batch_size: {{batch_size}}
21+
initial_interval: {{initial_interval}}
2122
{{#if site_ids }}
2223
site_ids: !!str {{site_ids}}
2324
{{/if}}
@@ -35,8 +36,17 @@ program: |-
3536
state.url.trim_right("/") + "/web/api/v2.1/threats?" + {
3637
"skipCount": ["true"],
3738
"limit": [string(state.batch_size)],
39+
"sortBy": ["updatedAt"],
40+
"sortOrder": ["asc"],
41+
"updatedAt__gte": [
42+
state.?cursor.?list_updated_at_gte.orValue(
43+
state.?cursor.?last_timestamp.orValue(
44+
(now - duration(state.initial_interval)).format(time_layout.RFC3339)
45+
)
46+
)
47+
],
3848
?"siteIds": state.?site_ids.optMap(v, [string(v)]),
39-
?"cursor": state.?cursor.next_page.token.optMap(v, [v]),
49+
?"cursor": state.?cursor.?next_page.token.optMap(v, [v]),
4050
}.format_query()
4151
).with(
4252
{
@@ -53,6 +63,12 @@ program: |-
5363
?"token": (body.?pagination.nextCursor.orValue(null) != null) ? optional.of(body.pagination.nextCursor) : optional.none(),
5464
},
5565
"fetch_more": body.?pagination.nextCursor.orValue(null) != null,
66+
"list_updated_at_gte": state.?cursor.?list_updated_at_gte.orValue(
67+
state.?cursor.?last_timestamp.orValue(
68+
(now - duration(state.initial_interval)).format(time_layout.RFC3339)
69+
)
70+
),
71+
?"last_timestamp": state.?cursor.last_timestamp,
5672
},
5773
}
5874
)
@@ -71,7 +87,6 @@ program: |-
7187
},
7288
},
7389
"want_more": false,
74-
"cursor": {},
7590
}
7691
)
7792
)
@@ -121,6 +136,11 @@ program: |-
121136
?"token": has_more_events ? optional.of(body.pagination.nextCursor) : optional.none(),
122137
},
123138
"fetch_more": state.?cursor.fetch_more.orValue(false),
139+
"list_updated_at_gte": state.cursor.list_updated_at_gte,
140+
?"last_timestamp": has_more_events ?
141+
state.?cursor.last_timestamp
142+
:
143+
state.cursor.worklist.data[0].?threatInfo.updatedAt.or(state.?cursor.last_timestamp),
124144
},
125145
}
126146
)
@@ -147,7 +167,6 @@ program: |-
147167
{
148168
"events": [],
149169
"want_more": false,
150-
"cursor": {},
151170
}
152171
)
153172
)

packages/sentinel_one/data_stream/threat_event/elasticsearch/ingest_pipeline/default.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ processors:
4545
field: event.original
4646
tag: json_event_original
4747
target_field: json
48+
- fingerprint:
49+
tag: fingerprint_threat_event_dedup
50+
fields:
51+
- json.id
52+
- json.createdAt
53+
target_field: _id
54+
ignore_missing: true
4855
- rename:
4956
field: json.id
5057
tag: rename_id

packages/sentinel_one/data_stream/threat_event/manifest.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,19 @@ streams:
88
enabled: false
99
template_path: cel.yml.hbs
1010
vars:
11+
- name: initial_interval
12+
type: text
13+
title: Initial Interval
14+
description: How far back to look for threats on the first run. Supported units for this parameter are h/m/s.
15+
default: 24h
16+
multi: false
17+
required: true
18+
show_user: true
1119
- name: interval
1220
type: text
1321
title: Interval
1422
description: Duration between requests to the SentinelOne API. Supported units for this parameter are h/m/s.
15-
default: 24h
23+
default: 5m
1624
multi: false
1725
required: true
1826
show_user: true

packages/sentinel_one/manifest.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
format_version: "3.4.0"
22
name: sentinel_one
33
title: SentinelOne
4-
version: "2.11.0"
4+
version: "2.11.1"
55
description: Collect logs from SentinelOne with Elastic Agent.
66
type: integration
77
categories:

0 commit comments

Comments
 (0)