mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[8.x] [ResponseOps][Alerting] Register anomaly detection and custom threshold rule types under stack alerts feature privilege (#194615) (#195171)
# Backport This will backport the following commits from `main` to `8.x`: - [[ResponseOps][Alerting] Register anomaly detection and custom threshold rule types under stack alerts feature privilege (#194615)](https://github.com/elastic/kibana/pull/194615) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Christos Nasikas","email":"christos.nasikas@elastic.co"},"sourceCommit":{"committedDate":"2024-10-06T11:46:44Z","message":"[ResponseOps][Alerting] Register anomaly detection and custom threshold rule types under stack alerts feature privilege (#194615)\n\n## Summary\r\n\r\nIn the ES query, anomaly detection, and custom threshold rule types\r\nusers can use the \"Role visibility\" dropdown to select where the rules\r\nshould be accessible. The \"Role visibility\" dropdown sets the `consumer`\r\nwhich is paramount for alerting RBAC. For the anomaly detection and\r\ncustom threshold rule types if the `consumer` is set to `stackAlerts`\r\nthen the rules will not be accessible from any rule page even if the\r\nuser has access to the \"Stack alerts\" feature privilege. This PR fixes\r\nthis bug.\r\n\r\nFixes https://github.com/elastic/kibana/issues/193549\r\nFixes https://github.com/elastic/kibana/issues/191075\r\nFixes https://github.com/elastic/kibana/issues/184422\r\nFixes https://github.com/elastic/kibana/issues/179082\r\n\r\n## Testing\r\n\r\n1. Create an anomaly detection and custom threshold rule and set the\r\n\"Role visibility\" to \"Stack alerts\".\r\n2. Create a user with access only to \"Stack alerts\".\r\n3. Login with the user created in Step 2.\r\n4. Verify that you can see the rules from the stack management page.\r\n5. Verify that you can see the alerts generated from the rules.\r\n6. Create a user with roles `kibana_admin` and verify the same.\r\n\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [x] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n\r\n### For maintainers\r\n\r\n- [x] This was checked for breaking API changes and was [labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n## Release notes\r\n\r\nFix bug where rule types with \"Stack alerts\" role visibility are not\r\nbeing shown in the stack management page","sha":"8d83a075f6228bb5a6e35a9bb4654fe29cee0cff","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:fix","Team:ResponseOps","v9.0.0","Feature:Alerting/RulesFramework","backport:prev-major","v8.16.0","v8.15.3"],"title":"[ResponseOps][Alerting] Register anomaly detection and custom threshold rule types under stack alerts feature privilege","number":194615,"url":"https://github.com/elastic/kibana/pull/194615","mergeCommit":{"message":"[ResponseOps][Alerting] Register anomaly detection and custom threshold rule types under stack alerts feature privilege (#194615)\n\n## Summary\r\n\r\nIn the ES query, anomaly detection, and custom threshold rule types\r\nusers can use the \"Role visibility\" dropdown to select where the rules\r\nshould be accessible. The \"Role visibility\" dropdown sets the `consumer`\r\nwhich is paramount for alerting RBAC. For the anomaly detection and\r\ncustom threshold rule types if the `consumer` is set to `stackAlerts`\r\nthen the rules will not be accessible from any rule page even if the\r\nuser has access to the \"Stack alerts\" feature privilege. This PR fixes\r\nthis bug.\r\n\r\nFixes https://github.com/elastic/kibana/issues/193549\r\nFixes https://github.com/elastic/kibana/issues/191075\r\nFixes https://github.com/elastic/kibana/issues/184422\r\nFixes https://github.com/elastic/kibana/issues/179082\r\n\r\n## Testing\r\n\r\n1. Create an anomaly detection and custom threshold rule and set the\r\n\"Role visibility\" to \"Stack alerts\".\r\n2. Create a user with access only to \"Stack alerts\".\r\n3. Login with the user created in Step 2.\r\n4. Verify that you can see the rules from the stack management page.\r\n5. Verify that you can see the alerts generated from the rules.\r\n6. Create a user with roles `kibana_admin` and verify the same.\r\n\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [x] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n\r\n### For maintainers\r\n\r\n- [x] This was checked for breaking API changes and was [labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n## Release notes\r\n\r\nFix bug where rule types with \"Stack alerts\" role visibility are not\r\nbeing shown in the stack management page","sha":"8d83a075f6228bb5a6e35a9bb4654fe29cee0cff"}},"sourceBranch":"main","suggestedTargetBranches":["8.x","8.15"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/194615","number":194615,"mergeCommit":{"message":"[ResponseOps][Alerting] Register anomaly detection and custom threshold rule types under stack alerts feature privilege (#194615)\n\n## Summary\r\n\r\nIn the ES query, anomaly detection, and custom threshold rule types\r\nusers can use the \"Role visibility\" dropdown to select where the rules\r\nshould be accessible. The \"Role visibility\" dropdown sets the `consumer`\r\nwhich is paramount for alerting RBAC. For the anomaly detection and\r\ncustom threshold rule types if the `consumer` is set to `stackAlerts`\r\nthen the rules will not be accessible from any rule page even if the\r\nuser has access to the \"Stack alerts\" feature privilege. This PR fixes\r\nthis bug.\r\n\r\nFixes https://github.com/elastic/kibana/issues/193549\r\nFixes https://github.com/elastic/kibana/issues/191075\r\nFixes https://github.com/elastic/kibana/issues/184422\r\nFixes https://github.com/elastic/kibana/issues/179082\r\n\r\n## Testing\r\n\r\n1. Create an anomaly detection and custom threshold rule and set the\r\n\"Role visibility\" to \"Stack alerts\".\r\n2. Create a user with access only to \"Stack alerts\".\r\n3. Login with the user created in Step 2.\r\n4. Verify that you can see the rules from the stack management page.\r\n5. Verify that you can see the alerts generated from the rules.\r\n6. Create a user with roles `kibana_admin` and verify the same.\r\n\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [x] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n\r\n### For maintainers\r\n\r\n- [x] This was checked for breaking API changes and was [labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n## Release notes\r\n\r\nFix bug where rule types with \"Stack alerts\" role visibility are not\r\nbeing shown in the stack management page","sha":"8d83a075f6228bb5a6e35a9bb4654fe29cee0cff"}},{"branch":"8.x","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.15","label":"v8.15.3","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Christos Nasikas <christos.nasikas@elastic.co>
This commit is contained in:
parent
4e4107b506
commit
a89a5388b4
4 changed files with 232 additions and 35 deletions
|
@ -27,26 +27,37 @@ describe('Stack Alerts Feature Privileges', () => {
|
|||
const featuresSetup = featuresPluginMock.createSetup();
|
||||
plugin.setup(coreSetup, { alerting: alertingSetup, features: featuresSetup });
|
||||
|
||||
const typesInFeaturePrivilege = BUILT_IN_ALERTS_FEATURE.alerting ?? [];
|
||||
const typesInFeaturePrivilegeAll =
|
||||
BUILT_IN_ALERTS_FEATURE.privileges?.all?.alerting?.rule?.all ?? [];
|
||||
const typesInFeaturePrivilegeRead =
|
||||
BUILT_IN_ALERTS_FEATURE.privileges?.read?.alerting?.rule?.read ?? [];
|
||||
// transform alerting rule is initialized during the transform plugin setup
|
||||
expect(alertingSetup.registerType.mock.calls.length).toEqual(
|
||||
typesInFeaturePrivilege.length - 1
|
||||
);
|
||||
expect(alertingSetup.registerType.mock.calls.length).toEqual(
|
||||
typesInFeaturePrivilegeAll.length - 1
|
||||
);
|
||||
expect(alertingSetup.registerType.mock.calls.length).toEqual(
|
||||
typesInFeaturePrivilegeRead.length - 1
|
||||
);
|
||||
expect(BUILT_IN_ALERTS_FEATURE.alerting).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
".index-threshold",
|
||||
".geo-containment",
|
||||
".es-query",
|
||||
"transform_health",
|
||||
"observability.rules.custom_threshold",
|
||||
"xpack.ml.anomaly_detection_alert",
|
||||
]
|
||||
`);
|
||||
|
||||
alertingSetup.registerType.mock.calls.forEach((call) => {
|
||||
expect(typesInFeaturePrivilege.indexOf(call[0].id)).toBeGreaterThanOrEqual(0);
|
||||
expect(typesInFeaturePrivilegeAll.indexOf(call[0].id)).toBeGreaterThanOrEqual(0);
|
||||
expect(typesInFeaturePrivilegeRead.indexOf(call[0].id)).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
expect(BUILT_IN_ALERTS_FEATURE.privileges?.all?.alerting?.rule?.all).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
".index-threshold",
|
||||
".geo-containment",
|
||||
".es-query",
|
||||
"transform_health",
|
||||
"observability.rules.custom_threshold",
|
||||
"xpack.ml.anomaly_detection_alert",
|
||||
]
|
||||
`);
|
||||
|
||||
expect(BUILT_IN_ALERTS_FEATURE.privileges?.read?.alerting?.rule?.read).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
".index-threshold",
|
||||
".geo-containment",
|
||||
".es-query",
|
||||
"transform_health",
|
||||
"observability.rules.custom_threshold",
|
||||
"xpack.ml.anomaly_detection_alert",
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,7 +9,11 @@ import { i18n } from '@kbn/i18n';
|
|||
import { KibanaFeatureConfig } from '@kbn/features-plugin/common';
|
||||
import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server';
|
||||
import { TRANSFORM_RULE_TYPE } from '@kbn/transform-plugin/common';
|
||||
import { STACK_ALERTS_FEATURE_ID } from '@kbn/rule-data-utils';
|
||||
import {
|
||||
ML_ANOMALY_DETECTION_RULE_TYPE_ID,
|
||||
OBSERVABILITY_THRESHOLD_RULE_TYPE_ID,
|
||||
STACK_ALERTS_FEATURE_ID,
|
||||
} from '@kbn/rule-data-utils';
|
||||
import { ES_QUERY_ID as ElasticsearchQuery } from '@kbn/rule-data-utils';
|
||||
import { KibanaFeatureScope } from '@kbn/features-plugin/common';
|
||||
import { ID as IndexThreshold } from './rule_types/index_threshold/rule_type';
|
||||
|
@ -28,7 +32,14 @@ export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = {
|
|||
management: {
|
||||
insightsAndAlerting: ['triggersActions'],
|
||||
},
|
||||
alerting: [IndexThreshold, GeoContainment, ElasticsearchQuery, TransformHealth],
|
||||
alerting: [
|
||||
IndexThreshold,
|
||||
GeoContainment,
|
||||
ElasticsearchQuery,
|
||||
TransformHealth,
|
||||
OBSERVABILITY_THRESHOLD_RULE_TYPE_ID,
|
||||
ML_ANOMALY_DETECTION_RULE_TYPE_ID,
|
||||
],
|
||||
privileges: {
|
||||
all: {
|
||||
app: [],
|
||||
|
@ -38,10 +49,24 @@ export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = {
|
|||
},
|
||||
alerting: {
|
||||
rule: {
|
||||
all: [IndexThreshold, GeoContainment, ElasticsearchQuery, TransformHealth],
|
||||
all: [
|
||||
IndexThreshold,
|
||||
GeoContainment,
|
||||
ElasticsearchQuery,
|
||||
TransformHealth,
|
||||
OBSERVABILITY_THRESHOLD_RULE_TYPE_ID,
|
||||
ML_ANOMALY_DETECTION_RULE_TYPE_ID,
|
||||
],
|
||||
},
|
||||
alert: {
|
||||
all: [IndexThreshold, GeoContainment, ElasticsearchQuery, TransformHealth],
|
||||
all: [
|
||||
IndexThreshold,
|
||||
GeoContainment,
|
||||
ElasticsearchQuery,
|
||||
TransformHealth,
|
||||
OBSERVABILITY_THRESHOLD_RULE_TYPE_ID,
|
||||
ML_ANOMALY_DETECTION_RULE_TYPE_ID,
|
||||
],
|
||||
},
|
||||
},
|
||||
savedObject: {
|
||||
|
@ -59,10 +84,24 @@ export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = {
|
|||
},
|
||||
alerting: {
|
||||
rule: {
|
||||
read: [IndexThreshold, GeoContainment, ElasticsearchQuery, TransformHealth],
|
||||
read: [
|
||||
IndexThreshold,
|
||||
GeoContainment,
|
||||
ElasticsearchQuery,
|
||||
TransformHealth,
|
||||
OBSERVABILITY_THRESHOLD_RULE_TYPE_ID,
|
||||
ML_ANOMALY_DETECTION_RULE_TYPE_ID,
|
||||
],
|
||||
},
|
||||
alert: {
|
||||
read: [IndexThreshold, GeoContainment, ElasticsearchQuery, TransformHealth],
|
||||
read: [
|
||||
IndexThreshold,
|
||||
GeoContainment,
|
||||
ElasticsearchQuery,
|
||||
TransformHealth,
|
||||
OBSERVABILITY_THRESHOLD_RULE_TYPE_ID,
|
||||
ML_ANOMALY_DETECTION_RULE_TYPE_ID,
|
||||
],
|
||||
},
|
||||
},
|
||||
savedObject: {
|
||||
|
|
|
@ -10,7 +10,12 @@ import { Agent as SuperTestAgent } from 'supertest';
|
|||
import { chunk, omit } from 'lodash';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services';
|
||||
import { SuperuserAtSpace1, UserAtSpaceScenarios } from '../../../scenarios';
|
||||
import {
|
||||
ES_QUERY_ID,
|
||||
ML_ANOMALY_DETECTION_RULE_TYPE_ID,
|
||||
OBSERVABILITY_THRESHOLD_RULE_TYPE_ID,
|
||||
} from '@kbn/rule-data-utils';
|
||||
import { SuperuserAtSpace1, UserAtSpaceScenarios, StackAlertsOnly } from '../../../scenarios';
|
||||
import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../common/lib';
|
||||
import { FtrProviderContext } from '../../../../common/ftr_provider_context';
|
||||
|
||||
|
@ -663,5 +668,120 @@ export default function createFindTests({ getService }: FtrProviderContext) {
|
|||
|
||||
findTestUtils('public', objectRemover, supertest, supertestWithoutAuth);
|
||||
findTestUtils('internal', objectRemover, supertest, supertestWithoutAuth);
|
||||
|
||||
describe('stack alerts', () => {
|
||||
const ruleTypes = [
|
||||
[
|
||||
ES_QUERY_ID,
|
||||
{
|
||||
searchType: 'esQuery',
|
||||
timeWindowSize: 5,
|
||||
timeWindowUnit: 'm',
|
||||
threshold: [1000],
|
||||
thresholdComparator: '>',
|
||||
size: 100,
|
||||
esQuery: '{\n "query":{\n "match_all" : {}\n }\n }',
|
||||
aggType: 'count',
|
||||
groupBy: 'all',
|
||||
termSize: 5,
|
||||
excludeHitsFromPreviousRun: false,
|
||||
sourceFields: [],
|
||||
index: ['.kibana'],
|
||||
timeField: 'created_at',
|
||||
},
|
||||
],
|
||||
[
|
||||
OBSERVABILITY_THRESHOLD_RULE_TYPE_ID,
|
||||
{
|
||||
criteria: [
|
||||
{
|
||||
comparator: '>',
|
||||
metrics: [
|
||||
{
|
||||
name: 'A',
|
||||
aggType: 'count',
|
||||
},
|
||||
],
|
||||
threshold: [100],
|
||||
timeSize: 1,
|
||||
timeUnit: 'm',
|
||||
},
|
||||
],
|
||||
alertOnNoData: false,
|
||||
alertOnGroupDisappear: false,
|
||||
searchConfiguration: {
|
||||
query: {
|
||||
query: '',
|
||||
language: 'kuery',
|
||||
},
|
||||
index: 'kibana-event-log-data-view',
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
ML_ANOMALY_DETECTION_RULE_TYPE_ID,
|
||||
{
|
||||
severity: 75,
|
||||
resultType: 'bucket',
|
||||
includeInterim: false,
|
||||
jobSelection: {
|
||||
jobIds: ['low_request_rate'],
|
||||
},
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
const createRule = async (rule = {}) => {
|
||||
const { body: createdAlert } = await supertest
|
||||
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send(getTestRuleData({ ...rule }))
|
||||
.expect(200);
|
||||
|
||||
objectRemover.add('space1', createdAlert.id, 'rule', 'alerting');
|
||||
};
|
||||
|
||||
for (const [ruleTypeId, params] of ruleTypes) {
|
||||
it(`should get rules of ${ruleTypeId} rule type ID and stackAlerts consumer`, async () => {
|
||||
/**
|
||||
* We create two rules. The first one is a test.noop
|
||||
* rule with stackAlerts as consumer. The second rule
|
||||
* is has different rule type ID but with the same consumer as the first rule (stackAlerts).
|
||||
* This way we can verify that the find API call returns only the rules the user is authorized to.
|
||||
* Specifically only the second rule because the StackAlertsOnly user does not have
|
||||
* access to the test.noop rule type.
|
||||
*/
|
||||
await createRule({ consumer: 'stackAlerts' });
|
||||
await createRule({ rule_type_id: ruleTypeId, params, consumer: 'stackAlerts' });
|
||||
|
||||
const response = await supertestWithoutAuth
|
||||
.get(`${getUrlPrefix('space1')}/api/alerting/rules/_find`)
|
||||
.auth(StackAlertsOnly.username, StackAlertsOnly.password);
|
||||
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body.total).to.equal(1);
|
||||
expect(response.body.data[0].rule_type_id).to.equal(ruleTypeId);
|
||||
expect(response.body.data[0].consumer).to.equal('stackAlerts');
|
||||
});
|
||||
}
|
||||
|
||||
for (const [ruleTypeId, params] of ruleTypes) {
|
||||
it(`should NOT get rules of ${ruleTypeId} rule type ID and NOT stackAlerts consumer`, async () => {
|
||||
/**
|
||||
* We create two rules with logs as consumer. The user is authorized to
|
||||
* access rules only with the stackAlerts consumers.
|
||||
*/
|
||||
await createRule({ consumer: 'logs' });
|
||||
await createRule({ rule_type_id: ruleTypeId, params, consumer: 'logs' });
|
||||
|
||||
const response = await supertestWithoutAuth
|
||||
.get(`${getUrlPrefix('space1')}/api/alerting/rules/_find`)
|
||||
.auth(StackAlertsOnly.username, StackAlertsOnly.password);
|
||||
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body.total).to.equal(0);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -190,6 +190,31 @@ const CasesAll: User = {
|
|||
},
|
||||
};
|
||||
|
||||
export const StackAlertsOnly: User = {
|
||||
username: 'stack_alerts_only',
|
||||
fullName: 'stack_alerts_only',
|
||||
password: 'stack_alerts_only-password',
|
||||
role: {
|
||||
name: 'stack_alerts_only_role',
|
||||
kibana: [
|
||||
{
|
||||
feature: {
|
||||
stackAlerts: ['all'],
|
||||
},
|
||||
spaces: ['space1'],
|
||||
},
|
||||
],
|
||||
elasticsearch: {
|
||||
indices: [
|
||||
{
|
||||
names: [`${ES_TEST_INDEX_NAME}*`],
|
||||
privileges: ['all'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Users: User[] = [
|
||||
NoKibanaPrivileges,
|
||||
Superuser,
|
||||
|
@ -198,6 +223,7 @@ export const Users: User[] = [
|
|||
Space1AllWithRestrictedFixture,
|
||||
Space1AllAlertingNoneActions,
|
||||
CasesAll,
|
||||
StackAlertsOnly,
|
||||
];
|
||||
|
||||
const Space1: Space = {
|
||||
|
@ -256,14 +282,6 @@ const GlobalReadAtSpace1: GlobalReadAtSpace1 = {
|
|||
space: Space1,
|
||||
};
|
||||
|
||||
interface Space1AllAtSpace1 extends Scenario {
|
||||
id: 'space_1_all at space1';
|
||||
}
|
||||
const Space1AllAtSpace1: Space1AllAtSpace1 = {
|
||||
id: 'space_1_all at space1',
|
||||
user: Space1All,
|
||||
space: Space1,
|
||||
};
|
||||
interface Space1AllWithRestrictedFixtureAtSpace1 extends Scenario {
|
||||
id: 'space_1_all_with_restricted_fixture at space1';
|
||||
}
|
||||
|
@ -301,6 +319,15 @@ export const systemActionScenario: SystemActionSpace1 = {
|
|||
space: Space1,
|
||||
};
|
||||
|
||||
interface Space1AllAtSpace1 extends Scenario {
|
||||
id: 'space_1_all at space1';
|
||||
}
|
||||
const Space1AllAtSpace1: Space1AllAtSpace1 = {
|
||||
id: 'space_1_all at space1',
|
||||
user: Space1All,
|
||||
space: Space1,
|
||||
};
|
||||
|
||||
export const UserAtSpaceScenarios: [
|
||||
NoKibanaPrivilegesAtSpace1,
|
||||
SuperuserAtSpace1,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue