diff --git a/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.test.tsx b/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.test.tsx index 01a8293163106..7b2752a1eeb4f 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/helper/get_alert_annotations.test.tsx @@ -11,6 +11,7 @@ import { ALERT_EVALUATION_VALUE, ALERT_ID, ALERT_PRODUCER, + ALERT_OWNER, ALERT_SEVERITY_LEVEL, ALERT_START, ALERT_STATUS, @@ -42,6 +43,7 @@ const alert: Alert = { 'transaction.type': ['page-load'], [ALERT_PRODUCER]: ['apm'], [ALERT_UUID]: ['af2ae371-df79-4fca-b0eb-a2dbd9478180'], + [ALERT_OWNER]: ['apm'], 'rule.uuid': ['82e0ee40-c2f4-11eb-9a42-a9da66a1722f'], 'event.action': ['active'], '@timestamp': ['2021-06-01T16:16:05.183Z'], diff --git a/x-pack/plugins/rule_registry/README.md b/x-pack/plugins/rule_registry/README.md index 19e276aeec489..16e4b8f3e01e6 100644 --- a/x-pack/plugins/rule_registry/README.md +++ b/x-pack/plugins/rule_registry/README.md @@ -124,7 +124,6 @@ The following fields are defined in the technical field component template and s - `rule.uuid`: the saved objects id of the rule. - `rule.name`: the name of the rule (as specified by the user). - `rule.category`: the name of the rule type (as defined by the rule type producer) -- `kibana.alert.producer`: the producer of the rule type. Usually a Kibana plugin. e.g., `APM`. - `kibana.alert.owner`: the feature which produced the alert. Usually a Kibana feature id like `apm`, `siem`... - `kibana.alert.id`: the id of the alert, that is unique within the context of the rule execution it was created in. E.g., for a rule that monitors latency for all services in all environments, this might be `opbeans-java:production`. - `kibana.alert.uuid`: the unique identifier for the alert during its lifespan. If an alert recovers (or closes), this identifier is re-generated when it is opened again. diff --git a/x-pack/plugins/rule_registry/common/assets/field_maps/ecs_field_map.ts b/x-pack/plugins/rule_registry/common/assets/field_maps/ecs_field_map.ts index ff81e05851f7e..859070bd498e3 100644 --- a/x-pack/plugins/rule_registry/common/assets/field_maps/ecs_field_map.ts +++ b/x-pack/plugins/rule_registry/common/assets/field_maps/ecs_field_map.ts @@ -2148,7 +2148,7 @@ export const ecsFieldMap = { 'rule.id': { type: 'keyword', array: false, - required: false, + required: true, }, 'rule.license': { type: 'keyword', diff --git a/x-pack/plugins/rule_registry/common/assets/field_maps/technical_rule_field_map.ts b/x-pack/plugins/rule_registry/common/assets/field_maps/technical_rule_field_map.ts index ebe7c88f756b2..11e572260d133 100644 --- a/x-pack/plugins/rule_registry/common/assets/field_maps/technical_rule_field_map.ts +++ b/x-pack/plugins/rule_registry/common/assets/field_maps/technical_rule_field_map.ts @@ -20,9 +20,9 @@ export const technicalRuleFieldMap = { Fields.RULE_CATEGORY, Fields.TAGS ), - [Fields.ALERT_OWNER]: { type: 'keyword' }, + [Fields.ALERT_OWNER]: { type: 'keyword', required: true }, [Fields.ALERT_PRODUCER]: { type: 'keyword' }, - [Fields.SPACE_IDS]: { type: 'keyword', array: true }, + [Fields.SPACE_IDS]: { type: 'keyword', array: true, required: true }, [Fields.ALERT_UUID]: { type: 'keyword' }, [Fields.ALERT_ID]: { type: 'keyword' }, [Fields.ALERT_START]: { type: 'date' }, diff --git a/x-pack/plugins/rule_registry/server/routes/get_alert_by_id.test.ts b/x-pack/plugins/rule_registry/server/routes/get_alert_by_id.test.ts index d89eb305545e8..073a48248f89a 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alert_by_id.test.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alert_by_id.test.ts @@ -13,6 +13,7 @@ import { CONSUMERS, ECS_VERSION, RULE_ID, + SPACE_IDS, TIMESTAMP, VERSION, } from '@kbn/rule-data-utils'; @@ -33,6 +34,7 @@ const getMockAlert = (): ParsedTechnicalFields => ({ [ALERT_OWNER]: 'apm', [ALERT_STATUS]: 'open', [ALERT_RULE_RISK_SCORE]: 20, + [SPACE_IDS]: ['fake-space-id'], [ALERT_RULE_SEVERITY]: 'warning', }); diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts index 80b75b8c74732..037efadabd8de 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts @@ -23,6 +23,9 @@ import { ALERT_STATUS, EVENT_ACTION, EVENT_KIND, + RULE_ID, + ALERT_OWNER, + SPACE_IDS, } from '../../common/technical_rule_data_field_names'; import { createRuleDataClientMock } from '../rule_data_client/create_rule_data_client_mock'; import { createLifecycleExecutor } from './create_lifecycle_executor'; @@ -128,12 +131,16 @@ describe('createLifecycleExecutor', () => { { fields: { [ALERT_ID]: 'TEST_ALERT_0', + [ALERT_OWNER]: 'CONSUMER', + [RULE_ID]: 'RULE_TYPE_ID', labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must not show up in the written doc }, }, { fields: { [ALERT_ID]: 'TEST_ALERT_1', + [ALERT_OWNER]: 'CONSUMER', + [RULE_ID]: 'RULE_TYPE_ID', labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must not show up in the written doc }, }, @@ -222,6 +229,9 @@ describe('createLifecycleExecutor', () => { fields: { '@timestamp': '', [ALERT_ID]: 'TEST_ALERT_0', + [ALERT_OWNER]: 'CONSUMER', + [RULE_ID]: 'RULE_TYPE_ID', + [SPACE_IDS]: ['fake-space-id'], labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must show up in the written doc }, }, @@ -229,6 +239,9 @@ describe('createLifecycleExecutor', () => { fields: { '@timestamp': '', [ALERT_ID]: 'TEST_ALERT_1', + [ALERT_OWNER]: 'CONSUMER', + [RULE_ID]: 'RULE_TYPE_ID', + [SPACE_IDS]: ['fake-space-id'], labels: { LABEL_0_KEY: 'LABEL_0_VALUE' }, // this must not show up in the written doc }, }, diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts index 50ac8afb945b4..23ae24cb91bc4 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts @@ -30,6 +30,7 @@ import { EVENT_ACTION, EVENT_KIND, ALERT_OWNER, + RULE_ID, RULE_UUID, TIMESTAMP, SPACE_IDS, @@ -154,6 +155,8 @@ export const createLifecycleExecutor = ( currentAlerts[id] = { ...fields, [ALERT_ID]: id, + [RULE_ID]: rule.ruleTypeId, + [ALERT_OWNER]: rule.consumer, }; return alertInstanceFactory(id); }, @@ -226,6 +229,8 @@ export const createLifecycleExecutor = ( alertsDataMap[alertId] = { ...fields, [ALERT_ID]: alertId, + [RULE_ID]: rule.ruleTypeId, + [ALERT_OWNER]: rule.consumer, }; }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_registry_log_client/rule_registry_log_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_registry_log_client/rule_registry_log_client.ts index 5094f9a8c6e3c..e76acae09d92e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_registry_log_client/rule_registry_log_client.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_registry_log_client/rule_registry_log_client.ts @@ -6,7 +6,14 @@ */ import { estypes } from '@elastic/elasticsearch'; -import { EVENT_ACTION, EVENT_KIND, RULE_ID, SPACE_IDS, TIMESTAMP } from '@kbn/rule-data-utils'; +import { + ALERT_OWNER, + EVENT_ACTION, + EVENT_KIND, + RULE_ID, + SPACE_IDS, + TIMESTAMP, +} from '@kbn/rule-data-utils'; import { once } from 'lodash/fp'; import moment from 'moment'; import { RuleDataClient, RuleDataPluginService } from '../../../../../../rule_registry/server'; @@ -216,6 +223,7 @@ export class RuleRegistryLogClient implements IRuleRegistryLogClient { [getMetricField(metric)]: value, [RULE_ID]: ruleId, [TIMESTAMP]: new Date().toISOString(), + [ALERT_OWNER]: 'siem', }, namespace ); @@ -239,6 +247,7 @@ export class RuleRegistryLogClient implements IRuleRegistryLogClient { [RULE_STATUS_SEVERITY]: statusSeverityDict[newStatus], [RULE_STATUS]: newStatus, [TIMESTAMP]: new Date().toISOString(), + [ALERT_OWNER]: 'siem', }, namespace ); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_factory.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_factory.ts index 8791db61bd596..f4bf73a2eec12 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_factory.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_factory.ts @@ -185,14 +185,14 @@ export const createSecurityRuleTypeFactory: CreateSecurityRuleTypeFactory = ({ logger, alertWithPersistence, buildRuleMessage, - refresh, - spaceId + refresh ); const wrapHits = wrapHitsFactory({ logger, mergeStrategy, ruleSO, + spaceId, }); for (const tuple of tuples) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/bulk_create_factory.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/bulk_create_factory.ts index eccb55c1891d4..c600e187bc8f1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/bulk_create_factory.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/bulk_create_factory.ts @@ -8,8 +8,6 @@ import { performance } from 'perf_hooks'; import { countBy, isEmpty } from 'lodash'; -import { ALERT_OWNER, SPACE_IDS } from '@kbn/rule-data-utils'; - import { Logger } from 'kibana/server'; import { BaseHit } from '../../../../../common/detection_engine/types'; import { BuildRuleMessage } from '../../signals/rule_messages'; @@ -30,8 +28,7 @@ export const bulkCreateFactory = ( logger: Logger, alertWithPersistence: PersistenceAlertService, buildRuleMessage: BuildRuleMessage, - refreshForBulkCreate: RefreshTypes, - spaceId: string + refreshForBulkCreate: RefreshTypes ) => async (wrappedDocs: Array>): Promise> => { if (wrappedDocs.length === 0) { return { @@ -48,11 +45,7 @@ export const bulkCreateFactory = ( const response = await alertWithPersistence( wrappedDocs.map((doc) => ({ id: doc._id, - fields: { - ...(doc.fields ?? doc._source ?? {}), - [ALERT_OWNER]: 'siem', - [SPACE_IDS]: [spaceId], - }, + fields: doc.fields ?? doc._source ?? {}, })), refreshForBulkCreate ); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts index 6b3053bcffdd9..8fa3e5da81c40 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts @@ -5,7 +5,13 @@ * 2.0. */ -import { ALERT_RULE_NAMESPACE, ALERT_STATUS, ALERT_WORKFLOW_STATUS } from '@kbn/rule-data-utils'; +import { + ALERT_OWNER, + ALERT_RULE_NAMESPACE, + ALERT_STATUS, + ALERT_WORKFLOW_STATUS, + SPACE_IDS, +} from '@kbn/rule-data-utils'; import { sampleDocNoSortIdWithTimestamp } from '../../../signals/__mocks__/es_results'; import { flatten } from './flatten'; @@ -32,6 +38,8 @@ type SignalDoc = SignalSourceHit & { _source: Required['_source'] & { '@timestamp': string }; }; +const SPACE_ID = 'space'; + describe('buildAlert', () => { beforeEach(() => { jest.clearAllMocks(); @@ -42,12 +50,14 @@ describe('buildAlert', () => { delete doc._source.event; const rule = getRulesSchemaMock(); const alert = { - ...buildAlert([doc], rule), + ...buildAlert([doc], rule, SPACE_ID), ...additionalAlertFields(doc), }; const timestamp = alert['@timestamp']; const expected = { '@timestamp': timestamp, + [SPACE_IDS]: [SPACE_ID], + [ALERT_OWNER]: 'siem', [ALERT_ANCESTORS]: [ { id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', @@ -109,12 +119,14 @@ describe('buildAlert', () => { }; const rule = getRulesSchemaMock(); const alert = { - ...buildAlert([doc], rule), + ...buildAlert([doc], rule, SPACE_ID), ...additionalAlertFields(doc), }; const timestamp = alert['@timestamp']; const expected = { '@timestamp': timestamp, + [SPACE_IDS]: [SPACE_ID], + [ALERT_OWNER]: 'siem', [ALERT_ANCESTORS]: [ { id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts index d8e4727aa9f14..371e7d52ecff5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts @@ -5,7 +5,13 @@ * 2.0. */ -import { ALERT_RULE_NAMESPACE, ALERT_STATUS, ALERT_WORKFLOW_STATUS } from '@kbn/rule-data-utils'; +import { + ALERT_OWNER, + ALERT_RULE_NAMESPACE, + ALERT_STATUS, + ALERT_WORKFLOW_STATUS, + SPACE_IDS, +} from '@kbn/rule-data-utils'; import { RulesSchema } from '../../../../../../common/detection_engine/schemas/response/rules_schema'; import { isEventTypeSignal } from '../../../signals/build_event_type_signal'; import { Ancestor, BaseSignalHit, SimpleHit } from '../../../signals/types'; @@ -89,7 +95,11 @@ export const removeClashes = (doc: SimpleHit) => { * @param docs The parent alerts/events of the new alert to be built. * @param rule The rule that is generating the new alert. */ -export const buildAlert = (docs: SimpleHit[], rule: RulesSchema): RACAlert => { +export const buildAlert = ( + docs: SimpleHit[], + rule: RulesSchema, + spaceId: string | null | undefined +): RACAlert => { const removedClashes = docs.map(removeClashes); const parents = removedClashes.map(buildParent).filter((parent) => parent != null) as Ancestor[]; const depth = parents.reduce((acc, parent) => Math.max(parent.depth, acc), 0) + 1; @@ -100,6 +110,8 @@ export const buildAlert = (docs: SimpleHit[], rule: RulesSchema): RACAlert => { return ({ '@timestamp': new Date().toISOString(), + [ALERT_OWNER]: 'siem', + [SPACE_IDS]: spaceId != null ? [spaceId] : [], [ALERT_ANCESTORS]: ancestors, [ALERT_STATUS]: 'open', [ALERT_WORKFLOW_STATUS]: 'open', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_bulk_body.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_bulk_body.ts index 417402ea4b78c..ca5857e0ee395 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_bulk_body.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_bulk_body.ts @@ -31,6 +31,7 @@ const isSourceDoc = ( * @returns The body that can be added to a bulk call for inserting the signal. */ export const buildBulkBody = ( + spaceId: string | null | undefined, ruleSO: SavedObject, doc: SignalSourceHit, mergeStrategy: ConfigType['alertMergeStrategy'], @@ -44,7 +45,7 @@ export const buildBulkBody = ( if (isSourceDoc(mergedDoc)) { return { ...filteredSource, - ...buildAlert([mergedDoc], rule), + ...buildAlert([mergedDoc], rule, spaceId), ...additionalAlertFields(mergedDoc), '@timestamp': new Date().toISOString(), }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/wrap_hits_factory.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/wrap_hits_factory.ts index bb2908fa56bd9..143c66ba5cdd4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/wrap_hits_factory.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/wrap_hits_factory.ts @@ -18,10 +18,12 @@ export const wrapHitsFactory = ({ logger, mergeStrategy, ruleSO, + spaceId, }: { logger: Logger; ruleSO: SearchAfterAndBulkCreateParams['ruleSO']; mergeStrategy: ConfigType['alertMergeStrategy']; + spaceId: string | null | undefined; }): WrapHits => (events) => { try { const wrappedDocs: WrappedRACAlert[] = events.flatMap((doc) => [ @@ -33,7 +35,7 @@ export const wrapHitsFactory = ({ String(doc._version), ruleSO.attributes.params.ruleId ?? '' ), - _source: buildBulkBody(ruleSO, doc as SignalSourceHit, mergeStrategy, true), + _source: buildBulkBody(spaceId, ruleSO, doc as SignalSourceHit, mergeStrategy, true), }, ]);