Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SecuritySolution][Endpoint][ResponseActions] Response action telemetry (endpoint/third party) #192685

Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
58a6894
Add server side EBTs for response action creation
ashokaditya Sep 12, 2024
1ee1f5d
add server side EBTs for sentinel_one action responses
ashokaditya Sep 12, 2024
a9edf08
update saved object mapping
ashokaditya Sep 16, 2024
38b1081
update error event properties
ashokaditya Sep 16, 2024
9826a8f
tests
ashokaditya Sep 16, 2024
29fe070
refactor for readability
ashokaditya Sep 19, 2024
5657893
report agent type on action creation
ashokaditya Sep 19, 2024
e446815
use alertIds to distinguish automated action
ashokaditya Sep 19, 2024
0b9cd35
telemetry for automated response actions
ashokaditya Sep 19, 2024
e2ae275
update test
ashokaditya Sep 19, 2024
1fb865c
lint
ashokaditya Sep 20, 2024
8e6dcca
Merge branch 'main' into task/edr-workflows-response-actions-telemetr…
ashokaditya Sep 20, 2024
5af5b6d
Update response_actions.test.ts
ashokaditya Sep 20, 2024
c42379e
Merge branch 'main' into task/edr-workflows-response-actions-telemetr…
ashokaditya Sep 20, 2024
5b94027
send telemetry from actions client instead
ashokaditya Sep 20, 2024
c9b9aeb
fix error event reporting
ashokaditya Sep 23, 2024
9239235
Merge branch 'main' into task/edr-workflows-response-actions-telemetr…
ashokaditya Sep 23, 2024
2c9f58d
fix isAutomated check
ashokaditya Sep 23, 2024
7fc4a78
tests for base actions client
ashokaditya Sep 23, 2024
d7d5d70
Merge branch 'task/edr-workflows-response-actions-telemetry-v1-7466' …
ashokaditya Sep 23, 2024
21d8991
remove comments
ashokaditya Sep 23, 2024
25dbc39
use constructor options
ashokaditya Sep 23, 2024
bf81183
update tests
ashokaditya Sep 23, 2024
484a6b4
Merge branch 'main' into task/edr-workflows-response-actions-telemetr…
ashokaditya Sep 24, 2024
fb2de6f
Merge branch 'main' into task/edr-workflows-response-actions-telemetr…
ashokaditya Sep 25, 2024
1b5dfab
Merge branch 'main' into task/edr-workflows-response-actions-telemetr…
ashokaditya Sep 25, 2024
5f5b265
Merge branch 'main' into task/edr-workflows-response-actions-telemetr…
ashokaditya Sep 26, 2024
7f4f62b
redundant comment
ashokaditya Sep 26, 2024
9a49b94
update kill-process action to use helper method
ashokaditya Sep 26, 2024
ce127fb
Update sentinel_one_actions_client.ts
ashokaditya Sep 26, 2024
9cbbbb7
add tests for sentinel_one client
ashokaditya Sep 26, 2024
c6882df
Update experimental_features.ts
ashokaditya Sep 26, 2024
6fc895f
refactor feature flag check
ashokaditya Sep 26, 2024
3b5711c
Merge branch 'main' into task/edr-workflows-response-actions-telemetr…
ashokaditya Sep 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ export const allowedExperimentalValues = Object.freeze({
*/
crowdstrikeDataInAnalyzerEnabled: true,

/**
* Enables Response actions telemetry collection
* Should be enabled in 8.17.0
*/
responseActionsTelemetryEnabled: false,

/**
* Enables experimental JAMF integration data to be available in Analyzer
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ export const ExecuteActionResult = memo<
>(({ command, setStore, store, status, setStatus, ResultComponent }) => {
const actionCreator = useSendExecuteEndpoint();
const actionRequestBody = useMemo<undefined | ExecuteActionRequestBody>(() => {
const endpointId = command.commandDefinition?.meta?.endpointId;
const { endpointId, agentType } = command.commandDefinition?.meta ?? {};

if (!endpointId) {
return;
}
return {
agent_type: agentType,
endpoint_ids: [endpointId],
parameters: {
command: command.args.args.command[0],
Expand All @@ -46,7 +47,7 @@ export const ExecuteActionResult = memo<
comment: command.args.args?.comment?.[0],
};
}, [
command.commandDefinition?.meta?.endpointId,
command.commandDefinition?.meta,
command.args.args.command,
command.args.args.timeout,
command.args.args?.comment,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ export const GetFileActionResult = memo<
const actionCreator = useSendGetFileRequest();

const actionRequestBody = useMemo<undefined | ResponseActionGetFileRequestBody>(() => {
const endpointId = command.commandDefinition?.meta?.endpointId;
const { agentType, endpointId } = command.commandDefinition?.meta ?? {};
const { path, comment } = command.args.args;
const agentType = command.commandDefinition?.meta?.agentType;

return endpointId
? {
Expand All @@ -37,11 +36,7 @@ export const GetFileActionResult = memo<
},
}
: undefined;
}, [
command.args.args,
command.commandDefinition?.meta?.agentType,
command.commandDefinition?.meta?.endpointId,
]);
}, [command.args.args, command.commandDefinition?.meta]);

const { result, actionDetails } = useConsoleActionSubmitter<ResponseActionGetFileRequestBody>({
ResultComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ describe('When using execute action from response actions console', () => {

await waitFor(() => {
expect(apiMocks.responseProvider.execute).toHaveBeenCalledWith({
body: '{"endpoint_ids":["a.b.c"],"parameters":{"command":"ls -al"}}',
body: '{"agent_type":"endpoint","endpoint_ids":["a.b.c"],"parameters":{"command":"ls -al"}}',
path: EXECUTE_ROUTE,
version: '2023-10-31',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ export const IsolateActionResult = memo<ActionRequestComponentProps>(
const isolateHostApi = useSendIsolateEndpointRequest();

const actionRequestBody = useMemo(() => {
const endpointId = command.commandDefinition?.meta?.endpointId;
const { agentType, endpointId } = command.commandDefinition?.meta ?? {};
const comment = command.args.args?.comment?.[0];
const agentType = command.commandDefinition?.meta?.agentType;

return endpointId
? {
Expand All @@ -30,12 +29,7 @@ export const IsolateActionResult = memo<ActionRequestComponentProps>(
comment,
}
: undefined;
}, [
command.args.args?.comment,
command.commandDefinition?.meta?.agentType,
command.commandDefinition?.meta?.endpointId,
isSentinelOneV1Enabled,
]);
}, [command.args.args?.comment, command.commandDefinition?.meta, isSentinelOneV1Enabled]);

return useConsoleActionSubmitter({
ResultComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ export const KillProcessActionResult = memo<
const actionCreator = useSendKillProcessRequest();

const actionRequestBody = useMemo<undefined | KillProcessRequestBody>(() => {
const endpointId = command.commandDefinition?.meta?.endpointId;
const agentType = command.commandDefinition?.meta?.agentType;
const { endpointId, agentType } = command.commandDefinition?.meta ?? {};
const parameters = parsedKillOrSuspendParameter(command.args.args);

return endpointId
Expand All @@ -30,11 +29,7 @@ export const KillProcessActionResult = memo<
parameters,
}
: undefined;
}, [
command.args.args,
command.commandDefinition?.meta?.agentType,
command.commandDefinition?.meta?.endpointId,
]);
}, [command.args.args, command.commandDefinition?.meta]);

return useConsoleActionSubmitter<KillProcessRequestBody>({
ResultComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ export const ReleaseActionResult = memo<ActionRequestComponentProps>(
const releaseHostApi = useSendReleaseEndpointRequest();

const actionRequestBody = useMemo(() => {
const endpointId = command.commandDefinition?.meta?.endpointId;
const { endpointId, agentType } = command.commandDefinition?.meta ?? {};
const comment = command.args.args?.comment?.[0];
const agentType = command.commandDefinition?.meta?.agentType;

return endpointId
? {
Expand All @@ -30,12 +29,7 @@ export const ReleaseActionResult = memo<ActionRequestComponentProps>(
comment,
}
: undefined;
}, [
command.args.args?.comment,
command.commandDefinition?.meta?.agentType,
command.commandDefinition?.meta?.endpointId,
isSentinelOneV1Enabled,
]);
}, [command.args.args?.comment, command.commandDefinition?.meta, isSentinelOneV1Enabled]);

return useConsoleActionSubmitter({
ResultComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,20 @@ export const SuspendProcessActionResult = memo<
const actionCreator = useSendSuspendProcessRequest();

const actionRequestBody = useMemo<undefined | SuspendProcessRequestBody>(() => {
const endpointId = command.commandDefinition?.meta?.endpointId;
const { agentType, endpointId } = command.commandDefinition?.meta ?? {};
const parameters = parsedKillOrSuspendParameter(command.args.args) as
| ResponseActionParametersWithPid
| ResponseActionParametersWithEntityId;

return endpointId
? {
agent_type: agentType,
endpoint_ids: [endpointId],
comment: command.args.args?.comment?.[0],
parameters,
}
: undefined;
}, [command.args.args, command.commandDefinition?.meta?.endpointId]);
}, [command.args.args, command.commandDefinition?.meta]);

return useConsoleActionSubmitter<SuspendProcessRequestBody, SuspendProcessActionOutputContent>({
ResultComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ export const UploadActionResult = memo<
const actionCreator = useSendUploadEndpointRequest();

const actionRequestBody = useMemo<undefined | UploadActionUIRequestBody>(() => {
const endpointId = command.commandDefinition?.meta?.endpointId;
const { agentType, endpointId } = command.commandDefinition?.meta ?? {};
const { comment, overwrite, file } = command.args.args;

if (!endpointId) {
return;
}

const reqBody: UploadActionUIRequestBody = {
agent_type: agentType,
endpoint_ids: [endpointId],
...(comment?.[0] ? { comment: comment?.[0] } : {}),
parameters:
Expand All @@ -49,7 +50,7 @@ export const UploadActionResult = memo<
};

return reqBody;
}, [command.args.args, command.commandDefinition?.meta?.endpointId]);
}, [command.args.args, command.commandDefinition?.meta]);

const { result, actionDetails } = useConsoleActionSubmitter<
UploadActionUIRequestBody,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
{"attributes":{"allowHidden":false,"fieldAttrs":"{\"properties.model\":{},\"properties.resourceAccessed\":{},\"properties.resultCount\":{},\"properties.responseTime\":{},\"properties.errorMessage\":{},\"properties.isEnabledKnowledgeBase\":{},\"properties.isEnabledRAGAlerts\":{},\"properties.assistantStreamingEnabled\":{},\"properties.actionTypeId\":{},\"properties.message\":{},\"properties.productTier\":{},\"properties.failedToDeleteCount\":{},\"properties.totalInstalledCount\":{},\"properties.scoresWritten\":{},\"properties.taskDurationInSeconds\":{},\"properties.interval\":{},\"properties.alertSampleSizePerShard\":{},\"properties.status\":{},\"properties.processing.startTime\":{},\"properties.processing.endTime\":{},\"properties.processing.tookMs\":{},\"properties.result.successful\":{},\"properties.result.failed\":{},\"properties.result.total\":{},\"properties.alertsContextCount\":{},\"properties.alertsCount\":{},\"properties.configuredAlertsCount\":{},\"properties.discoveriesGenerated\":{},\"properties.durationMs\":{},\"properties.provider\":{},\"properties.total_tokens\":{},\"properties.prompt_tokens\":{},\"properties.completion_tokens\":{},\"properties.suppressionRuleType\":{},\"properties.suppressionMissingFields\":{},\"properties.suppressionAlertsCreated\":{},\"properties.suppressionAlertsSuppressed\":{},\"properties.suppressionRuleName\":{},\"properties.suppressionDuration\":{},\"properties.suppressionFieldsNumber\":{},\"properties.suppressionGroupByFieldsNumber\":{},\"properties.suppressionGroupByFields\":{},\"properties.suppressionRuleId\":{}}","fieldFormatMap":"{}","fields":"[]","name":"security-solution-ebt-kibana-server","runtimeFieldMap":"{\"properties.message\":{\"type\":\"keyword\"},\"properties.productTier\":{\"type\":\"keyword\"},\"properties.failedToDeleteCount\":{\"type\":\"long\"},\"properties.totalInstalledCount\":{\"type\":\"long\"},\"properties.model\":{\"type\":\"keyword\"},\"properties.resourceAccessed\":{\"type\":\"keyword\"},\"properties.resultCount\":{\"type\":\"long\"},\"properties.responseTime\":{\"type\":\"long\"},\"properties.errorMessage\":{\"type\":\"keyword\"},\"properties.isEnabledKnowledgeBase\":{\"type\":\"boolean\"},\"properties.isEnabledRAGAlerts\":{\"type\":\"boolean\"},\"properties.assistantStreamingEnabled\":{\"type\":\"boolean\"},\"properties.actionTypeId\":{\"type\":\"keyword\"},\"properties.alertsContextCount\":{\"type\":\"long\"},\"properties.alertsCount\":{\"type\":\"long\"},\"properties.configuredAlertsCount\":{\"type\":\"long\"},\"properties.discoveriesGenerated\":{\"type\":\"long\"},\"properties.durationMs\":{\"type\":\"long\"},\"properties.provider\":{\"type\":\"keyword\"},\"properties.scoresWritten\":{\"type\":\"long\"},\"properties.taskDurationInSeconds\":{\"type\":\"long\"},\"properties.interval\":{\"type\":\"keyword\"},\"properties.alertSampleSizePerShard\":{\"type\":\"long\"},\"properties.status\":{\"type\":\"keyword\"},\"properties.processing.startTime\":{\"type\":\"date\"},\"properties.processing.endTime\":{\"type\":\"date\"},\"properties.processing.tookMs\":{\"type\":\"long\"},\"properties.result.successful\":{\"type\":\"long\"},\"properties.result.failed\":{\"type\":\"long\"},\"properties.result.total\":{\"type\":\"long\"},\"properties.total_tokens\":{\"type\":\"long\"},\"properties.prompt_tokens\":{\"type\":\"long\"},\"properties.completion_tokens\":{\"type\":\"keyword\"},\"properties.suppressionMissingFields\":{\"type\":\"boolean\"},\"properties.suppressionAlertsCreated\":{\"type\":\"long\"},\"properties.suppressionAlertsSuppressed\":{\"type\":\"long\"},\"properties.suppressionRuleName\":{\"type\":\"keyword\"},\"properties.suppressionDuration\":{\"type\":\"long\"},\"properties.suppressionRuleType\":{\"type\":\"keyword\"},\"properties.suppressionGroupByFieldsNumber\":{\"type\":\"long\"},\"properties.suppressionGroupByFields\":{\"type\":\"keyword\"},\"properties.suppressionRuleId\":{\"type\":\"keyword\"}}","sourceFilters":"[]","timeFieldName":"timestamp","title":"ebt-kibana-server"},"coreMigrationVersion":"8.8.0","created_at":"2024-05-30T16:12:44.874Z","id":"security-solution-ebt-kibana-server","managed":false,"references":[],"type":"index-pattern","typeMigrationVersion":"8.0.0","updated_at":"2024-07-30T11:12:43.928Z","version":"WzM4ODczLDVd"}
{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]}
{"attributes":{"allowHidden":false,"fieldAttrs":"{\"properties.model\":{},\"properties.resourceAccessed\":{},\"properties.resultCount\":{},\"properties.responseTime\":{},\"properties.errorMessage\":{},\"properties.isEnabledKnowledgeBase\":{},\"properties.isEnabledRAGAlerts\":{},\"properties.assistantStreamingEnabled\":{},\"properties.actionTypeId\":{},\"properties.message\":{},\"properties.productTier\":{},\"properties.failedToDeleteCount\":{},\"properties.totalInstalledCount\":{},\"properties.scoresWritten\":{},\"properties.taskDurationInSeconds\":{},\"properties.interval\":{},\"properties.alertSampleSizePerShard\":{},\"properties.status\":{},\"properties.processing.startTime\":{},\"properties.processing.endTime\":{},\"properties.processing.tookMs\":{},\"properties.result.successful\":{},\"properties.result.failed\":{},\"properties.result.total\":{},\"properties.alertsContextCount\":{},\"properties.alertsCount\":{},\"properties.configuredAlertsCount\":{},\"properties.discoveriesGenerated\":{},\"properties.durationMs\":{},\"properties.provider\":{},\"properties.total_tokens\":{},\"properties.prompt_tokens\":{},\"properties.completion_tokens\":{},\"properties.suppressionRuleType\":{},\"properties.suppressionMissingFields\":{},\"properties.suppressionAlertsCreated\":{},\"properties.suppressionAlertsSuppressed\":{},\"properties.suppressionRuleName\":{},\"properties.suppressionDuration\":{},\"properties.suppressionFieldsNumber\":{},\"properties.suppressionGroupByFieldsNumber\":{},\"properties.suppressionGroupByFields\":{},\"properties.suppressionRuleId\":{},\"properties.responseActions.actionId\":{},\"properties.responseActions.agentType\":{},\"properties.responseActions.command\":{},\"properties.responseActions.endpointIds\":{},\"properties.responseActions.isAutomated\":{},\"properties.responseActions.actionStatus\":{}}","fieldFormatMap":"{}","fields":"[]","name":"security-solution-ebt-kibana-server","runtimeFieldMap":"{\"properties.message\":{\"type\":\"keyword\"},\"properties.productTier\":{\"type\":\"keyword\"},\"properties.failedToDeleteCount\":{\"type\":\"long\"},\"properties.totalInstalledCount\":{\"type\":\"long\"},\"properties.isEnabledKnowledgeBase\":{\"type\":\"boolean\"},\"properties.isEnabledRAGAlerts\":{\"type\":\"boolean\"},\"properties.total_tokens\":{\"type\":\"long\"},\"properties.prompt_tokens\":{\"type\":\"long\"},\"properties.completion_tokens\":{\"type\":\"keyword\"},\"properties.suppressionGroupByFields\":{\"type\":\"keyword\"},\"properties.model\":{\"type\":\"keyword\"},\"properties.resourceAccessed\":{\"type\":\"keyword\"},\"properties.resultCount\":{\"type\":\"long\"},\"properties.responseTime\":{\"type\":\"long\"},\"properties.errorMessage\":{\"type\":\"keyword\"},\"properties.assistantStreamingEnabled\":{\"type\":\"boolean\"},\"properties.actionTypeId\":{\"type\":\"keyword\"},\"properties.alertsContextCount\":{\"type\":\"long\"},\"properties.alertsCount\":{\"type\":\"long\"},\"properties.configuredAlertsCount\":{\"type\":\"long\"},\"properties.discoveriesGenerated\":{\"type\":\"long\"},\"properties.durationMs\":{\"type\":\"long\"},\"properties.provider\":{\"type\":\"keyword\"},\"properties.scoresWritten\":{\"type\":\"long\"},\"properties.taskDurationInSeconds\":{\"type\":\"long\"},\"properties.interval\":{\"type\":\"keyword\"},\"properties.alertSampleSizePerShard\":{\"type\":\"long\"},\"properties.status\":{\"type\":\"keyword\"},\"properties.processing.startTime\":{\"type\":\"date\"},\"properties.processing.endTime\":{\"type\":\"date\"},\"properties.processing.tookMs\":{\"type\":\"long\"},\"properties.result.successful\":{\"type\":\"long\"},\"properties.result.failed\":{\"type\":\"long\"},\"properties.result.total\":{\"type\":\"long\"},\"properties.suppressionAlertsCreated\":{\"type\":\"long\"},\"properties.suppressionAlertsSuppressed\":{\"type\":\"long\"},\"properties.suppressionRuleName\":{\"type\":\"keyword\"},\"properties.suppressionDuration\":{\"type\":\"long\"},\"properties.suppressionGroupByFieldsNumber\":{\"type\":\"long\"},\"properties.suppressionRuleType\":{\"type\":\"keyword\"},\"properties.suppressionMissingFields\":{\"type\":\"boolean\"},\"properties.suppressionRuleId\":{\"type\":\"keyword\"},\"properties.responseActions.actionId\":{\"type\":\"keyword\"},\"properties.responseActions.agentType\":{\"type\":\"keyword\"},\"properties.responseActions.command\":{\"type\":\"keyword\"},\"properties.responseActions.endpointIds\":{\"type\":\"keyword\"},\"properties.responseActions.isAutomated\":{\"type\":\"boolean\"},\"properties.responseActions.actionStatus\":{\"type\":\"keyword\"}}","sourceFilters":"[]","timeFieldName":"timestamp","title":"ebt-kibana-server"},"coreMigrationVersion":"8.8.0","created_at":"2024-05-30T16:12:44.874Z","id":"security-solution-ebt-kibana-server","managed":false,"references":[],"type":"index-pattern","typeMigrationVersion":"8.0.0","updated_at":"2024-09-16T11:22:09.683Z","version":"WzQ2MDU0LDdd"}
{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import type {
AnalyticsServiceSetup,
ElasticsearchClient,
KibanaRequest,
Logger,
Expand Down Expand Up @@ -58,6 +59,7 @@ export interface EndpointAppContextServiceSetupContract {
securitySolutionRequestContextFactory: IRequestContextFactory;
cloud: CloudSetup;
loggerFactory: LoggerFactory;
telemetry: AnalyticsServiceSetup;
}

export interface EndpointAppContextServiceStartContract {
Expand Down Expand Up @@ -339,4 +341,11 @@ export class EndpointAppContextService {

return this.startDependencies.createFleetActionsClient('endpoint');
}

public getTelemetryService(): AnalyticsServiceSetup {
if (!this.setupDependencies?.telemetry) {
throw new EndpointAppContentServicesNotSetUpError();
}
return this.setupDependencies.telemetry;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import type { ScopedClusterClientMock } from '@kbn/core/server/mocks';
import {
analyticsServiceMock,
elasticsearchServiceMock,
httpServerMock,
httpServiceMock,
Expand Down Expand Up @@ -128,6 +129,7 @@ export const createMockEndpointAppContextService = (
getExceptionListsClient: jest.fn(),
getMessageSigningService: jest.fn().mockReturnValue(messageSigningService),
getFleetActionsClient: jest.fn(async (_) => fleetActionsClientMock),
getTelemetryService: jest.fn(),
getInternalResponseActionsClient: jest.fn(() => {
return responseActionsClientMock.create();
}),
Expand All @@ -143,6 +145,7 @@ export const createMockEndpointAppContextServiceSetupContract =
securitySolutionRequestContextFactory: requestContextFactoryMock.create(),
cloud: cloudMock.createSetup(),
loggerFactory: loggingSystemMock.create(),
telemetry: analyticsServiceMock.createAnalyticsServiceSetup(),
};
};

Expand Down
Loading