mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Defend Workflows] Limit endpoint fields in the query in automated response actions (#158704)
This commit is contained in:
parent
0d6657f831
commit
1a70ede796
28 changed files with 245 additions and 76 deletions
|
@ -37,7 +37,7 @@ export const OsqueryResult = React.memo<OsqueryResultProps>(
|
|||
<AlertAttachmentContext.Provider value={ecsData}>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiComment
|
||||
username={ruleName && ruleName[0]}
|
||||
username={ruleName}
|
||||
timestamp={<FormattedRelative value={startDate} />}
|
||||
event={ATTACHED_QUERY}
|
||||
data-test-subj={'osquery-results-comment'}
|
||||
|
|
|
@ -40,7 +40,7 @@ const OsqueryResultComponent = React.memo<OsqueryActionResultProps>(
|
|||
return (
|
||||
<AlertAttachmentContext.Provider value={ecsData}>
|
||||
<EuiComment
|
||||
username={ruleName && ruleName[0]}
|
||||
username={ruleName}
|
||||
timestamp={<FormattedRelative value={startDate} />}
|
||||
event={ATTACHED_QUERY}
|
||||
data-test-subj={'osquery-results-comment'}
|
||||
|
|
|
@ -32,7 +32,7 @@ const enablePrivileges = () => {
|
|||
};
|
||||
|
||||
const defaultProps: OsqueryActionResultsProps = {
|
||||
ruleName: ['Test-rule'],
|
||||
ruleName: 'Test-rule',
|
||||
actionItems: [
|
||||
{
|
||||
_id: 'test',
|
||||
|
|
|
@ -9,13 +9,13 @@ import type { Ecs } from '@kbn/cases-plugin/common';
|
|||
import type { ActionEdges } from '../../../common/search_strategy';
|
||||
|
||||
export interface OsqueryActionResultsProps {
|
||||
ruleName?: string[];
|
||||
ruleName?: string;
|
||||
ecsData?: Ecs | null;
|
||||
actionItems?: ActionEdges;
|
||||
}
|
||||
|
||||
export interface OsqueryActionResultProps {
|
||||
ruleName?: string[];
|
||||
ruleName?: string;
|
||||
ecsData?: Ecs | null;
|
||||
actionId: string;
|
||||
startDate: string;
|
||||
|
|
|
@ -102,3 +102,4 @@ export const ENDPOINT_ERROR_CODES: Record<string, number> = {
|
|||
};
|
||||
|
||||
export const ENDPOINT_FIELDS_SEARCH_STRATEGY = 'endpointFields';
|
||||
export const ENDPOINT_SEARCH_STRATEGY = 'endpointSearchStrategy';
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { IEsSearchResponse } from '@kbn/data-plugin/common';
|
||||
import type { ActionResponsesRequestStrategyParseResponse } from './response_actions/response';
|
||||
import type {
|
||||
ResponseActionsQueries,
|
||||
ActionRequestOptions,
|
||||
ActionRequestStrategyResponse,
|
||||
ActionResponsesRequestOptions,
|
||||
ActionResponsesRequestStrategyResponse,
|
||||
} from './response_actions';
|
||||
|
||||
export type EndpointFactoryQueryTypes = ResponseActionsQueries;
|
||||
|
||||
export type EndpointStrategyParseResponseType<T extends EndpointFactoryQueryTypes> =
|
||||
T extends ResponseActionsQueries.results
|
||||
? ActionResponsesRequestStrategyParseResponse
|
||||
: IEsSearchResponse;
|
||||
|
||||
export type EndpointStrategyResponseType<T extends EndpointFactoryQueryTypes> =
|
||||
T extends ResponseActionsQueries.actions
|
||||
? ActionRequestStrategyResponse
|
||||
: T extends ResponseActionsQueries.results
|
||||
? ActionResponsesRequestStrategyResponse
|
||||
: never;
|
||||
|
||||
export type EndpointStrategyRequestType<T extends EndpointFactoryQueryTypes> =
|
||||
T extends ResponseActionsQueries.actions
|
||||
? ActionRequestOptions
|
||||
: T extends ResponseActionsQueries.results
|
||||
? ActionResponsesRequestOptions
|
||||
: never;
|
|
@ -4,8 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import type { IEsSearchRequest, IEsSearchResponse } from '@kbn/data-plugin/common';
|
||||
import type { ActionResponsesRequestStrategyParseResponse } from './response_actions/response';
|
||||
import type { IEsSearchRequest } from '@kbn/data-plugin/common';
|
||||
import type { ESQuery } from '../../typed_json';
|
||||
import type {
|
||||
HostDetailsStrategyResponse,
|
||||
|
@ -100,13 +99,6 @@ import type {
|
|||
FirstLastSeenRequestOptions,
|
||||
FirstLastSeenStrategyResponse,
|
||||
} from './first_last_seen';
|
||||
import type {
|
||||
ActionRequestOptions,
|
||||
ActionRequestStrategyResponse,
|
||||
ActionResponsesRequestOptions,
|
||||
ActionResponsesRequestStrategyResponse,
|
||||
ResponseActionsQueries,
|
||||
} from './response_actions';
|
||||
import type {
|
||||
ManagedUserDetailsRequestOptions,
|
||||
ManagedUserDetailsStrategyResponse,
|
||||
|
@ -140,8 +132,7 @@ export type FactoryQueryTypes =
|
|||
| CtiQueries
|
||||
| typeof MatrixHistogramQuery
|
||||
| typeof FirstLastSeenQuery
|
||||
| RelatedEntitiesQueries
|
||||
| ResponseActionsQueries;
|
||||
| RelatedEntitiesQueries;
|
||||
|
||||
export interface RequestBasicOptions extends IEsSearchRequest {
|
||||
timerange: TimerangeInput;
|
||||
|
@ -157,11 +148,6 @@ export interface RequestOptionsPaginated<Field = string> extends RequestBasicOpt
|
|||
sort: SortField<Field>;
|
||||
}
|
||||
|
||||
export type StrategyParseResponseType<T extends FactoryQueryTypes> =
|
||||
T extends ResponseActionsQueries.results
|
||||
? ActionResponsesRequestStrategyParseResponse
|
||||
: IEsSearchResponse;
|
||||
|
||||
export type StrategyResponseType<T extends FactoryQueryTypes> = T extends HostsQueries.hosts
|
||||
? HostsStrategyResponse
|
||||
: T extends HostsQueries.details
|
||||
|
@ -230,10 +216,6 @@ export type StrategyResponseType<T extends FactoryQueryTypes> = T extends HostsQ
|
|||
? HostsRelatedUsersStrategyResponse
|
||||
: T extends RelatedEntitiesQueries.relatedHosts
|
||||
? UsersRelatedHostsStrategyResponse
|
||||
: T extends ResponseActionsQueries.actions
|
||||
? ActionRequestStrategyResponse
|
||||
: T extends ResponseActionsQueries.results
|
||||
? ActionResponsesRequestStrategyResponse
|
||||
: never;
|
||||
|
||||
export type StrategyRequestType<T extends FactoryQueryTypes> = T extends HostsQueries.hosts
|
||||
|
@ -304,10 +286,6 @@ export type StrategyRequestType<T extends FactoryQueryTypes> = T extends HostsQu
|
|||
? UsersRelatedHostsRequestOptions
|
||||
: T extends RelatedEntitiesQueries.relatedUsers
|
||||
? HostsRelatedUsersRequestOptions
|
||||
: T extends ResponseActionsQueries.actions
|
||||
? ActionRequestOptions
|
||||
: T extends ResponseActionsQueries.results
|
||||
? ActionResponsesRequestOptions
|
||||
: never;
|
||||
|
||||
export interface CommonFields {
|
||||
|
|
|
@ -80,7 +80,7 @@ export const useOsqueryTab = ({
|
|||
|
||||
const actionItems = actionsData?.data.items || [];
|
||||
|
||||
const ruleName = expandedEventFieldsObject?.kibana?.alert?.rule?.name;
|
||||
const ruleName = expandedEventFieldsObject?.kibana?.alert?.rule?.name?.[0];
|
||||
|
||||
const content = (
|
||||
<TabContentWrapper data-test-subj="osqueryViewWrapper">
|
||||
|
|
|
@ -36,7 +36,6 @@ export const useResponseActionsView = <T extends object = JSX.Element>({
|
|||
rawEventData: SearchHit | undefined;
|
||||
}): EuiTabbedContentTab | undefined => {
|
||||
const responseActionsEnabled = useIsExperimentalFeatureEnabled('endpointResponseActionsEnabled');
|
||||
|
||||
const expandedEventFieldsObject = rawEventData
|
||||
? (expandDottedObject((rawEventData as RawEventData).fields) as ExpandedEventFieldsObject)
|
||||
: undefined;
|
||||
|
@ -58,7 +57,7 @@ export const useResponseActionsView = <T extends object = JSX.Element>({
|
|||
return;
|
||||
}
|
||||
|
||||
const ruleName = expandedEventFieldsObject?.kibana?.alert?.rule?.name;
|
||||
const ruleName = expandedEventFieldsObject?.kibana?.alert?.rule?.name?.[0];
|
||||
|
||||
const totalItemCount = automatedList?.items?.length ?? 0;
|
||||
|
||||
|
|
|
@ -18,10 +18,14 @@ import { ResponseActionsEmptyPrompt } from './response_actions_empty_prompt';
|
|||
|
||||
interface EndpointResponseActionResultsProps {
|
||||
action: LogsEndpointActionWithHosts;
|
||||
ruleName?: string;
|
||||
}
|
||||
|
||||
export const EndpointResponseActionResults = ({ action }: EndpointResponseActionResultsProps) => {
|
||||
const { rule, agent } = action;
|
||||
export const EndpointResponseActionResults = ({
|
||||
action,
|
||||
ruleName,
|
||||
}: EndpointResponseActionResultsProps) => {
|
||||
const { agent } = action;
|
||||
const { action_id: actionId, expiration } = action.EndpointActions;
|
||||
const {
|
||||
endpointPrivileges: { canAccessEndpointActionsLogManagement },
|
||||
|
@ -52,7 +56,7 @@ export const EndpointResponseActionResults = ({ action }: EndpointResponseAction
|
|||
|
||||
return (
|
||||
<EuiComment
|
||||
username={rule?.name}
|
||||
username={ruleName}
|
||||
timestamp={<FormattedRelative value={action['@timestamp']} />}
|
||||
event={eventText}
|
||||
data-test-subj={'endpoint-results-comment'}
|
||||
|
|
|
@ -18,7 +18,7 @@ import { useKibana } from '../../lib/kibana';
|
|||
|
||||
interface ResponseActionsResultsProps {
|
||||
actions: Array<LogsEndpointActionWithHosts | LogsOsqueryAction>;
|
||||
ruleName?: string[];
|
||||
ruleName?: string;
|
||||
ecsData?: Ecs | null;
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,11 @@ export const ResponseActionsResults = React.memo(
|
|||
}
|
||||
if (isEndpoint(action)) {
|
||||
return (
|
||||
<EndpointResponseActionResults action={action} key={action.EndpointActions.action_id} />
|
||||
<EndpointResponseActionResults
|
||||
action={action}
|
||||
ruleName={ruleName}
|
||||
key={action.EndpointActions.action_id}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -8,19 +8,20 @@
|
|||
import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
|
||||
import { compact, filter, map } from 'lodash';
|
||||
|
||||
import { ENDPOINT_SEARCH_STRATEGY } from '../../../../common/endpoint/constants';
|
||||
import { expandDottedObject } from '../../../../common/utils/expand_dotted';
|
||||
import type { ActionDetails, LogsEndpointActionWithHosts } from '../../../../common/endpoint/types';
|
||||
import type { ResponseActionsSearchHit } from '../../../../common/search_strategy/security_solution/response_actions/types';
|
||||
import { SortOrder } from '../../../../common/search_strategy/security_solution/response_actions/types';
|
||||
import type { ResponseActionsSearchHit } from '../../../../common/search_strategy/endpoint/response_actions/types';
|
||||
import { SortOrder } from '../../../../common/search_strategy/endpoint/response_actions/types';
|
||||
import { ResponseActionsQueries } from '../../../../common/search_strategy/endpoint/response_actions';
|
||||
import type {
|
||||
ActionResponsesRequestOptions,
|
||||
ActionRequestOptions,
|
||||
ActionRequestStrategyResponse,
|
||||
ActionResponsesRequestStrategyResponse,
|
||||
} from '../../../../common/search_strategy/security_solution/response_actions';
|
||||
import { ResponseActionsQueries } from '../../../../common/search_strategy/security_solution/response_actions';
|
||||
} from '../../../../common/search_strategy/endpoint/response_actions';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
import type {
|
||||
EndpointAutomatedActionListRequestQuery,
|
||||
|
@ -52,7 +53,7 @@ export const useGetAutomatedActionList = (
|
|||
factoryQueryType: ResponseActionsQueries.actions,
|
||||
},
|
||||
{
|
||||
strategy: 'securitySolutionSearchStrategy',
|
||||
strategy: ENDPOINT_SEARCH_STRATEGY,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
@ -115,7 +116,7 @@ export const useGetAutomatedActionResponseList = (
|
|||
factoryQueryType: ResponseActionsQueries.results,
|
||||
},
|
||||
{
|
||||
strategy: 'securitySolutionSearchStrategy',
|
||||
strategy: ENDPOINT_SEARCH_STRATEGY,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
|
|
@ -17,6 +17,7 @@ import { Dataset } from '@kbn/rule-registry-plugin/server';
|
|||
import type { ListPluginSetup } from '@kbn/lists-plugin/server';
|
||||
import type { ILicense } from '@kbn/licensing-plugin/server';
|
||||
|
||||
import { endpointSearchStrategyProvider } from './search_strategy/endpoint';
|
||||
import { getScheduleNotificationResponseActionsService } from './lib/detection_engine/rule_response_actions/schedule_notification_response_actions';
|
||||
import { siemGuideId, siemGuideConfig } from '../common/guided_onboarding/siem_guide_config';
|
||||
import {
|
||||
|
@ -88,7 +89,10 @@ import { actionCreateService } from './endpoint/services/actions';
|
|||
import { setIsElasticCloudDeployment } from './lib/telemetry/helpers';
|
||||
import { artifactService } from './lib/telemetry/artifact';
|
||||
import { endpointFieldsProvider } from './search_strategy/endpoint_fields';
|
||||
import { ENDPOINT_FIELDS_SEARCH_STRATEGY } from '../common/endpoint/constants';
|
||||
import {
|
||||
ENDPOINT_FIELDS_SEARCH_STRATEGY,
|
||||
ENDPOINT_SEARCH_STRATEGY,
|
||||
} from '../common/endpoint/constants';
|
||||
import { AppFeatures } from './lib/app_features';
|
||||
|
||||
export type { SetupPlugins, StartPlugins, PluginSetup, PluginStart } from './plugin_contract';
|
||||
|
@ -351,6 +355,12 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
'securitySolutionSearchStrategy',
|
||||
securitySolutionSearchStrategy
|
||||
);
|
||||
const endpointSearchStrategy = endpointSearchStrategyProvider(
|
||||
depsStart.data,
|
||||
this.endpointContext
|
||||
);
|
||||
|
||||
plugins.data.search.registerSearchStrategy(ENDPOINT_SEARCH_STRATEGY, endpointSearchStrategy);
|
||||
});
|
||||
|
||||
setIsElasticCloudDeployment(plugins.cloud.isCloudEnabled ?? false);
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { EndpointFactoryQueryTypes } from '../../../../common/search_strategy/endpoint';
|
||||
|
||||
import { responseActionsFactory } from './response_actions';
|
||||
import type { EndpointFactory } from './types';
|
||||
|
||||
export const endpointFactory: Record<
|
||||
EndpointFactoryQueryTypes,
|
||||
EndpointFactory<EndpointFactoryQueryTypes>
|
||||
> = {
|
||||
...responseActionsFactory,
|
||||
};
|
|
@ -6,26 +6,27 @@
|
|||
*/
|
||||
|
||||
import type { IEsSearchResponse } from '@kbn/data-plugin/common';
|
||||
import { inspectStringifyObject } from '../../../../../utils/build_query';
|
||||
|
||||
import { inspectStringifyObject } from '@kbn/osquery-plugin/common/utils/build_query';
|
||||
import { buildResponseActionsQuery } from './query.all_actions.dsl';
|
||||
import type { SecuritySolutionFactory } from '../../types';
|
||||
import type { EndpointFactory } from '../../types';
|
||||
import type {
|
||||
ActionRequestOptions,
|
||||
ActionRequestStrategyResponse,
|
||||
ResponseActionsQueries,
|
||||
} from '../../../../../../common/search_strategy/security_solution/response_actions';
|
||||
} from '../../../../../../common/search_strategy/endpoint/response_actions';
|
||||
|
||||
export const allActions: SecuritySolutionFactory<ResponseActionsQueries.actions> = {
|
||||
buildDsl: (options: ActionRequestOptions) => {
|
||||
return buildResponseActionsQuery(options);
|
||||
export const allActions: EndpointFactory<ResponseActionsQueries.actions> = {
|
||||
buildDsl: (options: ActionRequestOptions, { authz }) => {
|
||||
return buildResponseActionsQuery(options, authz);
|
||||
},
|
||||
parse: async (
|
||||
options: ActionRequestOptions,
|
||||
response: IEsSearchResponse
|
||||
response: IEsSearchResponse,
|
||||
deps
|
||||
): Promise<ActionRequestStrategyResponse> => {
|
||||
const inspect = {
|
||||
dsl: [inspectStringifyObject(buildResponseActionsQuery(options))],
|
||||
dsl: [inspectStringifyObject(buildResponseActionsQuery(options, deps.authz))],
|
||||
};
|
||||
|
||||
return {
|
|
@ -9,19 +9,31 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
|||
|
||||
import type { ISearchRequestParams } from '@kbn/data-plugin/common';
|
||||
import { OSQUERY_ACTIONS_INDEX } from '@kbn/osquery-plugin/common/constants';
|
||||
import type { ActionRequestOptions } from '../../../../../../common/search_strategy/security_solution/response_actions';
|
||||
import type { EndpointAuthz } from '../../../../../../common/endpoint/types/authz';
|
||||
import type { ActionRequestOptions } from '../../../../../../common/search_strategy/endpoint/response_actions';
|
||||
import { ENDPOINT_ACTIONS_INDEX } from '../../../../../../common/endpoint/constants';
|
||||
|
||||
export const buildResponseActionsQuery = ({
|
||||
alertIds,
|
||||
sort,
|
||||
}: ActionRequestOptions): ISearchRequestParams => {
|
||||
const EndpointFieldsLimited = [
|
||||
'EndpointActions.action_id',
|
||||
'EndpointActions.input_type',
|
||||
'EndpointActions.expiration',
|
||||
'EndpointActions.data.command',
|
||||
];
|
||||
|
||||
export const buildResponseActionsQuery = (
|
||||
{ alertIds, sort }: ActionRequestOptions,
|
||||
authz: EndpointAuthz | void
|
||||
): ISearchRequestParams => {
|
||||
const fields = authz?.canAccessEndpointActionsLogManagement
|
||||
? [{ field: '*' }, { field: 'EndpointActions.*', include_unmapped: true }]
|
||||
: ['@timestamp', 'action_id', 'input_type', ...EndpointFieldsLimited];
|
||||
|
||||
const dslQuery = {
|
||||
allow_no_indices: true,
|
||||
index: [ENDPOINT_ACTIONS_INDEX, OSQUERY_ACTIONS_INDEX],
|
||||
ignore_unavailable: true,
|
||||
body: {
|
||||
fields: [{ field: '*' }, { field: 'EndpointActions.*', include_unmapped: true }],
|
||||
fields,
|
||||
query: {
|
||||
bool: {
|
||||
minimum_should_match: 2,
|
|
@ -5,15 +5,15 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FactoryQueryTypes } from '../../../../../common/search_strategy';
|
||||
import { ResponseActionsQueries } from '../../../../../common/search_strategy/security_solution/response_actions';
|
||||
import type { SecuritySolutionFactory } from '../types';
|
||||
import { ResponseActionsQueries } from '../../../../../common/search_strategy/endpoint/response_actions';
|
||||
import { allActions } from './actions';
|
||||
import { actionResults } from './results';
|
||||
import type { EndpointFactory } from '../types';
|
||||
import type { EndpointFactoryQueryTypes } from '../../../../../common/search_strategy/endpoint';
|
||||
|
||||
export const responseActionsFactory: Record<
|
||||
ResponseActionsQueries,
|
||||
SecuritySolutionFactory<FactoryQueryTypes>
|
||||
EndpointFactory<EndpointFactoryQueryTypes>
|
||||
> = {
|
||||
[ResponseActionsQueries.actions]: allActions,
|
||||
[ResponseActionsQueries.results]: actionResults,
|
|
@ -10,12 +10,12 @@ import type {
|
|||
ActionResponsesRequestOptions,
|
||||
ActionResponsesRequestStrategyResponse,
|
||||
ResponseActionsQueries,
|
||||
} from '../../../../../../common/search_strategy/security_solution/response_actions';
|
||||
} from '../../../../../../common/search_strategy/endpoint/response_actions';
|
||||
|
||||
import { buildActionResultsQuery } from './query.action_results.dsl';
|
||||
import type { SecuritySolutionFactory } from '../../types';
|
||||
import type { EndpointFactory } from '../../types';
|
||||
|
||||
export const actionResults: SecuritySolutionFactory<ResponseActionsQueries.results> = {
|
||||
export const actionResults: EndpointFactory<ResponseActionsQueries.results> = {
|
||||
buildDsl: (options: ActionResponsesRequestOptions) => {
|
||||
return buildActionResultsQuery(options);
|
||||
},
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { ISearchRequestParams } from '@kbn/data-plugin/common';
|
||||
import type { ActionResponsesRequestOptions } from '../../../../../../common/search_strategy/security_solution/response_actions';
|
||||
import type { ActionResponsesRequestOptions } from '../../../../../../common/search_strategy/endpoint/response_actions';
|
||||
import { ENDPOINT_ACTION_RESPONSES_INDEX } from '../../../../../../common/endpoint/constants';
|
||||
|
||||
export const buildActionResultsQuery = ({
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { ISearchRequestParams } from '@kbn/data-plugin/common';
|
||||
import type {
|
||||
EndpointFactoryQueryTypes,
|
||||
EndpointStrategyParseResponseType,
|
||||
EndpointStrategyRequestType,
|
||||
EndpointStrategyResponseType,
|
||||
} from '../../../../common/search_strategy/endpoint';
|
||||
import type { EndpointAuthz } from '../../../../common/endpoint/types/authz';
|
||||
|
||||
export interface EndpointFactory<T extends EndpointFactoryQueryTypes> {
|
||||
buildDsl: (
|
||||
options: EndpointStrategyRequestType<T>,
|
||||
deps: {
|
||||
authz: EndpointAuthz | undefined;
|
||||
}
|
||||
) => ISearchRequestParams;
|
||||
parse: (
|
||||
options: EndpointStrategyRequestType<T>,
|
||||
response: EndpointStrategyParseResponseType<T>,
|
||||
deps: {
|
||||
authz: EndpointAuthz | undefined;
|
||||
}
|
||||
) => Promise<EndpointStrategyResponseType<T>>;
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { map, mergeMap } from 'rxjs/operators';
|
||||
import type { ISearchStrategy, PluginStart } from '@kbn/data-plugin/server';
|
||||
import { shimHitsTotal } from '@kbn/data-plugin/server';
|
||||
import { ENHANCED_ES_SEARCH_STRATEGY } from '@kbn/data-plugin/common';
|
||||
import { from } from 'rxjs';
|
||||
import type {
|
||||
EndpointStrategyParseResponseType,
|
||||
EndpointStrategyRequestType,
|
||||
EndpointStrategyResponseType,
|
||||
EndpointFactoryQueryTypes,
|
||||
} from '../../../common/search_strategy/endpoint';
|
||||
import type { EndpointFactory } from './factory/types';
|
||||
|
||||
import type { EndpointAppContext } from '../../endpoint/types';
|
||||
import { endpointFactory } from './factory';
|
||||
|
||||
function isObj(req: unknown): req is Record<string, unknown> {
|
||||
return typeof req === 'object' && req !== null;
|
||||
}
|
||||
|
||||
function assertValidRequestType<T extends EndpointFactoryQueryTypes>(
|
||||
req: unknown
|
||||
): asserts req is EndpointStrategyRequestType<T> & { factoryQueryType: EndpointFactoryQueryTypes } {
|
||||
if (!isObj(req) || req.factoryQueryType == null) {
|
||||
throw new Error('factoryQueryType is required');
|
||||
}
|
||||
}
|
||||
|
||||
export const endpointSearchStrategyProvider = <T extends EndpointFactoryQueryTypes>(
|
||||
data: PluginStart,
|
||||
endpointContext: EndpointAppContext
|
||||
): ISearchStrategy<EndpointStrategyRequestType<T>, EndpointStrategyResponseType<T>> => {
|
||||
const es = data.search.getSearchStrategy(
|
||||
ENHANCED_ES_SEARCH_STRATEGY
|
||||
) as unknown as ISearchStrategy<
|
||||
EndpointStrategyRequestType<T>,
|
||||
EndpointStrategyParseResponseType<T>
|
||||
>;
|
||||
|
||||
return {
|
||||
search: (request, options, deps) => {
|
||||
assertValidRequestType<T>(request);
|
||||
|
||||
return from(endpointContext.service.getEndpointAuthz(deps.request)).pipe(
|
||||
mergeMap((authz) => {
|
||||
const queryFactory: EndpointFactory<T> = endpointFactory[request.factoryQueryType];
|
||||
const dsl = queryFactory.buildDsl(request, { authz });
|
||||
return es.search({ ...request, params: dsl }, options, deps).pipe(
|
||||
map((response) => {
|
||||
return {
|
||||
...response,
|
||||
...{
|
||||
rawResponse: shimHitsTotal(response.rawResponse, options),
|
||||
},
|
||||
};
|
||||
}),
|
||||
mergeMap((esSearchRes) =>
|
||||
queryFactory.parse(request, esSearchRes, {
|
||||
authz,
|
||||
})
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
},
|
||||
cancel: async (id, options, deps) => {
|
||||
if (es.cancel) {
|
||||
return es.cancel(id, options, deps);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
|
@ -16,7 +16,6 @@ import { riskScoreFactory } from './risk_score';
|
|||
import { usersFactory } from './users';
|
||||
import { firstLastSeenFactory } from './last_first_seen';
|
||||
import { relatedEntitiesFactory } from './related_entities';
|
||||
import { responseActionsFactory } from './response_actions';
|
||||
|
||||
export const securitySolutionFactory: Record<
|
||||
FactoryQueryTypes,
|
||||
|
@ -30,5 +29,4 @@ export const securitySolutionFactory: Record<
|
|||
...riskScoreFactory,
|
||||
...firstLastSeenFactory,
|
||||
...relatedEntitiesFactory,
|
||||
...responseActionsFactory,
|
||||
};
|
||||
|
|
|
@ -10,13 +10,12 @@ import type {
|
|||
KibanaRequest,
|
||||
SavedObjectsClientContract,
|
||||
} from '@kbn/core/server';
|
||||
import type { ISearchRequestParams } from '@kbn/data-plugin/common';
|
||||
import type { IEsSearchResponse, ISearchRequestParams } from '@kbn/data-plugin/common';
|
||||
import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server';
|
||||
import type {
|
||||
FactoryQueryTypes,
|
||||
StrategyRequestType,
|
||||
StrategyResponseType,
|
||||
StrategyParseResponseType,
|
||||
} from '../../../../common/search_strategy/security_solution';
|
||||
import type { EndpointAppContext } from '../../../endpoint/types';
|
||||
|
||||
|
@ -24,7 +23,7 @@ export interface SecuritySolutionFactory<T extends FactoryQueryTypes> {
|
|||
buildDsl: (options: StrategyRequestType<T>) => ISearchRequestParams;
|
||||
parse: (
|
||||
options: StrategyRequestType<T>,
|
||||
response: StrategyParseResponseType<T>,
|
||||
response: IEsSearchResponse,
|
||||
deps?: {
|
||||
esClient: IScopedClusterClient;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
|
|
|
@ -15,7 +15,6 @@ import type {
|
|||
FactoryQueryTypes,
|
||||
StrategyResponseType,
|
||||
StrategyRequestType,
|
||||
StrategyParseResponseType,
|
||||
} from '../../../common/search_strategy/security_solution';
|
||||
import { securitySolutionFactory } from './factory';
|
||||
import type { SecuritySolutionFactory } from './factory/types';
|
||||
|
@ -38,9 +37,7 @@ export const securitySolutionSearchStrategyProvider = <T extends FactoryQueryTyp
|
|||
getSpaceId?: (request: KibanaRequest) => string,
|
||||
ruleDataClient?: IRuleDataClient | null
|
||||
): ISearchStrategy<StrategyRequestType<T>, StrategyResponseType<T>> => {
|
||||
const es = data.search.getSearchStrategy(
|
||||
ENHANCED_ES_SEARCH_STRATEGY
|
||||
) as unknown as ISearchStrategy<StrategyRequestType<T>, StrategyParseResponseType<T>>;
|
||||
const es = data.search.getSearchStrategy(ENHANCED_ES_SEARCH_STRATEGY);
|
||||
|
||||
return {
|
||||
search: (request, options, deps) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue