[8.x] [ResponseOps][Alerting] Fix stackAlerts plugin missing rac API auth scope (#193948) (#195279)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[ResponseOps][Alerting] Fix stackAlerts plugin missing rac API auth
scope (#193948)](https://github.com/elastic/kibana/pull/193948)

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

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

<!--BACKPORT [{"author":{"name":"Umberto
Pepato","email":"umbopepato@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-10-07T15:17:31Z","message":"[ResponseOps][Alerting]
Fix stackAlerts plugin missing rac API auth scope (#193948)\n\n##
Summary\r\n\r\nAdds the `['rac']` API access scope to the Stack Alerts
feature to\r\ncorrectly authenticate alerts API endpoints with the
`stackAlerts`\r\npermission.\r\nAlso adds a dedicated API integration
test for the impacted endpoint and\r\npermission set.\r\n\r\n## Release
note\r\n\r\nFix Stack Alerts feature API access control\r\n\r\n## To
verify\r\n\r\n1. Create rules that fire alerts in Stack management\r\n2.
Wait for alerts to be created\r\n3. Create a role with only `Stack
Management > Rules : Read` privilege\r\n4. Create a user with that
role\r\n5. In another window, open Kibana with the newly created
user\r\n6. Check that the Stack Management > Alerts page renders
correctly, not\r\nshowing any missing 403 error
toasts","sha":"17fcaa5c8eb6cdff5f89a2fa28a20f42d020381f","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Team:ResponseOps","v9.0.0","backport:prev-minor"],"title":"[ResponseOps][Alerting]
Fix stackAlerts plugin missing rac API auth
scope","number":193948,"url":"https://github.com/elastic/kibana/pull/193948","mergeCommit":{"message":"[ResponseOps][Alerting]
Fix stackAlerts plugin missing rac API auth scope (#193948)\n\n##
Summary\r\n\r\nAdds the `['rac']` API access scope to the Stack Alerts
feature to\r\ncorrectly authenticate alerts API endpoints with the
`stackAlerts`\r\npermission.\r\nAlso adds a dedicated API integration
test for the impacted endpoint and\r\npermission set.\r\n\r\n## Release
note\r\n\r\nFix Stack Alerts feature API access control\r\n\r\n## To
verify\r\n\r\n1. Create rules that fire alerts in Stack management\r\n2.
Wait for alerts to be created\r\n3. Create a role with only `Stack
Management > Rules : Read` privilege\r\n4. Create a user with that
role\r\n5. In another window, open Kibana with the newly created
user\r\n6. Check that the Stack Management > Alerts page renders
correctly, not\r\nshowing any missing 403 error
toasts","sha":"17fcaa5c8eb6cdff5f89a2fa28a20f42d020381f"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/193948","number":193948,"mergeCommit":{"message":"[ResponseOps][Alerting]
Fix stackAlerts plugin missing rac API auth scope (#193948)\n\n##
Summary\r\n\r\nAdds the `['rac']` API access scope to the Stack Alerts
feature to\r\ncorrectly authenticate alerts API endpoints with the
`stackAlerts`\r\npermission.\r\nAlso adds a dedicated API integration
test for the impacted endpoint and\r\npermission set.\r\n\r\n## Release
note\r\n\r\nFix Stack Alerts feature API access control\r\n\r\n## To
verify\r\n\r\n1. Create rules that fire alerts in Stack management\r\n2.
Wait for alerts to be created\r\n3. Create a role with only `Stack
Management > Rules : Read` privilege\r\n4. Create a user with that
role\r\n5. In another window, open Kibana with the newly created
user\r\n6. Check that the Stack Management > Alerts page renders
correctly, not\r\nshowing any missing 403 error
toasts","sha":"17fcaa5c8eb6cdff5f89a2fa28a20f42d020381f"}}]}]
BACKPORT-->

Co-authored-by: Umberto Pepato <umbopepato@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2024-10-08 04:03:58 +11:00 committed by GitHub
parent 3ad02ed9ae
commit 821ddaa373
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 66 additions and 26 deletions

View file

@ -73,7 +73,7 @@ export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = {
all: [],
read: [],
},
api: [],
api: ['rac'],
ui: [],
},
read: {
@ -108,7 +108,7 @@ export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = {
all: [],
read: [],
},
api: [],
api: ['rac'],
ui: [],
},
},

View file

@ -126,6 +126,14 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
spaces: ['*'],
},
],
elasticsearch: {
indices: [
{
names: ['.alerts-*'],
privileges: ['read'],
},
],
},
},
only_actions_role: {
kibana: [

View file

@ -265,6 +265,23 @@ export const logsOnlyAllSpacesAll: Role = {
},
};
export const stackAlertsOnlyReadSpacesAll: Role = {
name: 'stack_alerts_only_read_spaces_all',
privileges: {
elasticsearch: {
indices: [],
},
kibana: [
{
feature: {
stackAlerts: ['read'],
},
spaces: ['*'],
},
],
},
};
export const stackAlertsOnlyAllSpacesAll: Role = {
name: 'stack_alerts_only_all_spaces_all',
privileges: {
@ -511,6 +528,7 @@ export const allRoles = [
securitySolutionOnlyReadSpacesAll,
observabilityOnlyAllSpacesAll,
logsOnlyAllSpacesAll,
stackAlertsOnlyReadSpacesAll,
stackAlertsOnlyAllSpacesAll,
observabilityOnlyReadSpacesAll,
observabilityOnlyAllSpacesAllWithReadESIndices,

View file

@ -30,7 +30,8 @@ import {
observabilityMinReadAlertsAllSpacesAll,
observabilityOnlyAllSpacesAllWithReadESIndices,
securitySolutionOnlyAllSpacesAllWithReadESIndices,
stackAlertsOnlyAllSpacesAll,
stackAlertsOnlyReadSpacesAll as stackAlertsOnlyReadSpacesAllRole,
stackAlertsOnlyAllSpacesAll as stackAlertsOnlyAllSpacesAllRole,
} from './roles';
import { User } from './types';
@ -130,6 +131,12 @@ export const obsOnlyReadSpacesAll: User = {
roles: [observabilityOnlyReadSpacesAll.name],
};
export const stackAlertsOnlyReadSpacesAll: User = {
username: 'stack_alerts_only_read_spaces_all',
password: 'stack_alerts_only_read_spaces_all',
roles: [stackAlertsOnlyReadSpacesAllRole.name],
};
export const users = [
superUser,
secOnly,
@ -177,10 +184,10 @@ export const logsOnlySpacesAll: User = {
roles: [logsOnlyAllSpacesAll.name],
};
export const stackAlertsOnlySpacesAll: User = {
export const stackAlertsOnlyAllSpacesAll: User = {
username: 'stack_alerts_only_all_spaces_all',
password: 'stack_alerts_only_all_spaces_all',
roles: [stackAlertsOnlyAllSpacesAll.name],
roles: [stackAlertsOnlyAllSpacesAllRole.name],
};
export const obsOnlySpacesAllEsRead: User = {
@ -297,7 +304,8 @@ export const allUsers = [
secOnlyReadSpacesAll,
obsOnlySpacesAll,
logsOnlySpacesAll,
stackAlertsOnlySpacesAll,
stackAlertsOnlyReadSpacesAll,
stackAlertsOnlyAllSpacesAll,
obsSecSpacesAll,
obsSecReadSpacesAll,
obsMinReadAlertsRead,

View file

@ -7,7 +7,12 @@
import expect from '@kbn/expect';
import { superUser, obsOnlySpacesAll, secOnlyRead } from '../../../common/lib/authentication/users';
import {
superUser,
obsOnlySpacesAll,
secOnlyRead,
stackAlertsOnlyReadSpacesAll,
} 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';
@ -22,27 +27,19 @@ export default ({ getService }: FtrProviderContext) => {
const SPACE1 = 'space1';
const APM_ALERT_INDEX = '.alerts-observability.apm.alerts-default';
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
const STACK_ALERT_INDEX = '.alerts-stack.alerts-default';
const getAPMIndexName = async (user: User, space: string, expectedStatusCode: number = 200) => {
const resp = await supertestWithoutAuth
.get(`${getSpaceUrlPrefix(space)}${ALERTS_INDEX_URL}?features=apm`)
.auth(user.username, user.password)
.set('kbn-xsrf', 'true')
.expect(expectedStatusCode);
return resp.body.index_name as string[];
};
const getSecuritySolutionIndexName = async (
const getIndexName = async (
featureIds: string[],
user: User,
space: string,
expectedStatusCode: number = 200
) => {
const resp = await supertestWithoutAuth
.get(`${getSpaceUrlPrefix(space)}${ALERTS_INDEX_URL}?features=siem`)
.get(`${getSpaceUrlPrefix(space)}${ALERTS_INDEX_URL}?features=${featureIds.join(',')}`)
.auth(user.username, user.password)
.set('kbn-xsrf', 'true')
.expect(expectedStatusCode);
return resp.body.index_name as string[];
};
@ -52,24 +49,33 @@ export default ({ getService }: FtrProviderContext) => {
});
describe('Users:', () => {
it(`${obsOnlySpacesAll.username} should be able to access the APM alert in ${SPACE1}`, async () => {
const indexNames = await getAPMIndexName(obsOnlySpacesAll, SPACE1);
const indexNames = await getIndexName(['apm'], obsOnlySpacesAll, SPACE1);
expect(indexNames.includes(APM_ALERT_INDEX)).to.eql(true); // assert this here so we can use constants in the dynamically-defined test cases below
});
it(`${superUser.username} should be able to access the APM alert in ${SPACE1}`, async () => {
const indexNames = await getAPMIndexName(superUser, SPACE1);
const indexNames = await getIndexName(['apm'], superUser, SPACE1);
expect(indexNames.includes(APM_ALERT_INDEX)).to.eql(true); // assert this here so we can use constants in the dynamically-defined test cases below
});
it(`${secOnlyRead.username} should NOT be able to access the APM alert in ${SPACE1}`, async () => {
const indexNames = await getAPMIndexName(secOnlyRead, SPACE1);
const indexNames = await getIndexName(['apm'], secOnlyRead, SPACE1);
expect(indexNames?.length).to.eql(0);
});
it(`${secOnlyRead.username} should be able to access the security solution alert in ${SPACE1}`, async () => {
const indexNames = await getSecuritySolutionIndexName(secOnlyRead, SPACE1);
const indexNames = await getIndexName(['siem'], secOnlyRead, SPACE1);
expect(indexNames.includes(`${SECURITY_SOLUTION_ALERT_INDEX}-${SPACE1}`)).to.eql(true); // assert this here so we can use constants in the dynamically-defined test cases below
});
it(`${stackAlertsOnlyReadSpacesAll.username} should be able to access the stack alert in ${SPACE1}`, async () => {
const indexNames = await getIndexName(
['stackAlerts'],
stackAlertsOnlyReadSpacesAll,
SPACE1
);
expect(indexNames.includes(STACK_ALERT_INDEX)).to.eql(true);
});
});
});
};

View file

@ -13,7 +13,7 @@ import {
obsOnlySpacesAll,
logsOnlySpacesAll,
secOnlySpacesAllEsReadAll,
stackAlertsOnlySpacesAll,
stackAlertsOnlyAllSpacesAll,
superUser,
} from '../../../common/lib/authentication/users';
@ -360,8 +360,8 @@ export default ({ getService }: FtrProviderContext) => {
const result = await secureBsearch.send<RuleRegistrySearchResponse>({
supertestWithoutAuth,
auth: {
username: stackAlertsOnlySpacesAll.username,
password: stackAlertsOnlySpacesAll.password,
username: stackAlertsOnlyAllSpacesAll.username,
password: stackAlertsOnlyAllSpacesAll.password,
},
referer: 'test',
kibanaVersion,