mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Security_Solution][Telemetry] - Update endpoint usage to use agentService (#93829)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
95271bf798
commit
ebd92a6e5d
8 changed files with 165 additions and 143 deletions
|
@ -162,19 +162,20 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
|
|||
|
||||
initSavedObjects(core.savedObjects);
|
||||
initUiSettings(core.uiSettings);
|
||||
initUsageCollectors({
|
||||
core,
|
||||
kibanaIndex: globalConfig.kibana.index,
|
||||
ml: plugins.ml,
|
||||
usageCollection: plugins.usageCollection,
|
||||
});
|
||||
|
||||
const endpointContext: EndpointAppContext = {
|
||||
logFactory: this.context.logger,
|
||||
service: this.endpointAppContextService,
|
||||
config: (): Promise<ConfigType> => Promise.resolve(config),
|
||||
};
|
||||
|
||||
initUsageCollectors({
|
||||
core,
|
||||
endpointAppContext: endpointContext,
|
||||
kibanaIndex: globalConfig.kibana.index,
|
||||
ml: plugins.ml,
|
||||
usageCollection: plugins.usageCollection,
|
||||
});
|
||||
|
||||
const router = core.http.createRouter<SecuritySolutionRequestHandlerContext>();
|
||||
core.http.registerRouteHandlerContext<SecuritySolutionRequestHandlerContext, typeof APP_ID>(
|
||||
APP_ID,
|
||||
|
|
|
@ -31,6 +31,7 @@ export async function getInternalSavedObjectsClient(core: CoreSetup) {
|
|||
|
||||
export const registerCollector: RegisterCollector = ({
|
||||
core,
|
||||
endpointAppContext,
|
||||
kibanaIndex,
|
||||
ml,
|
||||
usageCollection,
|
||||
|
@ -138,7 +139,7 @@ export const registerCollector: RegisterCollector = ({
|
|||
const [detections, detectionMetrics, endpoints] = await Promise.allSettled([
|
||||
fetchDetectionsUsage(kibanaIndex, esClient, ml, savedObjectsClient),
|
||||
fetchDetectionsMetrics(ml, savedObjectsClient),
|
||||
getEndpointTelemetryFromFleet(internalSavedObjectsClient),
|
||||
getEndpointTelemetryFromFleet(savedObjectsClient, endpointAppContext, esClient),
|
||||
]);
|
||||
|
||||
return {
|
||||
|
|
|
@ -7,10 +7,7 @@
|
|||
|
||||
import { SavedObjectsFindResponse } from 'src/core/server';
|
||||
import { AgentEventSOAttributes } from './../../../../fleet/common/types/models/agent';
|
||||
import {
|
||||
AGENT_SAVED_OBJECT_TYPE,
|
||||
AGENT_EVENT_SAVED_OBJECT_TYPE,
|
||||
} from '../../../../fleet/common/constants/agent';
|
||||
import { AGENT_EVENT_SAVED_OBJECT_TYPE } from '../../../../fleet/common/constants/agent';
|
||||
import { Agent } from '../../../../fleet/common';
|
||||
import { FLEET_ENDPOINT_PACKAGE_CONSTANT } from './fleet_saved_objects';
|
||||
|
||||
|
@ -36,84 +33,68 @@ export const MockOSFullName = 'somePlatformFullName';
|
|||
export const mockFleetObjectsResponse = (
|
||||
hasDuplicates = true,
|
||||
lastCheckIn = new Date().toISOString()
|
||||
): SavedObjectsFindResponse<Agent> => ({
|
||||
): { agents: Agent[]; total: number; page: number; perPage: number } | undefined => ({
|
||||
page: 1,
|
||||
per_page: 20,
|
||||
perPage: 20,
|
||||
total: 1,
|
||||
saved_objects: [
|
||||
agents: [
|
||||
{
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
active: true,
|
||||
id: testAgentId,
|
||||
attributes: {
|
||||
active: true,
|
||||
id: testAgentId,
|
||||
policy_id: 'randoAgentPolicyId',
|
||||
type: 'PERMANENT',
|
||||
user_provided_metadata: {},
|
||||
enrolled_at: lastCheckIn,
|
||||
current_error_events: [],
|
||||
local_metadata: {
|
||||
elastic: {
|
||||
agent: {
|
||||
id: testAgentId,
|
||||
},
|
||||
},
|
||||
host: {
|
||||
hostname: testHostName,
|
||||
name: testHostName,
|
||||
id: testHostId,
|
||||
},
|
||||
os: {
|
||||
platform: MockOSPlatform,
|
||||
version: MockOSVersion,
|
||||
name: MockOSName,
|
||||
full: MockOSFullName,
|
||||
policy_id: 'randoAgentPolicyId',
|
||||
type: 'PERMANENT',
|
||||
user_provided_metadata: {},
|
||||
enrolled_at: lastCheckIn,
|
||||
current_error_events: [],
|
||||
local_metadata: {
|
||||
elastic: {
|
||||
agent: {
|
||||
id: testAgentId,
|
||||
},
|
||||
},
|
||||
packages: [FLEET_ENDPOINT_PACKAGE_CONSTANT, 'system'],
|
||||
last_checkin: lastCheckIn,
|
||||
host: {
|
||||
hostname: testHostName,
|
||||
name: testHostName,
|
||||
id: testHostId,
|
||||
},
|
||||
os: {
|
||||
platform: MockOSPlatform,
|
||||
version: MockOSVersion,
|
||||
name: MockOSName,
|
||||
full: MockOSFullName,
|
||||
},
|
||||
},
|
||||
references: [],
|
||||
updated_at: lastCheckIn,
|
||||
version: 'WzI4MSwxXQ==',
|
||||
score: 0,
|
||||
packages: [FLEET_ENDPOINT_PACKAGE_CONSTANT, 'system'],
|
||||
last_checkin: lastCheckIn,
|
||||
},
|
||||
{
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
id: testAgentId,
|
||||
attributes: {
|
||||
active: true,
|
||||
id: 'oldTestAgentId',
|
||||
policy_id: 'randoAgentPolicyId',
|
||||
type: 'PERMANENT',
|
||||
user_provided_metadata: {},
|
||||
enrolled_at: lastCheckIn,
|
||||
current_error_events: [],
|
||||
local_metadata: {
|
||||
elastic: {
|
||||
agent: {
|
||||
id: 'oldTestAgentId',
|
||||
},
|
||||
},
|
||||
host: {
|
||||
hostname: hasDuplicates ? testHostName : 'oldRandoHostName',
|
||||
name: hasDuplicates ? testHostName : 'oldRandoHostName',
|
||||
id: hasDuplicates ? testHostId : 'oldRandoHostId',
|
||||
},
|
||||
os: {
|
||||
platform: MockOSPlatform,
|
||||
version: MockOSVersion,
|
||||
name: MockOSName,
|
||||
full: MockOSFullName,
|
||||
active: true,
|
||||
id: 'oldTestAgentId',
|
||||
policy_id: 'randoAgentPolicyId',
|
||||
type: 'PERMANENT',
|
||||
user_provided_metadata: {},
|
||||
enrolled_at: lastCheckIn,
|
||||
current_error_events: [],
|
||||
local_metadata: {
|
||||
elastic: {
|
||||
agent: {
|
||||
id: 'oldTestAgentId',
|
||||
},
|
||||
},
|
||||
packages: [FLEET_ENDPOINT_PACKAGE_CONSTANT, 'system'],
|
||||
last_checkin: lastCheckIn,
|
||||
host: {
|
||||
hostname: hasDuplicates ? testHostName : 'oldRandoHostName',
|
||||
name: hasDuplicates ? testHostName : 'oldRandoHostName',
|
||||
id: hasDuplicates ? testHostId : 'oldRandoHostId',
|
||||
},
|
||||
os: {
|
||||
platform: MockOSPlatform,
|
||||
version: MockOSVersion,
|
||||
name: MockOSName,
|
||||
full: MockOSFullName,
|
||||
},
|
||||
},
|
||||
references: [],
|
||||
updated_at: lastCheckIn,
|
||||
version: 'WzI4MSwxXQ==',
|
||||
score: 0,
|
||||
packages: [FLEET_ENDPOINT_PACKAGE_CONSTANT, 'system'],
|
||||
last_checkin: lastCheckIn,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { savedObjectsRepositoryMock } from 'src/core/server/mocks';
|
||||
import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks';
|
||||
import {
|
||||
mockFleetObjectsResponse,
|
||||
mockFleetEventsObjectsResponse,
|
||||
|
@ -13,23 +13,34 @@ import {
|
|||
MockOSPlatform,
|
||||
MockOSVersion,
|
||||
} from './endpoint.mocks';
|
||||
import { ISavedObjectsRepository, SavedObjectsFindResponse } from 'src/core/server';
|
||||
import { SavedObjectsClientContract, SavedObjectsFindResponse } from 'src/core/server';
|
||||
import { AgentEventSOAttributes } from '../../../../fleet/common/types/models/agent';
|
||||
import { Agent } from '../../../../fleet/common';
|
||||
import * as endpointTelemetry from './index';
|
||||
import * as fleetSavedObjects from './fleet_saved_objects';
|
||||
import { createMockEndpointAppContext } from '../../endpoint/mocks';
|
||||
import { EndpointAppContext } from '../../endpoint/types';
|
||||
|
||||
describe('test security solution endpoint telemetry', () => {
|
||||
let mockSavedObjectsRepository: jest.Mocked<ISavedObjectsRepository>;
|
||||
let getFleetSavedObjectsMetadataSpy: jest.SpyInstance<Promise<SavedObjectsFindResponse<Agent>>>;
|
||||
let mockSavedObjectsClient: jest.Mocked<SavedObjectsClientContract>;
|
||||
let mockEndpointAppContext: EndpointAppContext;
|
||||
let mockEsClient: ReturnType<typeof elasticsearchServiceMock.createElasticsearchClient>;
|
||||
let getEndpointIntegratedFleetMetadataSpy: jest.SpyInstance<
|
||||
Promise<{ agents: Agent[]; total: number; page: number; perPage: number } | undefined>
|
||||
>;
|
||||
let getLatestFleetEndpointEventSpy: jest.SpyInstance<
|
||||
Promise<SavedObjectsFindResponse<AgentEventSOAttributes>>
|
||||
>;
|
||||
|
||||
beforeAll(() => {
|
||||
getLatestFleetEndpointEventSpy = jest.spyOn(fleetSavedObjects, 'getLatestFleetEndpointEvent');
|
||||
getFleetSavedObjectsMetadataSpy = jest.spyOn(fleetSavedObjects, 'getFleetSavedObjectsMetadata');
|
||||
mockSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||
getEndpointIntegratedFleetMetadataSpy = jest.spyOn(
|
||||
fleetSavedObjects,
|
||||
'getEndpointIntegratedFleetMetadata'
|
||||
);
|
||||
mockSavedObjectsClient = savedObjectsClientMock.create();
|
||||
mockEndpointAppContext = createMockEndpointAppContext();
|
||||
mockEsClient = elasticsearchServiceMock.createElasticsearchClient();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
|
@ -55,28 +66,32 @@ describe('test security solution endpoint telemetry', () => {
|
|||
|
||||
describe('when a request for endpoint agents fails', () => {
|
||||
it('should return an empty object', async () => {
|
||||
getFleetSavedObjectsMetadataSpy.mockImplementation(() =>
|
||||
getEndpointIntegratedFleetMetadataSpy.mockImplementation(() =>
|
||||
Promise.reject(Error('No agents for you'))
|
||||
);
|
||||
|
||||
const endpointUsage = await endpointTelemetry.getEndpointTelemetryFromFleet(
|
||||
mockSavedObjectsRepository
|
||||
mockSavedObjectsClient,
|
||||
mockEndpointAppContext,
|
||||
mockEsClient
|
||||
);
|
||||
expect(getFleetSavedObjectsMetadataSpy).toHaveBeenCalled();
|
||||
expect(getEndpointIntegratedFleetMetadataSpy).toHaveBeenCalled();
|
||||
expect(endpointUsage).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when an agent has not been installed', () => {
|
||||
it('should return the default shape if no agents are found', async () => {
|
||||
getFleetSavedObjectsMetadataSpy.mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [], total: 0, per_page: 0, page: 0 })
|
||||
getEndpointIntegratedFleetMetadataSpy.mockImplementation(() =>
|
||||
Promise.resolve({ agents: [], total: 0, perPage: 0, page: 0 })
|
||||
);
|
||||
|
||||
const endpointUsage = await endpointTelemetry.getEndpointTelemetryFromFleet(
|
||||
mockSavedObjectsRepository
|
||||
mockSavedObjectsClient,
|
||||
mockEndpointAppContext,
|
||||
mockEsClient
|
||||
);
|
||||
expect(getFleetSavedObjectsMetadataSpy).toHaveBeenCalled();
|
||||
expect(getEndpointIntegratedFleetMetadataSpy).toHaveBeenCalled();
|
||||
expect(endpointUsage).toEqual({
|
||||
total_installed: 0,
|
||||
active_within_last_24_hours: 0,
|
||||
|
@ -95,7 +110,7 @@ describe('test security solution endpoint telemetry', () => {
|
|||
describe('when agent(s) have been installed', () => {
|
||||
describe('when a request for events has failed', () => {
|
||||
it('should show only one endpoint installed but it is inactive', async () => {
|
||||
getFleetSavedObjectsMetadataSpy.mockImplementation(() =>
|
||||
getEndpointIntegratedFleetMetadataSpy.mockImplementation(() =>
|
||||
Promise.resolve(mockFleetObjectsResponse())
|
||||
);
|
||||
getLatestFleetEndpointEventSpy.mockImplementation(() =>
|
||||
|
@ -103,7 +118,9 @@ describe('test security solution endpoint telemetry', () => {
|
|||
);
|
||||
|
||||
const endpointUsage = await endpointTelemetry.getEndpointTelemetryFromFleet(
|
||||
mockSavedObjectsRepository
|
||||
mockSavedObjectsClient,
|
||||
mockEndpointAppContext,
|
||||
mockEsClient
|
||||
);
|
||||
expect(endpointUsage).toEqual({
|
||||
total_installed: 1,
|
||||
|
@ -129,7 +146,7 @@ describe('test security solution endpoint telemetry', () => {
|
|||
|
||||
describe('when a request for events is successful', () => {
|
||||
it('should show one endpoint installed but endpoint has failed to run', async () => {
|
||||
getFleetSavedObjectsMetadataSpy.mockImplementation(() =>
|
||||
getEndpointIntegratedFleetMetadataSpy.mockImplementation(() =>
|
||||
Promise.resolve(mockFleetObjectsResponse())
|
||||
);
|
||||
getLatestFleetEndpointEventSpy.mockImplementation(() =>
|
||||
|
@ -137,7 +154,9 @@ describe('test security solution endpoint telemetry', () => {
|
|||
);
|
||||
|
||||
const endpointUsage = await endpointTelemetry.getEndpointTelemetryFromFleet(
|
||||
mockSavedObjectsRepository
|
||||
mockSavedObjectsClient,
|
||||
mockEndpointAppContext,
|
||||
mockEsClient
|
||||
);
|
||||
expect(endpointUsage).toEqual({
|
||||
total_installed: 1,
|
||||
|
@ -161,7 +180,7 @@ describe('test security solution endpoint telemetry', () => {
|
|||
});
|
||||
|
||||
it('should show two endpoints installed but both endpoints have failed to run', async () => {
|
||||
getFleetSavedObjectsMetadataSpy.mockImplementation(() =>
|
||||
getEndpointIntegratedFleetMetadataSpy.mockImplementation(() =>
|
||||
Promise.resolve(mockFleetObjectsResponse(false))
|
||||
);
|
||||
getLatestFleetEndpointEventSpy.mockImplementation(() =>
|
||||
|
@ -169,7 +188,9 @@ describe('test security solution endpoint telemetry', () => {
|
|||
);
|
||||
|
||||
const endpointUsage = await endpointTelemetry.getEndpointTelemetryFromFleet(
|
||||
mockSavedObjectsRepository
|
||||
mockSavedObjectsClient,
|
||||
mockEndpointAppContext,
|
||||
mockEsClient
|
||||
);
|
||||
expect(endpointUsage).toEqual({
|
||||
total_installed: 2,
|
||||
|
@ -197,7 +218,7 @@ describe('test security solution endpoint telemetry', () => {
|
|||
twoDaysAgo.setDate(twoDaysAgo.getDate() - 2);
|
||||
const twoDaysAgoISOString = twoDaysAgo.toISOString();
|
||||
|
||||
getFleetSavedObjectsMetadataSpy.mockImplementation(() =>
|
||||
getEndpointIntegratedFleetMetadataSpy.mockImplementation(() =>
|
||||
Promise.resolve(mockFleetObjectsResponse(false, twoDaysAgoISOString))
|
||||
);
|
||||
getLatestFleetEndpointEventSpy.mockImplementation(
|
||||
|
@ -205,7 +226,9 @@ describe('test security solution endpoint telemetry', () => {
|
|||
);
|
||||
|
||||
const endpointUsage = await endpointTelemetry.getEndpointTelemetryFromFleet(
|
||||
mockSavedObjectsRepository
|
||||
mockSavedObjectsClient,
|
||||
mockEndpointAppContext,
|
||||
mockEsClient
|
||||
);
|
||||
expect(endpointUsage).toEqual({
|
||||
total_installed: 2,
|
||||
|
@ -229,7 +252,7 @@ describe('test security solution endpoint telemetry', () => {
|
|||
});
|
||||
|
||||
it('should show one endpoint installed and endpoint is running', async () => {
|
||||
getFleetSavedObjectsMetadataSpy.mockImplementation(() =>
|
||||
getEndpointIntegratedFleetMetadataSpy.mockImplementation(() =>
|
||||
Promise.resolve(mockFleetObjectsResponse())
|
||||
);
|
||||
getLatestFleetEndpointEventSpy.mockImplementation(() =>
|
||||
|
@ -237,7 +260,9 @@ describe('test security solution endpoint telemetry', () => {
|
|||
);
|
||||
|
||||
const endpointUsage = await endpointTelemetry.getEndpointTelemetryFromFleet(
|
||||
mockSavedObjectsRepository
|
||||
mockSavedObjectsClient,
|
||||
mockEndpointAppContext,
|
||||
mockEsClient
|
||||
);
|
||||
expect(endpointUsage).toEqual({
|
||||
total_installed: 1,
|
||||
|
@ -262,7 +287,7 @@ describe('test security solution endpoint telemetry', () => {
|
|||
|
||||
describe('malware policy', () => {
|
||||
it('should have failed to enable', async () => {
|
||||
getFleetSavedObjectsMetadataSpy.mockImplementation(() =>
|
||||
getEndpointIntegratedFleetMetadataSpy.mockImplementation(() =>
|
||||
Promise.resolve(mockFleetObjectsResponse())
|
||||
);
|
||||
getLatestFleetEndpointEventSpy.mockImplementation(() =>
|
||||
|
@ -272,7 +297,9 @@ describe('test security solution endpoint telemetry', () => {
|
|||
);
|
||||
|
||||
const endpointUsage = await endpointTelemetry.getEndpointTelemetryFromFleet(
|
||||
mockSavedObjectsRepository
|
||||
mockSavedObjectsClient,
|
||||
mockEndpointAppContext,
|
||||
mockEsClient
|
||||
);
|
||||
expect(endpointUsage).toEqual({
|
||||
total_installed: 1,
|
||||
|
@ -296,7 +323,7 @@ describe('test security solution endpoint telemetry', () => {
|
|||
});
|
||||
|
||||
it('should be enabled successfully', async () => {
|
||||
getFleetSavedObjectsMetadataSpy.mockImplementation(() =>
|
||||
getEndpointIntegratedFleetMetadataSpy.mockImplementation(() =>
|
||||
Promise.resolve(mockFleetObjectsResponse())
|
||||
);
|
||||
getLatestFleetEndpointEventSpy.mockImplementation(() =>
|
||||
|
@ -304,7 +331,9 @@ describe('test security solution endpoint telemetry', () => {
|
|||
);
|
||||
|
||||
const endpointUsage = await endpointTelemetry.getEndpointTelemetryFromFleet(
|
||||
mockSavedObjectsRepository
|
||||
mockSavedObjectsClient,
|
||||
mockEndpointAppContext,
|
||||
mockEsClient
|
||||
);
|
||||
expect(endpointUsage).toEqual({
|
||||
total_installed: 1,
|
||||
|
@ -328,7 +357,7 @@ describe('test security solution endpoint telemetry', () => {
|
|||
});
|
||||
|
||||
it('should be disabled successfully', async () => {
|
||||
getFleetSavedObjectsMetadataSpy.mockImplementation(() =>
|
||||
getEndpointIntegratedFleetMetadataSpy.mockImplementation(() =>
|
||||
Promise.resolve(mockFleetObjectsResponse())
|
||||
);
|
||||
getLatestFleetEndpointEventSpy.mockImplementation(() =>
|
||||
|
@ -338,7 +367,9 @@ describe('test security solution endpoint telemetry', () => {
|
|||
);
|
||||
|
||||
const endpointUsage = await endpointTelemetry.getEndpointTelemetryFromFleet(
|
||||
mockSavedObjectsRepository
|
||||
mockSavedObjectsClient,
|
||||
mockEndpointAppContext,
|
||||
mockEsClient
|
||||
);
|
||||
expect(endpointUsage).toEqual({
|
||||
total_installed: 1,
|
||||
|
|
|
@ -5,38 +5,36 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ISavedObjectsRepository } from 'src/core/server';
|
||||
import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server';
|
||||
import { AgentService } from '../../../../fleet/server';
|
||||
import { AgentEventSOAttributes } from './../../../../fleet/common/types/models/agent';
|
||||
import {
|
||||
AGENT_SAVED_OBJECT_TYPE,
|
||||
AGENT_EVENT_SAVED_OBJECT_TYPE,
|
||||
} from './../../../../fleet/common/constants/agent';
|
||||
import { Agent, defaultPackages as FleetDefaultPackages } from '../../../../fleet/common';
|
||||
import { AGENT_EVENT_SAVED_OBJECT_TYPE } from './../../../../fleet/common/constants/agent';
|
||||
import { defaultPackages as FleetDefaultPackages } from '../../../../fleet/common';
|
||||
|
||||
export const FLEET_ENDPOINT_PACKAGE_CONSTANT = FleetDefaultPackages.Endpoint;
|
||||
|
||||
export const getFleetSavedObjectsMetadata = async (savedObjectsClient: ISavedObjectsRepository) =>
|
||||
savedObjectsClient.find<Agent>({
|
||||
// Get up to 10000 agents with endpoint installed
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
fields: [
|
||||
'packages',
|
||||
'last_checkin',
|
||||
'local_metadata.agent.id',
|
||||
'local_metadata.host.id',
|
||||
'local_metadata.host.name',
|
||||
'local_metadata.host.hostname',
|
||||
'local_metadata.elastic.agent.id',
|
||||
'local_metadata.os',
|
||||
],
|
||||
filter: `${AGENT_SAVED_OBJECT_TYPE}.attributes.packages: ${FLEET_ENDPOINT_PACKAGE_CONSTANT}`,
|
||||
export const getEndpointIntegratedFleetMetadata = async (
|
||||
agentService: AgentService | undefined,
|
||||
esClient: ElasticsearchClient
|
||||
) => {
|
||||
return agentService?.listAgents(esClient, {
|
||||
kuery: `(packages : ${FLEET_ENDPOINT_PACKAGE_CONSTANT})`,
|
||||
perPage: 10000,
|
||||
showInactive: false,
|
||||
sortField: 'enrolled_at',
|
||||
sortOrder: 'desc',
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
TODO: AS OF 7.13, this access will no longer work due to the enabling of fleet server. An alternative route will have
|
||||
to be discussed to retrieve the policy data we need, as well as when the endpoint was last active, which is obtained
|
||||
via the last endpoint 'check in' event that was sent to fleet. Also, the only policy currently tracked is `malware`,
|
||||
but the hope is to add more, so a better/more scalable solution would be desirable.
|
||||
*/
|
||||
|
||||
export const getLatestFleetEndpointEvent = async (
|
||||
savedObjectsClient: ISavedObjectsRepository,
|
||||
savedObjectsClient: SavedObjectsClientContract,
|
||||
agentId: string
|
||||
) =>
|
||||
savedObjectsClient.find<AgentEventSOAttributes>({
|
||||
|
|
|
@ -6,11 +6,15 @@
|
|||
*/
|
||||
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { ISavedObjectsRepository } from 'src/core/server';
|
||||
import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server';
|
||||
import { SavedObject } from './../../../../../../src/core/types/saved_objects';
|
||||
import { Agent, NewAgentEvent } from './../../../../fleet/common/types/models/agent';
|
||||
import { AgentMetadata } from '../../../../fleet/common/types/models/agent';
|
||||
import { getFleetSavedObjectsMetadata, getLatestFleetEndpointEvent } from './fleet_saved_objects';
|
||||
import {
|
||||
getEndpointIntegratedFleetMetadata,
|
||||
getLatestFleetEndpointEvent,
|
||||
} from './fleet_saved_objects';
|
||||
import { EndpointAppContext } from '../../endpoint/types';
|
||||
|
||||
export interface AgentOSMetadataTelemetry {
|
||||
full_name: string;
|
||||
|
@ -108,7 +112,7 @@ export const updateEndpointOSTelemetry = (
|
|||
* the same time span.
|
||||
*/
|
||||
export const updateEndpointDailyActiveCount = (
|
||||
latestEndpointEvent: SavedObject<NewAgentEvent>,
|
||||
latestEndpointEvent: SavedObject<NewAgentEvent>, // TODO: This information will be lost in 7.13, need to find an alternative route.
|
||||
lastAgentCheckin: Agent['last_checkin'],
|
||||
currentCount: number
|
||||
) => {
|
||||
|
@ -193,19 +197,22 @@ export const updateEndpointPolicyTelemetry = (
|
|||
};
|
||||
|
||||
/**
|
||||
* @description This aggregates the telemetry details from the two fleet savedObject sources, `fleet-agents` and `fleet-agent-events` to populate
|
||||
* @description This aggregates the telemetry details from the fleet agent service `listAgents` and the fleet saved object `fleet-agent-events` to populate
|
||||
* the telemetry details for endpoint. Since we cannot access our own indices due to `kibana_system` not having access, this is the best alternative.
|
||||
* Once the data is requested, we iterate over all agents with endpoints registered, and then request the events for each active agent (within last 24 hours)
|
||||
* to confirm whether or not the endpoint is still active
|
||||
*/
|
||||
export const getEndpointTelemetryFromFleet = async (
|
||||
soClient: ISavedObjectsRepository
|
||||
soClient: SavedObjectsClientContract,
|
||||
endpointAppContext: EndpointAppContext,
|
||||
esClient: ElasticsearchClient
|
||||
): Promise<EndpointUsage | {}> => {
|
||||
// Retrieve every agent (max 10000) that references the endpoint as an installed package. It will not be listed if it was never installed
|
||||
let endpointAgents;
|
||||
const agentService = endpointAppContext.service.getAgentService();
|
||||
try {
|
||||
const response = await getFleetSavedObjectsMetadata(soClient);
|
||||
endpointAgents = response.saved_objects;
|
||||
const response = await getEndpointIntegratedFleetMetadata(agentService, esClient);
|
||||
endpointAgents = response?.agents ?? [];
|
||||
} catch (error) {
|
||||
// Better to provide an empty object rather than default telemetry as this better informs us of an error
|
||||
return {};
|
||||
|
@ -225,8 +232,7 @@ export const getEndpointTelemetryFromFleet = async (
|
|||
|
||||
for (let i = 0; i < endpointAgentsCount; i += 1) {
|
||||
try {
|
||||
const { attributes: metadataAttributes } = endpointAgents[i];
|
||||
const { last_checkin: lastCheckin, local_metadata: localMetadata } = metadataAttributes;
|
||||
const { last_checkin: lastCheckin, local_metadata: localMetadata } = endpointAgents[i];
|
||||
const { host, os, elastic } = localMetadata as AgentLocalMetadata;
|
||||
|
||||
// Although not perfect, the goal is to dedupe hosts to get the most recent data for a host
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
*/
|
||||
|
||||
import { CoreSetup } from 'src/core/server';
|
||||
import { EndpointAppContext } from '../endpoint/types';
|
||||
import { SetupPlugins } from '../plugin';
|
||||
|
||||
export type CollectorDependencies = { kibanaIndex: string; core: CoreSetup } & Pick<
|
||||
SetupPlugins,
|
||||
'ml' | 'usageCollection'
|
||||
>;
|
||||
export type CollectorDependencies = {
|
||||
kibanaIndex: string;
|
||||
core: CoreSetup;
|
||||
endpointAppContext: EndpointAppContext;
|
||||
} & Pick<SetupPlugins, 'ml' | 'usageCollection'>;
|
||||
|
|
|
@ -12,7 +12,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const esArchiver = getService('esArchiver');
|
||||
const telemetryTestResources = getService('telemetryTestResources');
|
||||
|
||||
describe('security solution endpoint telemetry', () => {
|
||||
// The source of the data for these tests have changed and need to be updated
|
||||
// There are currently tests in the security_solution application being maintained
|
||||
describe.skip('security solution endpoint telemetry', () => {
|
||||
after(async () => {
|
||||
await esArchiver.load('empty_kibana');
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue