Skip to content

Commit ee5dca9

Browse files
committed
improve policy logic
1 parent a9c2095 commit ee5dca9

File tree

5 files changed

+170
-62
lines changed

5 files changed

+170
-62
lines changed

x-pack/plugins/security_solution/server/usage/collector.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ export const registerCollector: RegisterCollector = ({
6666
},
6767
policies: {
6868
malware: {
69-
success: { type: 'long' },
70-
warning: { type: 'long' },
69+
active: { type: 'long' },
70+
inactive: { type: 'long' },
7171
failure: { type: 'long' },
7272
},
7373
},

x-pack/plugins/security_solution/server/usage/endpoints/endpoint.mocks.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,55 @@ const mockPolicyPayload = (malwareStatus: 'success' | 'warning' | 'failure') =>
8080
JSON.stringify({
8181
'endpoint-security': {
8282
Endpoint: {
83+
configuration: {
84+
inputs: [
85+
{
86+
id: '0d466df0-c60f-11ea-a5c5-151665e785c4',
87+
policy: {
88+
linux: {
89+
events: {
90+
file: true,
91+
network: true,
92+
process: true,
93+
},
94+
logging: {
95+
file: 'info',
96+
},
97+
},
98+
mac: {
99+
events: {
100+
file: true,
101+
network: true,
102+
process: true,
103+
},
104+
logging: {
105+
file: 'info',
106+
},
107+
malware: {
108+
mode: 'prevent',
109+
},
110+
},
111+
windows: {
112+
events: {
113+
dll_and_driver_load: true,
114+
dns: true,
115+
file: true,
116+
network: true,
117+
process: true,
118+
registry: true,
119+
security: true,
120+
},
121+
logging: {
122+
file: 'info',
123+
},
124+
malware: {
125+
mode: 'prevent',
126+
},
127+
},
128+
},
129+
},
130+
],
131+
},
83132
policy: {
84133
applied: {
85134
id: '0d466df0-c60f-11ea-a5c5-151665e785c4',
@@ -114,6 +163,18 @@ const mockPolicyPayload = (malwareStatus: 'success' | 'warning' | 'failure') =>
114163
id: 'testAgentId',
115164
version: '8.0.0-SNAPSHOT',
116165
},
166+
host: {
167+
architecture: 'x86_64',
168+
id: 'a4148b63-1758-ab1f-a6d3-f95075cb1a9c',
169+
os: {
170+
Ext: {
171+
variant: 'Windows 10 Pro',
172+
},
173+
full: 'Windows 10 Pro 2004 (10.0.19041.329)',
174+
name: 'Windows',
175+
version: '2004 (10.0.19041.329)',
176+
},
177+
},
117178
},
118179
});
119180

x-pack/plugins/security_solution/server/usage/endpoints/endpoint.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ describe('test security solution endpoint telemetry', () => {
4141
"os": Array [],
4242
"policies": Object {
4343
"malware": Object {
44+
"active": 0,
4445
"failure": 0,
45-
"success": 0,
46-
"warning": 0,
46+
"inactive": 0,
4747
},
4848
},
4949
"total_installed": 0,
@@ -68,8 +68,8 @@ describe('test security solution endpoint telemetry', () => {
6868
policies: {
6969
malware: {
7070
failure: 0,
71-
success: 0,
72-
warning: 0,
71+
active: 0,
72+
inactive: 0,
7373
},
7474
},
7575
});
@@ -102,8 +102,8 @@ describe('test security solution endpoint telemetry', () => {
102102
policies: {
103103
malware: {
104104
failure: 1,
105-
success: 0,
106-
warning: 0,
105+
active: 0,
106+
inactive: 0,
107107
},
108108
},
109109
});
@@ -134,8 +134,8 @@ describe('test security solution endpoint telemetry', () => {
134134
policies: {
135135
malware: {
136136
failure: 0,
137-
success: 1,
138-
warning: 0,
137+
active: 1,
138+
inactive: 0,
139139
},
140140
},
141141
});

x-pack/plugins/security_solution/server/usage/endpoints/index.ts

Lines changed: 97 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ export interface AgentOSMetadataTelemetry {
1414
version: string;
1515
count: number;
1616
}
17-
18-
export type PolicyTypes = 'malware';
1917
export interface PolicyTelemetry {
20-
success: number;
21-
warning: number;
18+
active: number;
19+
inactive: number;
2220
failure: number;
2321
}
2422

25-
export type PoliciesTelemetry = Record<PolicyTypes, PolicyTelemetry>;
23+
export interface PoliciesTelemetry {
24+
malware: PolicyTelemetry;
25+
}
2626

2727
export interface EndpointUsage {
2828
total_installed: number;
@@ -31,6 +31,8 @@ export interface EndpointUsage {
3131
policies: PoliciesTelemetry;
3232
}
3333

34+
type EndpointOSNames = 'Linux' | 'Windows' | 'macOs';
35+
3436
export interface AgentLocalMetadata extends AgentMetadata {
3537
elastic: {
3638
agent: {
@@ -48,8 +50,8 @@ export interface AgentLocalMetadata extends AgentMetadata {
4850
};
4951
}
5052

51-
export type OSTracker = Record<string, AgentOSMetadataTelemetry>;
52-
53+
type OSTracker = Record<string, AgentOSMetadataTelemetry>;
54+
type AgentDailyActiveTracker = Map<string, boolean>;
5355
/**
5456
* @description returns an empty telemetry object to be incrmented and updated within the `getEndpointTelemetryFromFleet` fn
5557
*/
@@ -59,13 +61,16 @@ export const getDefaultEndpointTelemetry = (): EndpointUsage => ({
5961
os: [],
6062
policies: {
6163
malware: {
62-
success: 0,
63-
warning: 0,
64+
active: 0,
65+
inactive: 0,
6466
failure: 0,
6567
},
6668
},
6769
});
6870

71+
/**
72+
* @description this fun
73+
*/
6974
export const trackEndpointOSTelemetry = (
7075
os: AgentLocalMetadata['os'],
7176
osTracker: OSTracker
@@ -87,6 +92,80 @@ export const trackEndpointOSTelemetry = (
8792
return updatedOSTracker;
8893
};
8994

95+
/**
96+
* @description This iterates over all unique agents that currently track an endpoint package. It takes a list of agents who have checked in in the last 24 hours
97+
* and then checks whether those agents have endpoints whose latest status is 'RUNNING' to determine an active_within_last_24_hours. Since the policy information is also tracked in these events
98+
* we pull out the status of the current protection (malware) type. This must be done in a compound manner as the desired status is reflected in the config, and the successful application of that policy
99+
* is tracked in the policy.applied.response.configurations[protectionsType].status. Using these two we can determine whether the policy is toggled on, off, or failed to turn on.
100+
*/
101+
export const addEndpointDailyActivityAndPolicyDetailsToTelemetry = async (
102+
agentDailyActiveTracker: AgentDailyActiveTracker,
103+
savedObjectsClient: ISavedObjectsRepository,
104+
endpointTelemetry: EndpointUsage
105+
): Promise<EndpointUsage> => {
106+
const updatedEndpointTelemetry = { ...endpointTelemetry };
107+
108+
const policyHostTypeToPolicyType = {
109+
Linux: 'linux',
110+
macOs: 'mac',
111+
Windows: 'windows',
112+
};
113+
const enabledMalwarePolicyTypes = ['prevent', 'detect'];
114+
115+
for (const agentId of agentDailyActiveTracker.keys()) {
116+
const { saved_objects: agentEvents } = await getLatestFleetEndpointEvent(
117+
savedObjectsClient,
118+
agentId
119+
);
120+
121+
const latestEndpointEvent = agentEvents[0];
122+
if (latestEndpointEvent) {
123+
/*
124+
We can assume that if the last status of the endpoint is RUNNING and the agent has checked in within the last 24 hours
125+
then the endpoint has still been running within the last 24 hours.
126+
*/
127+
const { subtype, payload } = latestEndpointEvent.attributes;
128+
const endpointIsActive =
129+
subtype === 'RUNNING' && agentDailyActiveTracker.get(agentId) === true;
130+
131+
if (endpointIsActive) {
132+
updatedEndpointTelemetry.active_within_last_24_hours += 1;
133+
}
134+
135+
// The policy details are sent as a string on the 'payload' attribute of the agent event
136+
const endpointPolicyDetails = payload ? JSON.parse(payload) : null;
137+
if (endpointPolicyDetails) {
138+
// We get the setting the user desired to enable (treating prevent and detect as 'active' states) and then see if it succeded or failed.
139+
const hostType =
140+
policyHostTypeToPolicyType[
141+
endpointPolicyDetails['endpoint-security']?.host?.os?.name as EndpointOSNames
142+
];
143+
const userDesiredMalwareState =
144+
endpointPolicyDetails['endpoint-security'].Endpoint?.configuration?.inputs[0]?.policy[
145+
hostType
146+
]?.malware?.mode;
147+
148+
const isAnActiveMalwareState = enabledMalwarePolicyTypes.includes(userDesiredMalwareState);
149+
const malwareStatus =
150+
endpointPolicyDetails['endpoint-security'].Endpoint?.policy?.applied?.response
151+
?.configurations?.malware?.status;
152+
153+
if (isAnActiveMalwareState && malwareStatus !== 'failure') {
154+
updatedEndpointTelemetry.policies.malware.active += 1;
155+
}
156+
if (!isAnActiveMalwareState) {
157+
updatedEndpointTelemetry.policies.malware.inactive += 1;
158+
}
159+
if (isAnActiveMalwareState && malwareStatus === 'failure') {
160+
updatedEndpointTelemetry.policies.malware.failure += 1;
161+
}
162+
}
163+
}
164+
}
165+
166+
return updatedEndpointTelemetry;
167+
};
168+
90169
/**
91170
* @description This aggregates the telemetry details from the two fleet savedObject sources, `fleet-agents` and `fleet-agent-events` to populate
92171
* the telemetry details for endpoint. Since we cannot access our own indices due to `kibana_system` not having access, this is the best alternative.
@@ -106,7 +185,7 @@ export const getEndpointTelemetryFromFleet = async (
106185
// Use unique hosts to prevent any potential duplicates
107186
const uniqueHostIds: Set<string> = new Set();
108187
// Need agents to get events data for those that have run in last 24 hours as well as policy details
109-
const agentDailyActiveTracker: Map<string, boolean> = new Map();
188+
const agentDailyActiveTracker: AgentDailyActiveTracker = new Map();
110189

111190
const aDayAgo = new Date();
112191
aDayAgo.setDate(aDayAgo.getDate() - 1);
@@ -131,48 +210,16 @@ export const getEndpointTelemetryFromFleet = async (
131210
endpointTelemetry
132211
);
133212

134-
// All unique agents with an endpoint installed. You can technically install a new agent on a host, so relying on most recently installed.
213+
// All unique hosts with an endpoint installed.
135214
endpointTelemetry.total_installed = uniqueHostIds.size;
136215
// Get the objects to populate our OS Telemetry
137216
endpointMetadataTelemetry.os = Object.values(osTracker);
217+
// Populate endpoint telemetry with the finalized 24 hour count and policy details
218+
const finalizedEndpointTelemetryData = await addEndpointDailyActivityAndPolicyDetailsToTelemetry(
219+
agentDailyActiveTracker,
220+
savedObjectsClient,
221+
endpointMetadataTelemetry
222+
);
138223

139-
for (const agentId of agentDailyActiveTracker.keys()) {
140-
const { saved_objects: agentEvents } = await getLatestFleetEndpointEvent(
141-
savedObjectsClient,
142-
agentId
143-
);
144-
145-
const latestEndpointEvent = agentEvents[0];
146-
if (latestEndpointEvent) {
147-
/*
148-
We can assume that if the last status of the endpoint is RUNNING and the agent has checked in within the last 24 hours
149-
then the endpoint has still been running within the last 24 hours.
150-
*/
151-
const { subtype, payload } = latestEndpointEvent.attributes;
152-
const endpointIsActive =
153-
subtype === 'RUNNING' && agentDailyActiveTracker.get(agentId) === true;
154-
155-
if (endpointIsActive) {
156-
endpointMetadataTelemetry.active_within_last_24_hours += 1;
157-
}
158-
const endpointPolicyDetails = payload ? JSON.parse(payload) : null;
159-
if (endpointPolicyDetails) {
160-
const malwareStatus =
161-
endpointPolicyDetails['endpoint-security'].Endpoint?.policy?.applied?.response
162-
?.configurations?.malware?.status;
163-
164-
if (malwareStatus === 'success') {
165-
endpointMetadataTelemetry.policies.malware.success += 1;
166-
}
167-
if (malwareStatus === 'warning') {
168-
endpointMetadataTelemetry.policies.malware.warning += 1;
169-
}
170-
if (malwareStatus === 'failure') {
171-
endpointMetadataTelemetry.policies.malware.failure += 1;
172-
}
173-
}
174-
}
175-
}
176-
177-
return endpointMetadataTelemetry;
224+
return finalizedEndpointTelemetryData;
178225
};

x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,10 @@
246246
"properties": {
247247
"malware": {
248248
"properties": {
249-
"success": {
249+
"active": {
250250
"type": "long"
251251
},
252-
"warning": {
252+
"inactive": {
253253
"type": "long"
254254
},
255255
"failure": {

0 commit comments

Comments
 (0)