Skip to content

Commit 7c90377

Browse files
committed
Distinguish source and destination config for indicator matches
We were previously conflating the path to retrieve indicator fields with the path to persist indicator fields, since they were the same value. To reduce friction in use with the new filebeat modules, we've decided to make the default source path threatintel.indicator. However, we still want to persist to threat.indicator, so we add a new constant, here.
1 parent 10b1fdd commit 7c90377

8 files changed

Lines changed: 39 additions & 38 deletions

File tree

x-pack/plugins/security_solution/common/constants.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ export const DEFAULT_RULE_REFRESH_INTERVAL_VALUE = 60000; // ms
4545
export const DEFAULT_RULE_REFRESH_IDLE_VALUE = 2700000; // ms
4646
export const DEFAULT_RULE_NOTIFICATION_QUERY_SIZE = 100;
4747

48-
// Document path where threat indicator fields are expected. Used as
49-
// both the source of enrichment fields and the destination for enrichment in
50-
// the generated detection alert
51-
export const DEFAULT_INDICATOR_PATH = 'threat.indicator';
48+
// Document path where threat indicator fields are expected. Fields are used
49+
// to enrich signals, and are copied to threat.indicator.
50+
export const DEFAULT_INDICATOR_SOURCE_PATH = 'threatintel.indicator';
51+
export const INDICATOR_DESTINATION_PATH = 'threat.indicator';
5252

5353
export enum SecurityPageName {
5454
detections = 'detections',

x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.mock.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* 2.0.
66
*/
77

8-
import { DEFAULT_INDICATOR_PATH } from '../../../constants';
8+
import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../constants';
99
import {
1010
MachineLearningCreateSchema,
1111
MachineLearningUpdateSchema,
@@ -57,7 +57,7 @@ export const getCreateThreatMatchRulesSchemaMock = (
5757
rule_id: ruleId,
5858
threat_query: '*:*',
5959
threat_index: ['list-index'],
60-
threat_indicator_path: DEFAULT_INDICATOR_PATH,
60+
threat_indicator_path: DEFAULT_INDICATOR_SOURCE_PATH,
6161
threat_mapping: [
6262
{
6363
entries: [

x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* 2.0.
66
*/
77

8-
import { DEFAULT_INDICATOR_PATH } from '../../../constants';
8+
import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../constants';
99
import { getListArrayMock } from '../types/lists.mock';
1010

1111
import { RulesSchema } from './rules_schema';
@@ -151,7 +151,7 @@ export const getThreatMatchingSchemaPartialMock = (enabled = false): Partial<Rul
151151
language: 'kuery',
152152
threat_query: '*:*',
153153
threat_index: ['list-index'],
154-
threat_indicator_path: DEFAULT_INDICATOR_PATH,
154+
threat_indicator_path: DEFAULT_INDICATOR_SOURCE_PATH,
155155
threat_mapping: [
156156
{
157157
entries: [

x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import { RiskScoreField } from '../risk_score_mapping';
4141
import { AutocompleteField } from '../autocomplete_field';
4242
import { useFetchIndex } from '../../../../common/containers/source';
4343
import { isThreatMatchRule } from '../../../../../common/detection_engine/utils';
44-
import { DEFAULT_INDICATOR_PATH } from '../../../../../common/constants';
44+
import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../../common/constants';
4545

4646
const CommonUseField = getUseField({ component: Field });
4747

@@ -310,7 +310,7 @@ const StepAboutRuleComponent: FC<StepAboutRuleProps> = ({
310310
euiFieldProps: {
311311
fullWidth: true,
312312
disabled: isLoading,
313-
placeholder: DEFAULT_INDICATOR_PATH,
313+
placeholder: DEFAULT_INDICATOR_SOURCE_PATH,
314314
},
315315
}}
316316
/>

x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/schema.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ export const schema: FormSchema<AboutStepRule> = {
205205
'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.fieldThreatIndicatorPathHelpText',
206206
{
207207
defaultMessage:
208-
'Specify the document path containing your threat indicator fields. Used for enrichment of indicator match alerts. Defaults to threat.indicator unless otherwise specified.',
208+
'Specify the document path containing your threat indicator fields. Used for enrichment of indicator match alerts.',
209209
}
210210
),
211211
labelAppend: OptionalFieldLabel,

x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/build_threat_enrichment.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* 2.0.
66
*/
77

8-
import { DEFAULT_INDICATOR_PATH } from '../../../../../common/constants';
8+
import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../../common/constants';
99
import { SignalSearchResponse, SignalsEnrichment } from '../types';
1010
import { enrichSignalThreatMatches } from './enrich_signal_threat_matches';
1111
import { getThreatList } from './get_threat_list';
@@ -52,7 +52,9 @@ export const buildThreatEnrichment = ({
5252
return threatResponse.hits.hits;
5353
};
5454

55-
const defaultedIndicatorPath = threatIndicatorPath ? threatIndicatorPath : DEFAULT_INDICATOR_PATH;
55+
const defaultedIndicatorPath = threatIndicatorPath
56+
? threatIndicatorPath
57+
: DEFAULT_INDICATOR_SOURCE_PATH;
5658
return (signals: SignalSearchResponse): Promise<SignalSearchResponse> =>
5759
enrichSignalThreatMatches(signals, getMatchedThreats, defaultedIndicatorPath);
5860
};

x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.test.ts

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import { get } from 'lodash';
9-
import { DEFAULT_INDICATOR_PATH } from '../../../../../common/constants';
9+
import { INDICATOR_DESTINATION_PATH } from '../../../../../common/constants';
1010

1111
import { getThreatListItemMock } from './build_threat_mapping_filter.mock';
1212
import {
@@ -94,7 +94,7 @@ describe('buildMatchedIndicator', () => {
9494
const indicators = buildMatchedIndicator({
9595
queries: [],
9696
threats,
97-
indicatorPath: DEFAULT_INDICATOR_PATH,
97+
indicatorPath: 'threat.indicator',
9898
});
9999

100100
expect(indicators).toEqual([]);
@@ -104,7 +104,7 @@ describe('buildMatchedIndicator', () => {
104104
const [indicator] = buildMatchedIndicator({
105105
queries,
106106
threats,
107-
indicatorPath: DEFAULT_INDICATOR_PATH,
107+
indicatorPath: 'threat.indicator',
108108
});
109109

110110
expect(get(indicator, 'matched.atomic')).toEqual('domain_1');
@@ -114,7 +114,7 @@ describe('buildMatchedIndicator', () => {
114114
const [indicator] = buildMatchedIndicator({
115115
queries,
116116
threats,
117-
indicatorPath: DEFAULT_INDICATOR_PATH,
117+
indicatorPath: 'threat.indicator',
118118
});
119119

120120
expect(get(indicator, 'matched.field')).toEqual('event.field');
@@ -124,7 +124,7 @@ describe('buildMatchedIndicator', () => {
124124
const [indicator] = buildMatchedIndicator({
125125
queries,
126126
threats,
127-
indicatorPath: DEFAULT_INDICATOR_PATH,
127+
indicatorPath: 'threat.indicator',
128128
});
129129

130130
expect(get(indicator, 'matched.type')).toEqual('type_1');
@@ -153,7 +153,7 @@ describe('buildMatchedIndicator', () => {
153153
const indicators = buildMatchedIndicator({
154154
queries,
155155
threats,
156-
indicatorPath: DEFAULT_INDICATOR_PATH,
156+
indicatorPath: 'threat.indicator',
157157
});
158158

159159
expect(indicators).toHaveLength(queries.length);
@@ -163,7 +163,7 @@ describe('buildMatchedIndicator', () => {
163163
const indicators = buildMatchedIndicator({
164164
queries,
165165
threats,
166-
indicatorPath: DEFAULT_INDICATOR_PATH,
166+
indicatorPath: 'threat.indicator',
167167
});
168168

169169
expect(indicators).toEqual([
@@ -228,7 +228,7 @@ describe('buildMatchedIndicator', () => {
228228
const indicators = buildMatchedIndicator({
229229
queries,
230230
threats,
231-
indicatorPath: DEFAULT_INDICATOR_PATH,
231+
indicatorPath: 'threat.indicator',
232232
});
233233

234234
expect(indicators).toEqual([
@@ -253,7 +253,7 @@ describe('buildMatchedIndicator', () => {
253253
const indicators = buildMatchedIndicator({
254254
queries,
255255
threats,
256-
indicatorPath: DEFAULT_INDICATOR_PATH,
256+
indicatorPath: 'threat.indicator',
257257
});
258258

259259
expect(indicators).toEqual([
@@ -285,7 +285,7 @@ describe('buildMatchedIndicator', () => {
285285
const indicators = buildMatchedIndicator({
286286
queries,
287287
threats,
288-
indicatorPath: DEFAULT_INDICATOR_PATH,
288+
indicatorPath: 'threat.indicator',
289289
});
290290

291291
expect(indicators).toEqual([
@@ -317,7 +317,7 @@ describe('buildMatchedIndicator', () => {
317317
buildMatchedIndicator({
318318
queries,
319319
threats,
320-
indicatorPath: DEFAULT_INDICATOR_PATH,
320+
indicatorPath: 'threat.indicator',
321321
})
322322
).toThrowError('Expected indicator field to be an object, but found: not an object');
323323
});
@@ -338,7 +338,7 @@ describe('buildMatchedIndicator', () => {
338338
buildMatchedIndicator({
339339
queries,
340340
threats,
341-
indicatorPath: DEFAULT_INDICATOR_PATH,
341+
indicatorPath: 'threat.indicator',
342342
})
343343
).toThrowError('Expected indicator field to be an object, but found: not an object');
344344
});
@@ -367,7 +367,7 @@ describe('enrichSignalThreatMatches', () => {
367367
const enrichedSignals = await enrichSignalThreatMatches(
368368
signals,
369369
getMatchedThreats,
370-
DEFAULT_INDICATOR_PATH
370+
'threat.indicator'
371371
);
372372

373373
expect(enrichedSignals.hits.hits).toEqual([]);
@@ -382,10 +382,10 @@ describe('enrichSignalThreatMatches', () => {
382382
const enrichedSignals = await enrichSignalThreatMatches(
383383
signals,
384384
getMatchedThreats,
385-
DEFAULT_INDICATOR_PATH
385+
'threat.indicator'
386386
);
387387
const [enrichedHit] = enrichedSignals.hits.hits;
388-
const indicators = get(enrichedHit._source, DEFAULT_INDICATOR_PATH);
388+
const indicators = get(enrichedHit._source, INDICATOR_DESTINATION_PATH);
389389

390390
expect(indicators).toEqual([
391391
{ existing: 'indicator' },
@@ -407,10 +407,10 @@ describe('enrichSignalThreatMatches', () => {
407407
const enrichedSignals = await enrichSignalThreatMatches(
408408
signals,
409409
getMatchedThreats,
410-
DEFAULT_INDICATOR_PATH
410+
'threat.indicator'
411411
);
412412
const [enrichedHit] = enrichedSignals.hits.hits;
413-
const indicators = get(enrichedHit._source, DEFAULT_INDICATOR_PATH);
413+
const indicators = get(enrichedHit._source, INDICATOR_DESTINATION_PATH);
414414

415415
expect(indicators).toEqual([
416416
{
@@ -428,10 +428,10 @@ describe('enrichSignalThreatMatches', () => {
428428
const enrichedSignals = await enrichSignalThreatMatches(
429429
signals,
430430
getMatchedThreats,
431-
DEFAULT_INDICATOR_PATH
431+
'threat.indicator'
432432
);
433433
const [enrichedHit] = enrichedSignals.hits.hits;
434-
const indicators = get(enrichedHit._source, DEFAULT_INDICATOR_PATH);
434+
const indicators = get(enrichedHit._source, INDICATOR_DESTINATION_PATH);
435435

436436
expect(indicators).toEqual([
437437
{ existing: 'indicator' },
@@ -451,7 +451,7 @@ describe('enrichSignalThreatMatches', () => {
451451
});
452452
const signals = getSignalsResponseMock([signalHit]);
453453
await expect(() =>
454-
enrichSignalThreatMatches(signals, getMatchedThreats, DEFAULT_INDICATOR_PATH)
454+
enrichSignalThreatMatches(signals, getMatchedThreats, 'threat.indicator')
455455
).rejects.toThrowError('Expected threat field to be an object, but found: whoops');
456456
});
457457

@@ -487,7 +487,7 @@ describe('enrichSignalThreatMatches', () => {
487487
'custom_threat.custom_indicator'
488488
);
489489
const [enrichedHit] = enrichedSignals.hits.hits;
490-
const indicators = get(enrichedHit._source, DEFAULT_INDICATOR_PATH);
490+
const indicators = get(enrichedHit._source, INDICATOR_DESTINATION_PATH);
491491

492492
expect(indicators).toEqual([
493493
{
@@ -530,13 +530,13 @@ describe('enrichSignalThreatMatches', () => {
530530
const enrichedSignals = await enrichSignalThreatMatches(
531531
signals,
532532
getMatchedThreats,
533-
DEFAULT_INDICATOR_PATH
533+
'threat.indicator'
534534
);
535535
expect(enrichedSignals.hits.total).toEqual(expect.objectContaining({ value: 1 }));
536536
expect(enrichedSignals.hits.hits).toHaveLength(1);
537537

538538
const [enrichedHit] = enrichedSignals.hits.hits;
539-
const indicators = get(enrichedHit._source, DEFAULT_INDICATOR_PATH);
539+
const indicators = get(enrichedHit._source, INDICATOR_DESTINATION_PATH);
540540

541541
expect(indicators).toEqual([
542542
{

x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
*/
77

88
import { get, isObject } from 'lodash';
9-
import { DEFAULT_INDICATOR_PATH } from '../../../../../common/constants';
109

1110
import type { SignalSearchResponse, SignalSourceHit } from '../types';
1211
import type {
@@ -92,7 +91,7 @@ export const enrichSignalThreatMatches = async (
9291
if (!isObject(threat)) {
9392
throw new Error(`Expected threat field to be an object, but found: ${threat}`);
9493
}
95-
const existingIndicatorValue = get(signalHit._source, DEFAULT_INDICATOR_PATH) ?? [];
94+
const existingIndicatorValue = get(signalHit._source, 'threat.indicator') ?? [];
9695
const existingIndicators = [existingIndicatorValue].flat(); // ensure indicators is an array
9796

9897
return {

0 commit comments

Comments
 (0)