Skip to content

Commit f7dad89

Browse files
authored
[SIEM] Adds support for apm-* to the network map (#54876) (#55142)
## Summary Resolves #52297, #52565 To improve the display of APM data within SIEM (specifically the `HTTP Table` and `Network Map`), this PR adds `apm-*-transcation*` to `siem:defaultIndex`, and additional support for showing `client`/`server` layers on the `Network Map` when a matching `apm-*` index pattern is present. The map now supports pattern matching when checking for available Kibana Index Patterns, and so matches `apm-*-transcation*` -> `apm-*` (if exists). Additionally, the map config was updated to generate layers for client/server geo fields (instead of the usual source/dest) since these are the fields Transactions use. ![image](https://user-images.githubusercontent.com/2946766/72573225-2a038880-3882-11ea-9590-a545d726dbf9.png) <img width="1214" alt="Screen Shot 2020-01-14 at 18 22 11" src="https://user-images.githubusercontent.com/2946766/72407120-bcd5e300-371b-11ea-90cc-a0714320a59c.png"> ### Checklist Use ~~strikethroughs~~ to remove checklist items you don't feel are applicable to this PR. - [ ] ~This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility)~ - [X] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md) - [ ] [Documentation](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#writing-documentation) was added for features that require explanation or tutorials - Will work with @benskelker on updating the maps docs - [X] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios - [ ] ~This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist)~ ### For maintainers - [ ] ~This was checked for breaking API changes and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~ - [ ] ~This includes a feature addition or change that requires a release note and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~
1 parent 62a1a4a commit f7dad89

File tree

18 files changed

+661
-34
lines changed

18 files changed

+661
-34
lines changed

x-pack/legacy/plugins/siem/default_index_pattern.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
/** The comma-delimited list of Elasticsearch indices from which the SIEM app collects events */
88
export const defaultIndexPattern = [
9+
'apm-*-transaction*',
910
'auditbeat-*',
1011
'endgame-*',
1112
'filebeat-*',

x-pack/legacy/plugins/siem/public/components/drag_and_drop/__snapshots__/drag_drop_context_wrapper.test.tsx.snap

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/legacy/plugins/siem/public/components/embeddables/__mocks__/mock.ts

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@
55
*/
66

77
import { IndexPatternMapping } from '../types';
8+
import { IndexPatternSavedObject } from '../../ml_popover/types';
89

910
export const mockIndexPatternIds: IndexPatternMapping[] = [
1011
{ title: 'filebeat-*', id: '8c7323ac-97ad-4b53-ac0a-40f8f691a918' },
1112
];
1213

14+
export const mockAPMIndexPatternIds: IndexPatternMapping[] = [
15+
{ title: 'apm-*', id: '8c7323ac-97ad-4b53-ac0a-40f8f691a918' },
16+
];
17+
1318
export const mockSourceLayer = {
1419
sourceDescriptor: {
1520
id: 'uuid.v4()',
@@ -113,6 +118,109 @@ export const mockDestinationLayer = {
113118
query: { query: '', language: 'kuery' },
114119
};
115120

121+
export const mockClientLayer = {
122+
sourceDescriptor: {
123+
id: 'uuid.v4()',
124+
type: 'ES_SEARCH',
125+
applyGlobalQuery: true,
126+
geoField: 'client.geo.location',
127+
filterByMapBounds: false,
128+
tooltipProperties: [
129+
'host.name',
130+
'client.ip',
131+
'client.domain',
132+
'client.geo.country_iso_code',
133+
'client.as.organization.name',
134+
],
135+
useTopHits: false,
136+
topHitsTimeField: '@timestamp',
137+
topHitsSize: 1,
138+
indexPatternId: '8c7323ac-97ad-4b53-ac0a-40f8f691a918',
139+
},
140+
style: {
141+
type: 'VECTOR',
142+
properties: {
143+
fillColor: {
144+
type: 'STATIC',
145+
options: { color: '#6092C0' },
146+
},
147+
lineColor: {
148+
type: 'STATIC',
149+
options: { color: '#FFFFFF' },
150+
},
151+
lineWidth: { type: 'STATIC', options: { size: 2 } },
152+
iconSize: { type: 'STATIC', options: { size: 8 } },
153+
iconOrientation: {
154+
type: 'STATIC',
155+
options: { orientation: 0 },
156+
},
157+
symbol: {
158+
options: { symbolizeAs: 'icon', symbolId: 'home' },
159+
},
160+
},
161+
},
162+
id: 'uuid.v4()',
163+
label: `apm-* | Client Point`,
164+
minZoom: 0,
165+
maxZoom: 24,
166+
alpha: 1,
167+
visible: true,
168+
type: 'VECTOR',
169+
query: { query: '', language: 'kuery' },
170+
joins: [],
171+
};
172+
173+
export const mockServerLayer = {
174+
sourceDescriptor: {
175+
id: 'uuid.v4()',
176+
type: 'ES_SEARCH',
177+
applyGlobalQuery: true,
178+
geoField: 'server.geo.location',
179+
filterByMapBounds: true,
180+
tooltipProperties: [
181+
'host.name',
182+
'server.ip',
183+
'server.domain',
184+
'server.geo.country_iso_code',
185+
'server.as.organization.name',
186+
],
187+
useTopHits: false,
188+
topHitsTimeField: '@timestamp',
189+
topHitsSize: 1,
190+
indexPatternId: '8c7323ac-97ad-4b53-ac0a-40f8f691a918',
191+
},
192+
style: {
193+
type: 'VECTOR',
194+
properties: {
195+
fillColor: {
196+
type: 'STATIC',
197+
options: { color: '#D36086' },
198+
},
199+
lineColor: {
200+
type: 'STATIC',
201+
options: { color: '#FFFFFF' },
202+
},
203+
lineWidth: { type: 'STATIC', options: { size: 2 } },
204+
iconSize: { type: 'STATIC', options: { size: 8 } },
205+
iconOrientation: {
206+
type: 'STATIC',
207+
options: { orientation: 0 },
208+
},
209+
symbol: {
210+
options: { symbolizeAs: 'icon', symbolId: 'marker' },
211+
},
212+
},
213+
},
214+
id: 'uuid.v4()',
215+
label: `apm-* | Server Point`,
216+
minZoom: 0,
217+
maxZoom: 24,
218+
alpha: 1,
219+
visible: true,
220+
type: 'VECTOR',
221+
query: { query: '', language: 'kuery' },
222+
};
223+
116224
export const mockLineLayer = {
117225
sourceDescriptor: {
118226
type: 'ES_PEW_PEW',
@@ -173,6 +281,66 @@ export const mockLineLayer = {
173281
query: { query: '', language: 'kuery' },
174282
};
175283

284+
export const mockClientServerLineLayer = {
285+
sourceDescriptor: {
286+
type: 'ES_PEW_PEW',
287+
applyGlobalQuery: true,
288+
id: 'uuid.v4()',
289+
indexPatternId: '8c7323ac-97ad-4b53-ac0a-40f8f691a918',
290+
sourceGeoField: 'client.geo.location',
291+
destGeoField: 'server.geo.location',
292+
metrics: [
293+
{ type: 'sum', field: 'client.bytes', label: 'client.bytes' },
294+
{ type: 'sum', field: 'server.bytes', label: 'server.bytes' },
295+
],
296+
},
297+
style: {
298+
type: 'VECTOR',
299+
properties: {
300+
fillColor: {
301+
type: 'STATIC',
302+
options: { color: '#1EA593' },
303+
},
304+
lineColor: {
305+
type: 'STATIC',
306+
options: { color: '#6092C0' },
307+
},
308+
lineWidth: {
309+
type: 'DYNAMIC',
310+
options: {
311+
field: {
312+
label: 'count',
313+
name: 'doc_count',
314+
origin: 'source',
315+
},
316+
minSize: 1,
317+
maxSize: 8,
318+
fieldMetaOptions: {
319+
isEnabled: true,
320+
sigma: 3,
321+
},
322+
},
323+
},
324+
iconSize: { type: 'STATIC', options: { size: 10 } },
325+
iconOrientation: {
326+
type: 'STATIC',
327+
options: { orientation: 0 },
328+
},
329+
symbol: {
330+
options: { symbolizeAs: 'circle', symbolId: 'airfield' },
331+
},
332+
},
333+
},
334+
id: 'uuid.v4()',
335+
label: `apm-* | Line`,
336+
minZoom: 0,
337+
maxZoom: 24,
338+
alpha: 0.5,
339+
visible: true,
340+
type: 'VECTOR',
341+
query: { query: '', language: 'kuery' },
342+
};
343+
176344
export const mockLayerList = [
177345
{
178346
sourceDescriptor: { type: 'EMS_TMS', isAutoSelect: true },
@@ -209,3 +377,83 @@ export const mockLayerListDouble = [
209377
mockDestinationLayer,
210378
mockSourceLayer,
211379
];
380+
381+
export const mockLayerListMixed = [
382+
{
383+
sourceDescriptor: { type: 'EMS_TMS', isAutoSelect: true },
384+
id: 'uuid.v4()',
385+
label: null,
386+
minZoom: 0,
387+
maxZoom: 24,
388+
alpha: 1,
389+
visible: true,
390+
style: null,
391+
type: 'VECTOR_TILE',
392+
},
393+
mockLineLayer,
394+
mockDestinationLayer,
395+
mockSourceLayer,
396+
mockClientServerLineLayer,
397+
mockServerLayer,
398+
mockClientLayer,
399+
];
400+
401+
export const mockAPMIndexPattern: IndexPatternSavedObject = {
402+
id: 'apm-*',
403+
type: 'index-pattern',
404+
updated_at: '',
405+
version: 'abc',
406+
attributes: {
407+
title: 'apm-*',
408+
},
409+
};
410+
411+
export const mockAPMRegexIndexPattern: IndexPatternSavedObject = {
412+
id: 'apm-7.*',
413+
type: 'index-pattern',
414+
updated_at: '',
415+
version: 'abc',
416+
attributes: {
417+
title: 'apm-7.*',
418+
},
419+
};
420+
421+
export const mockFilebeatIndexPattern: IndexPatternSavedObject = {
422+
id: 'filebeat-*',
423+
type: 'index-pattern',
424+
updated_at: '',
425+
version: 'abc',
426+
attributes: {
427+
title: 'filebeat-*',
428+
},
429+
};
430+
431+
export const mockAuditbeatIndexPattern: IndexPatternSavedObject = {
432+
id: 'auditbeat-*',
433+
type: 'index-pattern',
434+
updated_at: '',
435+
version: 'abc',
436+
attributes: {
437+
title: 'auditbeat-*',
438+
},
439+
};
440+
441+
export const mockAPMTransactionIndexPattern: IndexPatternSavedObject = {
442+
id: 'apm-*-transaction*',
443+
type: 'index-pattern',
444+
updated_at: '',
445+
version: 'abc',
446+
attributes: {
447+
title: 'apm-*-transaction*',
448+
},
449+
};
450+
451+
export const mockGlobIndexPattern: IndexPatternSavedObject = {
452+
id: '*',
453+
type: 'index-pattern',
454+
updated_at: '',
455+
version: 'abc',
456+
attributes: {
457+
title: '*',
458+
},
459+
};

x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { Loader } from '../loader';
1818
import { displayErrorToast, useStateToaster } from '../toasters';
1919
import { Embeddable } from './embeddable';
2020
import { EmbeddableHeader } from './embeddable_header';
21-
import { createEmbeddable } from './embedded_map_helpers';
21+
import { createEmbeddable, findMatchingIndexPatterns } from './embedded_map_helpers';
2222
import { IndexPatternsMissingPrompt } from './index_patterns_missing_prompt';
2323
import { MapToolTip } from './map_tool_tip/map_tool_tip';
2424
import * as i18n from './translations';
@@ -107,10 +107,12 @@ export const EmbeddedMapComponent = ({
107107
useEffect(() => {
108108
let isSubscribed = true;
109109
async function setupEmbeddable() {
110-
// Ensure at least one `siem:defaultIndex` index pattern exists before trying to import
111-
const matchingIndexPatterns = kibanaIndexPatterns.filter(ip =>
112-
siemDefaultIndices.includes(ip.attributes.title)
113-
);
110+
// Ensure at least one `siem:defaultIndex` kibana index pattern exists before creating embeddable
111+
const matchingIndexPatterns = findMatchingIndexPatterns({
112+
kibanaIndexPatterns,
113+
siemDefaultIndices,
114+
});
115+
114116
if (matchingIndexPatterns.length === 0 && isSubscribed) {
115117
setIsLoading(false);
116118
setIsIndexError(true);

x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map_helpers.test.tsx

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import { createEmbeddable } from './embedded_map_helpers';
7+
import { createEmbeddable, findMatchingIndexPatterns } from './embedded_map_helpers';
88
import { createUiNewPlatformMock } from 'ui/new_platform/__mocks__/helpers';
99
import { createPortalNode } from 'react-reverse-portal';
10+
import {
11+
mockAPMIndexPattern,
12+
mockAPMRegexIndexPattern,
13+
mockAPMTransactionIndexPattern,
14+
mockAuditbeatIndexPattern,
15+
mockFilebeatIndexPattern,
16+
mockGlobIndexPattern,
17+
} from './__mocks__/mock';
1018

1119
jest.mock('ui/new_platform');
1220

@@ -51,4 +59,58 @@ describe('embedded_map_helpers', () => {
5159
expect(embeddable.reload).toHaveBeenCalledTimes(1);
5260
});
5361
});
62+
63+
describe('findMatchingIndexPatterns', () => {
64+
const siemDefaultIndices = [
65+
'apm-*-transaction*',
66+
'auditbeat-*',
67+
'endgame-*',
68+
'filebeat-*',
69+
'packetbeat-*',
70+
'winlogbeat-*',
71+
];
72+
73+
test('finds exact matching index patterns ', () => {
74+
const matchingIndexPatterns = findMatchingIndexPatterns({
75+
kibanaIndexPatterns: [mockFilebeatIndexPattern, mockAuditbeatIndexPattern],
76+
siemDefaultIndices,
77+
});
78+
expect(matchingIndexPatterns).toEqual([mockFilebeatIndexPattern, mockAuditbeatIndexPattern]);
79+
});
80+
81+
test('finds glob-matched index patterns ', () => {
82+
const matchingIndexPatterns = findMatchingIndexPatterns({
83+
kibanaIndexPatterns: [mockAPMIndexPattern, mockFilebeatIndexPattern],
84+
siemDefaultIndices,
85+
});
86+
expect(matchingIndexPatterns).toEqual([mockAPMIndexPattern, mockFilebeatIndexPattern]);
87+
});
88+
89+
test('does not find glob-matched index pattern containing regex', () => {
90+
const matchingIndexPatterns = findMatchingIndexPatterns({
91+
kibanaIndexPatterns: [mockAPMRegexIndexPattern, mockFilebeatIndexPattern],
92+
siemDefaultIndices,
93+
});
94+
expect(matchingIndexPatterns).toEqual([mockFilebeatIndexPattern]);
95+
});
96+
97+
test('finds exact glob-matched index patterns ', () => {
98+
const matchingIndexPatterns = findMatchingIndexPatterns({
99+
kibanaIndexPatterns: [mockAPMTransactionIndexPattern, mockFilebeatIndexPattern],
100+
siemDefaultIndices,
101+
});
102+
expect(matchingIndexPatterns).toEqual([
103+
mockAPMTransactionIndexPattern,
104+
mockFilebeatIndexPattern,
105+
]);
106+
});
107+
108+
test('finds glob-only index patterns ', () => {
109+
const matchingIndexPatterns = findMatchingIndexPatterns({
110+
kibanaIndexPatterns: [mockGlobIndexPattern, mockFilebeatIndexPattern],
111+
siemDefaultIndices,
112+
});
113+
expect(matchingIndexPatterns).toEqual([mockGlobIndexPattern, mockFilebeatIndexPattern]);
114+
});
115+
});
54116
});

0 commit comments

Comments
 (0)