mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security Solution] Add timelines installation to the new rule upgrade/install endpoints (#159694)
**Resolves: https://github.com/elastic/kibana/issues/152860** To replicate the behavior of the legacy prebuilt rule endpoint, this PR introduces a call to install prebuilt timeline templates each time any of the following endpoints are invoked: - `POST /internal/detection_engine/prebuilt_rules/installation/_perform` - `POST /internal/detection_engine/prebuilt_rules/upgrade/_perform`
This commit is contained in:
parent
25bf774893
commit
16193c6544
4 changed files with 70 additions and 28 deletions
|
@ -18,18 +18,16 @@ import type {
|
|||
SecuritySolutionApiRequestHandlerContext,
|
||||
SecuritySolutionPluginRouter,
|
||||
} from '../../../../../types';
|
||||
import { installPrepackagedTimelines } from '../../../../timeline/routes/prepackaged_timelines/install_prepackaged_timelines';
|
||||
import { buildSiemResponse } from '../../../routes/utils';
|
||||
import { importTimelineResultSchema } from '../../../../../../common/types/timeline/api';
|
||||
|
||||
import { getExistingPrepackagedRules } from '../../../rule_management/logic/search/get_existing_prepackaged_rules';
|
||||
import { ensureLatestRulesPackageInstalled } from '../../logic/ensure_latest_rules_package_installed';
|
||||
import { getRulesToInstall } from '../../logic/get_rules_to_install';
|
||||
import { getRulesToUpdate } from '../../logic/get_rules_to_update';
|
||||
import { performTimelinesInstallation } from '../../logic/perform_timelines_installation';
|
||||
import { createPrebuiltRuleAssetsClient } from '../../logic/rule_assets/prebuilt_rule_assets_client';
|
||||
import { createPrebuiltRules } from '../../logic/rule_objects/create_prebuilt_rules';
|
||||
import { upgradePrebuiltRules } from '../../logic/rule_objects/upgrade_prebuilt_rules';
|
||||
import { rulesToMap } from '../../logic/utils';
|
||||
import { ensureLatestRulesPackageInstalled } from '../../logic/ensure_latest_rules_package_installed';
|
||||
|
||||
export const installPrebuiltRulesAndTimelinesRoute = (router: SecuritySolutionPluginRouter) => {
|
||||
router.put(
|
||||
|
@ -84,14 +82,11 @@ export const createPrepackagedRules = async (
|
|||
exceptionsClient?: ExceptionListClient
|
||||
): Promise<InstallPrebuiltRulesAndTimelinesResponse | null> => {
|
||||
const config = context.getConfig();
|
||||
const frameworkRequest = context.getFrameworkRequest();
|
||||
const savedObjectsClient = context.core.savedObjects.client;
|
||||
const siemClient = context.getAppClient();
|
||||
const exceptionsListClient = context.getExceptionListClient() ?? exceptionsClient;
|
||||
const ruleAssetsClient = createPrebuiltRuleAssetsClient(savedObjectsClient);
|
||||
|
||||
const { maxTimelineImportExportSize } = config;
|
||||
|
||||
if (!siemClient || !rulesClient) {
|
||||
throw new PrepackagedRulesError('', 404);
|
||||
}
|
||||
|
@ -116,14 +111,8 @@ export const createPrepackagedRules = async (
|
|||
throw new AggregateError(result.errors, 'Error installing new prebuilt rules');
|
||||
}
|
||||
|
||||
const timeline = await installPrepackagedTimelines(
|
||||
maxTimelineImportExportSize,
|
||||
frameworkRequest,
|
||||
true
|
||||
);
|
||||
const [prepackagedTimelinesResult, timelinesErrors] = validate(
|
||||
timeline,
|
||||
importTimelineResultSchema
|
||||
const { result: timelinesResult, error: timelinesError } = await performTimelinesInstallation(
|
||||
context
|
||||
);
|
||||
|
||||
await upgradePrebuiltRules(rulesClient, rulesToUpdate);
|
||||
|
@ -131,8 +120,8 @@ export const createPrepackagedRules = async (
|
|||
const prebuiltRulesOutput: InstallPrebuiltRulesAndTimelinesResponse = {
|
||||
rules_installed: rulesToInstall.length,
|
||||
rules_updated: rulesToUpdate.length,
|
||||
timelines_installed: prepackagedTimelinesResult?.timelines_installed ?? 0,
|
||||
timelines_updated: prepackagedTimelinesResult?.timelines_updated ?? 0,
|
||||
timelines_installed: timelinesResult?.timelines_installed ?? 0,
|
||||
timelines_updated: timelinesResult?.timelines_updated ?? 0,
|
||||
};
|
||||
|
||||
const [validated, genericErrors] = validate(
|
||||
|
@ -140,9 +129,9 @@ export const createPrepackagedRules = async (
|
|||
InstallPrebuiltRulesAndTimelinesResponse
|
||||
);
|
||||
|
||||
if (genericErrors != null && timelinesErrors != null) {
|
||||
if (genericErrors != null && timelinesError != null) {
|
||||
throw new PrepackagedRulesError(
|
||||
[genericErrors, timelinesErrors].filter((msg) => msg != null).join(', '),
|
||||
[genericErrors, timelinesError].filter((msg) => msg != null).join(', '),
|
||||
500
|
||||
);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import { createPrebuiltRules } from '../../logic/rule_objects/create_prebuilt_ru
|
|||
import { createPrebuiltRuleObjectsClient } from '../../logic/rule_objects/prebuilt_rule_objects_client';
|
||||
import { fetchRuleVersionsTriad } from '../../logic/rule_versions/fetch_rule_versions_triad';
|
||||
import { getVersionBuckets } from '../../model/rule_versions/get_version_buckets';
|
||||
import { performTimelinesInstallation } from '../../logic/perform_timelines_installation';
|
||||
|
||||
export const performRuleInstallationRoute = (router: SecuritySolutionPluginRouter) => {
|
||||
router.post(
|
||||
|
@ -98,20 +99,32 @@ export const performRuleInstallationRoute = (router: SecuritySolutionPluginRoute
|
|||
rulesClient,
|
||||
installableRules
|
||||
);
|
||||
const combinedErrors = [...fetchErrors, ...installationErrors];
|
||||
const ruleErrors = [...fetchErrors, ...installationErrors];
|
||||
|
||||
const { error: timelineInstallationError } = await performTimelinesInstallation(
|
||||
ctx.securitySolution
|
||||
);
|
||||
|
||||
const allErrors = aggregatePrebuiltRuleErrors(ruleErrors);
|
||||
if (timelineInstallationError) {
|
||||
allErrors.push({
|
||||
message: timelineInstallationError,
|
||||
rules: [],
|
||||
});
|
||||
}
|
||||
|
||||
const body: PerformRuleInstallationResponseBody = {
|
||||
summary: {
|
||||
total: installedRules.length + skippedRules.length + combinedErrors.length,
|
||||
total: installedRules.length + skippedRules.length + ruleErrors.length,
|
||||
succeeded: installedRules.length,
|
||||
skipped: skippedRules.length,
|
||||
failed: combinedErrors.length,
|
||||
failed: ruleErrors.length,
|
||||
},
|
||||
results: {
|
||||
created: installedRules.map(({ result }) => internalRuleToAPIResponse(result)),
|
||||
skipped: skippedRules,
|
||||
},
|
||||
errors: aggregatePrebuiltRuleErrors(combinedErrors),
|
||||
errors: allErrors,
|
||||
};
|
||||
|
||||
return response.ok({ body });
|
||||
|
|
|
@ -23,6 +23,7 @@ import type { PromisePoolError } from '../../../../../utils/promise_pool';
|
|||
import { buildSiemResponse } from '../../../routes/utils';
|
||||
import { internalRuleToAPIResponse } from '../../../rule_management/normalization/rule_converters';
|
||||
import { aggregatePrebuiltRuleErrors } from '../../logic/aggregate_prebuilt_rule_errors';
|
||||
import { performTimelinesInstallation } from '../../logic/perform_timelines_installation';
|
||||
import { createPrebuiltRuleAssetsClient } from '../../logic/rule_assets/prebuilt_rule_assets_client';
|
||||
import { createPrebuiltRuleObjectsClient } from '../../logic/rule_objects/prebuilt_rule_objects_client';
|
||||
import { upgradePrebuiltRules } from '../../logic/rule_objects/upgrade_prebuilt_rules';
|
||||
|
@ -45,7 +46,7 @@ export const performRuleUpgradeRoute = (router: SecuritySolutionPluginRouter) =>
|
|||
const siemResponse = buildSiemResponse(response);
|
||||
|
||||
try {
|
||||
const ctx = await context.resolve(['core', 'alerting']);
|
||||
const ctx = await context.resolve(['core', 'alerting', 'securitySolution']);
|
||||
const soClient = ctx.core.savedObjects.client;
|
||||
const rulesClient = ctx.alerting.getRulesClient();
|
||||
const ruleAssetsClient = createPrebuiltRuleAssetsClient(soClient);
|
||||
|
@ -147,20 +148,32 @@ export const performRuleUpgradeRoute = (router: SecuritySolutionPluginRouter) =>
|
|||
rulesClient,
|
||||
targetRules
|
||||
);
|
||||
const combinedErrors = [...fetchErrors, ...installationErrors];
|
||||
const ruleErrors = [...fetchErrors, ...installationErrors];
|
||||
|
||||
const { error: timelineInstallationError } = await performTimelinesInstallation(
|
||||
ctx.securitySolution
|
||||
);
|
||||
|
||||
const allErrors = aggregatePrebuiltRuleErrors(ruleErrors);
|
||||
if (timelineInstallationError) {
|
||||
allErrors.push({
|
||||
message: timelineInstallationError,
|
||||
rules: [],
|
||||
});
|
||||
}
|
||||
|
||||
const body: PerformRuleUpgradeResponseBody = {
|
||||
summary: {
|
||||
total: updatedRules.length + skippedRules.length + combinedErrors.length,
|
||||
total: updatedRules.length + skippedRules.length + ruleErrors.length,
|
||||
skipped: skippedRules.length,
|
||||
succeeded: updatedRules.length,
|
||||
failed: combinedErrors.length,
|
||||
failed: ruleErrors.length,
|
||||
},
|
||||
results: {
|
||||
updated: updatedRules.map(({ result }) => internalRuleToAPIResponse(result)),
|
||||
skipped: skippedRules,
|
||||
},
|
||||
errors: aggregatePrebuiltRuleErrors(combinedErrors),
|
||||
errors: allErrors,
|
||||
};
|
||||
|
||||
return response.ok({ body });
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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 { validate } from '@kbn/securitysolution-io-ts-utils';
|
||||
import { importTimelineResultSchema } from '../../../../../common/types/timeline/api';
|
||||
import type { SecuritySolutionApiRequestHandlerContext } from '../../../../types';
|
||||
import { installPrepackagedTimelines } from '../../../timeline/routes/prepackaged_timelines/install_prepackaged_timelines';
|
||||
|
||||
export const performTimelinesInstallation = async (
|
||||
securitySolutionContext: SecuritySolutionApiRequestHandlerContext
|
||||
) => {
|
||||
const timeline = await installPrepackagedTimelines(
|
||||
securitySolutionContext.getConfig()?.maxTimelineImportExportSize,
|
||||
securitySolutionContext.getFrameworkRequest(),
|
||||
true
|
||||
);
|
||||
const [result, error] = validate(timeline, importTimelineResultSchema);
|
||||
|
||||
return {
|
||||
result,
|
||||
error,
|
||||
};
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue