Skip to content

Commit

Permalink
[8.x] [Security Solution][Endpoint] Enable Kibana feature controls (R…
Browse files Browse the repository at this point in the history
…BAC)configuration by space for Endpoint management (#193003) (#193525)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Security Solution][Endpoint] Enable Kibana feature controls
(RBAC)configuration by space for Endpoint management
(#193003)](#193003)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Paul
Tavares","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-09-20T09:47:37Z","message":"[Security
Solution][Endpoint] Enable Kibana feature controls (RBAC)configuration
by space for Endpoint management (#193003)\n\n## Summary\r\n\r\n###
Kibana Core Security plugin\r\n\r\n- Updated several Role forms to
include `data-test-subj` in order to\r\nbetter select items from
tests\r\n\r\n\r\n\r\n### Security Solution Plugin (and associated
packages)\r\n\r\nChanges in support of space awareness:\r\n\r\n- New
feature flag control: `endpointManagementSpaceAwarenessEnabled`\r\n-
Elastic Defend related kibana feature controls are changed
to\r\n`requireAllSpaces: false` when feature flag is enabled\r\n\r\nIn
addition:\r\n\r\n- The Cypress serverless FTR configuration used for
Defend Workflows\r\ntests was updated to enable the creation of spaces
and also role\r\nmanagement
UI","sha":"9a9c0f1afe0369d5cfaae1b9468c60dbe800d73b","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Defend
Workflows","backport:prev-minor","v8.16.0"],"title":"[Security
Solution][Endpoint] Enable Kibana feature controls (RBAC)configuration
by space for Endpoint
management","number":193003,"url":"https://github.com/elastic/kibana/pull/193003","mergeCommit":{"message":"[Security
Solution][Endpoint] Enable Kibana feature controls (RBAC)configuration
by space for Endpoint management (#193003)\n\n## Summary\r\n\r\n###
Kibana Core Security plugin\r\n\r\n- Updated several Role forms to
include `data-test-subj` in order to\r\nbetter select items from
tests\r\n\r\n\r\n\r\n### Security Solution Plugin (and associated
packages)\r\n\r\nChanges in support of space awareness:\r\n\r\n- New
feature flag control: `endpointManagementSpaceAwarenessEnabled`\r\n-
Elastic Defend related kibana feature controls are changed
to\r\n`requireAllSpaces: false` when feature flag is enabled\r\n\r\nIn
addition:\r\n\r\n- The Cypress serverless FTR configuration used for
Defend Workflows\r\ntests was updated to enable the creation of spaces
and also role\r\nmanagement
UI","sha":"9a9c0f1afe0369d5cfaae1b9468c60dbe800d73b"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/193003","number":193003,"mergeCommit":{"message":"[Security
Solution][Endpoint] Enable Kibana feature controls (RBAC)configuration
by space for Endpoint management (#193003)\n\n## Summary\r\n\r\n###
Kibana Core Security plugin\r\n\r\n- Updated several Role forms to
include `data-test-subj` in order to\r\nbetter select items from
tests\r\n\r\n\r\n\r\n### Security Solution Plugin (and associated
packages)\r\n\r\nChanges in support of space awareness:\r\n\r\n- New
feature flag control: `endpointManagementSpaceAwarenessEnabled`\r\n-
Elastic Defend related kibana feature controls are changed
to\r\n`requireAllSpaces: false` when feature flag is enabled\r\n\r\nIn
addition:\r\n\r\n- The Cypress serverless FTR configuration used for
Defend Workflows\r\ntests was updated to enable the creation of spaces
and also role\r\nmanagement
UI","sha":"9a9c0f1afe0369d5cfaae1b9468c60dbe800d73b"}},{"branch":"8.x","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Paul Tavares <[email protected]>
  • Loading branch information
kibanamachine and paul-tavares authored Sep 20, 2024
1 parent 1827d2e commit 5eb5c27
Show file tree
Hide file tree
Showing 15 changed files with 517 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { SecuritySubFeatureId } from '../product_features_keys';
import { APP_ID } from '../constants';
import type { SecurityFeatureParams } from './types';

const endpointListSubFeature: SubFeatureConfig = {
const endpointListSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.endpointList.privilegesTooltip',
Expand Down Expand Up @@ -67,8 +67,9 @@ const endpointListSubFeature: SubFeatureConfig = {
],
},
],
};
const trustedApplicationsSubFeature: SubFeatureConfig = {
});

const trustedApplicationsSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.trustedApplications.privilegesTooltip',
Expand Down Expand Up @@ -124,8 +125,8 @@ const trustedApplicationsSubFeature: SubFeatureConfig = {
],
},
],
};
const hostIsolationExceptionsBasicSubFeature: SubFeatureConfig = {
});
const hostIsolationExceptionsBasicSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.hostIsolationExceptions.privilegesTooltip',
Expand Down Expand Up @@ -181,8 +182,8 @@ const hostIsolationExceptionsBasicSubFeature: SubFeatureConfig = {
],
},
],
};
const blocklistSubFeature: SubFeatureConfig = {
});
const blocklistSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.blockList.privilegesTooltip',
Expand Down Expand Up @@ -235,8 +236,8 @@ const blocklistSubFeature: SubFeatureConfig = {
],
},
],
};
const eventFiltersSubFeature: SubFeatureConfig = {
});
const eventFiltersSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.eventFilters.privilegesTooltip',
Expand Down Expand Up @@ -292,8 +293,8 @@ const eventFiltersSubFeature: SubFeatureConfig = {
],
},
],
};
const policyManagementSubFeature: SubFeatureConfig = {
});
const policyManagementSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.policyManagement.privilegesTooltip',
Expand Down Expand Up @@ -343,9 +344,9 @@ const policyManagementSubFeature: SubFeatureConfig = {
],
},
],
};
});

const responseActionsHistorySubFeature: SubFeatureConfig = {
const responseActionsHistorySubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.responseActionsHistory.privilegesTooltip',
Expand Down Expand Up @@ -394,8 +395,8 @@ const responseActionsHistorySubFeature: SubFeatureConfig = {
],
},
],
};
const hostIsolationSubFeature: SubFeatureConfig = {
});
const hostIsolationSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.hostIsolation.privilegesTooltip',
Expand Down Expand Up @@ -431,9 +432,9 @@ const hostIsolationSubFeature: SubFeatureConfig = {
],
},
],
};
});

const processOperationsSubFeature: SubFeatureConfig = {
const processOperationsSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.processOperations.privilegesTooltip',
Expand Down Expand Up @@ -471,8 +472,8 @@ const processOperationsSubFeature: SubFeatureConfig = {
],
},
],
};
const fileOperationsSubFeature: SubFeatureConfig = {
});
const fileOperationsSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.fileOperations.privilegesTooltip',
Expand Down Expand Up @@ -510,11 +511,11 @@ const fileOperationsSubFeature: SubFeatureConfig = {
],
},
],
};
});

// execute operations are not available in 8.7,
// but will be available in 8.8
const executeActionSubFeature: SubFeatureConfig = {
const executeActionSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.executeOperations.privilegesTooltip',
Expand Down Expand Up @@ -552,10 +553,10 @@ const executeActionSubFeature: SubFeatureConfig = {
],
},
],
};
});

// 8.15 feature
const scanActionSubFeature: SubFeatureConfig = {
const scanActionSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.scanOperations.privilegesTooltip',
Expand Down Expand Up @@ -593,9 +594,9 @@ const scanActionSubFeature: SubFeatureConfig = {
],
},
],
};
});

const endpointExceptionsSubFeature: SubFeatureConfig = {
const endpointExceptionsSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.endpointExceptions.privilegesTooltip',
Expand Down Expand Up @@ -642,7 +643,7 @@ const endpointExceptionsSubFeature: SubFeatureConfig = {
],
},
],
};
});

/**
* Sub-features that will always be available for Security
Expand All @@ -660,20 +661,47 @@ export const getSecurityBaseKibanaSubFeatureIds = (
export const getSecuritySubFeaturesMap = ({
experimentalFeatures,
}: SecurityFeatureParams): Map<SecuritySubFeatureId, SubFeatureConfig> => {
const enableSpaceAwarenessIfNeeded = (subFeature: SubFeatureConfig): SubFeatureConfig => {
if (experimentalFeatures.endpointManagementSpaceAwarenessEnabled) {
subFeature.requireAllSpaces = false;
subFeature.privilegesTooltip = undefined;
}

return subFeature;
};

const securitySubFeaturesList: Array<[SecuritySubFeatureId, SubFeatureConfig]> = [
[SecuritySubFeatureId.endpointList, endpointListSubFeature],
[SecuritySubFeatureId.endpointExceptions, endpointExceptionsSubFeature],
[SecuritySubFeatureId.trustedApplications, trustedApplicationsSubFeature],
[SecuritySubFeatureId.hostIsolationExceptionsBasic, hostIsolationExceptionsBasicSubFeature],
[SecuritySubFeatureId.blocklist, blocklistSubFeature],
[SecuritySubFeatureId.eventFilters, eventFiltersSubFeature],
[SecuritySubFeatureId.policyManagement, policyManagementSubFeature],
[SecuritySubFeatureId.responseActionsHistory, responseActionsHistorySubFeature],
[SecuritySubFeatureId.hostIsolation, hostIsolationSubFeature],
[SecuritySubFeatureId.processOperations, processOperationsSubFeature],
[SecuritySubFeatureId.fileOperations, fileOperationsSubFeature],
[SecuritySubFeatureId.executeAction, executeActionSubFeature],
[SecuritySubFeatureId.scanAction, scanActionSubFeature],
[SecuritySubFeatureId.endpointList, enableSpaceAwarenessIfNeeded(endpointListSubFeature())],
[
SecuritySubFeatureId.endpointExceptions,
enableSpaceAwarenessIfNeeded(endpointExceptionsSubFeature()),
],
[
SecuritySubFeatureId.trustedApplications,
enableSpaceAwarenessIfNeeded(trustedApplicationsSubFeature()),
],
[
SecuritySubFeatureId.hostIsolationExceptionsBasic,
enableSpaceAwarenessIfNeeded(hostIsolationExceptionsBasicSubFeature()),
],
[SecuritySubFeatureId.blocklist, enableSpaceAwarenessIfNeeded(blocklistSubFeature())],
[SecuritySubFeatureId.eventFilters, enableSpaceAwarenessIfNeeded(eventFiltersSubFeature())],
[
SecuritySubFeatureId.policyManagement,
enableSpaceAwarenessIfNeeded(policyManagementSubFeature()),
],
[
SecuritySubFeatureId.responseActionsHistory,
enableSpaceAwarenessIfNeeded(responseActionsHistorySubFeature()),
],
[SecuritySubFeatureId.hostIsolation, enableSpaceAwarenessIfNeeded(hostIsolationSubFeature())],
[
SecuritySubFeatureId.processOperations,
enableSpaceAwarenessIfNeeded(processOperationsSubFeature()),
],
[SecuritySubFeatureId.fileOperations, enableSpaceAwarenessIfNeeded(fileOperationsSubFeature())],
[SecuritySubFeatureId.executeAction, enableSpaceAwarenessIfNeeded(executeActionSubFeature())],
[SecuritySubFeatureId.scanAction, enableSpaceAwarenessIfNeeded(scanActionSubFeature())],
];

// Use the following code to add feature based on feature flag
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import type { ProductFeatureSecurityKey, SecuritySubFeatureId } from '../product
import type { ProductFeatureKibanaConfig } from '../types';

export interface SecurityFeatureParams {
/**
* Experimental features.
* Unfortunately these can't be properly Typed due to it requiring an
* import directly from the Security Solution plugin. The list of `keys` in this
* object are defined here:
* @see https://github.com/elastic/kibana/blob/main/x-pack/plugins/security_solution/common/experimental_features.ts#L14
*/
experimentalFeatures: Record<string, boolean>;
savedObjects: string[];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export class FeatureTable extends Component<Props, State> {
arrowDisplay={canExpandCategory ? 'left' : 'none'}
forceState={canExpandCategory ? undefined : 'closed'}
buttonContent={buttonContent}
buttonProps={{ 'data-test-subj': `featureCategory_${category.id}_accordionToggle` }}
extraAction={canExpandCategory ? extraAction : undefined}
>
<div>
Expand All @@ -162,7 +163,10 @@ export class FeatureTable extends Component<Props, State> {
)}
<EuiFlexGroup direction="column" gutterSize="s">
{featuresInCategory.map((feature) => (
<EuiFlexItem key={feature.id}>
<EuiFlexItem
key={feature.id}
data-test-subj={`featureCategory_${category.id}_${feature.id}`}
>
{this.renderPrivilegeControlsForFeature(feature)}
</EuiFlexItem>
))}
Expand Down Expand Up @@ -229,6 +233,9 @@ export class FeatureTable extends Component<Props, State> {
data-test-subj="featurePrivilegeControls"
buttonContent={buttonContent}
buttonClassName="euiAccordionWithDescription"
buttonProps={{
'data-test-subj': `featurePrivilegeControls_${feature.category.id}_${feature.id}_accordionToggle`,
}}
extraAction={extraAction}
forceState={hasSubFeaturePrivileges ? undefined : 'closed'}
arrowDisplay={hasSubFeaturePrivileges ? 'left' : 'none'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,14 @@ export const FeatureTableExpandedRow = ({
};

return (
<EuiFlexGroup direction="column" gutterSize="s">
<EuiFlexItem>
<EuiFlexGroup
direction="column"
gutterSize="s"
data-test-subj={`${feature.category.id}_${feature.id}_subFeaturesTable`}
>
<EuiFlexItem
data-test-subj={`${feature.category.id}_${feature.id}_customizeSubFeaturesSwitchContainer`}
>
<div>
<EuiSwitch
label={
Expand Down Expand Up @@ -121,6 +127,7 @@ export const FeatureTableExpandedRow = ({
privilegeCalculator={privilegeCalculator}
privilegeIndex={privilegeIndex}
featureId={feature.id}
categoryId={feature.category.id}
subFeature={subFeature}
onChange={(updatedPrivileges) => onChange(feature.id, updatedPrivileges)}
selectedFeaturePrivileges={selectedFeaturePrivileges}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
EuiIconTip,
EuiText,
} from '@elastic/eui';
import React from 'react';
import React, { useCallback, useMemo } from 'react';

import { i18n } from '@kbn/i18n';
import type {
Expand All @@ -33,10 +33,23 @@ interface Props {
privilegeIndex: number;
onChange: (selectedPrivileges: string[]) => void;
disabled?: boolean;
categoryId?: string;
}

export const SubFeatureForm = (props: Props) => {
const groupsWithPrivileges = props.subFeature.getPrivilegeGroups();
const subFeatureNameTestId = useMemo(() => {
// Removes anything that is not a Number, Letter or space and replaces it with _
return props.subFeature.name.toLowerCase().replace(/[^\w\d]/g, '_');
}, [props.subFeature.name]);
const getTestId = useCallback(
(suffix: string = '') => {
return `${props.categoryId ? `${props.categoryId}_` : ''}${
props.featureId
}_${subFeatureNameTestId}${suffix ? `_${suffix}` : ''}`;
},
[props.categoryId, props.featureId, subFeatureNameTestId]
);

const getTooltip = () => {
if (!props.subFeature.privilegesTooltip) {
Expand All @@ -55,6 +68,7 @@ export const SubFeatureForm = (props: Props) => {
type="iInCircle"
color="subdued"
content={tooltipContent}
anchorProps={{ 'data-test-subj': getTestId('nameTooltip') }}
/>
);
};
Expand All @@ -63,11 +77,11 @@ export const SubFeatureForm = (props: Props) => {
return null;
}
return (
<EuiFlexGroup alignItems="center">
<EuiFlexGroup alignItems="center" data-test-subj={getTestId()}>
<EuiFlexItem grow={3}>
<EuiFlexGroup gutterSize="none" direction="column">
<EuiFlexItem>
<EuiText size="s">
<EuiText size="s" data-test-subj={getTestId('name')}>
{props.subFeature.name} {getTooltip()}
</EuiText>
</EuiFlexItem>
Expand All @@ -85,7 +99,9 @@ export const SubFeatureForm = (props: Props) => {
)}
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={2}>{groupsWithPrivileges.map(renderPrivilegeGroup)}</EuiFlexItem>
<EuiFlexItem grow={2} data-test-subj={getTestId('privilegeGroup')}>
{groupsWithPrivileges.map(renderPrivilegeGroup)}
</EuiFlexItem>
</EuiFlexGroup>
);

Expand Down
10 changes: 10 additions & 0 deletions x-pack/plugins/security_solution/common/experimental_features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ export const allowedExperimentalValues = Object.freeze({
*/
responseActionsCrowdstrikeManualHostIsolationEnabled: true,

/**
* Space awareness for Elastic Defend management.
* Feature depends on Fleet's corresponding features also being enabled:
* - `subfeaturePrivileges`
* - `useSpaceAwareness`
* and Fleet must set it runtime mode to spaces by calling the following API:
* - `POST /internal/fleet/enable_space_awareness`
*/
endpointManagementSpaceAwarenessEnabled: false,

/**
* Enables new notes
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ describe('Endpoints page', { tags: ['@ess', '@serverless', '@brokenInServerless'
expect(body.sortDirection).to.equal('desc');
});

// no sorting indicator is present on the screen
cy.get('.euiTableSortIcon').should('not.exist');
// no column shows sorting to be on
cy.get('.euiTableHeaderButton-isSorted').should('not.exist');
});

it('User can sort by any field', () => {
Expand All @@ -71,12 +71,12 @@ describe('Endpoints page', { tags: ['@ess', '@serverless', '@brokenInServerless'
cy.getByTestSubj(`tableHeaderCell_${field}_${i}`).as('header').click();
validateSortingInResponse(field, 'asc');
cy.get('@header').should('have.attr', 'aria-sort', 'ascending');
cy.get('.euiTableSortIcon').should('exist');
cy.get('.euiTableHeaderButton-isSorted').should('exist');

cy.get('@header').click();
validateSortingInResponse(field, 'desc');
cy.get('@header').should('have.attr', 'aria-sort', 'descending');
cy.get('.euiTableSortIcon').should('exist');
cy.get('.euiTableHeaderButton-isSorted').should('exist');
}
});

Expand Down
Loading

0 comments on commit 5eb5c27

Please sign in to comment.