[RAC] integrating rbac search strategy with alert table (#107242) (#107822)

### 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:
Kibana Machine 2021-08-05 23:31:47 -04:00 committed by GitHub
parent 1743212b9a
commit b1117dce3c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 50 additions and 17 deletions

View file

@ -10816,7 +10816,7 @@
"label": "alertConsumers",
"description": [],
"signature": [
"ALERTS_CONSUMERS",
"AlertConsumers",
"[] | undefined"
],
"path": "x-pack/plugins/timelines/common/search_strategy/timeline/index.ts",

View file

@ -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',

View file

@ -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: [],

View file

@ -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];

View file

@ -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> {

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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)

View file

@ -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: [],