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

[Security Solution][Detections] Adds Nested CTI row renderer #96275

Merged
merged 33 commits into from
Apr 16, 2021
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
20dd329
Move alert-specific mocks to more declarative mock file
rylnd Mar 31, 2021
6a1a613
Add placeholder interface for ECS threat fields
rylnd Mar 31, 2021
9b12c87
Test and implement CTI row renderer
rylnd Mar 31, 2021
e373e78
Pass full fields data to our row renderers
rylnd Apr 1, 2021
f42ba60
Rewrite existing row renderer in terms of flattened data
rylnd Apr 1, 2021
10a53f8
Moving logic into discrete files
rylnd Apr 1, 2021
9d7afd0
Register threat match row rendere
rylnd Apr 1, 2021
adf7067
WIP: Rendering draggable fields but hit the data loss issue with nest…
rylnd Apr 2, 2021
6fc1d90
WIP: implementing row renderer against new data format
rylnd Apr 6, 2021
c2eb905
Updating based on new data
rylnd Apr 6, 2021
b20b71b
Revert "Pass full fields data to our row renderers"
rylnd Apr 6, 2021
39f1880
Fix draggables
rylnd Apr 12, 2021
3477d27
Move indicator field strings to constants
rylnd Apr 12, 2021
0a6f6fd
Fix example data for CTI row renderer
rylnd Apr 12, 2021
f6f887c
Move CTI field constants to common folder
rylnd Apr 12, 2021
72b5b3f
Remove redundant CTI fields from client request
rylnd Apr 12, 2021
f95f8e3
Add missing graphQL type
rylnd Apr 12, 2021
838e548
Updates tests
rylnd Apr 12, 2021
73a3d1d
Merge branch 'master' into nested_row_renderer
rylnd Apr 14, 2021
90f6004
Split ThreatMatchRow into subcomponents
rylnd Apr 14, 2021
d625b2c
Make CTI row renderer look nice
rylnd Apr 14, 2021
d14f795
Make indicator reference field an external link
rylnd Apr 15, 2021
5fbcf64
Back to consistent horizontal spacing, here
rylnd Apr 15, 2021
d7cce75
Add hr as a visual separator between each match "row" of the row rend…
rylnd Apr 15, 2021
5a04c28
Fix tests broken due to addition of a new row renderer
rylnd Apr 15, 2021
d8bf839
Full-width hr
rylnd Apr 15, 2021
2f7433f
More descriptive constant
rylnd Apr 15, 2021
d49d692
More realistic data
rylnd Apr 15, 2021
542052b
Remove useless comment
rylnd Apr 15, 2021
9295afc
Add threat_match row renderer type to GQL client
rylnd Apr 15, 2021
b115dfe
Ensure contextId is unique for each CTI subrow
rylnd Apr 15, 2021
8f667c7
Merge branch 'master' into nested_row_renderer
kibanamachine Apr 15, 2021
37d737b
Merge branch 'master' into nested_row_renderer
kibanamachine Apr 15, 2021
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
35 changes: 35 additions & 0 deletions x-pack/plugins/security_solution/common/cti/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { INDICATOR_DESTINATION_PATH } from '../constants';

export const MATCHED_ATOMIC = 'matched.atomic';
export const MATCHED_FIELD = 'matched.field';
export const MATCHED_TYPE = 'matched.type';
export const INDICATOR_MATCH_SUBFIELDS = [MATCHED_ATOMIC, MATCHED_FIELD, MATCHED_TYPE];

export const INDICATOR_MATCHED_ATOMIC = `${INDICATOR_DESTINATION_PATH}.${MATCHED_ATOMIC}`;
export const INDICATOR_MATCHED_FIELD = `${INDICATOR_DESTINATION_PATH}.${MATCHED_FIELD}`;
export const INDICATOR_MATCHED_TYPE = `${INDICATOR_DESTINATION_PATH}.${MATCHED_TYPE}`;

export const EVENT_DATASET = 'event.dataset';
export const EVENT_REFERENCE = 'event.reference';
export const PROVIDER = 'provider';

export const INDICATOR_DATASET = `${INDICATOR_DESTINATION_PATH}.${EVENT_DATASET}`;
export const INDICATOR_REFERENCE = `${INDICATOR_DESTINATION_PATH}.${EVENT_REFERENCE}`;
export const INDICATOR_PROVIDER = `${INDICATOR_DESTINATION_PATH}.${PROVIDER}`;

// fields used to populate the CTI row renderer
rylnd marked this conversation as resolved.
Show resolved Hide resolved
export const REQUIRED_INDICATOR_MATCH_FIELDS = [
INDICATOR_MATCHED_ATOMIC,
INDICATOR_MATCHED_FIELD,
INDICATOR_MATCHED_TYPE,
INDICATOR_DATASET,
INDICATOR_REFERENCE,
INDICATOR_PROVIDER,
];
2 changes: 2 additions & 0 deletions x-pack/plugins/security_solution/common/ecs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { UserEcs } from './user';
import { WinlogEcs } from './winlog';
import { ProcessEcs } from './process';
import { SystemEcs } from './system';
import { ThreatEcs } from './threat';
import { Ransomware } from './ransomware';

export interface Ecs {
Expand Down Expand Up @@ -58,6 +59,7 @@ export interface Ecs {
process?: ProcessEcs;
file?: FileEcs;
system?: SystemEcs;
threat?: ThreatEcs;
// This should be temporary
eql?: { parentId: string; sequenceNumber: string };
Ransomware?: Ransomware;
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/security_solution/common/ecs/rule/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface RuleEcs {
id?: string[];
rule_id?: string[];
name?: string[];
false_positives: string[];
false_positives?: string[];
saved_id?: string[];
timeline_id?: string[];
timeline_title?: string[];
Expand Down
25 changes: 25 additions & 0 deletions x-pack/plugins/security_solution/common/ecs/threat/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { EventEcs } from '../event';

interface ThreatMatchEcs {
atomic?: string[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these truly optional? if you have an atomic, shouldn't you always have a field and a type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existing *Ecs types seemed to be very defensive, where almost everything was optional. If it's one of our detection alerts then it should have all three, but I think these are meant to be general to anything "compliant" with ECS.

field?: string[];
type?: string[];
}

export interface ThreatIndicatorEcs {
matched?: ThreatMatchEcs;
event?: EventEcs & { reference?: string[] };
provider?: string[];
type?: string[];
}

export interface ThreatEcs {
indicator: ThreatIndicatorEcs[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ export interface EventsActionGroupData {
doc_count: number;
}

export type Fields = Record<string, unknown[] | Fields[]>;
export interface Fields<T = unknown[]> {
[x: string]: T | Array<Fields<T>>;
}

export interface EventHit extends SearchHit {
sort: string[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ export enum RowRendererId {
system_fim = 'system_fim',
system_security_event = 'system_security_event',
system_socket = 'system_socket',
threat_match = 'threat_match',
zeek = 'zeek',
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from './header';
export * from './hook_wrapper';
export * from './index_pattern';
export * from './mock_detail_item';
export * from './mock_detection_alerts';
export * from './mock_ecs';
export * from './mock_local_storage';
export * from './mock_timeline_data';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { Ecs } from '../../../common/ecs';
import { TimelineNonEcsData } from '../../../common/search_strategy';

export const mockEcsDataWithAlert: Ecs = {
_id: '1',
timestamp: '2018-11-05T19:03:25.937Z',
host: {
name: ['apache'],
ip: ['192.168.0.1'],
},
event: {
id: ['1'],
action: ['Action'],
category: ['Access'],
module: ['nginx'],
severity: [3],
},
source: {
ip: ['192.168.0.1'],
port: [80],
},
destination: {
ip: ['192.168.0.3'],
port: [6343],
},
user: {
id: ['1'],
name: ['john.dee'],
},
geo: {
region_name: ['xx'],
country_iso_code: ['xx'],
},
signal: {
rule: {
created_at: ['2020-01-10T21:11:45.839Z'],
updated_at: ['2020-01-10T21:11:45.839Z'],
created_by: ['elastic'],
description: ['24/7'],
enabled: [true],
false_positives: ['test-1'],
filters: [],
from: ['now-300s'],
id: ['b5ba41ab-aaf3-4f43-971b-bdf9434ce0ea'],
immutable: [false],
index: ['auditbeat-*'],
interval: ['5m'],
rule_id: ['rule-id-1'],
language: ['kuery'],
output_index: ['.siem-signals-default'],
max_signals: [100],
risk_score: ['21'],
query: ['user.name: root or user.name: admin'],
references: ['www.test.co'],
saved_id: ["Garrett's IP"],
timeline_id: ['1234-2136-11ea-9864-ebc8cc1cb8c2'],
timeline_title: ['Untitled timeline'],
severity: ['low'],
updated_by: ['elastic'],
tags: [],
to: ['now'],
type: ['saved_query'],
threat: [],
note: ['# this is some markdown documentation'],
version: ['1'],
},
},
};

export const getDetectionAlertMock = (overrides: Partial<Ecs> = {}): Ecs => ({
...mockEcsDataWithAlert,
...overrides,
});

export const getThreatMatchDetectionAlert = (overrides: Partial<Ecs> = {}): Ecs => ({
...mockEcsDataWithAlert,
signal: {
...mockEcsDataWithAlert.signal,
rule: {
...mockEcsDataWithAlert.rule,
name: ['mock threat_match rule'],
type: ['threat_match'],
},
},
threat: {
indicator: [
{
matched: {
atomic: ['matched.atomic'],
field: ['matched.atomic'],
type: ['matched.domain'],
},
},
],
},
...overrides,
});

export const getDetectionAlertFieldsMock = (
fields: TimelineNonEcsData[] = []
): TimelineNonEcsData[] => [
{ field: '@timestamp', value: ['2021-03-27T06:28:47.292Z'] },
{ field: 'signal.rule.type', value: ['threat_match'] },
...fields,
];
66 changes: 0 additions & 66 deletions x-pack/plugins/security_solution/public/common/mock/mock_ecs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1026,69 +1026,3 @@ export const mockEcsData: Ecs[] = [
},
},
];

export const mockEcsDataWithAlert: Ecs = {
_id: '1',
timestamp: '2018-11-05T19:03:25.937Z',
host: {
name: ['apache'],
ip: ['192.168.0.1'],
},
event: {
id: ['1'],
action: ['Action'],
category: ['Access'],
module: ['nginx'],
severity: [3],
},
source: {
ip: ['192.168.0.1'],
port: [80],
},
destination: {
ip: ['192.168.0.3'],
port: [6343],
},
user: {
id: ['1'],
name: ['john.dee'],
},
geo: {
region_name: ['xx'],
country_iso_code: ['xx'],
},
signal: {
rule: {
created_at: ['2020-01-10T21:11:45.839Z'],
updated_at: ['2020-01-10T21:11:45.839Z'],
created_by: ['elastic'],
description: ['24/7'],
enabled: [true],
false_positives: ['test-1'],
filters: [],
from: ['now-300s'],
id: ['b5ba41ab-aaf3-4f43-971b-bdf9434ce0ea'],
immutable: [false],
index: ['auditbeat-*'],
interval: ['5m'],
rule_id: ['rule-id-1'],
language: ['kuery'],
output_index: ['.siem-signals-default'],
max_signals: [100],
risk_score: ['21'],
query: ['user.name: root or user.name: admin'],
references: ['www.test.co'],
saved_id: ["Garrett's IP"],
timeline_id: ['1234-2136-11ea-9864-ebc8cc1cb8c2'],
timeline_title: ['Untitled timeline'],
severity: ['low'],
updated_by: ['elastic'],
tags: [],
to: ['now'],
type: ['saved_query'],
threat: [],
note: ['# this is some markdown documentation'],
version: ['1'],
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,31 @@ export const mockTimelineData: TimelineItem[] = [
geo: { region_name: ['xx'], country_iso_code: ['xx'] },
},
},
{
_id: '32',
data: [],
ecs: {
_id: 'BuBP4W0BOpWiDweSoYSg',
timestamp: '2019-10-18T23:59:15.091Z',
// TODO use more realistic data
rylnd marked this conversation as resolved.
Show resolved Hide resolved
threat: {
indicator: [
{
matched: {
atomic: ['laptop.local'],
field: ['host.name'],
type: ['domain'],
},
event: {
dataset: ['threatintel.abuseurl'],
reference: ['https://urlhaus.abuse.ch/url/1055419/'],
},
provider: ['indicator_provider'],
},
],
},
},
},
];

export const mockFimFileCreatedEvent: Ecs = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
SystemFimExample,
SystemSecurityEventExample,
SystemSocketExample,
ThreatMatchExample,
ZeekExample,
} from '../examples';
import * as i18n from './translations';
Expand Down Expand Up @@ -204,6 +205,13 @@ export const renderers: RowRendererOption[] = [
example: SuricataExample,
searchableDescription: `${i18n.SURICATA_DESCRIPTION_PART1} ${i18n.SURICATA_NAME} ${i18n.SURICATA_DESCRIPTION_PART2}`,
},
{
id: RowRendererId.threat_match,
name: i18n.THREAT_MATCH_NAME,
description: i18n.THREAT_MATCH_DESCRIPTION,
example: ThreatMatchExample,
searchableDescription: `${i18n.THREAT_MATCH_NAME} ${i18n.THREAT_MATCH_DESCRIPTION}`,
},
{
id: RowRendererId.zeek,
name: i18n.ZEEK_NAME,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,19 @@ export const SYSTEM_DESCRIPTION_PART3 = i18n.translate(
'All datasets send both periodic state information (e.g. all currently running processes) and real-time changes (e.g. when a new process starts or stops).',
}
);
export const THREAT_MATCH_NAME = i18n.translate(
'xpack.securitySolution.eventRenderers.threatMatchName',
{
defaultMessage: 'Threat Indicator Match',
}
);

export const THREAT_MATCH_DESCRIPTION = i18n.translate(
'xpack.securitySolution.eventRenderers.threatMatchDescription',
{
defaultMessage: 'Summarizes events that matched threat indicators',
}
);

export const ZEEK_NAME = i18n.translate('xpack.securitySolution.eventRenderers.zeekName', {
defaultMessage: 'Zeek (formerly Bro)',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export * from './system_file';
export * from './system_fim';
export * from './system_security_event';
export * from './system_socket';
export * from './threat_match';
export * from './zeek';
Loading