From 49093a35b1f17e16a9bf2ccdb45465bc4cdb1f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20=C3=81brah=C3=A1m?= Date: Tue, 22 Jul 2025 17:39:18 +0200 Subject: [PATCH] [EDR Workflows][Bug] Show artifact links without endpoint list privilege (#226561) ## Summary In Serverless, Security solution, under Assets/Endpoints, if user didn't have access to Endpoints (`endpoint_list_read|all`), the whole Endpoints group was filtered without showing any other subpage. This can occur only with custom roles as no pre-built roles exist with these conditions. This PR fixes this by simply removing the `link` from the group, so it won't be filtered when Endpoint access is missing. image A small side effect is that on the breadcrumb, Endpoints won't be clickable. | Before | After | |-|-| | image | image | > [!NOTE] > The added cypress test does not test this issue actually, as custom roles cannot be used in cypress tests at the moment. Hopefully this can be improved in the future. ### How to test To do some manual tests, you can add the following custom roles to the file below **before starting up the local serverless instance**: src/platform/packages/shared/kbn-es/src/serverless_resources/project_roles/security/roles.yml
Custom roles ```yml endpoint_list_NONE_artifacts_NONE: cluster: [] indices: - names: - '.lists-*' - '.items-*' - '.alerts-security.alerts-*' - '.siem-signals*' privileges: - 'read' - 'view_index_metadata' allow_restricted_indices: false applications: - application: 'kibana-.kibana' privileges: - feature_siemV3.minimal_all resources: '*' run_as: [] endpoint_list_NONE_artifacts_READ: cluster: [] indices: - names: - '.lists-*' - '.items-*' - '.alerts-security.alerts-*' - '.siem-signals*' privileges: - 'read' - 'view_index_metadata' allow_restricted_indices: false applications: - application: 'kibana-.kibana' privileges: - feature_siemV3.minimal_all - feature_siemV3.trusted_applications_read - feature_siemV3.event_filters_read - feature_siemV3.host_isolation_exceptions_read - feature_siemV3.blocklist_read resources: '*' run_as: [] endpoint_list_READ_artifacts_READ: cluster: [] indices: - names: - '.lists-*' - '.items-*' - '.alerts-security.alerts-*' - '.siem-signals*' privileges: - 'read' - 'view_index_metadata' allow_restricted_indices: false applications: - application: 'kibana-.kibana' privileges: - feature_siemV3.minimal_all - feature_siemV3.endpoint_list_read - feature_siemV3.trusted_applications_read - feature_siemV3.event_filters_read - feature_siemV3.host_isolation_exceptions_read - feature_siemV3.blocklist_read resources: '*' run_as: [] endpoint_list_READ_artifacts_NONE: cluster: [] indices: - names: - '.lists-*' - '.items-*' - '.alerts-security.alerts-*' - '.siem-signals*' privileges: - 'read' - 'view_index_metadata' allow_restricted_indices: false applications: - application: 'kibana-.kibana' privileges: - feature_siemV3.minimal_all - feature_siemV3.endpoint_list_read resources: '*' run_as: [] ```
### Todo - [x] run on MKI before merge https://buildkite.com/elastic/kibana-serverless-security-solution-quality-gate-defend-workflows/builds/3027/steps/canvas?jid=0197d5be-7b77-44a0-85f2-8f4a37657980 ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [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 (cherry picked from commit 4b9d2c50d070ef18d709270c79cf4a1b7f98de14) --- .../navigation_tree/assets_navigation_tree.ts | 1 - .../cypress/e2e/rbac/navigation.cy.ts | 145 ++++++++++++++++++ .../cypress/screens/security_header.ts | 6 + .../screens/serverless_security_header.ts | 6 + 4 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/navigation.cy.ts diff --git a/x-pack/solutions/security/packages/navigation/src/navigation_tree/assets_navigation_tree.ts b/x-pack/solutions/security/packages/navigation/src/navigation_tree/assets_navigation_tree.ts index 8a38191332ea7..8d13869bd2fec 100644 --- a/x-pack/solutions/security/packages/navigation/src/navigation_tree/assets_navigation_tree.ts +++ b/x-pack/solutions/security/packages/navigation/src/navigation_tree/assets_navigation_tree.ts @@ -45,7 +45,6 @@ export const createAssetsNavigationTree = (core: CoreStart): NodeDefinition => ( }, { id: SecurityPageName.endpoints, - link: securityLink(SecurityPageName.endpoints), title: i18nStrings.assets.endpoints.title, children: [ { diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/navigation.cy.ts b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/navigation.cy.ts new file mode 100644 index 0000000000000..e4b158639d7d0 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/management/cypress/e2e/rbac/navigation.cy.ts @@ -0,0 +1,145 @@ +/* + * 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 * as ServerlessHeaders from '@kbn/test-suites-xpack/security_solution_cypress/cypress/screens/serverless_security_header'; +import * as EssHeaders from '@kbn/test-suites-xpack/security_solution_cypress/cypress/screens/security_header'; +import { login, ROLE } from '../../tasks/login'; +import { loadPage } from '../../tasks/common'; +import { SIEM_VERSIONS } from '../../common/constants'; + +describe('Navigation RBAC', () => { + const isServerless = Cypress.env('IS_SERVERLESS'); + + const Selectors = isServerless ? ServerlessHeaders : EssHeaders; + const MenuButtonSelector = isServerless + ? ServerlessHeaders.ASSETS_PANEL_BTN + : EssHeaders.SETTINGS_PANEL_BTN; + + const pages = [ + { + name: 'Endpoints', + privilegePrefix: 'endpoint_list_', + selector: Selectors.ENDPOINTS, + }, + { + name: 'Policies', + privilegePrefix: 'policy_management_', + selector: Selectors.POLICIES, + }, + { + name: 'Trusted applications', + privilegePrefix: 'trusted_applications_', + selector: Selectors.TRUSTED_APPS, + }, + { + name: 'Event filters', + privilegePrefix: 'event_filters_', + selector: Selectors.EVENT_FILTERS, + }, + { + name: 'Blocklist', + privilegePrefix: 'blocklist_', + selector: Selectors.BLOCKLIST, + }, + { + name: 'Host isolation exceptions', + privilegePrefix: 'host_isolation_exceptions_', + selector: Selectors.HOST_ISOLATION_EXCEPTIONS, + }, + { + name: 'Response actions history', + privilegePrefix: 'actions_log_management_', + selector: Selectors.RESPONSE_ACTIONS_HISTORY, + }, + ]; + + describe('ESS - using custom roles', { tags: ['@ess'] }, () => { + for (const siemVersion of SIEM_VERSIONS) { + describe(siemVersion, () => { + describe('NONE access', () => { + beforeEach(() => { + login.withCustomKibanaPrivileges({ [siemVersion]: ['all'] }); + }); + + it(`none of the links should be visible in navigation bar`, () => { + loadPage('/app/security'); + cy.get(MenuButtonSelector).click(); + + for (const page of pages) { + cy.get(page.selector).should('not.exist'); + } + }); + + it(`none of the cards should be visible on Management page`, () => { + loadPage('/app/security/manage'); + + for (const page of pages) { + cy.getByTestSubj('LandingItem').should('not.contain.text', page.name); + } + }); + }); + + for (const access of ['read', 'all']) { + for (const page of pages) { + describe(`${access.toUpperCase()} access only to ${page.name}`, () => { + beforeEach(() => { + login.withCustomKibanaPrivileges({ + [siemVersion]: ['read', `${page.privilegePrefix}${access}`], + }); + }); + + it(`only ${page.name} link should be displayed in navigation bar`, () => { + loadPage('/app/security'); + cy.get(MenuButtonSelector).click(); + + cy.get(page.selector); + pages + .filter((iterator) => iterator.name !== page.name) + .forEach((otherPage) => cy.get(otherPage.selector).should('not.exist')); + }); + + it(`only ${page.name} card should be displayed on Management page`, () => { + loadPage('/app/security/manage'); + + cy.contains(page.name); + pages + .filter((iterator) => iterator.name !== page.name) + .forEach((otherPage) => + cy.getByTestSubj('LandingItem').should('not.contain.text', otherPage.name) + ); + }); + }); + } + } + }); + } + }); + + describe('Serverless - using prebuilt roles (for now)', { tags: ['@serverless'] }, () => { + it('without access to any of the subpages, none of those should be displayed', () => { + login(ROLE.detections_admin); + loadPage('/app/security'); + cy.get(MenuButtonSelector).click(); + cy.get('[data-test-subj~="sideNavPanel-id-securityGroup:assets"]'); + + for (const page of pages) { + cy.get(page.selector).should('not.exist'); + } + }); + + it('with access to all of the subpages, all of those should be displayed', () => { + login(ROLE.soc_manager); + loadPage('/app/security'); + cy.get(MenuButtonSelector).click(); + cy.get('[data-test-subj~="sideNavPanel-id-securityGroup:assets"]'); + + for (const page of pages) { + cy.get(page.selector); + } + }); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/security_header.ts b/x-pack/test/security_solution_cypress/cypress/screens/security_header.ts index c5b61f065eda0..ed4a6118dfe4c 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/security_header.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/security_header.ts @@ -54,6 +54,12 @@ export const EVENT_FILTERS = '[data-test-subj="solutionSideNavPanelLink-event_fi export const BLOCKLIST = '[data-test-subj="solutionSideNavPanelLink-blocklist"]'; +export const HOST_ISOLATION_EXCEPTIONS = + '[data-test-subj="solutionSideNavPanelLink-host_isolation_exceptions"]'; + +export const RESPONSE_ACTIONS_HISTORY = + '[data-test-subj="solutionSideNavPanelLink-response_actions_history"]'; + export const CSP_BENCHMARKS = '[data-test-subj="solutionSideNavPanelLink-cloud_security_posture-benchmarks"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/serverless_security_header.ts b/x-pack/test/security_solution_cypress/cypress/screens/serverless_security_header.ts index 6b0b79cda1335..c3b40beff475a 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/serverless_security_header.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/serverless_security_header.ts @@ -49,6 +49,12 @@ export const EVENT_FILTERS = '[data-test-subj~="panelNavItem-id-event_filters"]' export const BLOCKLIST = '[data-test-subj~="panelNavItem-id-blocklist"]'; +export const HOST_ISOLATION_EXCEPTIONS = + '[data-test-subj~="panelNavItem-id-host_isolation_exceptions"]'; + +export const RESPONSE_ACTIONS_HISTORY = + '[data-test-subj~="panelNavItem-id-response_actions_history"]'; + export const CSP_BENCHMARKS = '[data-test-subj~="panelNavItem-id-cloud_security_posture-benchmarks"]';