diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx index bbbd81b4e49ea..63315590b06b6 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx @@ -335,7 +335,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) { defaultCellActions: getDefaultCellActions({ addToQuery }), end: rangeTo, filters: [], - indexNames: [indexName], + indexNames: indexName.split(','), itemsPerPage: 10, itemsPerPageOptions: [10, 25, 50], loadingText: i18n.translate('xpack.observability.alertsTable.loadingTextLabel', { diff --git a/x-pack/plugins/observability/server/plugin.ts b/x-pack/plugins/observability/server/plugin.ts index f653117113737..e11a6c027584e 100644 --- a/x-pack/plugins/observability/server/plugin.ts +++ b/x-pack/plugins/observability/server/plugin.ts @@ -120,6 +120,7 @@ export class ObservabilityPlugin implements Plugin { logger: this.initContext.logger.get(), repository: getGlobalObservabilityServerRouteRepository(), ruleDataClient, + ruleDataService, }); return { diff --git a/x-pack/plugins/observability/server/routes/register_routes.ts b/x-pack/plugins/observability/server/routes/register_routes.ts index 43b47f26dcdd1..03f062a721608 100644 --- a/x-pack/plugins/observability/server/routes/register_routes.ts +++ b/x-pack/plugins/observability/server/routes/register_routes.ts @@ -13,7 +13,7 @@ import { import { CoreSetup, CoreStart, Logger, RouteRegistrar } from 'kibana/server'; import Boom from '@hapi/boom'; import { RequestAbortedError } from '@elastic/elasticsearch/lib/errors'; -import { IRuleDataClient } from '../../../rule_registry/server'; +import { IRuleDataClient, RuleDataPluginService } from '../../../rule_registry/server'; import { ObservabilityRequestHandlerContext } from '../types'; import { AbstractObservabilityServerRouteRepository } from './types'; @@ -22,6 +22,7 @@ export function registerRoutes({ core, logger, ruleDataClient, + ruleDataService, }: { core: { setup: CoreSetup; @@ -30,6 +31,7 @@ export function registerRoutes({ repository: AbstractObservabilityServerRouteRepository; logger: Logger; ruleDataClient: IRuleDataClient; + ruleDataService: RuleDataPluginService; }) { const routes = repository.getRoutes(); @@ -63,6 +65,7 @@ export function registerRoutes({ logger, params: decodedParams, ruleDataClient, + ruleDataService, })) as any; return response.ok({ body: data }); diff --git a/x-pack/plugins/observability/server/routes/rules.ts b/x-pack/plugins/observability/server/routes/rules.ts index 6ca4dc58147f2..49f441ef74fca 100644 --- a/x-pack/plugins/observability/server/routes/rules.ts +++ b/x-pack/plugins/observability/server/routes/rules.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { observabilityFeatureId } from '../../common'; +import * as t from 'io-ts'; import { createObservabilityServerRoute } from './create_observability_server_route'; import { createObservabilityServerRouteRepository } from './create_observability_server_route_repository'; @@ -14,8 +14,20 @@ const alertsDynamicIndexPatternRoute = createObservabilityServerRoute({ options: { tags: [], }, - handler: async ({ ruleDataClient }) => { - const reader = ruleDataClient.getReader({ namespace: observabilityFeatureId }); + params: t.type({ + query: t.type({ + registrationContexts: t.array(t.string), + }), + }), + handler: async ({ ruleDataService, ruleDataClient, params }) => { + const { registrationContexts } = params.query; + + const indexNames = registrationContexts.map((registrationContext) => + ruleDataService.getBaseNameByRegistrationContext(registrationContext) + ); + const reader = ruleDataClient.getReader({ + indexNames: indexNames.filter((item: string | undefined): item is string => !!item), + }); return reader.getDynamicIndexPattern(); }, diff --git a/x-pack/plugins/observability/server/routes/types.ts b/x-pack/plugins/observability/server/routes/types.ts index 15a3274087d0e..034d6df9e030c 100644 --- a/x-pack/plugins/observability/server/routes/types.ts +++ b/x-pack/plugins/observability/server/routes/types.ts @@ -12,7 +12,7 @@ import type { ServerRouteRepository, } from '@kbn/server-route-repository'; import { CoreSetup, CoreStart, KibanaRequest, Logger } from 'kibana/server'; -import { IRuleDataClient } from '../../../rule_registry/server'; +import { IRuleDataClient, RuleDataPluginService } from '../../../rule_registry/server'; import { ObservabilityServerRouteRepository } from './get_global_observability_server_route_repository'; import { ObservabilityRequestHandlerContext } from '../types'; @@ -25,6 +25,7 @@ export interface ObservabilityRouteHandlerResources { setup: CoreSetup; }; ruleDataClient: IRuleDataClient; + ruleDataService: RuleDataPluginService; request: KibanaRequest; context: ObservabilityRequestHandlerContext; logger: Logger; 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 d2a8b914d10b6..090978949e2fd 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 @@ -650,6 +650,8 @@ export class AlertsClient { public async getAuthorizedAlertsIndices(featureIds: string[]): Promise { try { + // ATTENTION FUTURE DEVELOPER when you are a super user the augmentedRuleTypes.authorizedRuleTypes will + // return all of the features that you can access and does not care about your featureIds const augmentedRuleTypes = await this.authorization.getAugmentedRuleTypesWithAuthorization( featureIds, [ReadOperations.Find, ReadOperations.Get, WriteOperations.Update], @@ -665,7 +667,7 @@ export class AlertsClient { } const toReturn = Array.from(authorizedFeatures).flatMap((feature) => { - if (isValidFeatureId(feature)) { + if (featureIds.includes(feature) && isValidFeatureId(feature)) { if (feature === 'siem') { return `${mapConsumerToIndexName[feature]}-${this.spaceId}`; } else { diff --git a/x-pack/plugins/rule_registry/server/rule_data_client/rule_data_client.ts b/x-pack/plugins/rule_registry/server/rule_data_client/rule_data_client.ts index bbfa6abdd1a71..1816163331551 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_client/rule_data_client.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_client/rule_data_client.ts @@ -37,9 +37,13 @@ export class RuleDataClient implements IRuleDataClient { return this.options.isWriteEnabled; } - public getReader(options: { namespace?: string } = {}): IRuleDataReader { + public getReader(options: { namespace?: string; indexNames?: string[] } = {}): IRuleDataReader { const { indexInfo } = this.options; - const indexPattern = indexInfo.getPatternForReading(options.namespace); + const { namespace, indexNames } = options; + let indexPattern = indexInfo.getPatternForReading(namespace); + if (indexNames && indexNames.length > 0) { + indexPattern = indexNames.join(','); + } const waitUntilReady = async () => { const result = await this.options.waitUntilReadyForReading; diff --git a/x-pack/plugins/rule_registry/server/rule_data_client/types.ts b/x-pack/plugins/rule_registry/server/rule_data_client/types.ts index 979aa7e264848..d81afe7347ca3 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_client/types.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_client/types.ts @@ -15,7 +15,7 @@ import { TechnicalRuleDataFieldName } from '../../common/technical_rule_data_fie export interface IRuleDataClient { indexName: string; isWriteEnabled(): boolean; - getReader(options?: { namespace?: string }): IRuleDataReader; + getReader(options?: { namespace?: string; indexNames?: string[] }): IRuleDataReader; getWriter(options?: { namespace?: string }): IRuleDataWriter; } diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts index b95effd4801b9..3681fffbf9bd3 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts @@ -29,6 +29,7 @@ export class RuleDataPluginService { private readonly resourceInstaller: ResourceInstaller; private installCommonResources: Promise>; private isInitialized: boolean; + private registrationContextWithBaseName: Map; constructor(private readonly options: ConstructorOptions) { this.resourceInstaller = new ResourceInstaller({ @@ -40,6 +41,7 @@ export class RuleDataPluginService { this.installCommonResources = Promise.resolve(right('ok')); this.isInitialized = false; + this.registrationContextWithBaseName = new Map(); } /** @@ -105,6 +107,8 @@ export class RuleDataPluginService { indexOptions, }); + this.registrationContextWithBaseName.set(indexOptions.registrationContext, indexInfo.baseName); + const waitUntilClusterClientAvailable = async (): Promise => { try { const clusterClient = await this.options.getClusterClient(); @@ -148,4 +152,13 @@ export class RuleDataPluginService { waitUntilReadyForWriting, }); } + + /** + * Initializes alerts-as-data index and starts index bootstrapping right away. + * @param indexOptions Index parameters: names and resources. + * @returns Client for reading and writing data to this index. + */ + public getBaseNameByRegistrationContext(registrationContext: string): string | undefined { + return this.registrationContextWithBaseName.get(registrationContext); + } } diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/index.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/index.ts index bd70d989d97dd..40c6078fa5498 100644 --- a/x-pack/plugins/timelines/server/search_strategy/timeline/index.ts +++ b/x-pack/plugins/timelines/server/search_strategy/timeline/index.ts @@ -143,13 +143,7 @@ const timelineAlertsSearchStrategy = ({ }) => { // Based on what solution alerts you want to see, figures out what corresponding // index to query (ex: siem --> .alerts-security.alerts) - const indices = alertConsumers.flatMap((consumer) => { - if (consumer === CONSUMERS.SIEM) { - return request.defaultIndex ?? request.indexType; - } - - return `${mapConsumerToIndexName[consumer]}`; - }); + const indices = request.defaultIndex ?? request.indexType; const requestWithAlertsIndices = { ...request, defaultIndex: indices, indexName: indices }; // Note: Alerts RBAC are built off of the alerting's authorization class, which