Skip to content

Commit

Permalink
[Stack Connectors][Microsoft Defender] Adds new connector for Microso…
Browse files Browse the repository at this point in the history
…ft Defender for Endpoint (elastic#203183)

## Summary

- New connector for Microsoft Defender for Endpoint. To be used in
support of Security Solution Bi-Directional response actions.
  • Loading branch information
paul-tavares authored Jan 7, 2025
1 parent 1388cde commit b1957ae
Show file tree
Hide file tree
Showing 34 changed files with 1,953 additions and 15 deletions.
7 changes: 7 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -2343,8 +2343,15 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/
/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/sentinelone @elastic/security-defend-workflows
/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/sentinelone @elastic/security-defend-workflows
/x-pack/platform/plugins/shared/stack_connectors/common/sentinelone @elastic/security-defend-workflows
/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/sentinelone.ts @elastic/security-defend-workflows
/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/crowdstrike @elastic/security-defend-workflows
/x-pack/platform/plugins/shared/stack_connectors/common/crowdstrike @elastic/security-defend-workflows
/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/crowdstrike.ts @elastic/security-defend-workflows
/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/microsoft_defender_endpoint @elastic/security-defend-workflows
/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/microsoft_defender_endpoint @elastic/security-defend-workflows
/x-pack/platform/plugins/shared/stack_connectors/common/microsoft_defender_endpoint @elastic/security-defend-workflows
/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/microsoft_defender_endpoint.ts @elastic/security-defend-workflows


## Security Solution shared OAS schemas
/x-pack/solutions/security/plugins/security_solution/common/api/model @elastic/security-detection-rule-management @elastic/security-detection-engine
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const allowedExperimentalValues = Object.freeze({
crowdstrikeConnectorOn: true,
inferenceConnectorOn: false,
crowdstrikeConnectorRTROn: false,
microsoftDefenderEndpointOn: false,
});

export type ExperimentalConfigKeys = Array<keyof ExperimentalFeatures>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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.
*/

export const MICROSOFT_DEFENDER_ENDPOINT_TITLE = 'Microsoft Defender for Endpoint';
export const MICROSOFT_DEFENDER_ENDPOINT_CONNECTOR_ID = '.microsoft_defender_endpoint';

export enum MICROSOFT_DEFENDER_ENDPOINT_SUB_ACTION {
TEST_CONNECTOR = 'testConnector',
GET_AGENT_DETAILS = 'getAgentDetails',
ISOLATE_HOST = 'isolateHost',
RELEASE_HOST = 'releaseHost',
GET_ACTIONS = 'getActions',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* 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 { schema } from '@kbn/config-schema';
import { MICROSOFT_DEFENDER_ENDPOINT_SUB_ACTION } from './constants';

// ----------------------------------
// Connector setup schemas
// ----------------------------------
export const MicrosoftDefenderEndpointConfigSchema = schema.object({
clientId: schema.string({ minLength: 1 }),
tenantId: schema.string({ minLength: 1 }),
oAuthServerUrl: schema.string({ minLength: 1 }),
oAuthScope: schema.string({ minLength: 1 }),
apiUrl: schema.string({ minLength: 1 }),
});
export const MicrosoftDefenderEndpointSecretsSchema = schema.object({
clientSecret: schema.string({ minLength: 1 }),
});

// ----------------------------------
// Connector Methods
// ----------------------------------
export const MicrosoftDefenderEndpointDoNotValidateResponseSchema = schema.any();

export const MicrosoftDefenderEndpointBaseApiResponseSchema = schema.maybe(
schema.object({}, { unknowns: 'allow' })
);

export const TestConnectorParamsSchema = schema.object({});

export const AgentDetailsParamsSchema = schema.object({
id: schema.string({ minLength: 1 }),
});

export const IsolateHostParamsSchema = schema.object({
id: schema.string({ minLength: 1 }),
comment: schema.string({ minLength: 1 }),
});

export const ReleaseHostParamsSchema = schema.object({
id: schema.string({ minLength: 1 }),
comment: schema.string({ minLength: 1 }),
});

const MachineActionTypeSchema = schema.oneOf([
schema.literal('RunAntiVirusScan'),
schema.literal('Offboard'),
schema.literal('LiveResponse'),
schema.literal('CollectInvestigationPackage'),
schema.literal('Isolate'),
schema.literal('Unisolate'),
schema.literal('StopAndQuarantineFile'),
schema.literal('RestrictCodeExecution'),
schema.literal('UnrestrictCodeExecution'),
]);

const MachineActionStatusSchema = schema.oneOf([
schema.literal('Pending'),
schema.literal('InProgress'),
schema.literal('Succeeded'),
schema.literal('Failed'),
schema.literal('TimeOut'),
schema.literal('Cancelled'),
]);

export const GetActionsParamsSchema = schema.object({
id: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
status: schema.maybe(
schema.oneOf([
MachineActionStatusSchema,
schema.arrayOf(MachineActionStatusSchema, { minSize: 1 }),
])
),
machineId: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
type: schema.maybe(
schema.oneOf([MachineActionTypeSchema, schema.arrayOf(MachineActionTypeSchema, { minSize: 1 })])
),
requestor: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
creationDateTimeUtc: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
page: schema.maybe(schema.number({ min: 1, defaultValue: 1 })),
pageSize: schema.maybe(schema.number({ min: 1, max: 1000, defaultValue: 20 })),
});

// ----------------------------------
// Connector Sub-Actions
// ----------------------------------

const TestConnectorSchema = schema.object({
subAction: schema.literal(MICROSOFT_DEFENDER_ENDPOINT_SUB_ACTION.TEST_CONNECTOR),
subActionParams: TestConnectorParamsSchema,
});

const IsolateHostSchema = schema.object({
subAction: schema.literal(MICROSOFT_DEFENDER_ENDPOINT_SUB_ACTION.ISOLATE_HOST),
subActionParams: IsolateHostParamsSchema,
});

const ReleaseHostSchema = schema.object({
subAction: schema.literal(MICROSOFT_DEFENDER_ENDPOINT_SUB_ACTION.RELEASE_HOST),
subActionParams: ReleaseHostParamsSchema,
});

export const MicrosoftDefenderEndpointActionParamsSchema = schema.oneOf([
TestConnectorSchema,
IsolateHostSchema,
ReleaseHostSchema,
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
* 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 { TypeOf } from '@kbn/config-schema';

import {
MicrosoftDefenderEndpointSecretsSchema,
MicrosoftDefenderEndpointConfigSchema,
MicrosoftDefenderEndpointActionParamsSchema,
MicrosoftDefenderEndpointBaseApiResponseSchema,
IsolateHostParamsSchema,
ReleaseHostParamsSchema,
TestConnectorParamsSchema,
AgentDetailsParamsSchema,
GetActionsParamsSchema,
} from './schema';

export type MicrosoftDefenderEndpointConfig = TypeOf<typeof MicrosoftDefenderEndpointConfigSchema>;

export type MicrosoftDefenderEndpointSecrets = TypeOf<
typeof MicrosoftDefenderEndpointSecretsSchema
>;

export type MicrosoftDefenderEndpointBaseApiResponse = TypeOf<
typeof MicrosoftDefenderEndpointBaseApiResponseSchema
>;

export interface MicrosoftDefenderEndpointTestConnector {
results: string[];
}

export type MicrosoftDefenderEndpointAgentDetailsParams = TypeOf<typeof AgentDetailsParamsSchema>;

export type MicrosoftDefenderEndpointGetActionsParams = TypeOf<typeof GetActionsParamsSchema>;

export interface MicrosoftDefenderEndpointGetActionsResponse {
'@odata.context': string;
'@odata.count'?: number;
/** If value is `-1`, then API did not provide a total count */
total: number;
page: number;
pageSize: number;
value: MicrosoftDefenderEndpointMachineAction[];
}

/**
* @see https://learn.microsoft.com/en-us/defender-endpoint/api/machine
*/
export interface MicrosoftDefenderEndpointMachine {
/** machine identity. */
id: string;
/** machine fully qualified name. */
computerDnsName: string;
/** First date and time where the machine was observed by Microsoft Defender for Endpoint. */
firstSeen: string;
/** Time and date of the last received full device report. A device typically sends a full report every 24 hours. NOTE: This property doesn't correspond to the last seen value in the UI. It pertains to the last device update. */
lastSeen: string;
/** Operating system platform. */
osPlatform: string;
/** Status of machine onboarding. Possible values are: onboarded, CanBeOnboarded, Unsupported, and InsufficientInfo. */
onboardingstatus: string;
/** Operating system processor. Use osArchitecture property instead. */
osProcessor: string;
/** Operating system Version. */
version: string;
/** Operating system build number. */
osBuild?: number;
/** Last IP on local NIC on the machine. */
lastIpAddress: string;
/** Last IP through which the machine accessed the internet. */
lastExternalIpAddress: string;
/** machine health status. Possible values are: Active, Inactive, ImpairedCommunication, NoSensorData, NoSensorDataImpairedCommunication, and Unknown. */
healthStatus:
| 'Active'
| 'Inactive'
| 'ImpairedCommunication'
| 'NoSensorData'
| 'NoSensorDataImpairedCommunication'
| 'Unknown';
/** Machine group Name. */
rbacGroupName: string;
/** Machine group ID. */
rbacGroupId: string;
/** Risk score as evaluated by Microsoft Defender for Endpoint. Possible values are: None, Informational, Low, Medium, and High. */
riskScore?: 'None' | 'Informational' | 'Low' | 'Medium' | 'High';
/** Microsoft Entra Device ID (when machine is Microsoft Entra joined). */
aadDeviceId?: string;
/** Set of machine tags. */
machineTags: string[];
/** Exposure level as evaluated by Microsoft Defender for Endpoint. Possible values are: None, Low, Medium, and High. */
exposureLevel?: 'None' | 'Low' | 'Medium' | 'High';
/** The value of the device. Possible values are: Normal, Low, and High. */
deviceValue?: 'Normal' | 'Low' | 'High';
/** Set of IpAddress objects. See Get machines API. */
ipAddresses: Array<{
ipAddress: string;
macAddress: string;
type: string;
operationalStatus: string;
}>;
/** Operating system architecture. Possible values are: 32-bit, 64-bit. Use this property instead of osProcessor. */
osArchitecture: string;
}

/**
* @see https://learn.microsoft.com/en-us/defender-endpoint/api/machineaction
*/
export interface MicrosoftDefenderEndpointMachineAction {
/** Identity of the Machine Action entity. */
id: string;
/** Type of the action. Possible values are: RunAntiVirusScan, Offboard, LiveResponse, CollectInvestigationPackage, Isolate, Unisolate, StopAndQuarantineFile, RestrictCodeExecution, and UnrestrictCodeExecution. */
type:
| 'RunAntiVirusScan'
| 'Offboard'
| 'LiveResponse'
| 'CollectInvestigationPackage'
| 'Isolate'
| 'Unisolate'
| 'StopAndQuarantineFile'
| 'RestrictCodeExecution'
| 'UnrestrictCodeExecution';
/** Scope of the action. Full or Selective for Isolation, Quick or Full for antivirus scan. */
scope?: string;
/** Identity of the person that executed the action. */
requestor: string;
/** Id the customer can submit in the request for custom correlation. */
externalID?: string;
/** The name of the user/application that submitted the action. */
requestSource: string;
/** Commands to run. Allowed values are PutFile, RunScript, GetFile. */
commands: Array<'PutFile' | 'RunScript' | 'GetFile'>;
/** Identity of the person that canceled the action. */
cancellationRequestor: string;
/** Comment that was written when issuing the action. */
requestorComment: string;
/** Comment that was written when canceling the action. */
cancellationComment: string;
/** Current status of the command. Possible values are: Pending, InProgress, Succeeded, Failed, TimeOut, and Cancelled. */
status: 'Pending' | 'InProgress' | 'Succeeded' | 'Failed' | 'TimeOut' | 'Cancelled';
/** ID of the machine on which the action was executed. */
machineId: string;
/** Name of the machine on which the action was executed. */
computerDnsName: string;
/** The date and time when the action was created. */
creationDateTimeUtc: string;
/** The date and time when the action was canceled. */
cancellationDateTimeUtc: string;
/** The last date and time when the action status was updated. */
lastUpdateDateTimeUtc: string;
/** Machine action title. */
title: string;
/** Contains two Properties. string fileIdentifier, Enum fileIdentifierType with the possible values: Sha1, Sha256, and Md5. */
relatedFileInfo?: { fileIdentifier: string; fileIdentifierType: 'Sha1' | 'Sha256' | 'Md5' };
errorResult?: number;
troubleshootInfo?: string;
}

export type MicrosoftDefenderEndpointTestConnectorParams = TypeOf<typeof TestConnectorParamsSchema>;

export type MicrosoftDefenderEndpointIsolateHostParams = TypeOf<typeof IsolateHostParamsSchema>;

export type MicrosoftDefenderEndpointReleaseHostParams = TypeOf<typeof ReleaseHostParamsSchema>;

export type MicrosoftDefenderEndpointActionParams = TypeOf<
typeof MicrosoftDefenderEndpointActionParamsSchema
>;

export interface MicrosoftDefenderEndpointApiTokenResponse {
token_type: 'bearer';
/** The amount of time that an access token is valid (in seconds NOT milliseconds). */
expires_in: number;
access_token: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ export { CrowdstrikeLogo };

export { BEDROCK_CONNECTOR_ID } from '../../common/bedrock/constants';
export { BedrockLogo };

export { MicrosoftDefenderEndpointLogo } from '../connector_types/microsoft_defender_endpoint/logo';
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { ValidatedEmail, ValidateEmailAddressesOptions } from '@kbn/actions-plugin/common';
import { TriggersAndActionsUIPublicPluginSetup } from '@kbn/triggers-actions-ui-plugin/public';
import { getMicrosoftDefenderEndpointConnectorType } from './microsoft_defender_endpoint';
import { getCasesWebhookConnectorType } from './cases_webhook';
import { getEmailConnectorType } from './email';
import { getIndexConnectorType } from './es_index';
Expand Down Expand Up @@ -84,4 +85,7 @@ export function registerConnectorTypes({
if (ExperimentalFeaturesService.get().inferenceConnectorOn) {
connectorTypeRegistry.register(getInferenceConnectorType());
}
if (ExperimentalFeaturesService.get().microsoftDefenderEndpointOn) {
connectorTypeRegistry.register(getMicrosoftDefenderEndpointConnectorType());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* 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.
*/

export { getConnectorType as getMicrosoftDefenderEndpointConnectorType } from './microsoft_defender_endpoint';
Loading

0 comments on commit b1957ae

Please sign in to comment.