### Summary We are integrating alert search strategy with RBAC on top of alert tables for security solution and o11y. Co-authored-by: Xavier Mouligneau <189600+XavierM@users.noreply.github.com>
This commit is contained in:
parent
1743212b9a
commit
b1117dce3c
|
@ -10816,7 +10816,7 @@
|
|||
"label": "alertConsumers",
|
||||
"description": [],
|
||||
"signature": [
|
||||
"ALERTS_CONSUMERS",
|
||||
"AlertConsumers",
|
||||
"[] | undefined"
|
||||
],
|
||||
"path": "x-pack/plugins/timelines/common/search_strategy/timeline/index.ts",
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* setting, with which the user can change the index prefix.
|
||||
*/
|
||||
|
||||
export const ALERTS_CONSUMERS = {
|
||||
export const AlertConsumers = {
|
||||
APM: 'apm',
|
||||
LOGS: 'logs',
|
||||
INFRASTRUCTURE: 'infrastructure',
|
||||
|
@ -23,9 +23,9 @@ export const ALERTS_CONSUMERS = {
|
|||
SIEM: 'siem',
|
||||
SYNTHETICS: 'synthetics',
|
||||
} as const;
|
||||
export type ALERTS_CONSUMERS = typeof ALERTS_CONSUMERS[keyof typeof ALERTS_CONSUMERS];
|
||||
export type AlertConsumers = typeof AlertConsumers[keyof typeof AlertConsumers];
|
||||
|
||||
export const mapConsumerToIndexName: Record<ALERTS_CONSUMERS, string | string[]> = {
|
||||
export const mapConsumerToIndexName: Record<AlertConsumers, string | string[]> = {
|
||||
apm: '.alerts-observability-apm',
|
||||
logs: '.alerts-observability.logs',
|
||||
infrastructure: '.alerts-observability.metrics',
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { AlertConsumers } from '@kbn/rule-data-utils/target/alerts_as_data_rbac';
|
||||
import { EuiButtonIcon, EuiDataGridColumn } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import styled from 'styled-components';
|
||||
|
@ -115,6 +116,13 @@ const NO_ROW_RENDER: RowRenderer[] = [];
|
|||
|
||||
const trailingControlColumns: never[] = [];
|
||||
|
||||
const OBSERVABILITY_ALERT_CONSUMERS = [
|
||||
AlertConsumers.APM,
|
||||
AlertConsumers.LOGS,
|
||||
AlertConsumers.INFRASTRUCTURE,
|
||||
AlertConsumers.SYNTHETICS,
|
||||
];
|
||||
|
||||
export function AlertsTableTGrid(props: AlertsTableTGridProps) {
|
||||
const { core, observabilityRuleTypeRegistry } = usePluginContext();
|
||||
const { prepend } = core.http.basePath;
|
||||
|
@ -190,6 +198,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) {
|
|||
</Suspense>
|
||||
)}
|
||||
{timelines.getTGrid<'standalone'>({
|
||||
alertConsumers: OBSERVABILITY_ALERT_CONSUMERS,
|
||||
type: 'standalone',
|
||||
columns,
|
||||
deletedEventIds: [],
|
||||
|
|
|
@ -17,7 +17,8 @@ export enum TimelineEventsQueries {
|
|||
lastEventTime = 'eventsLastEventTime',
|
||||
}
|
||||
|
||||
export enum EntityType {
|
||||
ALERTS = 'alerts',
|
||||
EVENTS = 'events',
|
||||
}
|
||||
export const EntityType = {
|
||||
ALERTS: 'alerts',
|
||||
EVENTS: 'events',
|
||||
} as const;
|
||||
export type EntityType = typeof EntityType[keyof typeof EntityType];
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import type { ALERTS_CONSUMERS } from '@kbn/rule-data-utils/target/alerts_as_data_rbac';
|
||||
import type { AlertConsumers } from '@kbn/rule-data-utils/target/alerts_as_data_rbac';
|
||||
|
||||
import { IEsSearchRequest } from '../../../../../../src/plugins/data/common';
|
||||
import { ESQuery } from '../../typed_json';
|
||||
|
@ -44,7 +44,7 @@ export interface TimelineRequestBasicOptions extends IEsSearchRequest {
|
|||
docValueFields?: DocValueFields[];
|
||||
factoryQueryType?: TimelineFactoryQueryTypes;
|
||||
entityType?: EntityType;
|
||||
alertConsumers?: ALERTS_CONSUMERS[];
|
||||
alertConsumers?: AlertConsumers[];
|
||||
}
|
||||
|
||||
export interface TimelineRequestSortField<Field = string> extends SortField<Field> {
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { AlertConsumers } from '@kbn/rule-data-utils/target/alerts_as_data_rbac';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui';
|
||||
import { isEmpty } from 'lodash/fp';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
|
@ -100,6 +102,8 @@ const HeaderFilterGroupWrapper = styled.header<{ show: boolean }>`
|
|||
${({ show }) => (show ? '' : 'visibility: hidden;')}
|
||||
`;
|
||||
|
||||
const SECURITY_ALERTS_CONSUMERS = [AlertConsumers.SIEM];
|
||||
|
||||
export interface TGridIntegratedProps {
|
||||
browserFields: BrowserFields;
|
||||
columns: ColumnHeaderOptions[];
|
||||
|
@ -237,6 +241,7 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
|
|||
loading,
|
||||
{ events, updatedAt, loadPage, pageInfo, refetch, totalCount = 0, inspect },
|
||||
] = useTimelineEvents({
|
||||
alertConsumers: SECURITY_ALERTS_CONSUMERS,
|
||||
docValueFields,
|
||||
fields,
|
||||
filterQuery: combinedQueries!.filterQuery,
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import type { AlertConsumers } from '@kbn/rule-data-utils/target/alerts_as_data_rbac';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui';
|
||||
import { isEmpty } from 'lodash/fp';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
|
@ -97,6 +98,7 @@ const HeaderFilterGroupWrapper = styled.header<{ show: boolean }>`
|
|||
`;
|
||||
|
||||
export interface TGridStandaloneProps {
|
||||
alertConsumers: AlertConsumers[];
|
||||
columns: ColumnHeaderOptions[];
|
||||
defaultCellActions?: TGridCellAction[];
|
||||
deletedEventIds: Readonly<string[]>;
|
||||
|
@ -127,6 +129,7 @@ export interface TGridStandaloneProps {
|
|||
const basicUnit = (n: number) => i18n.UNIT(n);
|
||||
|
||||
const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({
|
||||
alertConsumers,
|
||||
columns,
|
||||
defaultCellActions,
|
||||
deletedEventIds,
|
||||
|
@ -221,6 +224,7 @@ const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({
|
|||
loading,
|
||||
{ events, updatedAt, loadPage, pageInfo, refetch, totalCount = 0, inspect },
|
||||
] = useTimelineEvents({
|
||||
alertConsumers,
|
||||
docValueFields: [],
|
||||
excludeEcsData: true,
|
||||
fields,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { AlertConsumers } from '@kbn/rule-data-utils/target/alerts_as_data_rbac';
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
import { isEmpty, isString, noop } from 'lodash/fp';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
@ -80,6 +81,7 @@ export interface UseTimelineEventsProps {
|
|||
startDate: string;
|
||||
timerangeKind?: 'absolute' | 'relative';
|
||||
data?: DataPublicPluginStart;
|
||||
alertConsumers?: AlertConsumers[];
|
||||
}
|
||||
|
||||
const createFilter = (filterQuery: ESQuery | string | undefined) =>
|
||||
|
@ -106,7 +108,9 @@ export const initSortDefault = [
|
|||
},
|
||||
];
|
||||
|
||||
const NO_CONSUMERS: AlertConsumers[] = [];
|
||||
export const useTimelineEvents = ({
|
||||
alertConsumers = NO_CONSUMERS,
|
||||
docValueFields,
|
||||
endDate,
|
||||
excludeEcsData = false,
|
||||
|
@ -185,11 +189,16 @@ export const useTimelineEvents = ({
|
|||
setLoading(true);
|
||||
if (data && data.search) {
|
||||
searchSubscription$.current = data.search
|
||||
.search<TimelineRequest<typeof language>, TimelineResponse<typeof language>>(request, {
|
||||
strategy:
|
||||
request.language === 'eql' ? 'timelineEqlSearchStrategy' : 'timelineSearchStrategy',
|
||||
abortSignal: abortCtrl.current.signal,
|
||||
})
|
||||
.search<TimelineRequest<typeof language>, TimelineResponse<typeof language>>(
|
||||
{ ...request, entityType: 'alerts' },
|
||||
{
|
||||
strategy:
|
||||
request.language === 'eql'
|
||||
? 'timelineEqlSearchStrategy'
|
||||
: 'timelineSearchStrategy',
|
||||
abortSignal: abortCtrl.current.signal,
|
||||
}
|
||||
)
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
if (isCompleteResponse(response)) {
|
||||
|
@ -262,6 +271,7 @@ export const useTimelineEvents = ({
|
|||
: 0;
|
||||
|
||||
const currentRequest = {
|
||||
alertConsumers,
|
||||
defaultIndex: indexNames,
|
||||
docValueFields: docValueFields ?? [],
|
||||
excludeEcsData,
|
||||
|
@ -291,6 +301,7 @@ export const useTimelineEvents = ({
|
|||
return prevRequest;
|
||||
});
|
||||
}, [
|
||||
alertConsumers,
|
||||
dispatch,
|
||||
indexNames,
|
||||
activePage,
|
||||
|
|
|
@ -11,7 +11,7 @@ import { from } from 'rxjs';
|
|||
import {
|
||||
isValidFeatureId,
|
||||
mapConsumerToIndexName,
|
||||
ALERTS_CONSUMERS,
|
||||
AlertConsumers,
|
||||
} from '@kbn/rule-data-utils/target/alerts_as_data_rbac';
|
||||
|
||||
import {
|
||||
|
@ -125,7 +125,7 @@ const timelineAlertsSearchStrategy = <T extends TimelineFactoryQueryTypes>({
|
|||
deps: SearchStrategyDependencies;
|
||||
alerting: AlertingPluginStartContract;
|
||||
queryFactory: TimelineFactory<T>;
|
||||
alertConsumers: ALERTS_CONSUMERS[];
|
||||
alertConsumers: AlertConsumers[];
|
||||
}) => {
|
||||
// Based on what solution alerts you want to see, figures out what corresponding
|
||||
// index to query (ex: siem --> .alerts-security.alerts)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { AlertConsumers } from '@kbn/rule-data-utils/target/alerts_as_data_rbac';
|
||||
import { Router } from 'react-router-dom';
|
||||
import React, { useCallback, useRef } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
@ -37,6 +38,7 @@ export function renderApp(
|
|||
ReactDOM.unmountComponentAtNode(parameters.element);
|
||||
};
|
||||
}
|
||||
const ALERT_CONSUMER = [AlertConsumers.SIEM];
|
||||
|
||||
const AppRoot = React.memo(
|
||||
({
|
||||
|
@ -61,6 +63,7 @@ const AppRoot = React.memo(
|
|||
{(timelinesPluginSetup &&
|
||||
timelinesPluginSetup.getTGrid &&
|
||||
timelinesPluginSetup.getTGrid<'standalone'>({
|
||||
alertConsumers: ALERT_CONSUMER,
|
||||
type: 'standalone',
|
||||
columns: [],
|
||||
indexNames: [],
|
||||
|
|
Loading…
Reference in a new issue