Skip to content

Commit

Permalink
[Security Solution][Detection Engine] adds rule actions PLI (#168510)
Browse files Browse the repository at this point in the history
## Summary

- implements the first phase of [rule external actions Serverless
PLI](https://docs.google.com/spreadsheets/d/1BR9kjzSR0F6o6huxbJidk5ro4CVYfhmLog9ArEbxA8g/edit#gid=301346322).
Phase 1 is defined by support of PLI capabilities in actions plugins and
described [here](#163751). It
allows only hiding actions that are not in tier. Upselling messages,
will be introduced in phase 2, according to response ops ticket


### Essentials Tier

Serverless config:
```yaml
xpack.securitySolutionServerless.productTypes:
  [
    { product_line: 'security', product_tier: 'essentials' },
    { product_line: 'endpoint', product_tier: 'complete' },
  ]
```

For Essentials, only 3 rule actions available:

- email
- index
- slack

<img width="2525" alt="Screenshot 2023-10-11 at 11 13 57"
src="https://github.com/elastic/kibana/assets/92328789/2a10d077-3090-494d-953f-2880c2afdccf">


### Complete Tier



Serverless config:
```yaml
xpack.securitySolutionServerless.productTypes:
  [
    { product_line: 'security', product_tier: 'complete' },
    { product_line: 'endpoint', product_tier: 'complete' },
  ]
```

<img width="2530" alt="Screenshot 2023-10-11 at 11 17 10"
src="https://github.com/elastic/kibana/assets/92328789/1e5912a5-a358-409b-8fd6-e526e047fe54">

### Checklist

Delete any items that are not applicable to this PR.

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
vitaliidm and kibanamachine authored Oct 13, 2023
1 parent 3f6872d commit 94284a1
Show file tree
Hide file tree
Showing 11 changed files with 213 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ export enum AppFeatureSecurityKey {
* Enables managing endpoint exceptions on rules and alerts
*/
endpointExceptions = 'endpointExceptions',

/**
* enables all rule actions
*/
externalRuleActions = 'external_rule_actions',
}

export enum AppFeatureCasesKey {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,6 @@ export const securityDefaultAppFeaturesConfig: DefaultSecurityAppFeaturesConfig
},

[AppFeatureSecurityKey.osqueryAutomatedResponseActions]: {},

[AppFeatureSecurityKey.externalRuleActions]: {},
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const PLI_APP_FEATURES: PliAppFeatures = {
AppFeatureKey.investigationGuide,
AppFeatureKey.threatIntelligence,
AppFeatureKey.casesConnectors,
AppFeatureKey.externalRuleActions,
],
},
endpoint: {
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/security_solution_serverless/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"serverless",
"taskManager",
"cloud",
"fleet"
"fleet",
"actions"
],
"optionalPlugins": [
"securitySolutionEss"
Expand Down
6 changes: 5 additions & 1 deletion x-pack/plugins/security_solution_serverless/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
endpointMeteringService,
setEndpointPackagePolicyServerlessFlag,
} from './endpoint/services';
import { enableRuleActions } from './rules/enable_rule_actions';

export class SecuritySolutionServerlessPlugin
implements
Expand All @@ -54,6 +55,7 @@ export class SecuritySolutionServerlessPlugin

public setup(coreSetup: CoreSetup, pluginsSetup: SecuritySolutionServerlessPluginSetupDeps) {
this.config = createConfig(this.initializerContext, pluginsSetup.securitySolution);
const enabledAppFeatures = getProductAppFeatures(this.config.productTypes);

// securitySolutionEss plugin should always be disabled when securitySolutionServerless is enabled.
// This check is an additional layer of security to prevent double registrations when
Expand All @@ -63,12 +65,14 @@ export class SecuritySolutionServerlessPlugin
const productTypesStr = JSON.stringify(this.config.productTypes, null, 2);
this.logger.info(`Security Solution running with product types:\n${productTypesStr}`);
const appFeaturesConfigurator = getProductAppFeaturesConfigurator(
getProductAppFeatures(this.config.productTypes),
enabledAppFeatures,
this.config
);
pluginsSetup.securitySolution.setAppFeaturesConfigurator(appFeaturesConfigurator);
}

enableRuleActions({ actions: pluginsSetup.actions, appFeatureKeys: enabledAppFeatures });

this.cloudSecurityUsageReportingTask = new SecurityUsageReportingTask({
core: coreSetup,
logFactory: this.initializerContext.logger,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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 { AppFeatureSecurityKey } from '@kbn/security-solution-features/keys';
import {
IndexConnectorTypeId,
SlackWebhookConnectorTypeId,
EmailConnectorTypeId,
} from '@kbn/stack-connectors-plugin/server/connector_types';
import { EnabledActionTypes } from '@kbn/actions-plugin/server/config';
import type { AppFeatureKeys } from '@kbn/security-solution-features/src/types';

import type { PluginSetupContract as ActionsPluginSetupContract } from '@kbn/actions-plugin/server';

const INTERNAL_RULE_ACTIONS = [
IndexConnectorTypeId,
SlackWebhookConnectorTypeId,
EmailConnectorTypeId,
];

/**
* enable rule actions based on AppFeature Config
*/
export const enableRuleActions = ({
actions,
appFeatureKeys,
}: {
actions: ActionsPluginSetupContract;
appFeatureKeys: AppFeatureKeys;
}) => {
if (appFeatureKeys.includes(AppFeatureSecurityKey.externalRuleActions)) {
// enables all rule actions
actions.setEnabledConnectorTypes([EnabledActionTypes.Any]);
} else {
actions.setEnabledConnectorTypes(INTERNAL_RULE_ACTIONS);
}
};
2 changes: 2 additions & 0 deletions x-pack/plugins/security_solution_serverless/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
import type { CloudSetup } from '@kbn/cloud-plugin/server';
import type { SecuritySolutionEssPluginSetup } from '@kbn/security-solution-ess/server';
import type { FleetStartContract } from '@kbn/fleet-plugin/server';
import type { PluginSetupContract as ActionsPluginSetupContract } from '@kbn/actions-plugin/server';

import type { ServerlessPluginSetup } from '@kbn/serverless/server';
import type { ProductTier } from '../common/product';
Expand All @@ -37,6 +38,7 @@ export interface SecuritySolutionServerlessPluginSetupDeps {
features: PluginSetupContract;
taskManager: TaskManagerSetupContract;
cloud: CloudSetup;
actions: ActionsPluginSetupContract;
}

export interface SecuritySolutionServerlessPluginStartDeps {
Expand Down
4 changes: 3 additions & 1 deletion x-pack/plugins/security_solution_serverless/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
"@kbn/usage-collection-plugin",
"@kbn/cloud-defend-plugin",
"@kbn/core-logging-server-mocks",
"@kbn/shared-ux-chrome-navigation"
"@kbn/shared-ux-chrome-navigation",
"@kbn/stack-connectors-plugin",
"@kbn/actions-plugin"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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 { getNewRule } from '../../../objects/rule';

import {
INDEX_SELECTOR,
SLACK_ACTION_BTN,
WEBHOOK_ACTION_BTN,
EMAIL_ACTION_BTN,
ACTION_BTN,
} from '../../../screens/common/rule_actions';

import { createRule } from '../../../tasks/api_calls/rules';

import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management';
import { cleanKibana, deleteAlertsAndRules } from '../../../tasks/common';
import { goToActionsStepTab } from '../../../tasks/create_new_rule';
import { login } from '../../../tasks/login';

import { editFirstRule } from '../../../tasks/alerts_detection_rules';

import { visit } from '../../../tasks/navigation';

const rule = getNewRule();

describe(
'Rule actions PLI complete product tier',
{
tags: ['@serverless'],

env: {
ftrConfig: {
productTypes: [
{ product_line: 'security', product_tier: 'complete' },
{ product_line: 'endpoint', product_tier: 'complete' },
],
},
},
},
() => {
before(() => {
cleanKibana();
login();
});

beforeEach(() => {
deleteAlertsAndRules();
createRule(rule);
login();
});

it('more than 3 rule actions should be available', () => {
visit(RULES_MANAGEMENT_URL);
editFirstRule();

goToActionsStepTab();

// all actions available
cy.get(ACTION_BTN).should('have.length.greaterThan', 4);

cy.get(INDEX_SELECTOR).should('be.visible');
cy.get(SLACK_ACTION_BTN).should('be.visible');
cy.get(EMAIL_ACTION_BTN).should('be.visible');
cy.get(WEBHOOK_ACTION_BTN).should('be.visible');
});
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* 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 { getNewRule } from '../../../objects/rule';

import {
INDEX_SELECTOR,
SLACK_ACTION_BTN,
WEBHOOK_ACTION_BTN,
EMAIL_ACTION_BTN,
ACTION_BTN,
} from '../../../screens/common/rule_actions';

import { createRule } from '../../../tasks/api_calls/rules';

import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management';
import { cleanKibana, deleteAlertsAndRules } from '../../../tasks/common';
import { goToActionsStepTab } from '../../../tasks/create_new_rule';
import { login } from '../../../tasks/login';

import { editFirstRule } from '../../../tasks/alerts_detection_rules';

import { visit } from '../../../tasks/navigation';

const rule = getNewRule();

describe(
'Rule actions PLI essentials product tier',
{
tags: ['@serverless'],

env: {
ftrConfig: {
productTypes: [
{ product_line: 'security', product_tier: 'essentials' },
{ product_line: 'endpoint', product_tier: 'essentials' },
],
},
},
},
() => {
before(() => {
cleanKibana();
login();
});

beforeEach(() => {
deleteAlertsAndRules();
createRule(rule);
login();
});

it('only 3 rule actions should be available', () => {
visit(RULES_MANAGEMENT_URL);
editFirstRule();

goToActionsStepTab();

// only 3 basic actions available
cy.get(ACTION_BTN).should('have.length', 3);

cy.get(INDEX_SELECTOR).should('be.visible');
cy.get(SLACK_ACTION_BTN).should('be.visible');
cy.get(EMAIL_ACTION_BTN).should('be.visible');

// webhook is not available
cy.get(WEBHOOK_ACTION_BTN).should('not.exist');
});
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@

export const EMAIL_ACTION_BTN = '[data-test-subj=".email-siem-ActionTypeSelectOption"]';

export const WEBHOOK_ACTION_BTN = '[data-test-subj=".webhook-siem-ActionTypeSelectOption"]';

/**
* all rule actions buttons, elements which data-test-subj attribute ends with '-siem-ActionTypeSelectOption'
*/
export const ACTION_BTN = '[data-test-subj$="-siem-ActionTypeSelectOption"]';

export const CREATE_ACTION_CONNECTOR_BTN = '[data-test-subj="createActionConnectorButton-0"]';

export const SAVE_ACTION_CONNECTOR_BTN = '[data-test-subj="saveActionButtonModal"]';
Expand Down

0 comments on commit 94284a1

Please sign in to comment.