mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Fleet] backfill agentless package policies with supports_agentless
field (#204410)
## Summary Closes https://github.com/elastic/kibana/issues/203821 Added a function to Fleet setup to query package policies that are missing `supports_agentless` field and backfilling them. Only doing this for `cloud_security_posture` package, to skip other non-related packages like `system`. To verify: - follow the steps in the description here to create an agentless agent policy with cspm integration: https://github.com/elastic/kibana/pull/199567 - manually update the package policy to simulate `supports_agentless:false` - trigger Fleet setup - verify that the cspm package policy has `supports_agentless:true` ``` PUT kbn:/api/fleet/package_policies/<policy_id> { "supports_agentless": false } POST kbn:/api/fleet/setup GET kbn:/api/fleet/package_policies/<policy_id> ``` Logs: ``` [2024-12-16T15:42:11.027+01:00][DEBUG][plugins.fleet] Backfilling package policy supports_agentless field [2024-12-16T15:42:11.034+01:00][DEBUG][plugins.fleet] Backfilling supports_agentless on package policies: 6a06d167-e02e-4057-9d71-e1f7e5dd2847 [2024-12-16T15:42:11.035+01:00][DEBUG][plugins.fleet] Starting update of package policy 6a06d167-e02e-4057-9d71-e1f7e5dd2847 [2024-12-16T15:42:13.213+01:00][DEBUG][plugins.fleet] Deploying policies: 0ed942d5-6c01-484f-a1c5-6c7fff92b020:12 [2024-12-16T15:42:13.610+01:00][DEBUG][plugins.fleet] Agent policy 0ed942d5-6c01-484f-a1c5-6c7fff92b020 update completed, revision: 12 [2024-12-16T15:42:13.610+01:00][DEBUG][plugins.fleet] Package policy 6a06d167-e02e-4057-9d71-e1f7e5dd2847 update completed ``` ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
513e025f89
commit
a229d7ab1d
4 changed files with 170 additions and 0 deletions
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 { backfillPackagePolicySupportsAgentless } from './backfill_agentless';
|
||||
import { packagePolicyService } from './package_policy';
|
||||
|
||||
jest.mock('.', () => ({
|
||||
appContextService: {
|
||||
getLogger: () => ({
|
||||
debug: jest.fn(),
|
||||
}),
|
||||
getInternalUserSOClientForSpaceId: jest.fn(),
|
||||
getInternalUserSOClientWithoutSpaceExtension: () => ({
|
||||
find: jest.fn().mockImplementation((options) => {
|
||||
if (options.type === 'ingest-agent-policies') {
|
||||
return {
|
||||
saved_objects: [{ id: 'agent_policy_1' }, { id: 'agent_policy_2' }],
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
saved_objects: [
|
||||
{
|
||||
id: 'package_policy_1',
|
||||
attributes: {
|
||||
inputs: [],
|
||||
policy_ids: ['agent_policy_1'],
|
||||
supports_agentless: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}),
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('./package_policy', () => ({
|
||||
packagePolicyService: {
|
||||
update: jest.fn(),
|
||||
},
|
||||
getPackagePolicySavedObjectType: jest.fn().mockResolvedValue('ingest-package-policies'),
|
||||
}));
|
||||
|
||||
describe('backfill agentless package policies', () => {
|
||||
it('should backfill package policies missing supports_agentless', async () => {
|
||||
await backfillPackagePolicySupportsAgentless(undefined as any);
|
||||
|
||||
expect(packagePolicyService.update).toHaveBeenCalledWith(
|
||||
undefined,
|
||||
undefined,
|
||||
'package_policy_1',
|
||||
{
|
||||
enabled: undefined,
|
||||
inputs: [],
|
||||
name: undefined,
|
||||
policy_ids: ['agent_policy_1'],
|
||||
supports_agentless: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
99
x-pack/plugins/fleet/server/services/backfill_agentless.ts
Normal file
99
x-pack/plugins/fleet/server/services/backfill_agentless.ts
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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 type { ElasticsearchClient } from '@kbn/core/server';
|
||||
|
||||
import pMap from 'p-map';
|
||||
|
||||
import { MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, SO_SEARCH_LIMIT } from '../constants';
|
||||
|
||||
import type { AgentPolicySOAttributes, PackagePolicy, PackagePolicySOAttributes } from '../types';
|
||||
|
||||
import { getAgentPolicySavedObjectType } from './agent_policy';
|
||||
|
||||
import { appContextService } from '.';
|
||||
import { getPackagePolicySavedObjectType, packagePolicyService } from './package_policy';
|
||||
import { mapPackagePolicySavedObjectToPackagePolicy } from './package_policies';
|
||||
|
||||
export async function backfillPackagePolicySupportsAgentless(esClient: ElasticsearchClient) {
|
||||
const apSavedObjectType = await getAgentPolicySavedObjectType();
|
||||
const internalSoClientWithoutSpaceExtension =
|
||||
appContextService.getInternalUserSOClientWithoutSpaceExtension();
|
||||
const findRes = await internalSoClientWithoutSpaceExtension.find<AgentPolicySOAttributes>({
|
||||
type: apSavedObjectType,
|
||||
page: 1,
|
||||
perPage: SO_SEARCH_LIMIT,
|
||||
filter: `${apSavedObjectType}.attributes.supports_agentless:true`,
|
||||
fields: [`id`],
|
||||
namespaces: ['*'],
|
||||
});
|
||||
|
||||
const agentPolicyIds = findRes.saved_objects.map((so) => so.id);
|
||||
|
||||
if (agentPolicyIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const savedObjectType = await getPackagePolicySavedObjectType();
|
||||
const packagePoliciesToUpdate = (
|
||||
await appContextService
|
||||
.getInternalUserSOClientWithoutSpaceExtension()
|
||||
.find<PackagePolicySOAttributes>({
|
||||
type: savedObjectType,
|
||||
fields: [
|
||||
'name',
|
||||
'policy_ids',
|
||||
'supports_agentless',
|
||||
'enabled',
|
||||
'policy_ids',
|
||||
'inputs',
|
||||
'package',
|
||||
],
|
||||
filter: `${savedObjectType}.attributes.package.name:cloud_security_posture AND (NOT ${savedObjectType}.attributes.supports_agentless:true) AND ${savedObjectType}.attributes.policy_ids:(${agentPolicyIds.join(
|
||||
' OR '
|
||||
)})`,
|
||||
perPage: SO_SEARCH_LIMIT,
|
||||
namespaces: ['*'],
|
||||
})
|
||||
).saved_objects.map((so) => mapPackagePolicySavedObjectToPackagePolicy(so, so.namespaces));
|
||||
|
||||
appContextService
|
||||
.getLogger()
|
||||
.debug(
|
||||
`Backfilling supports_agentless on package policies: ${packagePoliciesToUpdate.map(
|
||||
(policy) => policy.id
|
||||
)}`
|
||||
);
|
||||
|
||||
if (packagePoliciesToUpdate.length > 0) {
|
||||
const getPackagePolicyUpdate = (packagePolicy: PackagePolicy) => ({
|
||||
name: packagePolicy.name,
|
||||
enabled: packagePolicy.enabled,
|
||||
policy_ids: packagePolicy.policy_ids,
|
||||
inputs: packagePolicy.inputs,
|
||||
supports_agentless: true,
|
||||
});
|
||||
|
||||
await pMap(
|
||||
packagePoliciesToUpdate,
|
||||
(packagePolicy) => {
|
||||
const soClient = appContextService.getInternalUserSOClientForSpaceId(
|
||||
packagePolicy.spaceIds?.[0]
|
||||
);
|
||||
return packagePolicyService.update(
|
||||
soClient,
|
||||
esClient,
|
||||
packagePolicy.id,
|
||||
getPackagePolicyUpdate(packagePolicy)
|
||||
);
|
||||
},
|
||||
{
|
||||
concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ jest.mock('./epm/elasticsearch/template/install', () => {
|
|||
...jest.requireActual('./epm/elasticsearch/template/install'),
|
||||
};
|
||||
});
|
||||
jest.mock('./backfill_agentless');
|
||||
|
||||
const mockedMethodThrowsError = (mockFn: jest.Mock) =>
|
||||
mockFn.mockImplementation(() => {
|
||||
|
|
|
@ -62,6 +62,7 @@ import {
|
|||
ensureDeleteUnenrolledAgentsSetting,
|
||||
getPreconfiguredDeleteUnenrolledAgentsSettingFromConfig,
|
||||
} from './preconfiguration/delete_unenrolled_agent_setting';
|
||||
import { backfillPackagePolicySupportsAgentless } from './backfill_agentless';
|
||||
|
||||
export interface SetupStatus {
|
||||
isInitialized: boolean;
|
||||
|
@ -305,6 +306,9 @@ async function createSetupSideEffects(
|
|||
await ensureAgentPoliciesFleetServerKeysAndPolicies({ soClient, esClient, logger });
|
||||
stepSpan?.end();
|
||||
|
||||
logger.debug('Backfilling package policy supports_agentless field');
|
||||
await backfillPackagePolicySupportsAgentless(esClient);
|
||||
|
||||
const nonFatalErrors = [
|
||||
...preconfiguredPackagesNonFatalErrors,
|
||||
...(messageSigningServiceNonFatalError ? [messageSigningServiceNonFatalError] : []),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue