Skip to content

Commit

Permalink
Make owner and space id required fields
Browse files Browse the repository at this point in the history
  • Loading branch information
madirey committed Aug 4, 2021
1 parent 79adbfd commit 5cccc73
Show file tree
Hide file tree
Showing 14 changed files with 73 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ALERT_EVALUATION_VALUE,
ALERT_ID,
ALERT_PRODUCER,
ALERT_OWNER,
ALERT_SEVERITY_LEVEL,
ALERT_START,
ALERT_STATUS,
Expand Down Expand Up @@ -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'],
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/rule_registry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2148,7 +2148,7 @@ export const ecsFieldMap = {
'rule.id': {
type: 'keyword',
array: false,
required: false,
required: true,
},
'rule.license': {
type: 'keyword',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
CONSUMERS,
ECS_VERSION,
RULE_ID,
SPACE_IDS,
TIMESTAMP,
VERSION,
} from '@kbn/rule-data-utils';
Expand All @@ -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',
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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
},
},
Expand Down Expand Up @@ -222,13 +229,19 @@ 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
},
},
{
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
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
EVENT_ACTION,
EVENT_KIND,
ALERT_OWNER,
RULE_ID,
RULE_UUID,
TIMESTAMP,
SPACE_IDS,
Expand Down Expand Up @@ -154,6 +155,8 @@ export const createLifecycleExecutor = (
currentAlerts[id] = {
...fields,
[ALERT_ID]: id,
[RULE_ID]: rule.ruleTypeId,
[ALERT_OWNER]: rule.consumer,
};
return alertInstanceFactory(id);
},
Expand Down Expand Up @@ -226,6 +229,8 @@ export const createLifecycleExecutor = (
alertsDataMap[alertId] = {
...fields,
[ALERT_ID]: alertId,
[RULE_ID]: rule.ruleTypeId,
[ALERT_OWNER]: rule.consumer,
};
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -216,6 +223,7 @@ export class RuleRegistryLogClient implements IRuleRegistryLogClient {
[getMetricField(metric)]: value,
[RULE_ID]: ruleId,
[TIMESTAMP]: new Date().toISOString(),
[ALERT_OWNER]: 'siem',
},
namespace
);
Expand All @@ -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
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -30,8 +28,7 @@ export const bulkCreateFactory = <TContext extends AlertInstanceContext>(
logger: Logger,
alertWithPersistence: PersistenceAlertService<TContext>,
buildRuleMessage: BuildRuleMessage,
refreshForBulkCreate: RefreshTypes,
spaceId: string
refreshForBulkCreate: RefreshTypes
) => async <T>(wrappedDocs: Array<BaseHit<T>>): Promise<GenericBulkCreateResponse<T>> => {
if (wrappedDocs.length === 0) {
return {
Expand All @@ -48,11 +45,7 @@ export const bulkCreateFactory = <TContext extends AlertInstanceContext>(
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
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -32,6 +38,8 @@ type SignalDoc = SignalSourceHit & {
_source: Required<SignalSourceHit>['_source'] & { '@timestamp': string };
};

const SPACE_ID = 'space';

describe('buildAlert', () => {
beforeEach(() => {
jest.clearAllMocks();
Expand All @@ -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',
Expand Down Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
Expand All @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<AlertAttributes>,
doc: SignalSourceHit,
mergeStrategy: ConfigType['alertMergeStrategy'],
Expand All @@ -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(),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) => [
Expand All @@ -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),
},
]);

Expand Down

0 comments on commit 5cccc73

Please sign in to comment.