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

Asset criticality alert enrichment #171241

Merged
merged 46 commits into from
Dec 22, 2023
Merged
Changes from 1 commit
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
ee2fac5
Add new fields to alertsFieldMap
Nov 14, 2023
5f13e85
Add new fields to alerts model including BaseFieldsLatest, etc
Nov 14, 2023
37e1dbf
Add new alert columns to table
Nov 14, 2023
243c117
refactoring alert enrichment code.
Nov 14, 2023
8fd21de
fix makeSingleFieldMatchQuery snapshot
Nov 28, 2023
c692d33
restore create_single_field_match_enrichment to `main` version
Nov 28, 2023
887764a
remove references to should_minimum_match
Nov 29, 2023
0f6d337
add new extraFilter option to createSingleMatchEnrichment
Nov 29, 2023
29f7513
put back all the stuff abount minimum_should_match
Nov 29, 2023
12aa184
work in progress
Nov 29, 2023
e3b7020
Add alert enrichment
nkhristinin Nov 30, 2023
c9b2cf1
Add integrations tests
nkhristinin Nov 30, 2023
2111edf
remove owners.csv
nkhristinin Nov 30, 2023
219ba82
Merge branch 'main' into asset-criticality-alert-enrichment
kibanamachine Dec 1, 2023
070b43d
Schema changes
nkhristinin Dec 1, 2023
0b77a96
fix unit tests
nkhristinin Dec 1, 2023
b31beb6
Add more unit tests
nkhristinin Dec 1, 2023
f862201
Merge branch 'main' into asset-criticality-alert-enrichment
nkhristinin Dec 4, 2023
78a3694
Merge branch 'main' into asset-criticality-alert-enrichment
kibanamachine Dec 4, 2023
c4a461e
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Dec 4, 2023
c97c330
Merge branch 'main' into asset-criticality-alert-enrichment
kibanamachine Dec 6, 2023
d3c5122
Change alert schema
nkhristinin Dec 6, 2023
fe33f17
change how to set field to alert
nkhristinin Dec 7, 2023
10ee114
add more tests
nkhristinin Dec 7, 2023
c58cf48
Remove some comments
nkhristinin Dec 7, 2023
498e965
fix tests
nkhristinin Dec 7, 2023
bd872e1
update alert schema
nkhristinin Dec 11, 2023
78a5b2b
Merge branch 'main' into asset-criticality-alert-enrichment
kibanamachine Dec 11, 2023
d7d2c6c
change alert schema
nkhristinin Dec 11, 2023
4cf765e
remoe comments
nkhristinin Dec 11, 2023
744aace
Fix types
nkhristinin Dec 11, 2023
7b2e1ea
Merge branch 'main' into asset-criticality-alert-enrichment
kibanamachine Dec 12, 2023
00fdef5
Merge branch 'main' into asset-criticality-alert-enrichment
kibanamachine Dec 12, 2023
fa8df5c
Fix path
nkhristinin Dec 12, 2023
0695181
Move feature flag
nkhristinin Dec 12, 2023
9ca2fa7
Merge branch 'main' into asset-criticality-alert-enrichment
kibanamachine Dec 13, 2023
81142da
Remove type annotation
nkhristinin Dec 13, 2023
08611bf
Merge branch 'main' into asset-criticality-alert-enrichment
kibanamachine Dec 19, 2023
81ca783
fix tests
nkhristinin Dec 19, 2023
ffeb96e
PR fixes
nkhristinin Dec 21, 2023
35a9be3
Clean tests
nkhristinin Dec 21, 2023
c296a4c
Add utility function to check if index exist
nkhristinin Dec 21, 2023
b44541a
Rename file
nkhristinin Dec 21, 2023
ed77987
Merge branch 'main' into asset-criticality-alert-enrichment
kibanamachine Dec 21, 2023
84c8da9
specify test parameters
nkhristinin Dec 21, 2023
5c1de12
Merge branch 'main' into asset-criticality-alert-enrichment
nkhristinin Dec 21, 2023
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
Prev Previous commit
Next Next commit
Add utility function to check if index exist
  • Loading branch information
