Skip to content

Commit

Permalink
[Serverless][Security Solution][Endpoint] Restrict endpoint exception…
Browse files Browse the repository at this point in the history
…s on serverless via plugin sub-features (#164107)

### What this PR changes

branched from /pull/163759

- Introduces new AppFeatures package `@kbn/security-solution-features`
with the common logic and `AppFeatureService` to apply offering specific
configurations for Security Solution features independently for
Serverless and ESS. This logic is replacing the earlier `AppFeatures` in
order to introduce new Kibana feature privileges for serverless PLIs so
that new Kibana privileges introduced for serverless PLIs do not
affect/show up as new Kibana feature privileges in ESS.
- Gates endpoint exceptions on alerts/rules based on serverless PLI
configurations. On serverless `Endpoint exceptions` should be
accessible/seen only on endpoint essentials/complete.

New AppFeatures logic architecture diagram:

![Security Solution Features
(Current)](https://github.com/elastic/kibana/assets/17747913/f627406d-43bc-4db5-93b1-4e43eeb6d870)

**Note:** Corresponding API changes related to endpoint exceptions will
be in a new PR, along with the last set of UX changes for hiding the
`Endpoint exceptions` tab from the Rules details page.

### How to review

- Setup for _Servlerless_
  - Run `yarn es snapshot` on a terminal window to start ES.
- Copy `config/serverless.security.yml` to
`config/serverless.security.dev.yml`
- Run `yarn serverless-security --no-base-path` on another terminal
window to start kibana in serverless mode
- Run `node
x-pack/plugins/security_solution/scripts/endpoint/endpoint_agent_emulator.js
--asSuperuser` on a new window and then select `1` to `Load Endoints`
and then `1` to `Run` the loader script. This will load some fake
agents/alerts data to test with.

### Tests (Serverless)

- with 
`{ product_line: 'security', product_tier: 'essentials' }` or `{
product_line: 'security', product_tier: 'complete' }`
and
`{ product_line: 'endpoint', product_tier: 'essentials' }` or `{
product_line: 'endpoint', product_tier: 'complete' }`

1. Navigate to Rules>Shared exception lists via
`http://localhost:5601/app/security/exceptions`
2. Test that you can see `Endpoint Security Exception List` card on the
shared exception lists page.
3. Navigate to `Alerts` page via `app/security/alerts`, you should see
endpoint alerts. If not, then click on `Manage Rules` and then
disable/enable `Endpoint Security` rules. That should trigger alerts to
show up on the Alerts table.
4. Click on `View Details` button under `Actions` column. Once the
flyout is visible, click on `Take Action` and verify that `Add Endpoint
exception` is visible/enabled/clickable on the menu.
5. Click on `More actions` button under `Actions` column and verify that
`Add Endpoint exception` is visible/enabled/clickable on the menu.
6. Click on `Investigate in timeline` button under `Actions` column;
when the timeline view is visible and the alert item is displayed, click
on buttons mentioned in 4. and 5. above and verify the same.
7. Navigate to `Rules`>`DetectionRules`>`Endpoint Security` rule under
the `Rules` table. Select the `Alerts` tab.
8. Click and verify `View details`,`More actions` and `Investigate in
timeline` buttons same as in 4., 5., 6. above.
9. You should be able to see the `Endpoint exceptions` tab as well.
Click and verify that you can see the tab's content.

- with 
`{ product_line: 'security', product_tier: 'essentials' }` or `{
product_line: 'security', product_tier: 'complete' }`
1. Edit `config/serverless.security.dev.yml` so that `endpoint` product
line item is commented out.
2. Test that you can not see `Endpoint Security Exception List` card on
the shared exception lists page.
3. Items 4. 5. 6. as above but the menu items should be disabled. This
can be verified with fake data only as with a real endpoint, endpoint
alerts are actually not visible at all.


### Tests (ESS)
On the ESS side, endpoint exceptions are not affected by this change and
work as usual based on index privileges.

---------

Co-authored-by: semd <[email protected]>
Co-authored-by: kibanamachine <[email protected]>
Co-authored-by: YulNaumenko <[email protected]>
Co-authored-by: Pablo Neves Machado <[email protected]>
Co-authored-by: Pablo Machado <[email protected]>
  • Loading branch information
6 people authored Aug 31, 2023
1 parent 73469bf commit 6e367d9
Show file tree
Hide file tree
Showing 107 changed files with 2,197 additions and 1,302 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,7 @@ module.exports = {
overrides: [
{
files: [
'x-pack/packages/security-solution/features/**/*.{js,mjs,ts,tsx}',
'x-pack/packages/security-solution/navigation/**/*.{js,mjs,ts,tsx}',
'x-pack/plugins/security_solution/**/*.{js,mjs,ts,tsx}',
'x-pack/plugins/security_solution_ess/**/*.{js,mjs,ts,tsx}',
Expand Down
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,7 @@ x-pack/plugins/searchprofiler @elastic/platform-deployment-management
x-pack/test/security_api_integration/packages/helpers @elastic/kibana-security
x-pack/plugins/security @elastic/kibana-security
x-pack/plugins/security_solution_ess @elastic/security-solution
x-pack/packages/security-solution/features @elastic/security-threat-hunting-explore
x-pack/test/cases_api_integration/common/plugins/security_solution @elastic/response-ops
x-pack/packages/security-solution/navigation @elastic/security-threat-hunting-explore
x-pack/plugins/security_solution @elastic/security-solution
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@
"@kbn/searchprofiler-plugin": "link:x-pack/plugins/searchprofiler",
"@kbn/security-plugin": "link:x-pack/plugins/security",
"@kbn/security-solution-ess": "link:x-pack/plugins/security_solution_ess",
"@kbn/security-solution-features": "link:x-pack/packages/security-solution/features",
"@kbn/security-solution-fixtures-plugin": "link:x-pack/test/cases_api_integration/common/plugins/security_solution",
"@kbn/security-solution-navigation": "link:x-pack/packages/security-solution/navigation",
"@kbn/security-solution-plugin": "link:x-pack/plugins/security_solution",
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ pageLoadAssetSize:
security: 81771
securitySolution: 66738
securitySolutionEss: 16573
securitySolutionServerless: 40000
securitySolutionServerless: 45000
serverless: 16573
serverlessObservability: 68747
serverlessSearch: 71995
Expand Down
20 changes: 20 additions & 0 deletions packages/kbn-utility-types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,23 @@ export type ArrayElement<A> = A extends ReadonlyArray<infer T> ? T : never;
export type WithRequiredProperty<Type, Key extends keyof Type> = Omit<Type, Key> & {
[Property in Key]-?: Type[Property];
};

// Recursive partial object type. inspired by EUI RecursivePartial
export type RecursivePartial<T> = {
[P in keyof T]?: T[P] extends NonAny[]
? T[P]
: T[P] extends readonly NonAny[]
? T[P]
: T[P] extends Array<infer U>
? Array<RecursivePartial<U>>
: T[P] extends ReadonlyArray<infer U>
? ReadonlyArray<RecursivePartial<U>>
: T[P] extends Set<infer V>
? Set<RecursivePartial<V>>
: T[P] extends Map<infer K, infer V>
? Map<K, RecursivePartial<V>>
: T[P] extends NonAny
? T[P]
: RecursivePartial<T[P]>;
};
type NonAny = number | boolean | string | symbol | null;
2 changes: 2 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,8 @@
"@kbn/security-plugin/*": ["x-pack/plugins/security/*"],
"@kbn/security-solution-ess": ["x-pack/plugins/security_solution_ess"],
"@kbn/security-solution-ess/*": ["x-pack/plugins/security_solution_ess/*"],
"@kbn/security-solution-features": ["x-pack/packages/security-solution/features"],
"@kbn/security-solution-features/*": ["x-pack/packages/security-solution/features/*"],
"@kbn/security-solution-fixtures-plugin": ["x-pack/test/cases_api_integration/common/plugins/security_solution"],
"@kbn/security-solution-fixtures-plugin/*": ["x-pack/test/cases_api_integration/common/plugins/security_solution/*"],
"@kbn/security-solution-navigation": ["x-pack/packages/security-solution/navigation"],
Expand Down
4 changes: 4 additions & 0 deletions x-pack/packages/security-solution/features/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## Security Solution App Features

This package provides resources to be used for Security Solution app features

10 changes: 10 additions & 0 deletions x-pack/packages/security-solution/features/app_features.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* 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.
*/

export { getSecurityFeature } from './src/security';
export { getCasesFeature } from './src/cases';
export { getAssistantFeature } from './src/assistant';
12 changes: 12 additions & 0 deletions x-pack/packages/security-solution/features/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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.
*/

export { securityDefaultAppFeaturesConfig } from './src/security/app_feature_config';
export { getCasesDefaultAppFeaturesConfig } from './src/cases/app_feature_config';
export { assistantDefaultAppFeaturesConfig } from './src/assistant/app_feature_config';

export { createEnabledAppFeaturesConfigMap } from './src/helpers';
7 changes: 7 additions & 0 deletions x-pack/packages/security-solution/features/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* 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.
*/
export * from './src/types';
12 changes: 12 additions & 0 deletions x-pack/packages/security-solution/features/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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.
*/

module.exports = {
preset: '@kbn/test',
rootDir: '../../../..',
roots: ['<rootDir>/x-pack/packages/security-solution/features'],
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
* 2.0.
*/

export { AppFeatures } from './app_features';
export * from './src/app_features_keys';
5 changes: 5 additions & 0 deletions x-pack/packages/security-solution/features/kibana.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/security-solution-features",
"owner": "@elastic/security-threat-hunting-explore"
}
6 changes: 6 additions & 0 deletions x-pack/packages/security-solution/features/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@kbn/security-solution-features",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0"
}
7 changes: 7 additions & 0 deletions x-pack/packages/security-solution/features/privileges.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* 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.
*/
export { AppFeaturesPrivilegeId, AppFeaturesPrivileges } from './src/app_features_privileges';
Original file line number Diff line number Diff line change
Expand Up @@ -6,60 +6,48 @@
*/

export enum AppFeatureSecurityKey {
/**
* Enables Advanced Insights (Entity Risk, GenAI)
*/
/** Enables Advanced Insights (Entity Risk, GenAI) */
advancedInsights = 'advanced_insights',

/**
* Enables Investigation guide in Timeline
*/
investigationGuide = 'investigation_guide',

/**
* Enables access to the Endpoint List and associated views that allows management of hosts
* running endpoint security
*/
endpointHostManagement = 'endpoint_host_management',

/**
* Enables endpoint policy views that enables user to manage endpoint security policies
*/
endpointPolicyManagement = 'endpoint_policy_management',

/**
* Enables Endpoint Policy protections (like Malware, Ransomware, etc)
*/
endpointPolicyProtections = 'endpoint_policy_protections',

/**
* Enables management of all endpoint related artifacts (ex. Trusted Applications, Event Filters,
* Host Isolation Exceptions, Blocklist.
*/
endpointArtifactManagement = 'endpoint_artifact_management',

/**
* Enables all of endpoint's supported response actions - like host isolation, file operations,
* process operations, command execution, etc.
*/
endpointResponseActions = 'endpoint_response_actions',

/**
* Enables Threat Intelligence
*/
threatIntelligence = 'threat-intelligence',

/**
* Enables Osquery Response Actions
*/
osqueryAutomatedResponseActions = 'osquery_automated_response_actions',
}

export enum AppFeatureAssistantKey {
/**
* Enables Elastic AI Assistant
* Enables managing endpoint exceptions on rules and alerts
*/
assistant = 'assistant',
endpointExceptions = 'endpointExceptions',
}

export enum AppFeatureCasesKey {
Expand All @@ -69,14 +57,46 @@ export enum AppFeatureCasesKey {
casesConnectors = 'cases_connectors',
}

// Merges the two enums.
export type AppFeatureKey = AppFeatureSecurityKey | AppFeatureCasesKey | AppFeatureAssistantKey;
export type AppFeatureKeys = AppFeatureKey[];
export enum AppFeatureAssistantKey {
/**
* Enables Elastic AI Assistant
*/
assistant = 'assistant',
}

// We need to merge the value and the type and export both to replicate how enum works.
// Merges the two enums.
export const AppFeatureKey = {
...AppFeatureSecurityKey,
...AppFeatureCasesKey,
...AppFeatureAssistantKey,
};
// We need to merge the value and the type and export both to replicate how enum works.
export type AppFeatureKeyType = AppFeatureSecurityKey | AppFeatureCasesKey | AppFeatureAssistantKey;

export const ALL_APP_FEATURE_KEYS = Object.freeze(Object.values(AppFeatureKey));

/** Sub-features IDs for Security */
export enum SecuritySubFeatureId {
endpointList = 'endpointListSubFeature',
endpointExceptions = 'endpointExceptionsSubFeature',
trustedApplications = 'trustedApplicationsSubFeature',
hostIsolationExceptions = 'hostIsolationExceptionsSubFeature',
blocklist = 'blocklistSubFeature',
eventFilters = 'eventFiltersSubFeature',
policyManagement = 'policyManagementSubFeature',
responseActionsHistory = 'responseActionsHistorySubFeature',
hostIsolation = 'hostIsolationSubFeature',
processOperations = 'processOperationsSubFeature',
fileOperations = 'fileOperationsSubFeature',
executeAction = 'executeActionSubFeature',
}

/** Sub-features IDs for Cases */
export enum CasesSubFeatureId {
deleteCases = 'deleteCasesSubFeature',
}

/** Sub-features IDs for Security Assistant */
export enum AssistantSubFeatureId {
createConversation = 'createConversationSubFeature',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 { APP_ID } from './constants';

export enum AppFeaturesPrivilegeId {
endpointExceptions = 'endpoint_exceptions',
}

/**
* This is the mapping of the privileges that are registered
* using a different Kibana feature configuration (sub-feature, main feature privilege, etc)
* in each offering type (ess, serverless)
*/
export const AppFeaturesPrivileges = {
[AppFeaturesPrivilegeId.endpointExceptions]: {
all: {
ui: ['showEndpointExceptions', 'crudEndpointExceptions'],
api: [`${APP_ID}-showEndpointExceptions`, `${APP_ID}-crudEndpointExceptions`],
},
read: {
ui: ['showEndpointExceptions'],
api: [`${APP_ID}-showEndpointExceptions`],
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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 { AssistantSubFeatureId } from '../app_features_keys';
import { AppFeatureAssistantKey } from '../app_features_keys';
import type { AppFeatureKibanaConfig } from '../types';

/**
* App features privileges configuration for the Security Assistant Kibana Feature app.
* These are the configs that are shared between both offering types (ess and serverless).
* They can be extended on each offering plugin to register privileges using different way on each offering type.
*
* Privileges can be added in different ways:
* - `privileges`: the privileges that will be added directly into the main Security feature.
* - `subFeatureIds`: the ids of the sub-features that will be added into the Security subFeatures entry.
* - `subFeaturesPrivileges`: the privileges that will be added into the existing Security subFeature with the privilege `id` specified.
*/
export const assistantDefaultAppFeaturesConfig: Record<
AppFeatureAssistantKey,
AppFeatureKibanaConfig<AssistantSubFeatureId>
> = {
[AppFeatureAssistantKey.assistant]: {
privileges: {
all: {
ui: ['ai-assistant'],
},
},
},
};
19 changes: 19 additions & 0 deletions x-pack/packages/security-solution/features/src/assistant/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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 { AssistantSubFeatureId } from '../app_features_keys';
import type { AppFeatureParams } from '../types';
import { getAssistantBaseKibanaFeature } from './kibana_features';
import {
getAssistantBaseKibanaSubFeatureIds,
assistantSubFeaturesMap,
} from './kibana_sub_features';

export const getAssistantFeature = (): AppFeatureParams<AssistantSubFeatureId> => ({
baseKibanaFeature: getAssistantBaseKibanaFeature(),
baseKibanaSubFeatureIds: getAssistantBaseKibanaSubFeatureIds(),
subFeaturesMap: assistantSubFeaturesMap,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* 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 { i18n } from '@kbn/i18n';

import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common';
import { type BaseKibanaFeatureConfig } from '../types';
import { APP_ID, ASSISTANT_FEATURE_ID } from '../constants';

export const getAssistantBaseKibanaFeature = (): BaseKibanaFeatureConfig => ({
id: ASSISTANT_FEATURE_ID,
name: i18n.translate(
'securitySolutionPackages.features.featureRegistry.linkSecuritySolutionAssistantTitle',
{
defaultMessage: 'Elastic AI Assistant',
}
),
order: 1100,
category: DEFAULT_APP_CATEGORIES.security,
app: [ASSISTANT_FEATURE_ID, 'kibana'],
catalogue: [APP_ID],
minimumLicense: 'enterprise',
privileges: {
all: {
api: [],
app: [ASSISTANT_FEATURE_ID, 'kibana'],
catalogue: [APP_ID],
savedObject: {
all: [],
read: [],
},
ui: [],
},
read: {
// No read-only mode currently supported
disabled: true,
savedObject: {
all: [],
read: [],
},
ui: [],
},
},
});
Loading

0 comments on commit 6e367d9

Please sign in to comment.