diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts index 161e14769c7d..47e4f43565d4 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts @@ -176,7 +176,7 @@ export class AlertsClient { }) ); - return res.body.get?._source; + return res.body; } catch (error) { this.auditLogger?.log( alertAuditEvent({ diff --git a/x-pack/plugins/rule_registry/server/routes/get_alert_by_id.ts b/x-pack/plugins/rule_registry/server/routes/get_alert_by_id.ts index c901e6f90e96..de4519512415 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alert_by_id.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alert_by_id.ts @@ -28,7 +28,7 @@ export const getAlertByIdRoute = (router: IRouter) => ), t.exact( t.partial({ - indexName: t.string, + index: t.string, }) ), ]) @@ -41,8 +41,8 @@ export const getAlertByIdRoute = (router: IRouter) => async (context, request, response) => { try { const alertsClient = await context.rac.getAlertsClient(); - const { id, indexName } = request.query; - const alert = await alertsClient.get({ id, index: indexName }); + const { id, index } = request.query; + const alert = await alertsClient.get({ id, index }); return response.ok({ body: alert, }); diff --git a/x-pack/plugins/rule_registry/server/scripts/get_observability_alert.sh b/x-pack/plugins/rule_registry/server/scripts/get_observability_alert.sh index a44a3bdcea52..41bc27e1d765 100755 --- a/x-pack/plugins/rule_registry/server/scripts/get_observability_alert.sh +++ b/x-pack/plugins/rule_registry/server/scripts/get_observability_alert.sh @@ -10,6 +10,7 @@ set -e USER=${1:-'observer'} +ID=${2:-'DHEnOXoB8br9Z2X1fq_l'} cd ./hunter && sh ./post_detections_role.sh && sh ./post_detections_user.sh cd ../observer && sh ./post_detections_role.sh && sh ./post_detections_user.sh @@ -18,4 +19,4 @@ cd .. # Example: ./get_observability_alert.sh hunter curl -v -k \ -u $USER:changeme \ - -X GET "${KIBANA_URL}${SPACE_URL}/api/rac/alerts?id=DUgwMHoB4rQQN4aqv7Co&index=.alerts-observability-apm" | jq . + -X GET "${KIBANA_URL}${SPACE_URL}/api/rac/alerts?id=$ID&index=.alerts-observability-apm" | jq . diff --git a/x-pack/plugins/rule_registry/server/scripts/observer/detections_role.json b/x-pack/plugins/rule_registry/server/scripts/observer/detections_role.json index aebb5ecc6df6..05c8aaa0aab4 100644 --- a/x-pack/plugins/rule_registry/server/scripts/observer/detections_role.json +++ b/x-pack/plugins/rule_registry/server/scripts/observer/detections_role.json @@ -29,7 +29,7 @@ "feature": { "ml": ["read"], "monitoring": ["all"], - "apm": ["all"], + "apm": ["minimal_read", "alerts_all"], "ruleRegistry": ["all"], "actions": ["read"], "builtInAlerts": ["all"], diff --git a/x-pack/plugins/rule_registry/server/scripts/update_observability_alert.sh b/x-pack/plugins/rule_registry/server/scripts/update_observability_alert.sh index e34454cca73d..f5c7ad716ed1 100755 --- a/x-pack/plugins/rule_registry/server/scripts/update_observability_alert.sh +++ b/x-pack/plugins/rule_registry/server/scripts/update_observability_alert.sh @@ -25,4 +25,4 @@ curl -s -k \ -H 'kbn-xsrf: 123' \ -u observer:changeme \ -X POST ${KIBANA_URL}${SPACE_URL}/api/rac/alerts \ - -d "{\"ids\": $IDS, \"status\":\"$STATUS\", \"indexName\":\".alerts-observability-apm\"}" | jq . + -d "{\"ids\": $IDS, \"status\":\"$STATUS\", \"index\":\".alerts-observability-apm\"}" | jq . diff --git a/x-pack/test/rule_registry/common/lib/authentication/roles.ts b/x-pack/test/rule_registry/common/lib/authentication/roles.ts index 37f407e7a060..c27bb90edaca 100644 --- a/x-pack/test/rule_registry/common/lib/authentication/roles.ts +++ b/x-pack/test/rule_registry/common/lib/authentication/roles.ts @@ -142,19 +142,9 @@ export const observabilityOnlyRead: Role = { }, }; -export const roles = [ - noKibanaPrivileges, - globalRead, - securitySolutionOnlyAll, - securitySolutionOnlyRead, - observabilityOnlyAll, - observabilityOnlyRead, -]; - /** * These roles have access to all spaces. */ - export const securitySolutionOnlyAllSpacesAll: Role = { name: 'sec_only_all', privileges: { @@ -228,7 +218,7 @@ export const observabilityOnlyAllSpacesAll: Role = { }; export const observabilityOnlyReadSpacesAll: Role = { - name: 'obs_only_read', + name: 'obs_only_read_all_spaces', privileges: { elasticsearch: { indices: [ @@ -242,8 +232,10 @@ export const observabilityOnlyReadSpacesAll: Role = { { feature: { apm: ['read'], + ruleRegistry: ['all'], actions: ['read'], - actionsSimulators: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], }, spaces: ['*'], }, @@ -251,6 +243,16 @@ export const observabilityOnlyReadSpacesAll: Role = { }, }; +export const roles = [ + noKibanaPrivileges, + globalRead, + securitySolutionOnlyAll, + securitySolutionOnlyRead, + observabilityOnlyAll, + observabilityOnlyRead, + observabilityOnlyReadSpacesAll, +]; + /** * These roles are specifically for the security_only tests where the spaces plugin is disabled. Most of the roles (except * for noKibanaPrivileges) have spaces: ['*'] effectively giving it access to the space1 space since no other spaces @@ -264,3 +266,333 @@ export const rolesDefaultSpace = [ observabilityOnlyAllSpacesAll, observabilityOnlyReadSpacesAll, ]; + +/** + * These roles are only to be used in the 'trial' tests + * since they rely on subfeature privileges which are a gold licencse feature + * maybe put these roles into a separate roles file like "trial_roles"? + */ +export const observabilityMinReadAlertsRead: Role = { + name: 'obs_only_alerts_read', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + apm: ['minimal_read', 'alerts_read'], + ruleRegistry: ['all'], + actions: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], + }, + spaces: ['space1'], + }, + ], + }, +}; + +export const observabilityMinReadAlertsReadSpacesAll: Role = { + name: 'obs_minimal_read_alerts_read_spaces_all', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + apm: ['minimal_read', 'alerts_read'], + ruleRegistry: ['all'], + actions: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], + }, + spaces: ['*'], + }, + ], + }, +}; + +export const observabilityMinimalRead: Role = { + name: 'obs_minimal_read_spaces_all', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + apm: ['minimal_read'], + ruleRegistry: ['all'], + actions: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], + }, + spaces: ['space1'], + }, + ], + }, +}; + +export const observabilityMinimalReadSpacesAll: Role = { + name: 'obs_minimal_read_spaces_all', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + apm: ['minimal_read'], + ruleRegistry: ['all'], + actions: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], + }, + spaces: ['*'], + }, + ], + }, +}; + +export const observabilityOnlyAlertsRead: Role = { + name: 'obs_alerts_read_spaces_all', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + apm: ['alerts_read'], + ruleRegistry: ['all'], + actions: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], + }, + spaces: ['space1'], + }, + ], + }, +}; + +export const observabilityOnlyAlertsReadSpacesAll: Role = { + name: 'obs_alerts_read_spaces_all', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + apm: ['alerts_read'], + ruleRegistry: ['all'], + actions: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], + }, + spaces: ['*'], + }, + ], + }, +}; + +/** + * **************************************** + * These are used for testing update alerts privileges + * **************************************** + * **************************************** + * **************************************** + * **************************************** + * **************************************** + * **************************************** + * **************************************** + * **************************************** + */ + +export const observabilityMinReadAlertsAll: Role = { + name: 'obs_only_alerts_read', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + apm: ['minimal_read', 'alerts_all'], + ruleRegistry: ['all'], + actions: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], + }, + spaces: ['space1'], + }, + ], + }, +}; + +export const observabilityMinReadAlertsAllSpacesAll: Role = { + name: 'obs_minimal_read_alerts_read_spaces_all', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + apm: ['minimal_read', 'alerts_all'], + ruleRegistry: ['all'], + actions: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], + }, + spaces: ['*'], + }, + ], + }, +}; + +export const observabilityMinimalAll: Role = { + name: 'obs_minimal_read_spaces_all', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + apm: ['minimal_all'], + ruleRegistry: ['all'], + actions: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], + }, + spaces: ['space1'], + }, + ], + }, +}; + +export const observabilityMinimalAllSpacesAll: Role = { + name: 'obs_minimal_read_spaces_all', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + apm: ['minimal_all'], + ruleRegistry: ['all'], + actions: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], + }, + spaces: ['*'], + }, + ], + }, +}; + +export const observabilityOnlyAlertsAll: Role = { + name: 'obs_alerts_read_spaces_all', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + apm: ['alerts_all'], + ruleRegistry: ['all'], + actions: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], + }, + spaces: ['space1'], + }, + ], + }, +}; + +export const observabilityOnlyAlertsAllSpacesAll: Role = { + name: 'obs_alerts_read_spaces_all', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + apm: ['alerts_all'], + ruleRegistry: ['all'], + actions: ['read'], + builtInAlerts: ['all'], + alerting: ['all'], + }, + spaces: ['*'], + }, + ], + }, +}; diff --git a/x-pack/test/rule_registry/common/lib/authentication/users.ts b/x-pack/test/rule_registry/common/lib/authentication/users.ts index 1fa6e3c9f499..0a515dd22f73 100644 --- a/x-pack/test/rule_registry/common/lib/authentication/users.ts +++ b/x-pack/test/rule_registry/common/lib/authentication/users.ts @@ -16,6 +16,19 @@ import { securitySolutionOnlyReadSpacesAll, observabilityOnlyAllSpacesAll, observabilityOnlyReadSpacesAll, + // trial license roles + observabilityMinReadAlertsRead, + observabilityMinReadAlertsReadSpacesAll, + observabilityMinimalRead, + observabilityMinimalReadSpacesAll, + observabilityOnlyAlertsRead, + observabilityOnlyAlertsReadSpacesAll, + observabilityMinReadAlertsAll, + observabilityMinReadAlertsAllSpacesAll, + observabilityMinimalAll, + observabilityMinimalAllSpacesAll, + observabilityOnlyAlertsAll, + observabilityOnlyAlertsAllSpacesAll, } from './roles'; import { User } from './types'; @@ -73,6 +86,12 @@ export const noKibanaPrivileges: User = { roles: [noKibanaPrivilegesRole.name], }; +export const obsOnlyReadSpacesAll: User = { + username: 'obs_only_read_all_spaces', + password: 'obs_only_read_all_spaces', + roles: [observabilityOnlyReadSpacesAll.name], +}; + export const users = [ superUser, secOnly, @@ -83,6 +102,7 @@ export const users = [ obsSecRead, globalRead, noKibanaPrivileges, + obsOnlyReadSpacesAll, ]; /** @@ -107,12 +127,6 @@ export const obsOnlySpacesAll: User = { roles: [observabilityOnlyAllSpacesAll.name], }; -export const obsOnlyReadSpacesAll: User = { - username: 'obs_only_read', - password: 'obs_only_read', - roles: [observabilityOnlyReadSpacesAll.name], -}; - export const obsSecSpacesAll: User = { username: 'obs_sec', password: 'obs_sec', @@ -139,3 +153,104 @@ export const usersDefaultSpace = [ globalRead, noKibanaPrivileges, ]; + +/** + * Trial users with trial roles + */ + +// apm: ['minimal_read', 'alerts_read'] +// spaces: ['space1'] +export const obsMinReadAlertsRead: User = { + username: 'obs_minimal_read_alerts_read_single_space', + password: 'obs_minimal_read_alerts_read_single_space', + roles: [observabilityMinReadAlertsRead.name], +}; + +// apm: ['minimal_read', 'alerts_read'] +// spaces: ['*'] +export const obsMinReadAlertsReadSpacesAll: User = { + username: 'obs_minimal_read_alerts_read_all_spaces', + password: 'obs_minimal_read_alerts_read_all_spaces', + roles: [observabilityMinReadAlertsReadSpacesAll.name], +}; + +// apm: ['minimal_read'] +// spaces: ['space1'] +export const obsMinRead: User = { + username: 'obs_minimal_read_single_space', + password: 'obs_minimal_read_single_space', + roles: [observabilityMinimalRead.name], +}; + +// apm: ['minimal_read'] +// spaces: ['*'] +export const obsMinReadSpacesAll: User = { + username: 'obs_minimal_read_all_space', + password: 'obs_minimal_read_all_space', + roles: [observabilityMinimalReadSpacesAll.name], +}; + +// apm: ['alerts_read'] +// spaces: ['space1] +export const obsAlertsRead: User = { + username: 'obs_alerts_read_single_space', + password: 'obs_alerts_read_single_space', + roles: [observabilityOnlyAlertsRead.name], +}; + +// apm: ['alerts_read'] +// spaces: ['*'] +export const obsAlertsReadSpacesAll: User = { + username: 'obs_alerts_read_all_spaces', + password: 'obs_alerts_read_all_spaces', + roles: [observabilityOnlyAlertsReadSpacesAll.name], +}; + +// FOR UPDATES +// apm: ['minimal_read', 'alerts_all'] +// spaces: ['space1'] +export const obsMinReadAlertsAll: User = { + username: 'obs_minimal_read_alerts_all_single_space', + password: 'obs_minimal_read_alerts_all_single_space', + roles: [observabilityMinReadAlertsRead.name], +}; + +// apm: ['minimal_read', 'alerts_all'] +// spaces: ['*'] +export const obsMinReadAlertsAllSpacesAll: User = { + username: 'obs_minimal_read_alerts_all_all_spaces', + password: 'obs_minimal_read_alerts_all_all_spaces', + roles: [observabilityMinReadAlertsReadSpacesAll.name], +}; + +// apm: ['minimal_all'] +// spaces: ['space1'] +export const obsMinAll: User = { + username: 'obs_minimal_all_single_space', + password: 'obs_minimal_all_single_space', + roles: [observabilityMinimalRead.name], +}; + +// apm: ['minimal_all'] +// spaces: ['*'] +export const obsMinAllSpacesAll: User = { + username: 'obs_minimal_all_all_space', + password: 'obs_minimal_read_all_space', + roles: [observabilityMinimalReadSpacesAll.name], +}; + +// apm: ['alerts_all'] +// spaces: ['space1] +export const obsAlertsAll: User = { + username: 'obs_alerts_all_single_space', + password: 'obs_alerts_all_single_space', + roles: [observabilityOnlyAlertsRead.name], +}; + +// apm: ['alerts_all'] +// spaces: ['*'] +export const obsAlertsAllSpacesAll: User = { + username: 'obs_alerts_all_all_spaces', + password: 'obs_alerts_all_all_spaces', + roles: [observabilityOnlyAlertsReadSpacesAll.name], +}; diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_alerts.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_alerts.ts index 62aec9f15b56..27f4c00875bc 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_alerts.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_alerts.ts @@ -58,9 +58,7 @@ export default ({ getService }: FtrProviderContext) => { it(`${superUser.username} should be able to access the APM alert in ${SPACE1}`, async () => { const apmIndex = await getAPMIndexName(superUser); await supertestWithoutAuth - .get( - `${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&indexName=${apmIndex}` - ) + .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}`) .auth(superUser.username, superUser.password) .set('kbn-xsrf', 'true') .expect(200); @@ -68,9 +66,7 @@ export default ({ getService }: FtrProviderContext) => { it(`${globalRead.username} should be able to access the APM alert in ${SPACE1}`, async () => { const apmIndex = await getAPMIndexName(superUser); await supertestWithoutAuth - .get( - `${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&indexName=${apmIndex}` - ) + .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}`) .auth(globalRead.username, globalRead.password) .set('kbn-xsrf', 'true') .expect(200); @@ -78,9 +74,7 @@ export default ({ getService }: FtrProviderContext) => { it(`${obsOnlySpacesAll.username} should be able to access the APM alert in ${SPACE1}`, async () => { const apmIndex = await getAPMIndexName(superUser); await supertestWithoutAuth - .get( - `${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&indexName=${apmIndex}` - ) + .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}`) .auth(obsOnlySpacesAll.username, obsOnlySpacesAll.password) .set('kbn-xsrf', 'true') .expect(200); @@ -88,9 +82,7 @@ export default ({ getService }: FtrProviderContext) => { it(`${obsOnlyReadSpacesAll.username} should be able to access the APM alert in ${SPACE1}`, async () => { const apmIndex = await getAPMIndexName(superUser); await supertestWithoutAuth - .get( - `${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&indexName=${apmIndex}` - ) + .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}`) .auth(obsOnlyReadSpacesAll.username, obsOnlyReadSpacesAll.password) .set('kbn-xsrf', 'true') .expect(200); @@ -111,9 +103,7 @@ export default ({ getService }: FtrProviderContext) => { const apmIndex = await getAPMIndexName(superUser); await supertestWithoutAuth .get( - `${getSpaceUrlPrefix( - SPACE1 - )}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&indexName=${apmIndex}` + `${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}` ) .auth(scenario.user.username, scenario.user.password) .set('kbn-xsrf', 'true') @@ -131,9 +121,7 @@ export default ({ getService }: FtrProviderContext) => { const apmIndex = await getAPMIndexName(superUser); await supertestWithoutAuth .get( - `${getSpaceUrlPrefix( - SPACE2 - )}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&indexName=${apmIndex}` + `${getSpaceUrlPrefix(SPACE2)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}` ) .auth(scenario.user.username, scenario.user.password) .set('kbn-xsrf', 'true') @@ -160,9 +148,7 @@ export default ({ getService }: FtrProviderContext) => { const apmIndex = await getAPMIndexName(superUser); await supertestWithoutAuth .get( - `${getSpaceUrlPrefix( - SPACE2 - )}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&indexName=${apmIndex}` + `${getSpaceUrlPrefix(SPACE2)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}` ) .auth(scenario.user.username, scenario.user.password) .set('kbn-xsrf', 'true') diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/trial/get_alerts.ts b/x-pack/test/rule_registry/security_and_spaces/tests/trial/get_alerts.ts new file mode 100644 index 000000000000..245aab4b3311 --- /dev/null +++ b/x-pack/test/rule_registry/security_and_spaces/tests/trial/get_alerts.ts @@ -0,0 +1,167 @@ +/* + * 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 expect from '@kbn/expect'; + +import { + superUser, + obsMinReadSpacesAll, + obsMinRead, + obsMinReadAlertsRead, + obsMinReadAlertsReadSpacesAll, + obsAlertsRead, + obsAlertsReadSpacesAll, +} from '../../../common/lib/authentication/users'; +import type { User } from '../../../common/lib/authentication/types'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import { getSpaceUrlPrefix } from '../../../common/lib/authentication/spaces'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + + const TEST_URL = '/api/rac/alerts'; + const ALERTS_INDEX_URL = `${TEST_URL}/index`; + const SPACE1 = 'space1'; + const SPACE2 = 'space2'; + + const getAPMIndexName = async (user: User) => { + const { + body: indexNames, + }: { body: { index_name: string[] | undefined } } = await supertestWithoutAuth + .get(`${getSpaceUrlPrefix(SPACE1)}${ALERTS_INDEX_URL}`) + .auth(user.username, user.password) + .set('kbn-xsrf', 'true') + .expect(200); + const observabilityIndex = indexNames?.index_name?.find( + (indexName) => indexName === '.alerts-observability-apm' + ); + expect(observabilityIndex).to.eql('.alerts-observability-apm'); + return observabilityIndex; + }; + + describe('rbac with subfeatures', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); + }); + describe('Users:', () => { + // user with minimal_read and alerts_read privileges should be able to access apm alert + it(`${obsMinReadAlertsRead.username} should be able to access the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}`) + .auth(obsMinReadAlertsRead.username, obsMinReadAlertsRead.password) + .set('kbn-xsrf', 'true') + .expect(200); + }); + it(`${obsMinReadAlertsReadSpacesAll.username} should be able to access the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}`) + .auth(obsMinReadAlertsReadSpacesAll.username, obsMinReadAlertsReadSpacesAll.password) + .set('kbn-xsrf', 'true') + .expect(200); + }); + + it(`${obsMinRead.username} should NOT be able to access the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}`) + .auth(obsMinRead.username, obsMinRead.password) + .set('kbn-xsrf', 'true') + .expect(403); + }); + + it(`${obsMinReadSpacesAll.username} should NOT be able to access the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}`) + .auth(obsMinReadSpacesAll.username, obsMinReadSpacesAll.password) + .set('kbn-xsrf', 'true') + .expect(403); + }); + + it(`${obsAlertsRead.username} should NOT be able to access the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}`) + .auth(obsAlertsRead.username, obsAlertsRead.password) + .set('kbn-xsrf', 'true') + .expect(403); + }); + + it(`${obsAlertsReadSpacesAll.username} should NOT be able to access the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}`) + .auth(obsAlertsReadSpacesAll.username, obsAlertsReadSpacesAll.password) + .set('kbn-xsrf', 'true') + .expect(403); + }); + + for (const scenario of [ + { + user: obsMinRead, + }, + { + user: obsAlertsRead, + }, + ]) { + it(`${scenario.user.username} should not be able to access the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .get( + `${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}` + ) + .auth(scenario.user.username, scenario.user.password) + .set('kbn-xsrf', 'true') + .expect(403); + }); + } + }); + + describe('Space:', () => { + it(`${obsMinReadAlertsRead.username} should NOT be able to access the APM alert in ${SPACE2}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .get(`${getSpaceUrlPrefix(SPACE2)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}`) + .auth(obsMinReadAlertsRead.username, obsMinReadAlertsRead.password) + .set('kbn-xsrf', 'true') + .expect(403); + }); + + it(`${obsMinReadAlertsReadSpacesAll.username} should be able to access the APM alert in ${SPACE2}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .get(`${getSpaceUrlPrefix(SPACE2)}${TEST_URL}?id=NoxgpHkBqbdrfX07MqXV&index=${apmIndex}`) + .auth(obsMinReadAlertsReadSpacesAll.username, obsMinReadAlertsReadSpacesAll.password) + .set('kbn-xsrf', 'true') + .expect(200); + }); + + describe('extra params', () => { + it('should NOT allow to pass a filter query parameter', async () => { + await supertest + .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?sortOrder=asc&namespaces[0]=*`) + .set('kbn-xsrf', 'true') + .send() + .expect(400); + }); + + it('should NOT allow to pass a non supported query parameter', async () => { + await supertest + .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}?notExists=something`) + .set('kbn-xsrf', 'true') + .send() + .expect(400); + }); + }); + }); + }); +}; diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/trial/index.ts b/x-pack/test/rule_registry/security_and_spaces/tests/trial/index.ts new file mode 100644 index 000000000000..8da24646baf2 --- /dev/null +++ b/x-pack/test/rule_registry/security_and_spaces/tests/trial/index.ts @@ -0,0 +1,128 @@ +/* + * 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 { FtrProviderContext } from '../../../common/ftr_provider_context'; +import { + createSpaces, + createUsersAndRoles, + deleteSpaces, + deleteUsersAndRoles, +} from '../../../common/lib/authentication'; + +import { + observabilityMinReadAlertsRead, + observabilityMinReadAlertsReadSpacesAll, + observabilityMinimalRead, + observabilityMinimalReadSpacesAll, + observabilityOnlyAlertsRead, + observabilityOnlyAlertsReadSpacesAll, + observabilityMinReadAlertsAll, + observabilityMinReadAlertsAllSpacesAll, + observabilityMinimalAll, + observabilityMinimalAllSpacesAll, + observabilityOnlyAlertsAll, + observabilityOnlyAlertsAllSpacesAll, +} from '../../../common/lib/authentication/roles'; +import { + obsMinReadAlertsRead, + obsMinReadAlertsReadSpacesAll, + obsMinRead, + obsMinReadSpacesAll, + obsAlertsRead, + obsAlertsReadSpacesAll, + superUser, + obsMinReadAlertsAll, + obsMinReadAlertsAllSpacesAll, + obsMinAll, + obsMinAllSpacesAll, + obsAlertsAll, + obsAlertsAllSpacesAll, +} from '../../../common/lib/authentication/users'; + +// eslint-disable-next-line import/no-default-export +export default ({ loadTestFile, getService }: FtrProviderContext): void => { + describe('rules security and spaces enabled: basic', function () { + // Fastest ciGroup for the moment. + this.tags('ciGroup5'); + + before(async () => { + await createSpaces(getService); + await createUsersAndRoles( + getService, + [ + obsMinReadAlertsRead, + obsMinReadAlertsReadSpacesAll, + obsMinRead, + obsMinReadSpacesAll, + obsAlertsRead, + obsAlertsReadSpacesAll, + superUser, + obsMinReadAlertsAll, + obsMinReadAlertsAllSpacesAll, + obsMinAll, + obsMinAllSpacesAll, + obsAlertsAll, + obsAlertsAllSpacesAll, + ], + [ + observabilityMinReadAlertsRead, + observabilityMinReadAlertsReadSpacesAll, + observabilityMinimalRead, + observabilityMinimalReadSpacesAll, + observabilityOnlyAlertsRead, + observabilityOnlyAlertsReadSpacesAll, + observabilityMinReadAlertsAll, + observabilityMinReadAlertsAllSpacesAll, + observabilityMinimalAll, + observabilityMinimalAllSpacesAll, + observabilityOnlyAlertsAll, + observabilityOnlyAlertsAllSpacesAll, + ] + ); + }); + + after(async () => { + await deleteSpaces(getService); + await deleteUsersAndRoles( + getService, + [ + obsMinReadAlertsRead, + obsMinReadAlertsReadSpacesAll, + obsMinRead, + obsMinReadSpacesAll, + obsAlertsRead, + obsAlertsReadSpacesAll, + superUser, + obsMinReadAlertsAll, + obsMinReadAlertsAllSpacesAll, + obsMinAll, + obsMinAllSpacesAll, + obsAlertsAll, + obsAlertsAllSpacesAll, + ], + [ + observabilityMinReadAlertsRead, + observabilityMinReadAlertsReadSpacesAll, + observabilityMinimalRead, + observabilityMinimalReadSpacesAll, + observabilityOnlyAlertsRead, + observabilityOnlyAlertsReadSpacesAll, + observabilityMinReadAlertsAll, + observabilityMinReadAlertsAllSpacesAll, + observabilityMinimalAll, + observabilityMinimalAllSpacesAll, + observabilityOnlyAlertsAll, + observabilityOnlyAlertsAllSpacesAll, + ] + ); + }); + + // Basic + loadTestFile(require.resolve('./get_alerts')); + loadTestFile(require.resolve('./update_alert')); + }); +}; diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/trial/update_alert.ts b/x-pack/test/rule_registry/security_and_spaces/tests/trial/update_alert.ts new file mode 100644 index 000000000000..93acc3e803a7 --- /dev/null +++ b/x-pack/test/rule_registry/security_and_spaces/tests/trial/update_alert.ts @@ -0,0 +1,124 @@ +/* + * 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 expect from '@kbn/expect'; + +import { + superUser, + obsMinReadAlertsAll, + obsMinReadAlertsAllSpacesAll, + obsMinAll, + obsMinAllSpacesAll, + obsAlertsAll, + obsAlertsAllSpacesAll, +} from '../../../common/lib/authentication/users'; +import type { User } from '../../../common/lib/authentication/types'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import { getSpaceUrlPrefix } from '../../../common/lib/authentication/spaces'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + + const TEST_URL = '/api/rac/alerts'; + const ALERTS_INDEX_URL = `${TEST_URL}/index`; + const SPACE1 = 'space1'; + + const getAPMIndexName = async (user: User) => { + const { + body: indexNames, + }: { body: { index_name: string[] | undefined } } = await supertestWithoutAuth + .get(`${getSpaceUrlPrefix(SPACE1)}${ALERTS_INDEX_URL}`) + .auth(user.username, user.password) + .set('kbn-xsrf', 'true') + .expect(200); + const observabilityIndex = indexNames?.index_name?.find( + (indexName) => indexName === '.alerts-observability-apm' + ); + expect(observabilityIndex).to.eql('.alerts-observability-apm'); + return observabilityIndex; + }; + + describe('rbac', () => { + describe('Users update:', () => { + beforeEach(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); + }); + afterEach(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/rule_registry/alerts'); + }); + it(`${superUser.username} should be able to update the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .post(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}`) + .auth(superUser.username, superUser.password) + .set('kbn-xsrf', 'true') + .send({ ids: ['NoxgpHkBqbdrfX07MqXV'], status: 'closed', index: apmIndex }) + .expect(200); + }); + + it(`${obsMinReadAlertsAllSpacesAll.username} should be able to update the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .post(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}`) + .auth(obsMinReadAlertsAllSpacesAll.username, obsMinReadAlertsAllSpacesAll.password) + .set('kbn-xsrf', 'true') + .send({ ids: ['NoxgpHkBqbdrfX07MqXV'], status: 'closed', index: apmIndex }) + .expect(200); + }); + + it(`${obsMinReadAlertsAll.username} should be able to update the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .post(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}`) + .auth(obsMinReadAlertsAll.username, obsMinReadAlertsAll.password) + .set('kbn-xsrf', 'true') + .send({ ids: ['NoxgpHkBqbdrfX07MqXV'], status: 'closed', index: apmIndex }) + .expect(200); + }); + it(`${obsMinAll.username} should NOT be able to update the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .post(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}`) + .auth(obsMinAll.username, obsMinAll.password) + .set('kbn-xsrf', 'true') + .send({ ids: ['NoxgpHkBqbdrfX07MqXV'], status: 'closed', index: apmIndex }) + .expect(403); + }); + + it(`${obsMinAllSpacesAll.username} should NOT be able to update the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .post(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}`) + .auth(obsMinAllSpacesAll.username, obsMinAllSpacesAll.password) + .set('kbn-xsrf', 'true') + .send({ ids: ['NoxgpHkBqbdrfX07MqXV'], status: 'closed', index: apmIndex }) + .expect(403); + }); + + it(`${obsAlertsAll.username} should NOT be able to update the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .post(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}`) + .auth(obsAlertsAll.username, obsAlertsAll.password) + .set('kbn-xsrf', 'true') + .send({ ids: ['NoxgpHkBqbdrfX07MqXV'], status: 'closed', index: apmIndex }) + .expect(403); + }); + + it(`${obsAlertsAllSpacesAll.username} should NOT be able to update the APM alert in ${SPACE1}`, async () => { + const apmIndex = await getAPMIndexName(superUser); + await supertestWithoutAuth + .post(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}`) + .auth(obsAlertsAllSpacesAll.username, obsAlertsAllSpacesAll.password) + .set('kbn-xsrf', 'true') + .send({ ids: ['NoxgpHkBqbdrfX07MqXV'], status: 'closed', index: apmIndex }) + .expect(403); + }); + }); + }); +};