mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
# Backport This will backport the following commits from `main` to `8.10`: - [[RAM] Alert search strategy fields for security (#165040)](https://github.com/elastic/kibana/pull/165040) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Xavier Mouligneau","email":"xavier.mouligneau@elastic.co"},"sourceCommit":{"committedDate":"2023-08-29T17:18:28Z","message":"[RAM] Alert search strategy fields for security (#165040)\n\n## Summary\r\n\r\nFix => https://github.com/elastic/kibana/issues/164769\r\n\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"6b20ca94bc4cb352bbcdad4e849cf3c7fa166a79","branchLabelMapping":{"^v8.11.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:skip","impact:high","Team:ResponseOps","v8.10.0","v8.11.0"],"number":165040,"url":"https://github.com/elastic/kibana/pull/165040","mergeCommit":{"message":"[RAM] Alert search strategy fields for security (#165040)\n\n## Summary\r\n\r\nFix => https://github.com/elastic/kibana/issues/164769\r\n\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"6b20ca94bc4cb352bbcdad4e849cf3c7fa166a79"}},"sourceBranch":"main","suggestedTargetBranches":["8.10"],"targetPullRequestStates":[{"branch":"8.10","label":"v8.10.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.11.0","labelRegex":"^v8.11.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/165040","number":165040,"mergeCommit":{"message":"[RAM] Alert search strategy fields for security (#165040)\n\n## Summary\r\n\r\nFix => https://github.com/elastic/kibana/issues/164769\r\n\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"6b20ca94bc4cb352bbcdad4e849cf3c7fa166a79"}}]}] BACKPORT--> Co-authored-by: Xavier Mouligneau <xavier.mouligneau@elastic.co>
This commit is contained in:
parent
a13ba490b3
commit
e451a3378e
13 changed files with 424 additions and 357 deletions
|
@ -8,3 +8,4 @@
|
|||
|
||||
export * from './src/field_maps';
|
||||
export * from './src/schemas';
|
||||
export * from './src/search';
|
||||
|
|
13
packages/kbn-alerts-as-data-utils/jest.config.js
Normal file
13
packages/kbn-alerts-as-data-utils/jest.config.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test',
|
||||
rootDir: '../..',
|
||||
roots: ['<rootDir>/packages/kbn-alerts-as-data-utils'],
|
||||
};
|
9
packages/kbn-alerts-as-data-utils/src/search/index.ts
Normal file
9
packages/kbn-alerts-as-data-utils/src/search/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { buildAlertFieldsRequest, ALERT_EVENTS_FIELDS } from './security';
|
|
@ -1,34 +1,36 @@
|
|||
/*
|
||||
* 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.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import { buildFieldsRequest } from './build_fields_request';
|
||||
import { TIMELINE_EVENTS_FIELDS } from './constants';
|
||||
|
||||
import { buildAlertFieldsRequest } from './build_fields_request';
|
||||
import { ALERT_EVENTS_FIELDS } from './fields';
|
||||
|
||||
describe('buildFieldsRequest', () => {
|
||||
it('should include ecs fields by default', () => {
|
||||
const fields: string[] = [];
|
||||
const fieldsRequest = buildFieldsRequest(fields);
|
||||
expect(fieldsRequest).toHaveLength(TIMELINE_EVENTS_FIELDS.length);
|
||||
const fieldsRequest = buildAlertFieldsRequest(fields);
|
||||
expect(fieldsRequest).toHaveLength(ALERT_EVENTS_FIELDS.length);
|
||||
});
|
||||
|
||||
it('should not show ecs fields', () => {
|
||||
const fields: string[] = [];
|
||||
const fieldsRequest = buildFieldsRequest(fields, true);
|
||||
const fieldsRequest = buildAlertFieldsRequest(fields, true);
|
||||
expect(fieldsRequest).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should map the expected (non underscore prefixed) fields', () => {
|
||||
const fields = ['_dontShow1', '_dontShow2', 'showsup'];
|
||||
const fieldsRequest = buildFieldsRequest(fields, true);
|
||||
const fieldsRequest = buildAlertFieldsRequest(fields, true);
|
||||
expect(fieldsRequest).toEqual([{ field: 'showsup', include_unmapped: true }]);
|
||||
});
|
||||
|
||||
it('should map provided fields with ecs fields', () => {
|
||||
const fields = ['showsup'];
|
||||
const fieldsRequest = buildFieldsRequest(fields);
|
||||
expect(fieldsRequest).toHaveLength(TIMELINE_EVENTS_FIELDS.length + fields.length);
|
||||
const fieldsRequest = buildAlertFieldsRequest(fields);
|
||||
expect(fieldsRequest).toHaveLength(ALERT_EVENTS_FIELDS.length + fields.length);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { uniq } from 'lodash/fp';
|
||||
import { ALERT_EVENTS_FIELDS } from './fields';
|
||||
|
||||
export const buildAlertFieldsRequest = (fields: string[], excludeEcsData?: boolean) =>
|
||||
uniq([
|
||||
...fields.filter((field) => !field.startsWith('_')),
|
||||
...(excludeEcsData ? [] : ALERT_EVENTS_FIELDS),
|
||||
]).map((field) => ({
|
||||
field,
|
||||
include_unmapped: true,
|
||||
...(field === '@timestamp'
|
||||
? {
|
||||
format: 'strict_date_optional_time',
|
||||
}
|
||||
: {}),
|
||||
}));
|
289
packages/kbn-alerts-as-data-utils/src/search/security/fields.ts
Normal file
289
packages/kbn-alerts-as-data-utils/src/search/security/fields.ts
Normal file
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
ALERT_RULE_CONSUMER,
|
||||
ALERT_RISK_SCORE,
|
||||
ALERT_SEVERITY,
|
||||
ALERT_RULE_PARAMETERS,
|
||||
ALERT_WORKFLOW_TAGS,
|
||||
} from '@kbn/rule-data-utils';
|
||||
|
||||
const ENRICHMENT_DESTINATION_PATH = 'threat.enrichments';
|
||||
|
||||
const MATCHED_ATOMIC = 'matched.atomic';
|
||||
const MATCHED_FIELD = 'matched.field';
|
||||
const MATCHED_TYPE = 'matched.type';
|
||||
|
||||
const INDICATOR_MATCHED_ATOMIC = `${ENRICHMENT_DESTINATION_PATH}.${MATCHED_ATOMIC}`;
|
||||
const INDICATOR_MATCHED_FIELD = `${ENRICHMENT_DESTINATION_PATH}.${MATCHED_FIELD}`;
|
||||
const INDICATOR_MATCHED_TYPE = `${ENRICHMENT_DESTINATION_PATH}.${MATCHED_TYPE}`;
|
||||
|
||||
const PROVIDER = 'indicator.provider';
|
||||
const REFERENCE = 'indicator.reference';
|
||||
const FEED_NAME = 'feed.name';
|
||||
|
||||
const INDICATOR_PROVIDER = `${ENRICHMENT_DESTINATION_PATH}.${PROVIDER}`;
|
||||
const INDICATOR_REFERENCE = `${ENRICHMENT_DESTINATION_PATH}.${REFERENCE}`;
|
||||
const FEED_NAME_REFERENCE = `${ENRICHMENT_DESTINATION_PATH}.${FEED_NAME}`;
|
||||
|
||||
const CTI_ROW_RENDERER_FIELDS = [
|
||||
INDICATOR_MATCHED_ATOMIC,
|
||||
INDICATOR_MATCHED_FIELD,
|
||||
INDICATOR_MATCHED_TYPE,
|
||||
INDICATOR_REFERENCE,
|
||||
INDICATOR_PROVIDER,
|
||||
FEED_NAME_REFERENCE,
|
||||
];
|
||||
|
||||
// TODO: update all of these fields to use the constants from technical field names
|
||||
export const ALERT_EVENTS_FIELDS = [
|
||||
ALERT_RULE_CONSUMER,
|
||||
'@timestamp',
|
||||
'kibana.alert.ancestors.index',
|
||||
'kibana.alert.workflow_status',
|
||||
ALERT_WORKFLOW_TAGS,
|
||||
'kibana.alert.group.id',
|
||||
'kibana.alert.original_time',
|
||||
'kibana.alert.reason',
|
||||
'kibana.alert.rule.from',
|
||||
'kibana.alert.rule.name',
|
||||
'kibana.alert.rule.to',
|
||||
'kibana.alert.rule.uuid',
|
||||
'kibana.alert.rule.rule_id',
|
||||
'kibana.alert.rule.type',
|
||||
'kibana.alert.original_event.kind',
|
||||
'kibana.alert.original_event.module',
|
||||
'kibana.alert.rule.version',
|
||||
ALERT_SEVERITY,
|
||||
ALERT_RISK_SCORE,
|
||||
ALERT_RULE_PARAMETERS,
|
||||
'kibana.alert.threshold_result',
|
||||
'kibana.alert.building_block_type',
|
||||
'kibana.alert.suppression.docs_count',
|
||||
'event.code',
|
||||
'event.module',
|
||||
'event.action',
|
||||
'event.category',
|
||||
'host.name',
|
||||
'user.name',
|
||||
'source.ip',
|
||||
'destination.ip',
|
||||
'message',
|
||||
'system.auth.ssh.signature',
|
||||
'system.auth.ssh.method',
|
||||
'system.audit.package.arch',
|
||||
'system.audit.package.entity_id',
|
||||
'system.audit.package.name',
|
||||
'system.audit.package.size',
|
||||
'system.audit.package.summary',
|
||||
'system.audit.package.version',
|
||||
'event.created',
|
||||
'event.dataset',
|
||||
'event.duration',
|
||||
'event.end',
|
||||
'event.hash',
|
||||
'event.id',
|
||||
'event.kind',
|
||||
'event.original',
|
||||
'event.outcome',
|
||||
'event.risk_score',
|
||||
'event.risk_score_norm',
|
||||
'event.severity',
|
||||
'event.start',
|
||||
'event.timezone',
|
||||
'event.type',
|
||||
'agent.type',
|
||||
'agent.id',
|
||||
'auditd.result',
|
||||
'auditd.session',
|
||||
'auditd.data.acct',
|
||||
'auditd.data.terminal',
|
||||
'auditd.data.op',
|
||||
'auditd.summary.actor.primary',
|
||||
'auditd.summary.actor.secondary',
|
||||
'auditd.summary.object.primary',
|
||||
'auditd.summary.object.secondary',
|
||||
'auditd.summary.object.type',
|
||||
'auditd.summary.how',
|
||||
'auditd.summary.message_type',
|
||||
'auditd.summary.sequence',
|
||||
'file.Ext.original.path',
|
||||
'file.name',
|
||||
'file.target_path',
|
||||
'file.extension',
|
||||
'file.type',
|
||||
'file.device',
|
||||
'file.inode',
|
||||
'file.uid',
|
||||
'file.owner',
|
||||
'file.gid',
|
||||
'file.group',
|
||||
'file.mode',
|
||||
'file.size',
|
||||
'file.mtime',
|
||||
'file.ctime',
|
||||
'file.path',
|
||||
// NOTE: 7.10+ file.Ext.code_signature populated
|
||||
// as array of objects, prior to that populated as
|
||||
// single object
|
||||
'file.Ext.code_signature',
|
||||
'file.Ext.code_signature.subject_name',
|
||||
'file.Ext.code_signature.trusted',
|
||||
'file.hash.sha256',
|
||||
'host.os.family',
|
||||
'host.os.name',
|
||||
'host.id',
|
||||
'host.ip',
|
||||
'registry.key',
|
||||
'registry.path',
|
||||
'rule.reference',
|
||||
'source.bytes',
|
||||
'source.packets',
|
||||
'source.port',
|
||||
'source.geo.continent_name',
|
||||
'source.geo.country_name',
|
||||
'source.geo.country_iso_code',
|
||||
'source.geo.city_name',
|
||||
'source.geo.region_iso_code',
|
||||
'source.geo.region_name',
|
||||
'destination.bytes',
|
||||
'destination.packets',
|
||||
'destination.port',
|
||||
'destination.geo.continent_name',
|
||||
'destination.geo.country_name',
|
||||
'destination.geo.country_iso_code',
|
||||
'destination.geo.city_name',
|
||||
'destination.geo.region_iso_code',
|
||||
'destination.geo.region_name',
|
||||
'dns.question.name',
|
||||
'dns.question.type',
|
||||
'dns.resolved_ip',
|
||||
'dns.response_code',
|
||||
'endgame.exit_code',
|
||||
'endgame.file_name',
|
||||
'endgame.file_path',
|
||||
'endgame.logon_type',
|
||||
'endgame.parent_process_name',
|
||||
'endgame.pid',
|
||||
'endgame.process_name',
|
||||
'endgame.subject_domain_name',
|
||||
'endgame.subject_logon_id',
|
||||
'endgame.subject_user_name',
|
||||
'endgame.target_domain_name',
|
||||
'endgame.target_logon_id',
|
||||
'endgame.target_user_name',
|
||||
'kibana.alert.rule.timeline_id',
|
||||
'kibana.alert.rule.timeline_title',
|
||||
'kibana.alert.rule.note',
|
||||
'kibana.alert.rule.exceptions_list',
|
||||
'kibana.alert.rule.building_block_type',
|
||||
'suricata.eve.proto',
|
||||
'suricata.eve.flow_id',
|
||||
'suricata.eve.alert.signature',
|
||||
'suricata.eve.alert.signature_id',
|
||||
'network.bytes',
|
||||
'network.community_id',
|
||||
'network.direction',
|
||||
'network.packets',
|
||||
'network.protocol',
|
||||
'network.transport',
|
||||
'http.version',
|
||||
'http.request.method',
|
||||
'http.request.body.bytes',
|
||||
'http.request.body.content',
|
||||
'http.request.referrer',
|
||||
'http.response.status_code',
|
||||
'http.response.body.bytes',
|
||||
'http.response.body.content',
|
||||
'tls.client_certificate.fingerprint.sha1',
|
||||
'tls.fingerprints.ja3.hash',
|
||||
'tls.server_certificate.fingerprint.sha1',
|
||||
'user.domain',
|
||||
'winlog.event_id',
|
||||
'process.end',
|
||||
'process.entry_leader.entry_meta.type',
|
||||
'process.entry_leader.entry_meta.source.ip',
|
||||
'process.exit_code',
|
||||
'process.hash.md5',
|
||||
'process.hash.sha1',
|
||||
'process.hash.sha256',
|
||||
'process.interactive',
|
||||
'process.parent.name',
|
||||
'process.parent.pid',
|
||||
'process.pid',
|
||||
'process.name',
|
||||
'process.ppid',
|
||||
'process.args',
|
||||
'process.entity_id',
|
||||
'process.executable',
|
||||
'process.start',
|
||||
'process.title',
|
||||
'process.working_directory',
|
||||
'process.entry_leader.entity_id',
|
||||
'process.entry_leader.name',
|
||||
'process.entry_leader.pid',
|
||||
'process.entry_leader.start',
|
||||
'process.session_leader.entity_id',
|
||||
'process.session_leader.name',
|
||||
'process.session_leader.pid',
|
||||
'process.group_leader.entity_id',
|
||||
'process.group_leader.name',
|
||||
'process.group_leader.pid',
|
||||
'zeek.session_id',
|
||||
'zeek.connection.local_resp',
|
||||
'zeek.connection.local_orig',
|
||||
'zeek.connection.missed_bytes',
|
||||
'zeek.connection.state',
|
||||
'zeek.connection.history',
|
||||
'zeek.notice.suppress_for',
|
||||
'zeek.notice.msg',
|
||||
'zeek.notice.note',
|
||||
'zeek.notice.sub',
|
||||
'zeek.notice.dst',
|
||||
'zeek.notice.dropped',
|
||||
'zeek.notice.peer_descr',
|
||||
'zeek.dns.AA',
|
||||
'zeek.dns.qclass_name',
|
||||
'zeek.dns.RD',
|
||||
'zeek.dns.qtype_name',
|
||||
'zeek.dns.qtype',
|
||||
'zeek.dns.query',
|
||||
'zeek.dns.trans_id',
|
||||
'zeek.dns.qclass',
|
||||
'zeek.dns.RA',
|
||||
'zeek.dns.TC',
|
||||
'zeek.http.resp_mime_types',
|
||||
'zeek.http.trans_depth',
|
||||
'zeek.http.status_msg',
|
||||
'zeek.http.resp_fuids',
|
||||
'zeek.http.tags',
|
||||
'zeek.files.session_ids',
|
||||
'zeek.files.timedout',
|
||||
'zeek.files.local_orig',
|
||||
'zeek.files.tx_host',
|
||||
'zeek.files.source',
|
||||
'zeek.files.is_orig',
|
||||
'zeek.files.overflow_bytes',
|
||||
'zeek.files.sha1',
|
||||
'zeek.files.duration',
|
||||
'zeek.files.depth',
|
||||
'zeek.files.analyzers',
|
||||
'zeek.files.mime_type',
|
||||
'zeek.files.rx_host',
|
||||
'zeek.files.total_bytes',
|
||||
'zeek.files.fuid',
|
||||
'zeek.files.seen_bytes',
|
||||
'zeek.files.missing_bytes',
|
||||
'zeek.files.md5',
|
||||
'zeek.ssl.cipher',
|
||||
'zeek.ssl.established',
|
||||
'zeek.ssl.resumed',
|
||||
'zeek.ssl.version',
|
||||
...CTI_ROW_RENDERER_FIELDS,
|
||||
];
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { buildAlertFieldsRequest } from './build_fields_request';
|
||||
export { ALERT_EVENTS_FIELDS } from './fields';
|
|
@ -8,6 +8,7 @@ import { of } from 'rxjs';
|
|||
import { merge } from 'lodash';
|
||||
import { loggerMock } from '@kbn/logging-mocks';
|
||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||
import { ALERT_EVENTS_FIELDS } from '@kbn/alerts-as-data-utils';
|
||||
import { ruleRegistrySearchStrategyProvider, EMPTY_RESPONSE } from './search_strategy';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/server/mocks';
|
||||
import { SearchStrategyDependencies } from '@kbn/data-plugin/server';
|
||||
|
@ -313,18 +314,31 @@ describe('ruleRegistrySearchStrategyProvider()', () => {
|
|||
await strategy
|
||||
.search(request, options, deps as unknown as SearchStrategyDependencies)
|
||||
.toPromise();
|
||||
expect(searchStrategySearch).toHaveBeenCalledWith(
|
||||
{
|
||||
params: {
|
||||
const arg0 = searchStrategySearch.mock.calls[0][0];
|
||||
expect(arg0.params.body.fields.length).toEqual(
|
||||
// +2 because of fields.push({ field: 'kibana.alert.*', include_unmapped: false }); and
|
||||
// fields.push({ field: 'signal.*', include_unmapped: false });
|
||||
ALERT_EVENTS_FIELDS.length + 2
|
||||
);
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
x: 2,
|
||||
y: 3,
|
||||
}),
|
||||
]);
|
||||
expect(arg0).toEqual(
|
||||
expect.objectContaining({
|
||||
id: undefined,
|
||||
params: expect.objectContaining({
|
||||
allow_no_indices: true,
|
||||
body: {
|
||||
body: expect.objectContaining({
|
||||
_source: false,
|
||||
fields: [
|
||||
{
|
||||
field: '*',
|
||||
fields: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: '@timestamp',
|
||||
include_unmapped: true,
|
||||
},
|
||||
],
|
||||
}),
|
||||
]),
|
||||
from: 0,
|
||||
query: {
|
||||
ids: {
|
||||
|
@ -333,13 +347,11 @@ describe('ruleRegistrySearchStrategyProvider()', () => {
|
|||
},
|
||||
size: 1000,
|
||||
sort: [],
|
||||
},
|
||||
}),
|
||||
ignore_unavailable: true,
|
||||
index: ['security-siem'],
|
||||
},
|
||||
},
|
||||
{},
|
||||
{ request: {} }
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -349,7 +361,7 @@ describe('ruleRegistrySearchStrategyProvider()', () => {
|
|||
query: {
|
||||
ids: { values: ['test-id'] },
|
||||
},
|
||||
fields: [{ field: '@timestamp', include_unmapped: true }],
|
||||
fields: [{ field: 'my-super-field', include_unmapped: true }],
|
||||
};
|
||||
const options = {};
|
||||
const deps = {
|
||||
|
@ -363,13 +375,26 @@ describe('ruleRegistrySearchStrategyProvider()', () => {
|
|||
await strategy
|
||||
.search(request, options, deps as unknown as SearchStrategyDependencies)
|
||||
.toPromise();
|
||||
expect(searchStrategySearch).toHaveBeenCalledWith(
|
||||
{
|
||||
params: {
|
||||
|
||||
const arg0 = searchStrategySearch.mock.calls[0][0];
|
||||
expect(arg0.params.body.fields.length).toEqual(
|
||||
// +2 because of fields.push({ field: 'kibana.alert.*', include_unmapped: false }); and
|
||||
// fields.push({ field: 'signal.*', include_unmapped: false }); + my-super-field
|
||||
ALERT_EVENTS_FIELDS.length + 3
|
||||
);
|
||||
expect(arg0).toEqual(
|
||||
expect.objectContaining({
|
||||
id: undefined,
|
||||
params: expect.objectContaining({
|
||||
allow_no_indices: true,
|
||||
body: {
|
||||
body: expect.objectContaining({
|
||||
_source: false,
|
||||
fields: [{ field: '@timestamp', include_unmapped: true }],
|
||||
fields: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: 'my-super-field',
|
||||
include_unmapped: true,
|
||||
}),
|
||||
]),
|
||||
from: 0,
|
||||
query: {
|
||||
ids: {
|
||||
|
@ -378,13 +403,11 @@ describe('ruleRegistrySearchStrategyProvider()', () => {
|
|||
},
|
||||
size: 1000,
|
||||
sort: [],
|
||||
},
|
||||
}),
|
||||
ignore_unavailable: true,
|
||||
index: ['security-siem'],
|
||||
},
|
||||
},
|
||||
{},
|
||||
{ request: {} }
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,7 +8,6 @@ import { map, mergeMap, catchError } from 'rxjs/operators';
|
|||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { Logger } from '@kbn/core/server';
|
||||
import { from, of } from 'rxjs';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { isValidFeatureId, AlertConsumers } from '@kbn/rule-data-utils';
|
||||
import { ENHANCED_ES_SEARCH_STRATEGY } from '@kbn/data-plugin/common';
|
||||
import { ISearchStrategy, PluginStart } from '@kbn/data-plugin/server';
|
||||
|
@ -19,6 +18,7 @@ import {
|
|||
} from '@kbn/alerting-plugin/server';
|
||||
import { SecurityPluginSetup } from '@kbn/security-plugin/server';
|
||||
import { SpacesPluginStart } from '@kbn/spaces-plugin/server';
|
||||
import { buildAlertFieldsRequest } from '@kbn/alerts-as-data-utils';
|
||||
import {
|
||||
RuleRegistrySearchRequest,
|
||||
RuleRegistrySearchResponse,
|
||||
|
@ -31,8 +31,6 @@ export const EMPTY_RESPONSE: RuleRegistrySearchResponse = {
|
|||
rawResponse: {} as RuleRegistrySearchResponse['rawResponse'],
|
||||
};
|
||||
|
||||
const EMPTY_FIELDS = [{ field: '*', include_unmapped: true }];
|
||||
|
||||
export const RULE_SEARCH_STRATEGY_NAME = 'privateRuleRegistryAlertsSearchStrategy';
|
||||
|
||||
export const ruleRegistrySearchStrategyProvider = (
|
||||
|
@ -124,6 +122,17 @@ export const ruleRegistrySearchStrategyProvider = (
|
|||
},
|
||||
}),
|
||||
};
|
||||
let fields = request?.fields ?? [];
|
||||
fields.push({ field: 'kibana.alert.*', include_unmapped: false });
|
||||
|
||||
if (siemRequest) {
|
||||
fields.push({ field: 'signal.*', include_unmapped: false });
|
||||
fields = fields.concat(buildAlertFieldsRequest([], false));
|
||||
} else {
|
||||
// only for o11y solutions
|
||||
fields.push({ field: '*', include_unmapped: true });
|
||||
}
|
||||
|
||||
const size = request.pagination ? request.pagination.pageSize : MAX_ALERT_SEARCH_SIZE;
|
||||
params = {
|
||||
allow_no_indices: true,
|
||||
|
@ -131,8 +140,7 @@ export const ruleRegistrySearchStrategyProvider = (
|
|||
ignore_unavailable: true,
|
||||
body: {
|
||||
_source: false,
|
||||
// TODO the fields need to come from the request
|
||||
fields: !isEmpty(request?.fields) ? request?.fields : EMPTY_FIELDS,
|
||||
fields,
|
||||
sort,
|
||||
size,
|
||||
from: request.pagination ? request.pagination.pageIndex * size : 0,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { cloneDeep, getOr } from 'lodash/fp';
|
||||
import type { IEsSearchResponse } from '@kbn/data-plugin/common';
|
||||
import { buildAlertFieldsRequest as buildFieldsRequest } from '@kbn/alerts-as-data-utils';
|
||||
import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../../common/constants';
|
||||
import {
|
||||
EventHit,
|
||||
|
@ -18,7 +19,6 @@ import {
|
|||
import { TimelineFactory } from '../../types';
|
||||
import { buildTimelineEventsAllQuery } from './query.events_all.dsl';
|
||||
import { inspectStringifyObject } from '../../../../../utils/build_query';
|
||||
import { buildFieldsRequest } from '../../helpers/build_fields_request';
|
||||
import { formatTimelineData } from '../../helpers/format_timeline_data';
|
||||
import { TIMELINE_EVENTS_FIELDS } from '../../helpers/constants';
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* 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 { uniq } from 'lodash/fp';
|
||||
import { TIMELINE_EVENTS_FIELDS } from './constants';
|
||||
|
||||
export const buildFieldsRequest = (fields: string[], excludeEcsData?: boolean) =>
|
||||
uniq([
|
||||
...fields.filter((field) => !field.startsWith('_')),
|
||||
...(excludeEcsData ? [] : TIMELINE_EVENTS_FIELDS),
|
||||
]).map((field) => ({
|
||||
field,
|
||||
include_unmapped: true,
|
||||
}));
|
|
@ -5,292 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
ALERT_RULE_CONSUMER,
|
||||
ALERT_RISK_SCORE,
|
||||
ALERT_SEVERITY,
|
||||
ALERT_RULE_PARAMETERS,
|
||||
ALERT_WORKFLOW_TAGS,
|
||||
} from '@kbn/rule-data-utils';
|
||||
import { ENRICHMENT_DESTINATION_PATH } from '../../../../../common/constants';
|
||||
import { ALERT_EVENTS_FIELDS as TIMELINE_EVENTS_FIELDS } from '@kbn/alerts-as-data-utils';
|
||||
|
||||
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];
|
||||
const ECS_METADATA_FIELDS = ['_id', '_index', '_type', '_score'];
|
||||
|
||||
export const INDICATOR_MATCHED_ATOMIC = `${ENRICHMENT_DESTINATION_PATH}.${MATCHED_ATOMIC}`;
|
||||
export const INDICATOR_MATCHED_FIELD = `${ENRICHMENT_DESTINATION_PATH}.${MATCHED_FIELD}`;
|
||||
export const INDICATOR_MATCHED_TYPE = `${ENRICHMENT_DESTINATION_PATH}.${MATCHED_TYPE}`;
|
||||
|
||||
export const EVENT_DATASET = 'event.dataset';
|
||||
|
||||
export const FIRST_SEEN = 'indicator.first_seen';
|
||||
export const LAST_SEEN = 'indicator.last_seen';
|
||||
export const PROVIDER = 'indicator.provider';
|
||||
export const REFERENCE = 'indicator.reference';
|
||||
export const FEED_NAME = 'feed.name';
|
||||
|
||||
export const INDICATOR_FIRSTSEEN = `${ENRICHMENT_DESTINATION_PATH}.${FIRST_SEEN}`;
|
||||
export const INDICATOR_LASTSEEN = `${ENRICHMENT_DESTINATION_PATH}.${LAST_SEEN}`;
|
||||
export const INDICATOR_PROVIDER = `${ENRICHMENT_DESTINATION_PATH}.${PROVIDER}`;
|
||||
export const INDICATOR_REFERENCE = `${ENRICHMENT_DESTINATION_PATH}.${REFERENCE}`;
|
||||
export const FEED_NAME_REFERENCE = `${ENRICHMENT_DESTINATION_PATH}.${FEED_NAME}`;
|
||||
|
||||
export const CTI_ROW_RENDERER_FIELDS = [
|
||||
INDICATOR_MATCHED_ATOMIC,
|
||||
INDICATOR_MATCHED_FIELD,
|
||||
INDICATOR_MATCHED_TYPE,
|
||||
INDICATOR_REFERENCE,
|
||||
INDICATOR_PROVIDER,
|
||||
FEED_NAME_REFERENCE,
|
||||
];
|
||||
|
||||
// TODO: update all of these fields to use the constants from technical field names
|
||||
export const TIMELINE_EVENTS_FIELDS = [
|
||||
ALERT_RULE_CONSUMER,
|
||||
'@timestamp',
|
||||
'kibana.alert.ancestors.index',
|
||||
'kibana.alert.workflow_status',
|
||||
ALERT_WORKFLOW_TAGS,
|
||||
'kibana.alert.group.id',
|
||||
'kibana.alert.original_time',
|
||||
'kibana.alert.reason',
|
||||
'kibana.alert.rule.from',
|
||||
'kibana.alert.rule.name',
|
||||
'kibana.alert.rule.to',
|
||||
'kibana.alert.rule.uuid',
|
||||
'kibana.alert.rule.rule_id',
|
||||
'kibana.alert.rule.type',
|
||||
'kibana.alert.original_event.kind',
|
||||
'kibana.alert.original_event.module',
|
||||
'kibana.alert.rule.version',
|
||||
ALERT_SEVERITY,
|
||||
ALERT_RISK_SCORE,
|
||||
ALERT_RULE_PARAMETERS,
|
||||
'kibana.alert.threshold_result',
|
||||
'kibana.alert.building_block_type',
|
||||
'kibana.alert.suppression.docs_count',
|
||||
'event.code',
|
||||
'event.module',
|
||||
'event.action',
|
||||
'event.category',
|
||||
'host.name',
|
||||
'user.name',
|
||||
'source.ip',
|
||||
'destination.ip',
|
||||
'message',
|
||||
'system.auth.ssh.signature',
|
||||
'system.auth.ssh.method',
|
||||
'system.audit.package.arch',
|
||||
'system.audit.package.entity_id',
|
||||
'system.audit.package.name',
|
||||
'system.audit.package.size',
|
||||
'system.audit.package.summary',
|
||||
'system.audit.package.version',
|
||||
'event.created',
|
||||
'event.dataset',
|
||||
'event.duration',
|
||||
'event.end',
|
||||
'event.hash',
|
||||
'event.id',
|
||||
'event.kind',
|
||||
'event.original',
|
||||
'event.outcome',
|
||||
'event.risk_score',
|
||||
'event.risk_score_norm',
|
||||
'event.severity',
|
||||
'event.start',
|
||||
'event.timezone',
|
||||
'event.type',
|
||||
'agent.type',
|
||||
'agent.id',
|
||||
'auditd.result',
|
||||
'auditd.session',
|
||||
'auditd.data.acct',
|
||||
'auditd.data.terminal',
|
||||
'auditd.data.op',
|
||||
'auditd.summary.actor.primary',
|
||||
'auditd.summary.actor.secondary',
|
||||
'auditd.summary.object.primary',
|
||||
'auditd.summary.object.secondary',
|
||||
'auditd.summary.object.type',
|
||||
'auditd.summary.how',
|
||||
'auditd.summary.message_type',
|
||||
'auditd.summary.sequence',
|
||||
'file.Ext.original.path',
|
||||
'file.name',
|
||||
'file.target_path',
|
||||
'file.extension',
|
||||
'file.type',
|
||||
'file.device',
|
||||
'file.inode',
|
||||
'file.uid',
|
||||
'file.owner',
|
||||
'file.gid',
|
||||
'file.group',
|
||||
'file.mode',
|
||||
'file.size',
|
||||
'file.mtime',
|
||||
'file.ctime',
|
||||
'file.path',
|
||||
// NOTE: 7.10+ file.Ext.code_signature populated
|
||||
// as array of objects, prior to that populated as
|
||||
// single object
|
||||
'file.Ext.code_signature',
|
||||
'file.Ext.code_signature.subject_name',
|
||||
'file.Ext.code_signature.trusted',
|
||||
'file.hash.sha256',
|
||||
'host.os.family',
|
||||
'host.os.name',
|
||||
'host.id',
|
||||
'host.ip',
|
||||
'registry.key',
|
||||
'registry.path',
|
||||
'rule.reference',
|
||||
'source.bytes',
|
||||
'source.packets',
|
||||
'source.port',
|
||||
'source.geo.continent_name',
|
||||
'source.geo.country_name',
|
||||
'source.geo.country_iso_code',
|
||||
'source.geo.city_name',
|
||||
'source.geo.region_iso_code',
|
||||
'source.geo.region_name',
|
||||
'destination.bytes',
|
||||
'destination.packets',
|
||||
'destination.port',
|
||||
'destination.geo.continent_name',
|
||||
'destination.geo.country_name',
|
||||
'destination.geo.country_iso_code',
|
||||
'destination.geo.city_name',
|
||||
'destination.geo.region_iso_code',
|
||||
'destination.geo.region_name',
|
||||
'dns.question.name',
|
||||
'dns.question.type',
|
||||
'dns.resolved_ip',
|
||||
'dns.response_code',
|
||||
'endgame.exit_code',
|
||||
'endgame.file_name',
|
||||
'endgame.file_path',
|
||||
'endgame.logon_type',
|
||||
'endgame.parent_process_name',
|
||||
'endgame.pid',
|
||||
'endgame.process_name',
|
||||
'endgame.subject_domain_name',
|
||||
'endgame.subject_logon_id',
|
||||
'endgame.subject_user_name',
|
||||
'endgame.target_domain_name',
|
||||
'endgame.target_logon_id',
|
||||
'endgame.target_user_name',
|
||||
'kibana.alert.rule.timeline_id',
|
||||
'kibana.alert.rule.timeline_title',
|
||||
'kibana.alert.rule.note',
|
||||
'kibana.alert.rule.exceptions_list',
|
||||
'kibana.alert.rule.building_block_type',
|
||||
'suricata.eve.proto',
|
||||
'suricata.eve.flow_id',
|
||||
'suricata.eve.alert.signature',
|
||||
'suricata.eve.alert.signature_id',
|
||||
'network.bytes',
|
||||
'network.community_id',
|
||||
'network.direction',
|
||||
'network.packets',
|
||||
'network.protocol',
|
||||
'network.transport',
|
||||
'http.version',
|
||||
'http.request.method',
|
||||
'http.request.body.bytes',
|
||||
'http.request.body.content',
|
||||
'http.request.referrer',
|
||||
'http.response.status_code',
|
||||
'http.response.body.bytes',
|
||||
'http.response.body.content',
|
||||
'tls.client_certificate.fingerprint.sha1',
|
||||
'tls.fingerprints.ja3.hash',
|
||||
'tls.server_certificate.fingerprint.sha1',
|
||||
'user.domain',
|
||||
'winlog.event_id',
|
||||
'process.end',
|
||||
'process.entry_leader.entry_meta.type',
|
||||
'process.entry_leader.entry_meta.source.ip',
|
||||
'process.exit_code',
|
||||
'process.hash.md5',
|
||||
'process.hash.sha1',
|
||||
'process.hash.sha256',
|
||||
'process.interactive',
|
||||
'process.parent.name',
|
||||
'process.parent.pid',
|
||||
'process.pid',
|
||||
'process.name',
|
||||
'process.ppid',
|
||||
'process.args',
|
||||
'process.entity_id',
|
||||
'process.executable',
|
||||
'process.start',
|
||||
'process.title',
|
||||
'process.working_directory',
|
||||
'process.entry_leader.entity_id',
|
||||
'process.entry_leader.name',
|
||||
'process.entry_leader.pid',
|
||||
'process.entry_leader.start',
|
||||
'process.session_leader.entity_id',
|
||||
'process.session_leader.name',
|
||||
'process.session_leader.pid',
|
||||
'process.group_leader.entity_id',
|
||||
'process.group_leader.name',
|
||||
'process.group_leader.pid',
|
||||
'zeek.session_id',
|
||||
'zeek.connection.local_resp',
|
||||
'zeek.connection.local_orig',
|
||||
'zeek.connection.missed_bytes',
|
||||
'zeek.connection.state',
|
||||
'zeek.connection.history',
|
||||
'zeek.notice.suppress_for',
|
||||
'zeek.notice.msg',
|
||||
'zeek.notice.note',
|
||||
'zeek.notice.sub',
|
||||
'zeek.notice.dst',
|
||||
'zeek.notice.dropped',
|
||||
'zeek.notice.peer_descr',
|
||||
'zeek.dns.AA',
|
||||
'zeek.dns.qclass_name',
|
||||
'zeek.dns.RD',
|
||||
'zeek.dns.qtype_name',
|
||||
'zeek.dns.qtype',
|
||||
'zeek.dns.query',
|
||||
'zeek.dns.trans_id',
|
||||
'zeek.dns.qclass',
|
||||
'zeek.dns.RA',
|
||||
'zeek.dns.TC',
|
||||
'zeek.http.resp_mime_types',
|
||||
'zeek.http.trans_depth',
|
||||
'zeek.http.status_msg',
|
||||
'zeek.http.resp_fuids',
|
||||
'zeek.http.tags',
|
||||
'zeek.files.session_ids',
|
||||
'zeek.files.timedout',
|
||||
'zeek.files.local_orig',
|
||||
'zeek.files.tx_host',
|
||||
'zeek.files.source',
|
||||
'zeek.files.is_orig',
|
||||
'zeek.files.overflow_bytes',
|
||||
'zeek.files.sha1',
|
||||
'zeek.files.duration',
|
||||
'zeek.files.depth',
|
||||
'zeek.files.analyzers',
|
||||
'zeek.files.mime_type',
|
||||
'zeek.files.rx_host',
|
||||
'zeek.files.total_bytes',
|
||||
'zeek.files.fuid',
|
||||
'zeek.files.seen_bytes',
|
||||
'zeek.files.missing_bytes',
|
||||
'zeek.files.md5',
|
||||
'zeek.ssl.cipher',
|
||||
'zeek.ssl.established',
|
||||
'zeek.ssl.resumed',
|
||||
'zeek.ssl.version',
|
||||
...CTI_ROW_RENDERER_FIELDS,
|
||||
];
|
||||
|
||||
export const ECS_METADATA_FIELDS = ['_id', '_index', '_type', '_score'];
|
||||
export { TIMELINE_EVENTS_FIELDS, ECS_METADATA_FIELDS };
|
||||
|
|
|
@ -39,8 +39,6 @@ export interface UseColumnsResp {
|
|||
}>;
|
||||
}
|
||||
|
||||
const EMPTY_FIELDS = [{ field: '*', include_unmapped: true }];
|
||||
|
||||
const fieldTypeToDataGridColumnTypeMapper = (fieldType: string | undefined) => {
|
||||
if (fieldType === 'date') return 'datetime';
|
||||
if (fieldType === 'number') return 'numeric';
|
||||
|
@ -275,16 +273,8 @@ export const useColumns = ({
|
|||
[columns, setColumnsAndSave, visibleColumns]
|
||||
);
|
||||
|
||||
/*
|
||||
* In some case such security, we need some special fields such as threat.enrichments which are
|
||||
* not fetched when passing only EMPTY_FIELDS. Hence, we will fetch all the fields that user has added to the table.
|
||||
*
|
||||
* Additionally, system such as o11y needs fields which are not even added in the table such as rule_type_id and hence we
|
||||
* additionly pass EMPTY_FIELDS so that it brings all fields apart from special fields
|
||||
*
|
||||
* */
|
||||
const fieldsToFetch = useMemo(
|
||||
() => [...columns.map((col) => ({ field: col.id, include_unmapped: true })), ...EMPTY_FIELDS],
|
||||
() => [...columns.map((col) => ({ field: col.id, include_unmapped: true }))],
|
||||
[columns]
|
||||
);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue