From cd6c260fa722abd3f8bdf885cd70ad0d81df46c3 Mon Sep 17 00:00:00 2001 From: Michel Losier Date: Mon, 30 Jun 2025 08:19:45 -0700 Subject: [PATCH] Ensure fleet deployment uses fleet url provided by fleet_server_host_id (#225699) ## Summary Resolves: https://github.com/elastic/kibana/issues/221900 In an ECH environment, if a user creates a new fleet server and sets it as default, a new agentless deployment can be created that uses the url of the new default fleet server, but the enrollment API key of the expected preconfigured fleet server. For agentless deployments, we'll want to use the default managed fleet server provided in the cloud environment. This PR ensures we use the fleet server id provided in the request to obtain the url. --------- Co-authored-by: Julia Bardi <90178898+juliaElastic@users.noreply.github.com> (cherry picked from commit 09abd61c5b2bebf0ab48b2098458a30ba02ab02a) --- .../services/agents/agentless_agent.test.ts | 342 ++++++++---------- .../server/services/agents/agentless_agent.ts | 35 +- 2 files changed, 176 insertions(+), 201 deletions(-) diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agents/agentless_agent.test.ts b/x-pack/platform/plugins/shared/fleet/server/services/agents/agentless_agent.test.ts index 2d99cba7eded5..61f625de63794 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agents/agentless_agent.test.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agents/agentless_agent.test.ts @@ -94,7 +94,7 @@ describe('Agentless Agent service', () => { mockedAppContextService.getExperimentalFeatures.mockReturnValue({ agentless: false } as any); (axios as jest.MockedFunction).mockReset(); jest.spyOn(agentPolicyService, 'getFullAgentPolicy').mockResolvedValue({ - outputs: { agentless: {} as any }, + outputs: { default: {} as any }, } as any); jest.clearAllMocks(); }); @@ -131,16 +131,12 @@ describe('Agentless Agent service', () => { jest .spyOn(appContextService, 'getKibanaVersion') .mockReturnValue('mocked-kibana-version-infinite'); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -159,6 +155,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, global_data_tags: [ { @@ -198,7 +196,7 @@ describe('Agentless Agent service', () => { elasticsearch_app_token: 'es-app-token', }, policy_details: { - output_name: 'agentless', + output_name: 'default', }, }), headers: expect.anything(), @@ -239,16 +237,12 @@ describe('Agentless Agent service', () => { jest .spyOn(appContextService, 'getKibanaVersion') .mockReturnValue('mocked-kibana-version-infinite'); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -267,6 +261,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, global_data_tags: [ { @@ -305,7 +301,7 @@ describe('Agentless Agent service', () => { elasticsearch_app_token: 'es-app-token', }, policy_details: { - output_name: 'agentless', + output_name: 'default', }, }), headers: expect.anything(), @@ -346,16 +342,12 @@ describe('Agentless Agent service', () => { jest .spyOn(appContextService, 'getKibanaVersion') .mockReturnValue('mocked-kibana-version-infinite'); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -374,6 +366,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, agentless: { resources: { @@ -426,7 +420,7 @@ describe('Agentless Agent service', () => { elasticsearch_app_token: 'es-app-token', }, policy_details: { - output_name: 'agentless', + output_name: 'default', }, }), headers: expect.anything(), @@ -467,16 +461,12 @@ describe('Agentless Agent service', () => { jest .spyOn(appContextService, 'getKibanaVersion') .mockReturnValue('mocked-kibana-version-infinite'); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -495,6 +485,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, agentless: { resources: { @@ -555,7 +547,7 @@ describe('Agentless Agent service', () => { elasticsearch_app_token: 'es-app-token', }, policy_details: { - output_name: 'agentless', + output_name: 'default', }, }), headers: expect.anything(), @@ -594,16 +586,12 @@ describe('Agentless Agent service', () => { jest .spyOn(appContextService, 'getKibanaVersion') .mockReturnValue('mocked-kibana-version-infinite'); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -622,6 +610,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy ); @@ -798,16 +788,12 @@ describe('Agentless Agent service', () => { .spyOn(appContextService, 'getKibanaVersion') .mockReturnValue('mocked-kibana-version-infinite'); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ @@ -824,6 +810,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy); @@ -856,16 +844,12 @@ describe('Agentless Agent service', () => { .spyOn(appContextService, 'getKibanaVersion') .mockReturnValue('mocked-kibana-version-infinite'); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ @@ -883,6 +867,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError(); @@ -916,16 +902,12 @@ describe('Agentless Agent service', () => { } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ @@ -947,6 +929,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError(); @@ -986,16 +970,12 @@ describe('Agentless Agent service', () => { jest .spyOn(appContextService, 'getKibanaVersion') .mockReturnValue('mocked-kibana-version-infinite'); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -1011,6 +991,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy); @@ -1052,6 +1034,8 @@ describe('Agentless Agent service', () => { id: 'mocked', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: false, } as AgentPolicy) ).rejects.toThrowError( @@ -1089,6 +1073,8 @@ describe('Agentless Agent service', () => { id: 'mocked', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError( @@ -1110,6 +1096,8 @@ describe('Agentless Agent service', () => { id: 'mocked', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError( @@ -1138,7 +1126,7 @@ describe('Agentless Agent service', () => { }, } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - mockedFleetServerHostService.list.mockResolvedValue({ items: [] } as any); + mockedFleetServerHostService.get.mockRejectedValue(new Error('NOT FOUND')); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ { @@ -1154,6 +1142,8 @@ describe('Agentless Agent service', () => { id: 'mocked', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-invalid-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError(new AgentlessAgentConfigError('missing default Fleet server host')); @@ -1180,15 +1170,11 @@ describe('Agentless Agent service', () => { }, } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked', + host: 'http://fleetserver:8220', + active: true, + is_default: true, } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [], @@ -1199,6 +1185,8 @@ describe('Agentless Agent service', () => { id: 'mocked', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError(new AgentlessAgentConfigError('missing Fleet enrollment token')); @@ -1225,16 +1213,12 @@ describe('Agentless Agent service', () => { }, } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -1260,6 +1244,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError(); @@ -1289,16 +1275,12 @@ describe('Agentless Agent service', () => { }, } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -1324,6 +1306,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError(); @@ -1353,16 +1337,12 @@ describe('Agentless Agent service', () => { }, } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -1388,6 +1368,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError(); @@ -1417,16 +1399,12 @@ describe('Agentless Agent service', () => { }, } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -1452,6 +1430,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError(); @@ -1481,16 +1461,12 @@ describe('Agentless Agent service', () => { }, } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -1516,6 +1492,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError(); @@ -1545,16 +1523,12 @@ describe('Agentless Agent service', () => { }, } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -1580,6 +1554,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError(); @@ -1609,16 +1585,12 @@ describe('Agentless Agent service', () => { }, } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -1644,6 +1616,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError(); @@ -1673,16 +1647,12 @@ describe('Agentless Agent service', () => { }, } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - mockedFleetServerHostService.list.mockResolvedValue({ - items: [ - { - id: 'mocked-fleet-server-id', - host: 'http://fleetserver:8220', - active: true, - is_default: true, - host_urls: ['http://fleetserver:8220'], - }, - ], + mockedFleetServerHostService.get.mockResolvedValue({ + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], } as any); mockedListEnrollmentApiKeys.mockResolvedValue({ items: [ @@ -1708,6 +1678,8 @@ describe('Agentless Agent service', () => { id: 'mocked-agentless-agent-policy-id', name: 'agentless agent policy', namespace: 'default', + fleet_server_host_id: 'mock-fleet-default-fleet-server-host', + data_output_id: 'mock-fleet-default-output', supports_agentless: true, } as AgentPolicy) ).rejects.toThrowError(); diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agents/agentless_agent.ts b/x-pack/platform/plugins/shared/fleet/server/services/agents/agentless_agent.ts index c7c0e37207800..644e7451ebad8 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agents/agentless_agent.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agents/agentless_agent.ts @@ -19,7 +19,7 @@ import apm from 'elastic-apm-node'; import { AgentlessAgentCreateOverProvisionedError } from '../../../common/errors'; import { SO_SEARCH_LIMIT } from '../../constants'; import type { AgentPolicy } from '../../types'; -import type { AgentlessApiDeploymentResponse } from '../../../common/types'; +import type { AgentlessApiDeploymentResponse, FleetServerHost } from '../../../common/types'; import { AgentlessAgentConfigError, AgentlessAgentCreateError, @@ -92,10 +92,9 @@ class AgentlessAgentService { ); } - const policyId = agentlessAgentPolicy.id; const { fleetUrl, fleetToken } = await this.getFleetUrlAndTokenForAgentlessAgent( esClient, - policyId, + agentlessAgentPolicy, soClient ); @@ -105,7 +104,7 @@ class AgentlessAgentService { if (agentlessAgentPolicy.agentless?.cloud_connectors?.enabled) { logger.debug( - `[Agentless API] Creating agentless agent with ${agentlessAgentPolicy.agentless?.cloud_connectors?.target_csp} cloud connector enabled for agentless policy ${policyId}` + `[Agentless API] Creating agentless agent with ${agentlessAgentPolicy.agentless?.cloud_connectors?.target_csp} cloud connector enabled for agentless policy ${agentlessAgentPolicy.id}` ); } @@ -123,7 +122,7 @@ class AgentlessAgentService { const requestConfig: AxiosRequestConfig = { url: prependAgentlessApiBasePathToEndpoint(agentlessConfig, '/deployments'), data: { - policy_id: policyId, + policy_id: agentlessAgentPolicy.id, fleet_url: fleetUrl, fleet_token: fleetToken, resources: agentlessAgentPolicy.agentless?.resources, @@ -370,27 +369,31 @@ class AgentlessAgentService { private async getFleetUrlAndTokenForAgentlessAgent( esClient: ElasticsearchClient, - policyId: string, + policy: AgentPolicy, soClient: SavedObjectsClientContract ) { const { items: enrollmentApiKeys } = await listEnrollmentApiKeys(esClient, { perPage: SO_SEARCH_LIMIT, showInactive: true, - kuery: `policy_id:"${policyId}"`, + kuery: `policy_id:"${policy.id}"`, }); - const { items: fleetHosts } = await fleetServerHostService.list(soClient); - // Tech Debt: change this when we add the internal fleet server config to use the internal fleet server host - // https://github.com/elastic/security-team/issues/9695 - const defaultFleetHost = - fleetHosts.length === 1 ? fleetHosts[0] : fleetHosts.find((host) => host.is_default); - - if (!defaultFleetHost) { - throw new AgentlessAgentConfigError('missing default Fleet server host'); - } if (!enrollmentApiKeys.length) { throw new AgentlessAgentConfigError('missing Fleet enrollment token'); } + + if (!policy.fleet_server_host_id) { + throw new AgentlessAgentConfigError('missing fleet_server_host_id'); + } + + let defaultFleetHost: FleetServerHost; + + try { + defaultFleetHost = await fleetServerHostService.get(soClient, policy.fleet_server_host_id); + } catch (e) { + throw new AgentlessAgentConfigError('missing default Fleet server host'); + } + const fleetToken = enrollmentApiKeys[0].api_key; const fleetUrl = defaultFleetHost?.host_urls[0]; return { fleetUrl, fleetToken };