From db696c91c2405e916380e0264323bae7b5e3b602 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Thu, 21 Oct 2021 17:05:28 -0400 Subject: [PATCH 1/3] Add `.catch()` statement to ES calls in order to get better stacktraces --- .../server/endpoint/routes/metadata/handlers.ts | 6 ++++-- .../security_solution/factory/hosts/details/helpers.ts | 10 ++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts index e98cdc4f11404..028850d4f2afc 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts @@ -41,7 +41,7 @@ import { findAllUnenrolledAgentIds } from './support/unenroll'; import { getAllEndpointPackagePolicies } from './support/endpoint_package_policies'; import { findAgentIdsByStatus } from './support/agent_status'; import { EndpointAppContextService } from '../../endpoint_app_context_services'; -import { fleetAgentStatusToEndpointHostStatus } from '../../utils'; +import { catchAndWrapError, fleetAgentStatusToEndpointHostStatus } from '../../utils'; import { queryResponseToHostListResult, queryResponseToHostResult, @@ -194,7 +194,9 @@ export async function getHostMetaData( const query = getESQueryHostMetadataByID(id); - const response = await esClient.asCurrentUser.search(query); + const response = await esClient.asCurrentUser + .search(query) + .catch(catchAndWrapError); const hostResult = queryResponseToHostResult(response.body); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts index ae68d81d6b922..a55bcd06f2eb3 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts @@ -24,7 +24,10 @@ import { import { toObjectArrayOfStrings } from '../../../../../../common/utils/to_array'; import { getHostMetaData } from '../../../../../endpoint/routes/metadata/handlers'; import { EndpointAppContext } from '../../../../../endpoint/types'; -import { fleetAgentStatusToEndpointHostStatus } from '../../../../../endpoint/utils'; +import { + catchAndWrapError, + fleetAgentStatusToEndpointHostStatus, +} from '../../../../../endpoint/utils'; import { getPendingActionCounts } from '../../../../../endpoint/services'; export const HOST_FIELDS = [ @@ -207,7 +210,10 @@ export const getHostEndpoint = async ( ? [undefined, {}] : await Promise.all([ // Get Agent Status - agentService.getAgentStatusById(esClient.asCurrentUser, fleetAgentId), + agentService + .getAgentStatusById(esClient.asCurrentUser, fleetAgentId) + .catch(catchAndWrapError), + // Get a list of pending actions (if any) getPendingActionCounts( esClient.asCurrentUser, From b6d81103e573b5b9f85b6d12f4188e343c375810 Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Thu, 21 Oct 2021 17:18:51 -0400 Subject: [PATCH 2/3] Improve efficiency of getHostEndpoint() search strategy method --- .../factory/hosts/details/helpers.ts | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts index a55bcd06f2eb3..154e773977b32 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts @@ -29,6 +29,7 @@ import { fleetAgentStatusToEndpointHostStatus, } from '../../../../../endpoint/utils'; import { getPendingActionCounts } from '../../../../../endpoint/services'; +import { EndpointError } from '../../../../../endpoint/errors'; export const HOST_FIELDS = [ '_id', @@ -187,25 +188,34 @@ export const getHostEndpoint = async ( endpointContext: EndpointAppContext; } ): Promise => { + if (!id) { + return null; + } + const { esClient, endpointContext, savedObjectsClient } = deps; const logger = endpointContext.logFactory.get('metadata'); + try { const agentService = endpointContext.service.getAgentService(); - if (agentService === undefined) { + + if (!agentService) { throw new Error('agentService not available'); } + const metadataRequestContext = { esClient, endpointAppContextService: endpointContext.service, logger, savedObjectsClient, }; - const endpointData = - id != null && metadataRequestContext.endpointAppContextService.getAgentService() != null - ? await getHostMetaData(metadataRequestContext, id) - : null; - const fleetAgentId = endpointData?.elastic.agent.id; + const endpointData = await getHostMetaData(metadataRequestContext, id); + + if (!endpointData) { + throw new EndpointError(`Unable to retrieve endpoint with id ${id}`); + } + + const fleetAgentId = endpointData.elastic.agent.id; const [fleetAgentStatus, pendingActions] = !fleetAgentId ? [undefined, {}] : await Promise.all([ @@ -224,17 +234,15 @@ export const getHostEndpoint = async ( }), ]); - return endpointData != null && endpointData - ? { - endpointPolicy: endpointData.Endpoint.policy.applied.name, - policyStatus: endpointData.Endpoint.policy.applied.status, - sensorVersion: endpointData.agent.version, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - elasticAgentStatus: fleetAgentStatusToEndpointHostStatus(fleetAgentStatus!), - isolation: endpointData.Endpoint.state?.isolation ?? false, - pendingActions, - } - : null; + return { + endpointPolicy: endpointData.Endpoint.policy.applied.name, + policyStatus: endpointData.Endpoint.policy.applied.status, + sensorVersion: endpointData.agent.version, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + elasticAgentStatus: fleetAgentStatusToEndpointHostStatus(fleetAgentStatus!), + isolation: endpointData.Endpoint.state?.isolation ?? false, + pendingActions, + }; } catch (err) { logger.warn(err); return null; From 62a9811f961559ea63a4bbd2c89d21770e4ba0da Mon Sep 17 00:00:00 2001 From: Paul Tavares Date: Mon, 25 Oct 2021 12:45:40 -0400 Subject: [PATCH 3/3] Refactor `getHostEndpoint()` to use new Metadata service as well as the internal kibana ES client --- .../factory/hosts/details/helpers.ts | 73 ++++++++----------- 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts index 154e773977b32..fbc51aa0360ce 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts @@ -22,14 +22,8 @@ import { HostValue, } from '../../../../../../common/search_strategy/security_solution/hosts'; import { toObjectArrayOfStrings } from '../../../../../../common/utils/to_array'; -import { getHostMetaData } from '../../../../../endpoint/routes/metadata/handlers'; import { EndpointAppContext } from '../../../../../endpoint/types'; -import { - catchAndWrapError, - fleetAgentStatusToEndpointHostStatus, -} from '../../../../../endpoint/utils'; import { getPendingActionCounts } from '../../../../../endpoint/services'; -import { EndpointError } from '../../../../../endpoint/errors'; export const HOST_FIELDS = [ '_id', @@ -192,7 +186,7 @@ export const getHostEndpoint = async ( return null; } - const { esClient, endpointContext, savedObjectsClient } = deps; + const { esClient, endpointContext } = deps; const logger = endpointContext.logFactory.get('metadata'); try { @@ -202,45 +196,38 @@ export const getHostEndpoint = async ( throw new Error('agentService not available'); } - const metadataRequestContext = { - esClient, - endpointAppContextService: endpointContext.service, - logger, - savedObjectsClient, - }; - - const endpointData = await getHostMetaData(metadataRequestContext, id); - - if (!endpointData) { - throw new EndpointError(`Unable to retrieve endpoint with id ${id}`); - } - - const fleetAgentId = endpointData.elastic.agent.id; - const [fleetAgentStatus, pendingActions] = !fleetAgentId - ? [undefined, {}] - : await Promise.all([ - // Get Agent Status - agentService - .getAgentStatusById(esClient.asCurrentUser, fleetAgentId) - .catch(catchAndWrapError), - - // Get a list of pending actions (if any) - getPendingActionCounts( - esClient.asCurrentUser, - endpointContext.service.getEndpointMetadataService(), - [fleetAgentId] - ).then((results) => { + const endpointData = await endpointContext.service + .getEndpointMetadataService() + // Using `internalUser` ES client below due to the fact that Fleet data has been moved to + // system indices (`.fleet*`). Because this is a readonly action, this should be ok to do + // here until proper RBOC controls are implemented + .getEnrichedHostMetadata(esClient.asInternalUser, id); + + const fleetAgentId = endpointData.metadata.elastic.agent.id; + + const pendingActions = fleetAgentId + ? getPendingActionCounts( + esClient.asInternalUser, + endpointContext.service.getEndpointMetadataService(), + [fleetAgentId] + ) + .then((results) => { return results[0].pending_actions; - }), - ]); + }) + .catch((error) => { + // Failure in retrieving the number of pending actions should not fail the entire + // call to get endpoint details. Log the error and return an empty object + logger.warn(error); + return {}; + }) + : {}; return { - endpointPolicy: endpointData.Endpoint.policy.applied.name, - policyStatus: endpointData.Endpoint.policy.applied.status, - sensorVersion: endpointData.agent.version, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - elasticAgentStatus: fleetAgentStatusToEndpointHostStatus(fleetAgentStatus!), - isolation: endpointData.Endpoint.state?.isolation ?? false, + endpointPolicy: endpointData.metadata.Endpoint.policy.applied.name, + policyStatus: endpointData.metadata.Endpoint.policy.applied.status, + sensorVersion: endpointData.metadata.agent.version, + elasticAgentStatus: endpointData.host_status, + isolation: endpointData.metadata.Endpoint.state?.isolation ?? false, pendingActions, }; } catch (err) {