Skip to content

Commit

Permalink
[RAC] integrating rbac search strategy with alert table (#107242)
Browse files Browse the repository at this point in the history
### Summary

We are integrating alert search strategy with RBAC on top of alert tables for security solution and o11y.
  • Loading branch information
XavierM committed Aug 6, 2021
1 parent 28084f8 commit 923eca0
Show file tree
Hide file tree
Showing 10 changed files with 50 additions and 17 deletions.
2 changes: 1 addition & 1 deletion api_docs/timelines.json
Original file line number Diff line number Diff line change
Expand Up @@ -10918,7 +10918,7 @@
"label": "alertConsumers",
"description": [],
"signature": [
"ALERTS_CONSUMERS",
"AlertConsumers",
"[] | undefined"
],
"path": "x-pack/plugins/timelines/common/search_strategy/timeline/index.ts",
Expand Down
6 changes: 3 additions & 3 deletions packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@
* setting, with which the user can change the index prefix.
*/

export const ALERTS_CONSUMERS = {
export const AlertConsumers = {
APM: 'apm',
LOGS: 'logs',
INFRASTRUCTURE: 'infrastructure',
OBSERVABILITY: 'observability',
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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -190,6 +198,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) {
</Suspense>
)}
{timelines.getTGrid<'standalone'>({
alertConsumers: OBSERVABILITY_ALERT_CONSUMERS,
type: 'standalone',
columns,
deletedEventIds: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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[];
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -97,6 +98,7 @@ const HeaderFilterGroupWrapper = styled.header<{ show: boolean }>`
`;

export interface TGridStandaloneProps {
alertConsumers: AlertConsumers[];
columns: ColumnHeaderOptions[];
defaultCellActions?: TGridCellAction[];
deletedEventIds: Readonly<string[]>;
Expand Down Expand Up @@ -127,6 +129,7 @@ export interface TGridStandaloneProps {
const basicUnit = (n: number) => i18n.UNIT(n);

const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({
alertConsumers,
columns,
defaultCellActions,
deletedEventIds,
Expand Down Expand Up @@ -221,6 +224,7 @@ const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({
loading,
{ events, updatedAt, loadPage, pageInfo, refetch, totalCount = 0, inspect },
] = useTimelineEvents({
alertConsumers,
docValueFields: [],
excludeEcsData: true,
fields,
Expand Down
21 changes: 16 additions & 5 deletions x-pack/plugins/timelines/public/container/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -80,6 +81,7 @@ export interface UseTimelineEventsProps {
startDate: string;
timerangeKind?: 'absolute' | 'relative';
data?: DataPublicPluginStart;
alertConsumers?: AlertConsumers[];
}

const createFilter = (filterQuery: ESQuery | string | undefined) =>
Expand All @@ -106,7 +108,9 @@ export const initSortDefault = [
},
];

const NO_CONSUMERS: AlertConsumers[] = [];
export const useTimelineEvents = ({
alertConsumers = NO_CONSUMERS,
docValueFields,
endDate,
excludeEcsData = false,
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -262,6 +271,7 @@ export const useTimelineEvents = ({
: 0;

const currentRequest = {
alertConsumers,
defaultIndex: indexNames,
docValueFields: docValueFields ?? [],
excludeEcsData,
Expand Down Expand Up @@ -291,6 +301,7 @@ export const useTimelineEvents = ({
return prevRequest;
});
}, [
alertConsumers,
dispatch,
indexNames,
activePage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -37,6 +38,7 @@ export function renderApp(
ReactDOM.unmountComponentAtNode(parameters.element);
};
}
const ALERT_CONSUMER = [AlertConsumers.SIEM];

const AppRoot = React.memo(
({
Expand All @@ -61,6 +63,7 @@ const AppRoot = React.memo(
{(timelinesPluginSetup &&
timelinesPluginSetup.getTGrid &&
timelinesPluginSetup.getTGrid<'standalone'>({
alertConsumers: ALERT_CONSUMER,
type: 'standalone',
columns: [],
indexNames: [],
Expand Down

0 comments on commit 923eca0

Please sign in to comment.