nkhristinin committed Dec 21, 2023
commit c296a4c3af4f86f8c34b36ee7d26fb916a601acf
Original file line number Diff line number Diff line change
@@ -11,26 +11,10 @@ import {
ALERT_USER_CRITICALITY,
} from '../../../../../../../common/field_maps/field_names';
import { createSingleFieldMatchEnrichment } from '../create_single_field_match_enrichment';
import type {
CreateCriticalityEnrichment,
DoesAssetCriticalityAvailable,
CreateEnrichmentFunction,
} from '../types';
import type { CreateCriticalityEnrichment, CreateEnrichmentFunction } from '../types';
import { getFieldValue } from '../utils/events';
import { getAssetCriticalityIndex } from '../../../../../../../common/entity_analytics/asset_criticality';

export const doesAssetCriticalityIndexExist: DoesAssetCriticalityAvailable = async ({
spaceId,
services,
}) => {
const isAssetCriticalityIndexExist =
await services.scopedClusterClient.asInternalUser.indices.exists({
index: getAssetCriticalityIndex(spaceId),
});

return isAssetCriticalityIndexExist;
};

const enrichmentResponseFields = ['id_value', 'criticality_level'];

const getExtraFiltersForEnrichment = (field: string) => [
Original file line number Diff line number Diff line change
@@ -10,23 +10,9 @@ import { cloneDeep } from 'lodash';
import { getHostRiskIndex } from '../../../../../../../common/search_strategy/security_solution/risk_score/common';
import { RiskScoreFields } from '../../../../../../../common/search_strategy/security_solution/risk_score/all';
import { createSingleFieldMatchEnrichment } from '../create_single_field_match_enrichment';
import type { CreateRiskEnrichment, GetIsRiskScoreAvailable } from '../types';
import type { CreateRiskEnrichment } from '../types';
import { getFieldValue } from '../utils/events';

export const getIsHostRiskScoreAvailable: GetIsRiskScoreAvailable = async ({
spaceId,
services,
isNewRiskScoreModuleInstalled,
}) => {
const isHostRiskScoreIndexExist = await services.scopedClusterClient.asCurrentUser.indices.exists(
{
index: getHostRiskIndex(spaceId, true, isNewRiskScoreModuleInstalled),
}
);

return isHostRiskScoreIndexExist;
};

export const createHostRiskEnrichments: CreateRiskEnrichment = async ({
services,
logger,
Original file line number Diff line number Diff line change
@@ -9,23 +9,9 @@ import { cloneDeep } from 'lodash';
import { getUserRiskIndex } from '../../../../../../../common/search_strategy/security_solution/risk_score/common';
import { RiskScoreFields } from '../../../../../../../common/search_strategy/security_solution/risk_score/all';
import { createSingleFieldMatchEnrichment } from '../create_single_field_match_enrichment';
import type { CreateRiskEnrichment, GetIsRiskScoreAvailable } from '../types';
import type { CreateRiskEnrichment } from '../types';
import { getFieldValue } from '../utils/events';

export const getIsUserRiskScoreAvailable: GetIsRiskScoreAvailable = async ({
services,
spaceId,
isNewRiskScoreModuleInstalled,
}) => {
const isUserRiskScoreIndexExist = await services.scopedClusterClient.asCurrentUser.indices.exists(
{
index: getUserRiskIndex(spaceId, true, isNewRiskScoreModuleInstalled),
}
);

return isUserRiskScoreIndexExist;
};

export const createUserRiskEnrichments: CreateRiskEnrichment = async ({
services,
logger,
Original file line number Diff line number Diff line change
@@ -11,34 +11,20 @@ import { enrichEvents } from '.';
import { searchEnrichments } from './search_enrichments';
import { ruleExecutionLogMock } from '../../../rule_monitoring/mocks';
import { createAlert } from './__mocks__/alerts';
import { getIsHostRiskScoreAvailable } from './enrichment_by_type/host_risk';
import { getIsUserRiskScoreAvailable } from './enrichment_by_type/user_risk';
import { doesAssetCriticalityIndexExist } from './enrichment_by_type/asset_criticality';

import { isIndexExist } from './utils/isIndexExist';

import { allowedExperimentalValues } from '../../../../../../common';

jest.mock('./search_enrichments', () => ({
searchEnrichments: jest.fn(),
}));
const mockSearchEnrichments = searchEnrichments as jest.Mock;

jest.mock('./enrichment_by_type/host_risk', () => ({
...jest.requireActual('./enrichment_by_type/host_risk'),
getIsHostRiskScoreAvailable: jest.fn(),
}));
const mockGetIsHostRiskScoreAvailable = getIsHostRiskScoreAvailable as jest.Mock;

jest.mock('./enrichment_by_type/user_risk', () => ({
...jest.requireActual('./enrichment_by_type/user_risk'),
getIsUserRiskScoreAvailable: jest.fn(),
jest.mock('./utils/isIndexExist', () => ({
isIndexExist: jest.fn(),
}));

jest.mock('./enrichment_by_type/asset_criticality', () => ({
...jest.requireActual('./enrichment_by_type/asset_criticality'),
doesAssetCriticalityIndexExist: jest.fn(),
}));

const mockGetIsUserRiskScoreAvailable = getIsUserRiskScoreAvailable as jest.Mock;
const mockDoesAssetCriticalityIndexExist = doesAssetCriticalityIndexExist as jest.Mock;
const mockIsIndexExist = isIndexExist as jest.Mock;

const hostEnrichmentResponse = [
{
@@ -109,15 +95,12 @@ describe('enrichEvents', () => {
alertServices = alertsMock.createRuleExecutorServices();
});
afterEach(() => {
mockGetIsUserRiskScoreAvailable.mockClear();
mockGetIsUserRiskScoreAvailable.mockClear();
mockDoesAssetCriticalityIndexExist.mockClear();
mockIsIndexExist.mockClear();
});

it('return the same events, if risk indexes are not available', async () => {
mockSearchEnrichments.mockImplementation(() => []);
mockGetIsUserRiskScoreAvailable.mockImplementation(() => false);
mockGetIsHostRiskScoreAvailable.mockImplementation(() => false);
mockIsIndexExist.mockImplementation(() => false);
const events = [
createAlert('1', createEntity('host', 'host name')),
createAlert('2', createEntity('user', 'user name')),
@@ -134,8 +117,7 @@ describe('enrichEvents', () => {

it('return the same events, if there no fields', async () => {
mockSearchEnrichments.mockImplementation(() => []);
mockGetIsUserRiskScoreAvailable.mockImplementation(() => true);
mockGetIsHostRiskScoreAvailable.mockImplementation(() => true);
mockIsIndexExist.mockImplementation(() => true);
const events = [createAlert('1'), createAlert('2')];
const enrichedEvents = await enrichEvents({
logger: ruleExecutionLogger,
@@ -151,8 +133,7 @@ describe('enrichEvents', () => {
mockSearchEnrichments
.mockReturnValueOnce(hostEnrichmentResponse)
.mockReturnValueOnce(userEnrichmentResponse);
mockGetIsUserRiskScoreAvailable.mockImplementation(() => true);
mockGetIsHostRiskScoreAvailable.mockImplementation(() => true);
mockIsIndexExist.mockImplementation(() => true);

const enrichedEvents = await enrichEvents({
logger: ruleExecutionLogger,
@@ -201,9 +182,12 @@ describe('enrichEvents', () => {
.mockReturnValueOnce(assetCriticalityUserResponse)
.mockReturnValueOnce(assetCriticalityHostResponse);

mockGetIsUserRiskScoreAvailable.mockImplementation(() => false);
mockGetIsHostRiskScoreAvailable.mockImplementation(() => false);
mockDoesAssetCriticalityIndexExist.mockImplementation(() => true);
// disable risk score enrichments
mockIsIndexExist.mockImplementationOnce(() => false);
mockIsIndexExist.mockImplementationOnce(() => false);
mockIsIndexExist.mockImplementationOnce(() => false);
// enable for asset criticality
mockIsIndexExist.mockImplementation(() => true);

const enrichedEvents = await enrichEvents({
logger: ruleExecutionLogger,
@@ -242,8 +226,8 @@ describe('enrichEvents', () => {
throw new Error('1');
})
.mockImplementationOnce(() => userEnrichmentResponse);
mockGetIsUserRiskScoreAvailable.mockImplementation(() => true);
mockGetIsHostRiskScoreAvailable.mockImplementation(() => true);
mockIsIndexExist.mockImplementation(() => true);
mockIsIndexExist.mockImplementation(() => true);

const enrichedEvents = await enrichEvents({
logger: ruleExecutionLogger,
Original file line number Diff line number Diff line change
@@ -5,28 +5,26 @@
* 2.0.
*/

import {
createHostRiskEnrichments,
getIsHostRiskScoreAvailable,
} from './enrichment_by_type/host_risk';
import { createHostRiskEnrichments } from './enrichment_by_type/host_risk';

import {
createUserRiskEnrichments,
getIsUserRiskScoreAvailable,
} from './enrichment_by_type/user_risk';
import { createUserRiskEnrichments } from './enrichment_by_type/user_risk';

import {
createHostAssetCriticalityEnrichments,
createUserAssetCriticalityEnrichments,
doesAssetCriticalityIndexExist,
} from './enrichment_by_type/asset_criticality';

import { getAssetCriticalityIndex } from '../../../../../../common/entity_analytics/asset_criticality';
import type {
EnrichEventsFunction,
EventsMapByEnrichments,
CreateEnrichEventsFunction,
} from './types';
import { applyEnrichmentsToEvents } from './utils/transforms';
import { isIndexExist } from './utils/isIndexExist';
import {
getHostRiskIndex,
getUserRiskIndex,
} from '../../../../../../common/search_strategy/security_solution/risk_score/common';

export const enrichEvents: EnrichEventsFunction = async ({
services,
@@ -45,16 +43,21 @@ export const enrichEvents: EnrichEventsFunction = async ({

let isNewRiskScoreModuleInstalled = false;
if (isNewRiskScoreModuleAvailable) {
isNewRiskScoreModuleInstalled = await getIsHostRiskScoreAvailable({
spaceId,
isNewRiskScoreModuleInstalled = await isIndexExist({
services,
isNewRiskScoreModuleInstalled: true,
index: getHostRiskIndex(spaceId, true, true),
});
}

const [isHostRiskScoreIndexExist, isUserRiskScoreIndexExist] = await Promise.all([
getIsHostRiskScoreAvailable({ spaceId, services, isNewRiskScoreModuleInstalled }),
getIsUserRiskScoreAvailable({ spaceId, services, isNewRiskScoreModuleInstalled }),
isIndexExist({
services,
index: getHostRiskIndex(spaceId, true, isNewRiskScoreModuleInstalled),
}),
isIndexExist({
services,
index: getUserRiskIndex(spaceId, true, isNewRiskScoreModuleInstalled),
}),
]);

if (isHostRiskScoreIndexExist) {
@@ -82,9 +85,9 @@ export const enrichEvents: EnrichEventsFunction = async ({
}

if (isAssetCriticalityEnabled) {
const assetCriticalityIndexExist = await doesAssetCriticalityIndexExist({
spaceId,
const assetCriticalityIndexExist = await isIndexExist({
services,
index: getAssetCriticalityIndex(spaceId),
});
if (assetCriticalityIndexExist) {
enrichments.push(
Original file line number Diff line number Diff line change
@@ -75,10 +75,7 @@ export type GetIsRiskScoreAvailable = (params: {
isNewRiskScoreModuleInstalled: boolean;
}) => Promise<boolean>;

export type DoesAssetCriticalityAvailable = (params: {
spaceId: string;
services: RuleServices;
}) => Promise<boolean>;
export type IsIndexExist = (params: { services: RuleServices; index: string }) => Promise<boolean>;

export type CreateRiskEnrichment = <T extends BaseFieldsLatest>(
params: BasedEnrichParamters<T> & {
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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 type { IsIndexExist } from '../types';

export const isIndexExist: IsIndexExist = async ({ services, index }) => {
const isAssetCriticalityIndexExist =
await services.scopedClusterClient.asInternalUser.indices.exists({
index,
});

return isAssetCriticalityIndexExist;
};