Skip to content

Commit 1ea5d11

Browse files
authored
[Security Solution][Endpoint] Fix artifacts display of "Applied to x policies" on policy details tabs (#226461)
## Summary - Fixes the `Applied to {count} policies` popup only showing policy names for the first 1k policies - API call was changed to use `fleet/package_policies/_bulk_get` instead of the `find` api - Fixes the creation of Microsoft Defender integration policy when run from dev scripts - Improves the create endpoint policy dev script to be more robust and prevent less run failures
1 parent a9559ef commit 1ea5d11

4 files changed

Lines changed: 239 additions & 10 deletions

File tree

x-pack/solutions/security/plugins/security_solution/public/management/pages/policy/view/artifacts/list/policy_artifacts_list.test.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import { SEARCHABLE_FIELDS } from '../../../../event_filters/constants';
2121
import { getEndpointPrivilegesInitialStateMock } from '../../../../../../common/components/user_privileges/endpoint/mocks';
2222
import { POLICY_ARTIFACT_LIST_LABELS } from './translations';
2323
import { EventFiltersApiClient } from '../../../../event_filters/service/api_client';
24+
import { ExceptionsListItemGenerator } from '../../../../../../../common/endpoint/data_generators/exceptions_list_item_generator';
25+
import { buildPerPolicyTag } from '../../../../../../../common/endpoint/service/artifacts/utils';
2426

2527
const endpointGenerator = new EndpointDocGenerator('seed');
2628
const getDefaultQueryParameters = (customFilter: string | undefined = '') => ({
@@ -183,6 +185,33 @@ describe('Policy details artifacts list', () => {
183185
expect(history.location.search).not.toMatch('page_size');
184186
});
185187

188+
it('should retrieve all policies using getById api', async () => {
189+
const generator = new ExceptionsListItemGenerator('seed');
190+
191+
mockedApi.responseProvider.eventFiltersList.mockReturnValue({
192+
data: [
193+
generator.generateEventFilter({
194+
tags: [buildPerPolicyTag('policy-1'), buildPerPolicyTag('policy-2')],
195+
}),
196+
generator.generateEventFilter({
197+
tags: [buildPerPolicyTag('policy-3'), buildPerPolicyTag('policy-2')],
198+
}),
199+
],
200+
page: 1,
201+
per_page: 1,
202+
total: 1,
203+
});
204+
await render();
205+
206+
expect(mockedContext.coreStart.http.post).toHaveBeenCalledWith(
207+
'/api/fleet/package_policies/_bulk_get',
208+
{
209+
body: '{"ids":["policy-1","policy-2","policy-3"],"ignoreMissing":true}',
210+
version: expect.any(String),
211+
}
212+
);
213+
});
214+
186215
describe('without external privileges', () => {
187216
it('should not display the delete action, do show the full details', async () => {
188217
mockedApi.responseProvider.eventFiltersList.mockReturnValue(

x-pack/solutions/security/plugins/security_solution/public/management/pages/policy/view/artifacts/list/policy_artifacts_list.tsx

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import React, { useCallback, useMemo, useState } from 'react';
99
import type { Pagination } from '@elastic/eui';
1010
import { EuiSpacer, EuiText } from '@elastic/eui';
1111
import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types';
12+
import { useBulkFetchFleetIntegrationPolicies } from '../../../../../hooks/policy/use_bulk_fetch_fleet_integration_policies';
1213
import type { ArtifactEntryCardDecoratorProps } from '../../../../../components/artifact_entry_card';
1314
import { useAppUrl } from '../../../../../../common/lib/kibana';
1415
import { APP_UI_ID } from '../../../../../../../common/constants';
@@ -17,13 +18,15 @@ import { SearchExceptions } from '../../../../../components/search_exceptions';
1718
import { useEndpointPoliciesToArtifactPolicies } from '../../../../../components/artifact_entry_card/hooks/use_endpoint_policies_to_artifact_policies';
1819
import { useUrlParams } from '../../../../../hooks/use_url_params';
1920
import { useUrlPagination } from '../../../../../hooks/use_url_pagination';
20-
import { useGetEndpointSpecificPolicies } from '../../../../../services/policies/hooks';
2121
import { useOldUrlSearchPaginationReplace } from '../../../../../hooks/use_old_url_search_pagination_replace';
2222
import type { ArtifactCardGridProps } from '../../../../../components/artifact_card_grid';
2323
import { ArtifactCardGrid } from '../../../../../components/artifact_card_grid';
2424
import { usePolicyDetailsArtifactsNavigateCallback } from '../../policy_hooks';
2525
import type { ImmutableObject, PolicyData } from '../../../../../../../common/endpoint/types';
26-
import { isArtifactGlobal } from '../../../../../../../common/endpoint/service/artifacts';
26+
import {
27+
getPolicyIdsFromArtifact,
28+
isArtifactGlobal,
29+
} from '../../../../../../../common/endpoint/service/artifacts';
2730
import { useUserPrivileges } from '../../../../../../common/components/user_privileges';
2831
import { useGetLinkTo } from '../empty/use_policy_artifacts_empty_hooks';
2932
import type { ExceptionsListApiClient } from '../../../../../services/exceptions_list/exceptions_list_api_client';
@@ -58,7 +61,6 @@ export const PolicyArtifactsList = React.memo<PolicyArtifactsListProps>(
5861
useOldUrlSearchPaginationReplace();
5962
const { getAppUrl } = useAppUrl();
6063
const { canCreateArtifactsByPolicy } = useUserPrivileges().endpointPrivileges;
61-
const policiesRequest = useGetEndpointSpecificPolicies({ perPage: 1000 });
6264
const navigateCallback = usePolicyDetailsArtifactsNavigateCallback(apiClient.listId);
6365
const { urlParams } = useUrlParams();
6466
const [expandedItemsMap, setExpandedItemsMap] = useState<Map<string, boolean>>(new Map());
@@ -82,6 +84,23 @@ export const PolicyArtifactsList = React.memo<PolicyArtifactsListProps>(
8284
searchableFields
8385
);
8486

87+
const allArtifactReferencedPolicyIds: string[] = useMemo(() => {
88+
const ids = new Set<string>();
89+
90+
if (artifacts?.data) {
91+
for (const artifact of artifacts.data) {
92+
getPolicyIdsFromArtifact(artifact).forEach((policyId) => ids.add(policyId));
93+
}
94+
}
95+
96+
return Array.from(ids);
97+
}, [artifacts?.data]);
98+
99+
const policiesRequest = useBulkFetchFleetIntegrationPolicies<PolicyData>(
100+
{ ids: allArtifactReferencedPolicyIds },
101+
{ enabled: allArtifactReferencedPolicyIds.length > 0, keepPreviousData: false }
102+
);
103+
85104
const pagination: Pagination = useMemo(
86105
() => ({
87106
pageSize: urlPagination.pageSize,

x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/fleet_services.ts

Lines changed: 170 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,7 @@ export const addMicrosoftDefenderForEndpointIntegrationToAgentPolicy = async ({
11261126
value: clientId,
11271127
},
11281128
enable_request_tracer: {
1129+
value: false,
11291130
type: 'bool',
11301131
},
11311132
client_secret: {
@@ -1136,9 +1137,13 @@ export const addMicrosoftDefenderForEndpointIntegrationToAgentPolicy = async ({
11361137
type: 'text',
11371138
value: tenantId,
11381139
},
1140+
initial_interval: {
1141+
value: '5m',
1142+
type: 'text',
1143+
},
11391144
interval: {
1145+
value: '5m',
11401146
type: 'text',
1141-
value: '30s',
11421147
},
11431148
scopes: {
11441149
value: [],
@@ -1209,6 +1214,170 @@ export const addMicrosoftDefenderForEndpointIntegrationToAgentPolicy = async ({
12091214
},
12101215
],
12111216
},
1217+
{
1218+
type: 'cel',
1219+
policy_template: 'microsoft_defender_endpoint',
1220+
enabled: false,
1221+
streams: [
1222+
{
1223+
enabled: false,
1224+
data_stream: {
1225+
type: 'logs',
1226+
dataset: 'microsoft_defender_endpoint.machine',
1227+
},
1228+
vars: {
1229+
interval: {
1230+
value: '24h',
1231+
type: 'text',
1232+
},
1233+
batch_size: {
1234+
value: 1000,
1235+
type: 'text',
1236+
},
1237+
http_client_timeout: {
1238+
value: '30s',
1239+
type: 'text',
1240+
},
1241+
enable_request_tracer: {
1242+
value: false,
1243+
type: 'bool',
1244+
},
1245+
tags: {
1246+
value: ['forwarded', 'microsoft_defender_endpoint-machine'],
1247+
type: 'text',
1248+
},
1249+
preserve_original_event: {
1250+
value: false,
1251+
type: 'bool',
1252+
},
1253+
preserve_duplicate_custom_fields: {
1254+
type: 'bool',
1255+
},
1256+
processors: {
1257+
type: 'yaml',
1258+
},
1259+
},
1260+
},
1261+
{
1262+
enabled: false,
1263+
data_stream: {
1264+
type: 'logs',
1265+
dataset: 'microsoft_defender_endpoint.machine_action',
1266+
},
1267+
vars: {
1268+
initial_interval: {
1269+
value: '24h',
1270+
type: 'text',
1271+
},
1272+
interval: {
1273+
value: '5m',
1274+
type: 'text',
1275+
},
1276+
batch_size: {
1277+
value: 1000,
1278+
type: 'text',
1279+
},
1280+
http_client_timeout: {
1281+
value: '30s',
1282+
type: 'text',
1283+
},
1284+
enable_request_tracer: {
1285+
value: false,
1286+
type: 'bool',
1287+
},
1288+
tags: {
1289+
value: ['forwarded', 'microsoft_defender_endpoint-machine_action'],
1290+
type: 'text',
1291+
},
1292+
preserve_original_event: {
1293+
value: false,
1294+
type: 'bool',
1295+
},
1296+
preserve_duplicate_custom_fields: {
1297+
type: 'bool',
1298+
},
1299+
processors: {
1300+
type: 'yaml',
1301+
},
1302+
},
1303+
},
1304+
{
1305+
enabled: false,
1306+
data_stream: {
1307+
type: 'logs',
1308+
dataset: 'microsoft_defender_endpoint.vulnerability',
1309+
},
1310+
vars: {
1311+
interval: {
1312+
value: '4h',
1313+
type: 'text',
1314+
},
1315+
batch_size: {
1316+
value: 8000,
1317+
type: 'integer',
1318+
},
1319+
affected_machines_only: {
1320+
value: true,
1321+
type: 'bool',
1322+
},
1323+
enable_request_tracer: {
1324+
value: false,
1325+
type: 'bool',
1326+
},
1327+
preserve_original_event: {
1328+
value: false,
1329+
type: 'bool',
1330+
},
1331+
tags: {
1332+
value: ['forwarded', 'microsoft_defender_endpoint-vulnerability'],
1333+
type: 'text',
1334+
},
1335+
http_client_timeout: {
1336+
value: '30s',
1337+
type: 'text',
1338+
},
1339+
preserve_duplicate_custom_fields: {
1340+
value: false,
1341+
type: 'bool',
1342+
},
1343+
processors: {
1344+
type: 'yaml',
1345+
},
1346+
},
1347+
},
1348+
],
1349+
vars: {
1350+
client_id: {
1351+
type: 'text',
1352+
},
1353+
client_secret: {
1354+
type: 'password',
1355+
},
1356+
login_url: {
1357+
value: 'https://login.microsoftonline.com',
1358+
type: 'text',
1359+
},
1360+
url: {
1361+
value: 'https://api.security.microsoft.com',
1362+
type: 'text',
1363+
},
1364+
tenant_id: {
1365+
type: 'text',
1366+
},
1367+
token_scopes: {
1368+
value: ['https://securitycenter.onmicrosoft.com/windowsatpservice/.default'],
1369+
type: 'text',
1370+
},
1371+
proxy_url: {
1372+
type: 'text',
1373+
},
1374+
ssl: {
1375+
value:
1376+
'#certificate_authorities:\n# - |\n# -----BEGIN CERTIFICATE-----\n# MIIDCjCCAfKgAwIBAgITJ706Mu2wJlKckpIvkWxEHvEyijANBgkqhkiG9w0BAQsF\n# ADAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwIBcNMTkwNzIyMTkyOTA0WhgPMjExOTA2\n# MjgxOTI5MDRaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEB\n# BQADggEPADCCAQoCggEBANce58Y/JykI58iyOXpxGfw0/gMvF0hUQAcUrSMxEO6n\n# fZRA49b4OV4SwWmA3395uL2eB2NB8y8qdQ9muXUdPBWE4l9rMZ6gmfu90N5B5uEl\n# 94NcfBfYOKi1fJQ9i7WKhTjlRkMCgBkWPkUokvBZFRt8RtF7zI77BSEorHGQCk9t\n# /D7BS0GJyfVEhftbWcFEAG3VRcoMhF7kUzYwp+qESoriFRYLeDWv68ZOvG7eoWnP\n# PsvZStEVEimjvK5NSESEQa9xWyJOmlOKXhkdymtcUd/nXnx6UTCFgnkgzSdTWV41\n# CI6B6aJ9svCTI2QuoIq2HxX/ix7OvW1huVmcyHVxyUECAwEAAaNTMFEwHQYDVR0O\n# BBYEFPwN1OceFGm9v6ux8G+DZ3TUDYxqMB8GA1UdIwQYMBaAFPwN1OceFGm9v6ux\n# 8G+DZ3TUDYxqMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG5D\n# 874A4YI7YUwOVsVAdbWtgp1d0zKcPRR+r2OdSbTAV5/gcS3jgBJ3i1BN34JuDVFw\n# 3DeJSYT3nxy2Y56lLnxDeF8CUTUtVQx3CuGkRg1ouGAHpO/6OqOhwLLorEmxi7tA\n# H2O8mtT0poX5AnOAhzVy7QW0D/k4WaoLyckM5hUa6RtvgvLxOwA0U+VGurCDoctu\n# 8F4QOgTAWyh8EZIwaKCliFRSynDpv3JTUwtfZkxo6K6nce1RhCWFAsMvDZL8Dgc0\n# yvgJ38BRsFOtkRuAGSf6ZUwTO8JJRRIFnpUzXflAnGivK9M13D5GEQMmIl6U9Pvk\n# sxSmbIUfc2SGJGCJD4I=\n# -----END CERTIFICATE-----\n',
1377+
type: 'yaml',
1378+
},
1379+
},
1380+
},
12121381
],
12131382
package: {
12141383
name: packageName,

x-pack/solutions/security/plugins/security_solution/scripts/endpoint/endpoint_policies/index.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,22 @@ import { BaseDataGenerator } from '../../../common/endpoint/data_generators/base
1414
import { getEndpointPackageInfo } from '../../../common/endpoint/utils/package';
1515

1616
class EndpointPolicyGenerator extends BaseDataGenerator {
17+
private counter = 1;
18+
1719
public policyName(preFix: string | number = '') {
18-
return `${preFix}${preFix ? ' ' : ''}${this.randomString(5)} Endpoint Policy`;
20+
return `${preFix}${preFix ? ' ' : ''}${this.randomString(5)}-${this.counter++} Endpoint Policy`;
1921
}
2022
}
2123

2224
const generate = new EndpointPolicyGenerator();
2325

24-
export const cli = () => {
25-
run(
26+
export const cli = async () => {
27+
await run(
2628
async ({ log, flags: { kibana, count } }) => {
2729
const kbn = new KbnClient({ log, url: kibana as string });
2830
const max = Number(count);
31+
const maxErrors = 10; // Max errors encountered until the script exits
32+
const errors: string[] = [];
2933
let created = 0;
3034

3135
log.info(`Creating ${count} endpoint policies...`);
@@ -35,16 +39,24 @@ export const cli = () => {
3539
const endpointPackage = await getEndpointPackageInfo(kbn);
3640

3741
while (created < max) {
38-
created++;
3942
await indexFleetEndpointPolicy(
4043
kbn,
4144
generate.policyName(created),
4245
endpointPackage.version
4346
);
47+
created++;
4448
}
4549
} catch (error) {
46-
log.error(error);
47-
throw createFailError(error.message);
50+
error.push(error.message);
51+
52+
if (errors.length >= maxErrors) {
53+
log.error(
54+
`${errors.length} errors were encountered: ${JSON.stringify(errors, null, 2)}\n`
55+
);
56+
throw createFailError(
57+
`Too many errors encountered (${errors.length}. Only ${created} policies were created`
58+
);
59+
}
4860
}
4961

5062
log.success(`Done!`);

0 commit comments

Comments
 (0)