mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[8.x] [Security Solution] Fix prebuilt rules force upgrade on Endpoint policy creation (#217959) (#218154)
# Backport This will backport the following commits from `main` to `8.x`: - [[Security Solution] Fix prebuilt rules force upgrade on Endpoint policy creation (#217959)](https://github.com/elastic/kibana/pull/217959) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Dmitrii Shevchenko","email":"dmitrii.shevchenko@elastic.co"},"sourceCommit":{"committedDate":"2025-04-14T17:22:38Z","message":"[Security Solution] Fix prebuilt rules force upgrade on Endpoint policy creation (#217959)\n\n**Resolves: https://github.com/elastic/security-team/issues/7216**\n\n## Summary\n\nThis PR updates the Endpoint policy callback to: \n\n- **Install only the Elastic Defend rule if it's missing**, without\nupgrading it to the latest version. Previously, the rule was both\ninstalled and updated whenever an Endpoint policy was created, which\nconflicted with rule customization. Automatic upgrades could erase\nexisting user customizations.\n\n- **Avoid triggering the installation or upgrade of any other prebuilt\nrules** as part of this flow. The Endpoint package policy creation\ncallback\n([source](f7d8bc3c25/x-pack/solutions/security/plugins/security_solution/server/fleet_integration/fleet_integration.ts (L181-L187)
))\npreviously installed and upgraded **all** prebuilt detection rules to\ntheir target versions whenever an Endpoint policy was created.\n\nThis logic relied on the legacy rule upgrade method, which has a known\nissue that causes all configured rule actions and exceptions to be lost.\nBy removing the upgrade logic, this PR eliminates that incorrect\nbehavior.","sha":"9f5425f061e6fff8579f7db1117af075b1b6ca1b","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:fix","impact:high","Feature:Endpoint","Team:Detections and Resp","Team: SecuritySolution","Team:Detection Rule Management","Feature:Prebuilt Detection Rules","backport:version","v9.1.0","v8.19.0","v8.18.1","v9.0.1","v8.17.5"],"title":"[Security Solution] Fix prebuilt rules force upgrade on Endpoint policy creation","number":217959,"url":"https://github.com/elastic/kibana/pull/217959","mergeCommit":{"message":"[Security Solution] Fix prebuilt rules force upgrade on Endpoint policy creation (#217959)\n\n**Resolves: https://github.com/elastic/security-team/issues/7216**\n\n## Summary\n\nThis PR updates the Endpoint policy callback to: \n\n- **Install only the Elastic Defend rule if it's missing**, without\nupgrading it to the latest version. Previously, the rule was both\ninstalled and updated whenever an Endpoint policy was created, which\nconflicted with rule customization. Automatic upgrades could erase\nexisting user customizations.\n\n- **Avoid triggering the installation or upgrade of any other prebuilt\nrules** as part of this flow. The Endpoint package policy creation\ncallback\n([source](f7d8bc3c25/x-pack/solutions/security/plugins/security_solution/server/fleet_integration/fleet_integration.ts (L181-L187)
))\npreviously installed and upgraded **all** prebuilt detection rules to\ntheir target versions whenever an Endpoint policy was created.\n\nThis logic relied on the legacy rule upgrade method, which has a known\nissue that causes all configured rule actions and exceptions to be lost.\nBy removing the upgrade logic, this PR eliminates that incorrect\nbehavior.","sha":"9f5425f061e6fff8579f7db1117af075b1b6ca1b"}},"sourceBranch":"main","suggestedTargetBranches":["8.x","8.18","9.0","8.17"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/217959","number":217959,"mergeCommit":{"message":"[Security Solution] Fix prebuilt rules force upgrade on Endpoint policy creation (#217959)\n\n**Resolves: https://github.com/elastic/security-team/issues/7216**\n\n## Summary\n\nThis PR updates the Endpoint policy callback to: \n\n- **Install only the Elastic Defend rule if it's missing**, without\nupgrading it to the latest version. Previously, the rule was both\ninstalled and updated whenever an Endpoint policy was created, which\nconflicted with rule customization. Automatic upgrades could erase\nexisting user customizations.\n\n- **Avoid triggering the installation or upgrade of any other prebuilt\nrules** as part of this flow. The Endpoint package policy creation\ncallback\n([source](f7d8bc3c25/x-pack/solutions/security/plugins/security_solution/server/fleet_integration/fleet_integration.ts (L181-L187)
))\npreviously installed and upgraded **all** prebuilt detection rules to\ntheir target versions whenever an Endpoint policy was created.\n\nThis logic relied on the legacy rule upgrade method, which has a known\nissue that causes all configured rule actions and exceptions to be lost.\nBy removing the upgrade logic, this PR eliminates that incorrect\nbehavior.","sha":"9f5425f061e6fff8579f7db1117af075b1b6ca1b"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.18","label":"v8.18.1","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"9.0","label":"v9.0.1","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.17","label":"v8.17.5","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Dmitrii Shevchenko <dmitrii.shevchenko@elastic.co>
This commit is contained in:
parent
0ab217af55
commit
48554f91e1
5 changed files with 92 additions and 68 deletions
|
@ -185,7 +185,6 @@ export class EndpointAppContextService {
|
|||
this.setupDependencies.securitySolutionRequestContextFactory,
|
||||
alerting,
|
||||
licenseService,
|
||||
exceptionListsClient,
|
||||
this.setupDependencies.cloud,
|
||||
productFeaturesService,
|
||||
telemetryConfigProvider
|
||||
|
|
|
@ -191,7 +191,6 @@ describe('Fleet integrations', () => {
|
|||
requestContextFactoryMock.create(),
|
||||
endpointAppContextStartContract.alerting,
|
||||
licenseService,
|
||||
exceptionListClient,
|
||||
cloudService,
|
||||
productFeaturesService,
|
||||
telemetryConfigProviderMock
|
||||
|
|
|
@ -47,7 +47,7 @@ import type { NewPolicyData, PolicyConfig } from '../../common/endpoint/types';
|
|||
import type { LicenseService } from '../../common/license';
|
||||
import type { ManifestManager } from '../endpoint/services';
|
||||
import type { IRequestContextFactory } from '../request_context_factory';
|
||||
import { installPrepackagedRules } from './handlers/install_prepackaged_rules';
|
||||
import { installEndpointSecurityPrebuiltRule } from '../lib/detection_engine/prebuilt_rules/logic/rules_package/install_endpoint_security_prebuilt_rule';
|
||||
import { createPolicyArtifactManifest } from './handlers/create_policy_artifact_manifest';
|
||||
import { createDefaultPolicy } from './handlers/create_default_policy';
|
||||
import { validatePolicyAgainstLicense } from './handlers/validate_policy_against_license';
|
||||
|
@ -122,7 +122,6 @@ export const getPackagePolicyCreateCallback = (
|
|||
securitySolutionRequestContextFactory: IRequestContextFactory,
|
||||
alerts: AlertingServerStart,
|
||||
licenseService: LicenseService,
|
||||
exceptionsClient: ExceptionListClient | undefined,
|
||||
cloud: CloudSetup,
|
||||
productFeatures: ProductFeaturesService,
|
||||
telemetryConfigProvider: TelemetryConfigProvider
|
||||
|
@ -176,15 +175,13 @@ export const getPackagePolicyCreateCallback = (
|
|||
|
||||
// perform these operations in parallel in order to help in not delaying the API response too much
|
||||
const [, manifestValue] = await Promise.all([
|
||||
// Install Detection Engine prepackaged rules
|
||||
exceptionsClient &&
|
||||
installPrepackagedRules({
|
||||
logger,
|
||||
context: securitySolutionContext,
|
||||
request,
|
||||
alerts,
|
||||
exceptionsClient,
|
||||
}),
|
||||
installEndpointSecurityPrebuiltRule({
|
||||
logger,
|
||||
context: securitySolutionContext,
|
||||
request,
|
||||
alerts,
|
||||
soClient,
|
||||
}),
|
||||
|
||||
// create the Artifact Manifest for this policy
|
||||
createPolicyArtifactManifest(logger, manifestManager),
|
||||
|
|
|
@ -1,55 +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 type { KibanaRequest, Logger } from '@kbn/core/server';
|
||||
import type { ExceptionListClient } from '@kbn/lists-plugin/server';
|
||||
import type { AlertingServerStart } from '@kbn/alerting-plugin/server';
|
||||
import { createDetectionIndex } from '../../lib/detection_engine/routes/index/create_index_route';
|
||||
import { createPrepackagedRules } from '../../lib/detection_engine/prebuilt_rules';
|
||||
import type { SecuritySolutionApiRequestHandlerContext } from '../../types';
|
||||
|
||||
export interface InstallPrepackagedRulesProps {
|
||||
logger: Logger;
|
||||
context: SecuritySolutionApiRequestHandlerContext;
|
||||
request: KibanaRequest;
|
||||
alerts: AlertingServerStart;
|
||||
exceptionsClient: ExceptionListClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* As part of a user taking advantage of Endpoint Security from within fleet, we attempt to install
|
||||
* the pre-packaged rules from the detection engine, which includes an Endpoint Rule enabled by default
|
||||
*/
|
||||
export const installPrepackagedRules = async ({
|
||||
logger,
|
||||
context,
|
||||
request,
|
||||
alerts,
|
||||
exceptionsClient,
|
||||
}: InstallPrepackagedRulesProps): Promise<void> => {
|
||||
// Create detection index & rules (if necessary). move past any failure, this is just a convenience
|
||||
try {
|
||||
await createDetectionIndex(context);
|
||||
} catch (err) {
|
||||
if (err.statusCode !== 409) {
|
||||
// 409 -> detection index already exists, which is fine
|
||||
logger.warn(
|
||||
`Possible problem creating detection signals index (${err.statusCode}): ${err.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
try {
|
||||
// this checks to make sure index exists first, safe to try in case of failure above
|
||||
// may be able to recover from minor errors
|
||||
const rulesClient = await alerts.getRulesClientWithRequest(request);
|
||||
await createPrepackagedRules(context, rulesClient, exceptionsClient);
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`Unable to create detection rules automatically (${err.statusCode}): ${err.message}`
|
||||
);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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 { KibanaRequest, Logger, SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import type { AlertingServerStart } from '@kbn/alerting-plugin/server';
|
||||
import { createDetectionIndex } from '../../../routes/index/create_index_route';
|
||||
import type { SecuritySolutionApiRequestHandlerContext } from '../../../../../types';
|
||||
import { ELASTIC_SECURITY_RULE_ID } from '../../../../../../common';
|
||||
import { createPrebuiltRuleObjectsClient } from '../rule_objects/prebuilt_rule_objects_client';
|
||||
import { createPrebuiltRuleAssetsClient } from '../rule_assets/prebuilt_rule_assets_client';
|
||||
import { createPrebuiltRules } from '../rule_objects/create_prebuilt_rules';
|
||||
|
||||
export interface InstallEndpointSecurityPrebuiltRuleProps {
|
||||
logger: Logger;
|
||||
context: SecuritySolutionApiRequestHandlerContext;
|
||||
request: KibanaRequest;
|
||||
alerts: AlertingServerStart;
|
||||
soClient: SavedObjectsClientContract;
|
||||
}
|
||||
|
||||
/**
|
||||
* As part of a user taking advantage of the Elastic Defend (formerly Endpoint
|
||||
* Security) integration from within fleet, we attempt to install the `Endpoint
|
||||
* Security (Elastic Defend)` prebuilt rule which will be enabled by default.
|
||||
*/
|
||||
export const installEndpointSecurityPrebuiltRule = async ({
|
||||
logger,
|
||||
context,
|
||||
request,
|
||||
alerts,
|
||||
soClient,
|
||||
}: InstallEndpointSecurityPrebuiltRuleProps): Promise<void> => {
|
||||
// Create detection index & rules (if necessary). move past any failure, this is just a convenience
|
||||
try {
|
||||
await createDetectionIndex(context);
|
||||
} catch (err) {
|
||||
if (err.statusCode !== 409) {
|
||||
// 409 -> detection index already exists, which is fine
|
||||
logger.warn(
|
||||
`Possible problem creating detection signals index (${err.statusCode}): ${err.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
try {
|
||||
const rulesClient = await alerts.getRulesClientWithRequest(request);
|
||||
const detectionRulesClient = context.getDetectionRulesClient();
|
||||
const ruleAssetsClient = createPrebuiltRuleAssetsClient(soClient);
|
||||
const ruleObjectsClient = createPrebuiltRuleObjectsClient(rulesClient);
|
||||
const exceptionsListClient = context.getExceptionListClient();
|
||||
|
||||
const elasticDefendRule = await ruleObjectsClient.fetchInstalledRulesByIds({
|
||||
ruleIds: [ELASTIC_SECURITY_RULE_ID],
|
||||
});
|
||||
if (elasticDefendRule.length > 0) {
|
||||
// Elastic Defend rule already installed
|
||||
return;
|
||||
}
|
||||
// Elastic Defend rule not installed, find the latest version in the
|
||||
// prebuilt rule assets and install it
|
||||
|
||||
// This will create the endpoint list if it does not exist yet
|
||||
await exceptionsListClient?.createEndpointList();
|
||||
|
||||
const latestRuleVersion = await ruleAssetsClient.fetchLatestVersions([
|
||||
ELASTIC_SECURITY_RULE_ID,
|
||||
]);
|
||||
if (latestRuleVersion.length === 0) {
|
||||
logger.error(
|
||||
`Unable to find Elastic Defend rule in the prebuilt rule assets (rule_id: ${ELASTIC_SECURITY_RULE_ID})`
|
||||
);
|
||||
return;
|
||||
}
|
||||
const ruleAssetsToInstall = await ruleAssetsClient.fetchAssetsByVersion(latestRuleVersion);
|
||||
await createPrebuiltRules(detectionRulesClient, ruleAssetsToInstall);
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`Unable to create Endpoint Security rule automatically (${err.statusCode}): ${err.message}`
|
||||
);
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue