From 7461aa6d89c6feeb9ca495cc4838c6e9ec5ef562 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Wed, 2 Oct 2024 04:57:23 -0700 Subject: [PATCH] [8.x] [UII] Add proxy args to install snippets (#193922) (#194642) # Backport This will backport the following commits from `main` to `8.x`: - [[UII] Add proxy args to install snippets (#193922)](https://github.com/elastic/kibana/pull/193922) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) --- .../fleet_settings_enrollment_response.yaml | 12 + .../fleet/common/types/rest_spec/settings.ts | 13 +- .../steps/install_fleet_server.tsx | 33 +- .../utils/install_command_utils.test.ts | 695 +++++++++++++++--- .../utils/install_command_utils.ts | 86 ++- .../install_agent_standalone.tsx | 2 +- .../agent_enrollment_flyout/index.tsx | 10 +- .../steps/compute_steps.tsx | 12 +- .../agent_enrollment_flyout/types.ts | 1 + .../enrollment_instructions/manual/index.tsx | 57 +- .../standalone/index.tsx | 27 +- ...use_fleet_server_hosts_for_policy.test.tsx | 52 ++ .../use_fleet_server_hosts_for_policy.ts | 8 +- .../settings/enrollment_settings_handler.ts | 37 +- .../apis/settings/enrollment.ts | 45 +- .../es_archives/fleet/fleet_server/data.json | 5 +- 16 files changed, 907 insertions(+), 188 deletions(-) diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/fleet_settings_enrollment_response.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/fleet_settings_enrollment_response.yaml index 5c9204e5f35a3..8de00dae5c9ea 100644 --- a/x-pack/plugins/fleet/common/openapi/components/schemas/fleet_settings_enrollment_response.yaml +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/fleet_settings_enrollment_response.yaml @@ -23,6 +23,12 @@ properties: type: string download_source_id: type: string + space_ids: + type: array + items: + type: string + data_output_id: + type: string required: - id - name @@ -33,10 +39,16 @@ properties: $ref: ./fleet_server_host.yaml host_proxy: $ref: ./proxies.yaml + es_output: + $ref: ./output_create_request_elasticsearch.yaml + es_output_proxy: + $ref: ./proxies.yaml required: - agent_policies - has_active download_source: $ref: ./download_sources.yaml + download_source_proxy: + $ref: ./proxies.yaml required: - fleet_server diff --git a/x-pack/plugins/fleet/common/types/rest_spec/settings.ts b/x-pack/plugins/fleet/common/types/rest_spec/settings.ts index 6961a0254562f..c281b79b4d50c 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/settings.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/settings.ts @@ -5,7 +5,14 @@ * 2.0. */ -import type { Settings, AgentPolicy, FleetServerHost, FleetProxy, DownloadSource } from '../models'; +import type { + Settings, + AgentPolicy, + FleetServerHost, + FleetProxy, + DownloadSource, + Output, +} from '../models'; export interface GetSettingsResponse { item: Settings; @@ -35,16 +42,20 @@ export type EnrollmentSettingsFleetServerPolicy = Pick< | 'fleet_server_host_id' | 'download_source_id' | 'space_ids' + | 'data_output_id' >; export interface GetEnrollmentSettingsResponse { fleet_server: { policies: EnrollmentSettingsFleetServerPolicy[]; has_active: boolean; + es_output?: Output; + es_output_proxy?: FleetProxy; host?: FleetServerHost; host_proxy?: FleetProxy; }; download_source?: DownloadSource; + download_source_proxy?: FleetProxy; } export interface PutSpaceSettingsRequest { body: { diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/steps/install_fleet_server.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/steps/install_fleet_server.tsx index 97edbd849e0ae..a7631deb88b80 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/steps/install_fleet_server.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/steps/install_fleet_server.tsx @@ -13,8 +13,8 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { PLATFORM_TYPE } from '../../../hooks'; -import { useDefaultDownloadSource } from '../../../hooks'; -import { useStartServices, useDefaultOutput, useKibanaVersion } from '../../../hooks'; +import { useFleetServerHostsForPolicy } from '../../../hooks'; +import { useStartServices, useKibanaVersion } from '../../../hooks'; import { PlatformSelector } from '../..'; @@ -61,24 +61,31 @@ const InstallFleetServerStepContent: React.FunctionComponent<{ }> = ({ serviceToken, fleetServerHost, fleetServerPolicyId, deploymentMode }) => { const { docLinks } = useStartServices(); const kibanaVersion = useKibanaVersion(); - const { output } = useDefaultOutput(); - const { downloadSource } = useDefaultDownloadSource(); - const commandOutput = output?.type === 'elasticsearch' ? output : undefined; + const { esOutput, esOutputProxy, downloadSource, downloadSourceProxy } = + useFleetServerHostsForPolicy( + fleetServerPolicyId + ? { + id: fleetServerPolicyId, + } + : null + ); const installCommands = (['linux', 'mac', 'windows', 'deb', 'rpm'] as PLATFORM_TYPE[]).reduce( (acc, platform) => { - acc[platform] = getInstallCommandForPlatform( + acc[platform] = getInstallCommandForPlatform({ platform, - commandOutput?.hosts?.[0] ?? '', - serviceToken ?? '', - fleetServerPolicyId, + esOutputHost: esOutput?.hosts?.[0] ?? '', + esOutputProxy, + serviceToken: serviceToken ?? '', + policyId: fleetServerPolicyId, fleetServerHost, - deploymentMode === 'production', - commandOutput?.ca_trusted_fingerprint ?? undefined, + isProductionDeployment: deploymentMode === 'production', + sslCATrustedFingerprint: esOutput?.ca_trusted_fingerprint ?? undefined, kibanaVersion, - downloadSource - ); + downloadSource, + downloadSourceProxy, + }); return acc; }, diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts index 21a2cc53257f7..c86811da2fde7 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts @@ -10,11 +10,11 @@ import { getInstallCommandForPlatform } from './install_command_utils'; describe('getInstallCommandForPlatform', () => { describe('without policy id', () => { it('should return the correct command if the the policyId is not set for linux', () => { - const res = getInstallCommandForPlatform( - 'linux', - 'http://elasticsearch:9200', - 'service-token-1' - ); + const res = getInstallCommandForPlatform({ + platform: 'linux', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--linux-x86_64.tar.gz @@ -28,11 +28,11 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command if the the policyId is not set for mac', () => { - const res = getInstallCommandForPlatform( - 'mac', - 'http://elasticsearch:9200', - 'service-token-1' - ); + const res = getInstallCommandForPlatform({ + platform: 'mac', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--darwin-aarch64.tar.gz @@ -46,11 +46,11 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command if the the policyId is not set for windows', () => { - const res = getInstallCommandForPlatform( - 'windows', - 'http://elasticsearch:9200', - 'service-token-1' - ); + const res = getInstallCommandForPlatform({ + platform: 'windows', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + }); expect(res).toMatchInlineSnapshot(` "$ProgressPreference = 'SilentlyContinue' @@ -65,11 +65,11 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command if the the policyId is not set for rpm', () => { - const res = getInstallCommandForPlatform( - 'rpm', - 'http://elasticsearch:9200', - 'service-token-1' - ); + const res = getInstallCommandForPlatform({ + platform: 'rpm', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--x86_64.rpm @@ -84,11 +84,11 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command if the the policyId is not set for deb', () => { - const res = getInstallCommandForPlatform( - 'deb', - 'http://elasticsearch:9200', - 'service-token-1' - ); + const res = getInstallCommandForPlatform({ + platform: 'deb', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb @@ -103,15 +103,12 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command sslCATrustedFingerprint option is passed', () => { - const res = getInstallCommandForPlatform( - 'linux', - 'http://elasticsearch:9200', - 'service-token-1', - undefined, - undefined, - false, - 'fingerprint123456' - ); + const res = getInstallCommandForPlatform({ + platform: 'linux', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + sslCATrustedFingerprint: 'fingerprint123456', + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--linux-x86_64.tar.gz @@ -128,12 +125,12 @@ describe('getInstallCommandForPlatform', () => { describe('with policy id', () => { it('should return the correct command if the the policyId is set for linux', () => { - const res = getInstallCommandForPlatform( - 'linux', - 'http://elasticsearch:9200', - 'service-token-1', - 'policy-1' - ); + const res = getInstallCommandForPlatform({ + platform: 'linux', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + policyId: 'policy-1', + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--linux-x86_64.tar.gz @@ -148,12 +145,12 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command if the the policyId is set for mac', () => { - const res = getInstallCommandForPlatform( - 'mac', - 'http://elasticsearch:9200', - 'service-token-1', - 'policy-1' - ); + const res = getInstallCommandForPlatform({ + platform: 'mac', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + policyId: 'policy-1', + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--darwin-aarch64.tar.gz @@ -168,12 +165,12 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command if the the policyId is set for windows', () => { - const res = getInstallCommandForPlatform( - 'windows', - 'http://elasticsearch:9200', - 'service-token-1', - 'policy-1' - ); + const res = getInstallCommandForPlatform({ + platform: 'windows', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + policyId: 'policy-1', + }); expect(res).toMatchInlineSnapshot(` "$ProgressPreference = 'SilentlyContinue' @@ -189,12 +186,12 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command if the the policyId is set for rpm', () => { - const res = getInstallCommandForPlatform( - 'rpm', - 'http://elasticsearch:9200', - 'service-token-1', - 'policy-1' - ); + const res = getInstallCommandForPlatform({ + platform: 'rpm', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + policyId: 'policy-1', + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--x86_64.rpm @@ -210,12 +207,12 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command if the the policyId is set for deb', () => { - const res = getInstallCommandForPlatform( - 'deb', - 'http://elasticsearch:9200', - 'service-token-1', - 'policy-1' - ); + const res = getInstallCommandForPlatform({ + platform: 'deb', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + policyId: 'policy-1', + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb @@ -233,22 +230,18 @@ describe('getInstallCommandForPlatform', () => { describe('with policy id and downloadSource', () => { it('should return the correct command if the the policyId is set for linux', () => { - const res = getInstallCommandForPlatform( - 'linux', - 'http://elasticsearch:9200', - 'service-token-1', - 'policy-1', - undefined, - undefined, - undefined, - undefined, - { + const res = getInstallCommandForPlatform({ + platform: 'linux', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + policyId: 'policy-1', + downloadSource: { id: 'test', name: 'test', is_default: false, host: 'https://test.fr/8.12.0-test/', - } - ); + }, + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://test.fr/8.12.0-test/beats/elastic-agent/elastic-agent--linux-x86_64.tar.gz @@ -265,14 +258,14 @@ describe('getInstallCommandForPlatform', () => { describe('with policy id and fleet server host and production deployment', () => { it('should return the correct command if the the policyId is set for linux', () => { - const res = getInstallCommandForPlatform( - 'linux', - 'http://elasticsearch:9200', - 'service-token-1', - 'policy-1', - 'http://fleetserver:8220', - true - ); + const res = getInstallCommandForPlatform({ + platform: 'linux', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + isProductionDeployment: true, + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--linux-x86_64.tar.gz @@ -291,14 +284,14 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command if the the policyId is set for mac', () => { - const res = getInstallCommandForPlatform( - 'mac', - 'http://elasticsearch:9200', - 'service-token-1', - 'policy-1', - 'http://fleetserver:8220', - true - ); + const res = getInstallCommandForPlatform({ + platform: 'mac', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + isProductionDeployment: true, + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--darwin-aarch64.tar.gz @@ -317,14 +310,14 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command if the the policyId is set for windows', () => { - const res = getInstallCommandForPlatform( - 'windows', - 'http://elasticsearch:9200', - 'service-token-1', - 'policy-1', - 'http://fleetserver:8220', - true - ); + const res = getInstallCommandForPlatform({ + platform: 'windows', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + isProductionDeployment: true, + }); expect(res).toMatchInlineSnapshot(` "$ProgressPreference = 'SilentlyContinue' @@ -344,14 +337,14 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command if the the policyId is set for rpm', () => { - const res = getInstallCommandForPlatform( - 'rpm', - 'http://elasticsearch:9200', - 'service-token-1', - 'policy-1', - 'http://fleetserver:8220', - true - ); + const res = getInstallCommandForPlatform({ + platform: 'rpm', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + isProductionDeployment: true, + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--x86_64.rpm @@ -371,14 +364,14 @@ describe('getInstallCommandForPlatform', () => { }); it('should return the correct command if the the policyId is set for deb', () => { - const res = getInstallCommandForPlatform( - 'deb', - 'http://elasticsearch:9200', - 'service-token-1', - 'policy-1', - 'http://fleetserver:8220', - true - ); + const res = getInstallCommandForPlatform({ + platform: 'deb', + esOutputHost: 'http://elasticsearch:9200', + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + isProductionDeployment: true, + }); expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb @@ -397,4 +390,474 @@ describe('getInstallCommandForPlatform', () => { `); }); }); + + describe('with simple proxy settings', () => { + it('should return the correct command if proxies are set for linux', () => { + const res = getInstallCommandForPlatform({ + platform: 'linux', + esOutputHost: 'http://elasticsearch:9200', + esOutputProxy: { + id: 'es-proxy', + name: 'es-proxy', + url: 'http://es-proxy:1111', + is_preconfigured: false, + }, + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + downloadSource: { + id: 'download-src', + name: 'download-src', + host: 'https://download-src/8.12.0-test/', + is_default: false, + proxy_id: 'download-proxy', + }, + downloadSourceProxy: { + id: 'download-src-proxy', + name: 'download-src-proxy', + url: 'http://download-src-proxy:2222', + is_preconfigured: false, + }, + }); + + expect(res).toMatchInlineSnapshot(` + "curl -L -O https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--linux-x86_64.tar.gz --proxy http://download-src-proxy:2222 + tar xzvf elastic-agent--linux-x86_64.tar.gz + cd elastic-agent--linux-x86_64 + sudo ./elastic-agent install \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1 \\\\ + --fleet-server-policy=policy-1 \\\\ + --fleet-server-port=8220 \\\\ + --proxy-url=http://es-proxy:1111" + `); + }); + + it('should return the correct command if proxies are set for mac', () => { + const res = getInstallCommandForPlatform({ + platform: 'mac', + esOutputHost: 'http://elasticsearch:9200', + esOutputProxy: { + id: 'es-proxy', + name: 'es-proxy', + url: 'http://es-proxy:1111', + is_preconfigured: false, + }, + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + downloadSource: { + id: 'download-src', + name: 'download-src', + host: 'https://download-src/8.12.0-test/', + is_default: false, + proxy_id: 'download-proxy', + }, + downloadSourceProxy: { + id: 'download-src-proxy', + name: 'download-src-proxy', + url: 'http://download-src-proxy:2222', + is_preconfigured: false, + }, + }); + + expect(res).toMatchInlineSnapshot(` + "curl -L -O https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--darwin-aarch64.tar.gz --proxy http://download-src-proxy:2222 + tar xzvf elastic-agent--darwin-aarch64.tar.gz + cd elastic-agent--darwin-aarch64 + sudo ./elastic-agent install \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1 \\\\ + --fleet-server-policy=policy-1 \\\\ + --fleet-server-port=8220 \\\\ + --proxy-url=http://es-proxy:1111" + `); + }); + + it('should return the correct command if proxies are set for windows', () => { + const res = getInstallCommandForPlatform({ + platform: 'windows', + esOutputHost: 'http://elasticsearch:9200', + esOutputProxy: { + id: 'es-proxy', + name: 'es-proxy', + url: 'http://es-proxy:1111', + is_preconfigured: false, + }, + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + downloadSource: { + id: 'download-src', + name: 'download-src', + host: 'https://download-src/8.12.0-test/', + is_default: false, + proxy_id: 'download-proxy', + }, + downloadSourceProxy: { + id: 'download-src-proxy', + name: 'download-src-proxy', + url: 'http://download-src-proxy:2222', + is_preconfigured: false, + }, + }); + + expect(res).toMatchInlineSnapshot(` + "$ProgressPreference = 'SilentlyContinue' + Invoke-WebRequest -Uri https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--windows-x86_64.zip -OutFile elastic-agent--windows-x86_64.zip -Proxy \\"http://download-src-proxy:2222\\" + Expand-Archive .\\\\elastic-agent--windows-x86_64.zip + cd elastic-agent--windows-x86_64 + .\\\\elastic-agent.exe install \` + --fleet-server-es=http://elasticsearch:9200 \` + --fleet-server-service-token=service-token-1 \` + --fleet-server-policy=policy-1 \` + --fleet-server-port=8220 \` + --proxy-url=http://es-proxy:1111" + `); + }); + + it('should return the correct command if proxies are set for rpm', () => { + const res = getInstallCommandForPlatform({ + platform: 'rpm', + esOutputHost: 'http://elasticsearch:9200', + esOutputProxy: { + id: 'es-proxy', + name: 'es-proxy', + url: 'http://es-proxy:1111', + is_preconfigured: false, + }, + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + downloadSource: { + id: 'download-src', + name: 'download-src', + host: 'https://download-src/8.12.0-test/', + is_default: false, + proxy_id: 'download-proxy', + }, + downloadSourceProxy: { + id: 'download-src-proxy', + name: 'download-src-proxy', + url: 'http://download-src-proxy:2222', + is_preconfigured: false, + }, + }); + + expect(res).toMatchInlineSnapshot(` + "curl -L -O https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--x86_64.rpm --proxy http://download-src-proxy:2222 + sudo rpm -vi elastic-agent--x86_64.rpm + sudo elastic-agent enroll \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1 \\\\ + --fleet-server-policy=policy-1 \\\\ + --fleet-server-port=8220 \\\\ + --proxy-url=http://es-proxy:1111 + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent" + `); + }); + + it('should return the correct command if proxies are set for deb', () => { + const res = getInstallCommandForPlatform({ + platform: 'deb', + esOutputHost: 'http://elasticsearch:9200', + esOutputProxy: { + id: 'es-proxy', + name: 'es-proxy', + url: 'http://es-proxy:1111', + is_preconfigured: false, + }, + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + downloadSource: { + id: 'download-src', + name: 'download-src', + host: 'https://download-src/8.12.0-test/', + is_default: false, + proxy_id: 'download-proxy', + }, + downloadSourceProxy: { + id: 'download-src-proxy', + name: 'download-src-proxy', + url: 'http://download-src-proxy:2222', + is_preconfigured: false, + }, + }); + + expect(res).toMatchInlineSnapshot(` + "curl -L -O https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--amd64.deb --proxy http://download-src-proxy:2222 + sudo dpkg -i elastic-agent--amd64.deb + sudo elastic-agent enroll \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1 \\\\ + --fleet-server-policy=policy-1 \\\\ + --fleet-server-port=8220 \\\\ + --proxy-url=http://es-proxy:1111 + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent" + `); + }); + }); + + describe('with full proxy settings', () => { + it('should return the correct command if proxies are set for linux', () => { + const res = getInstallCommandForPlatform({ + platform: 'linux', + esOutputHost: 'http://elasticsearch:9200', + esOutputProxy: { + id: 'es-proxy', + name: 'es-proxy', + url: 'http://es-proxy:1111', + proxy_headers: { + 'X-Forwarded-For': 'forwarded-value', + 'test-header': 'test-value', + }, + is_preconfigured: false, + }, + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + downloadSource: { + id: 'download-src', + name: 'download-src', + host: 'https://download-src/8.12.0-test/', + is_default: false, + proxy_id: 'download-proxy', + }, + downloadSourceProxy: { + id: 'download-src-proxy', + name: 'download-src-proxy', + url: 'http://download-src-proxy:2222', + proxy_headers: { + 'Accept-Language': 'en-US,en;q=0.5', + 'second-header': 'second-value', + }, + is_preconfigured: false, + }, + }); + + expect(res).toMatchInlineSnapshot(` + "curl -L -O https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--linux-x86_64.tar.gz --proxy http://download-src-proxy:2222 --proxy-header \\"Accept-Language=en-US,en;q=0.5\\" --proxy-header \\"second-header=second-value\\" + tar xzvf elastic-agent--linux-x86_64.tar.gz + cd elastic-agent--linux-x86_64 + sudo ./elastic-agent install \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1 \\\\ + --fleet-server-policy=policy-1 \\\\ + --fleet-server-port=8220 \\\\ + --proxy-url=http://es-proxy:1111 \\\\ + --proxy-header=\\"X-Forwarded-For=forwarded-value\\" \\\\ + --proxy-header=\\"test-header=test-value\\"" + `); + }); + + it('should return the correct command if proxies are set for mac', () => { + const res = getInstallCommandForPlatform({ + platform: 'mac', + esOutputHost: 'http://elasticsearch:9200', + esOutputProxy: { + id: 'es-proxy', + name: 'es-proxy', + url: 'http://es-proxy:1111', + proxy_headers: { + 'X-Forwarded-For': 'forwarded-value', + 'test-header': 'test-value', + }, + is_preconfigured: false, + }, + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + downloadSource: { + id: 'download-src', + name: 'download-src', + host: 'https://download-src/8.12.0-test/', + is_default: false, + proxy_id: 'download-proxy', + }, + downloadSourceProxy: { + id: 'download-src-proxy', + name: 'download-src-proxy', + url: 'http://download-src-proxy:2222', + proxy_headers: { + 'Accept-Language': 'en-US,en;q=0.5', + 'second-header': 'second-value', + }, + is_preconfigured: false, + }, + }); + + expect(res).toMatchInlineSnapshot(` + "curl -L -O https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--darwin-aarch64.tar.gz --proxy http://download-src-proxy:2222 --proxy-header \\"Accept-Language=en-US,en;q=0.5\\" --proxy-header \\"second-header=second-value\\" + tar xzvf elastic-agent--darwin-aarch64.tar.gz + cd elastic-agent--darwin-aarch64 + sudo ./elastic-agent install \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1 \\\\ + --fleet-server-policy=policy-1 \\\\ + --fleet-server-port=8220 \\\\ + --proxy-url=http://es-proxy:1111 \\\\ + --proxy-header=\\"X-Forwarded-For=forwarded-value\\" \\\\ + --proxy-header=\\"test-header=test-value\\"" + `); + }); + + it('should return the correct command if proxies are set for windows', () => { + const res = getInstallCommandForPlatform({ + platform: 'windows', + esOutputHost: 'http://elasticsearch:9200', + esOutputProxy: { + id: 'es-proxy', + name: 'es-proxy', + url: 'http://es-proxy:1111', + proxy_headers: { + 'X-Forwarded-For': 'forwarded-value', + 'test-header': 'test-value', + }, + is_preconfigured: false, + }, + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + downloadSource: { + id: 'download-src', + name: 'download-src', + host: 'https://download-src/8.12.0-test/', + is_default: false, + proxy_id: 'download-proxy', + }, + downloadSourceProxy: { + id: 'download-src-proxy', + name: 'download-src-proxy', + url: 'http://download-src-proxy:2222', + proxy_headers: { + 'Accept-Language': 'en-US,en;q=0.5', + 'second-header': 'second-value', + }, + is_preconfigured: false, + }, + }); + + expect(res).toMatchInlineSnapshot(` + "$ProgressPreference = 'SilentlyContinue' + Invoke-WebRequest -Uri https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--windows-x86_64.zip -OutFile elastic-agent--windows-x86_64.zip -Proxy \\"http://download-src-proxy:2222\\" -Headers @{\\"Accept-Language\\"=\\"en-US,en;q=0.5\\"; \\"second-header\\"=\\"second-value\\"} + Expand-Archive .\\\\elastic-agent--windows-x86_64.zip + cd elastic-agent--windows-x86_64 + .\\\\elastic-agent.exe install \` + --fleet-server-es=http://elasticsearch:9200 \` + --fleet-server-service-token=service-token-1 \` + --fleet-server-policy=policy-1 \` + --fleet-server-port=8220 \` + --proxy-url=http://es-proxy:1111 \` + --proxy-header=\\"X-Forwarded-For=forwarded-value\\" \` + --proxy-header=\\"test-header=test-value\\"" + `); + }); + + it('should return the correct command if proxies are set for rpm', () => { + const res = getInstallCommandForPlatform({ + platform: 'rpm', + esOutputHost: 'http://elasticsearch:9200', + esOutputProxy: { + id: 'es-proxy', + name: 'es-proxy', + url: 'http://es-proxy:1111', + proxy_headers: { + 'X-Forwarded-For': 'forwarded-value', + 'test-header': 'test-value', + }, + is_preconfigured: false, + }, + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + downloadSource: { + id: 'download-src', + name: 'download-src', + host: 'https://download-src/8.12.0-test/', + is_default: false, + proxy_id: 'download-proxy', + }, + downloadSourceProxy: { + id: 'download-src-proxy', + name: 'download-src-proxy', + url: 'http://download-src-proxy:2222', + proxy_headers: { + 'Accept-Language': 'en-US,en;q=0.5', + 'second-header': 'second-value', + }, + is_preconfigured: false, + }, + }); + + expect(res).toMatchInlineSnapshot(` + "curl -L -O https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--x86_64.rpm --proxy http://download-src-proxy:2222 --proxy-header \\"Accept-Language=en-US,en;q=0.5\\" --proxy-header \\"second-header=second-value\\" + sudo rpm -vi elastic-agent--x86_64.rpm + sudo elastic-agent enroll \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1 \\\\ + --fleet-server-policy=policy-1 \\\\ + --fleet-server-port=8220 \\\\ + --proxy-url=http://es-proxy:1111 \\\\ + --proxy-header=\\"X-Forwarded-For=forwarded-value\\" \\\\ + --proxy-header=\\"test-header=test-value\\" + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent" + `); + }); + + it('should return the correct command if proxies are set for deb', () => { + const res = getInstallCommandForPlatform({ + platform: 'deb', + esOutputHost: 'http://elasticsearch:9200', + esOutputProxy: { + id: 'es-proxy', + name: 'es-proxy', + url: 'http://es-proxy:1111', + proxy_headers: { + 'X-Forwarded-For': 'forwarded-value', + 'test-header': 'test-value', + }, + is_preconfigured: false, + }, + serviceToken: 'service-token-1', + policyId: 'policy-1', + fleetServerHost: 'http://fleetserver:8220', + downloadSource: { + id: 'download-src', + name: 'download-src', + host: 'https://download-src/8.12.0-test/', + is_default: false, + proxy_id: 'download-proxy', + }, + downloadSourceProxy: { + id: 'download-src-proxy', + name: 'download-src-proxy', + url: 'http://download-src-proxy:2222', + proxy_headers: { + 'Accept-Language': 'en-US,en;q=0.5', + 'second-header': 'second-value', + }, + is_preconfigured: false, + }, + }); + + expect(res).toMatchInlineSnapshot(` + "curl -L -O https://download-src/8.12.0-test/beats/elastic-agent/elastic-agent--amd64.deb --proxy http://download-src-proxy:2222 --proxy-header \\"Accept-Language=en-US,en;q=0.5\\" --proxy-header \\"second-header=second-value\\" + sudo dpkg -i elastic-agent--amd64.deb + sudo elastic-agent enroll \\\\ + --fleet-server-es=http://elasticsearch:9200 \\\\ + --fleet-server-service-token=service-token-1 \\\\ + --fleet-server-policy=policy-1 \\\\ + --fleet-server-port=8220 \\\\ + --proxy-url=http://es-proxy:1111 \\\\ + --proxy-header=\\"X-Forwarded-For=forwarded-value\\" \\\\ + --proxy-header=\\"test-header=test-value\\" + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent" + `); + }); + }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts index 79809b94470e4..5656e49de4bc9 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts @@ -5,7 +5,11 @@ * 2.0. */ -import type { DownloadSource } from '../../../../../../common/types'; +import type { DownloadSource, FleetProxy } from '../../../../../../common/types'; +import { + getDownloadBaseUrl, + getDownloadSourceProxyArgs, +} from '../../../../../components/enrollment_instructions/manual'; import type { PLATFORM_TYPE } from '../../../hooks'; export type CommandsByPlatform = { @@ -15,27 +19,31 @@ export type CommandsByPlatform = { function getArtifact( platform: PLATFORM_TYPE, kibanaVersion: string, - downloadSource?: DownloadSource + downloadSource?: DownloadSource, + downloadSourceProxy?: FleetProxy ) { - const ARTIFACT_BASE_URL = `${ - downloadSource - ? downloadSource.host.endsWith('/') - ? downloadSource.host.substring(0, downloadSource.host.length - 1) - : downloadSource.host - : 'https://artifacts.elastic.co/downloads' - }/beats/elastic-agent`; + const ARTIFACT_BASE_URL = `${getDownloadBaseUrl(downloadSource)}/beats/elastic-agent`; + const { windows: windowsDownloadSourceProxyArgs, curl: curlDownloadSourceProxyArgs } = + getDownloadSourceProxyArgs(downloadSourceProxy); + + const appendWindowsDownloadSourceProxyArgs = windowsDownloadSourceProxyArgs + ? ` ${windowsDownloadSourceProxyArgs}` + : ''; + const appendCurlDownloadSourceProxyArgs = curlDownloadSourceProxyArgs + ? ` ${curlDownloadSourceProxyArgs}` + : ''; const artifactMap: Record = { linux: { downloadCommand: [ - `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-linux-x86_64.tar.gz`, + `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-linux-x86_64.tar.gz${appendCurlDownloadSourceProxyArgs}`, `tar xzvf elastic-agent-${kibanaVersion}-linux-x86_64.tar.gz`, `cd elastic-agent-${kibanaVersion}-linux-x86_64`, ].join(`\n`), }, mac: { downloadCommand: [ - `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-darwin-aarch64.tar.gz`, + `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-darwin-aarch64.tar.gz${appendCurlDownloadSourceProxyArgs}`, `tar xzvf elastic-agent-${kibanaVersion}-darwin-aarch64.tar.gz`, `cd elastic-agent-${kibanaVersion}-darwin-aarch64`, ].join(`\n`), @@ -43,20 +51,20 @@ function getArtifact( windows: { downloadCommand: [ `$ProgressPreference = 'SilentlyContinue'`, - `Invoke-WebRequest -Uri https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-${kibanaVersion}-windows-x86_64.zip -OutFile elastic-agent-${kibanaVersion}-windows-x86_64.zip`, + `Invoke-WebRequest -Uri ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-windows-x86_64.zip -OutFile elastic-agent-${kibanaVersion}-windows-x86_64.zip${appendWindowsDownloadSourceProxyArgs}`, `Expand-Archive .\\elastic-agent-${kibanaVersion}-windows-x86_64.zip`, `cd elastic-agent-${kibanaVersion}-windows-x86_64`, ].join(`\n`), }, deb: { downloadCommand: [ - `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-amd64.deb`, + `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-amd64.deb${appendCurlDownloadSourceProxyArgs}`, `sudo dpkg -i elastic-agent-${kibanaVersion}-amd64.deb`, ].join(`\n`), }, rpm: { downloadCommand: [ - `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-x86_64.rpm`, + `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-x86_64.rpm${appendCurlDownloadSourceProxyArgs}`, `sudo rpm -vi elastic-agent-${kibanaVersion}-x86_64.rpm`, ].join(`\n`), }, @@ -68,20 +76,34 @@ function getArtifact( return artifactMap[platform]; } -export function getInstallCommandForPlatform( - platform: PLATFORM_TYPE, - esHost: string, - serviceToken: string, - policyId?: string, - fleetServerHost?: string, - isProductionDeployment?: boolean, - sslCATrustedFingerprint?: string, - kibanaVersion?: string, - downloadSource?: DownloadSource -): string { +export function getInstallCommandForPlatform({ + platform, + esOutputHost, + esOutputProxy, + serviceToken, + policyId, + fleetServerHost, + isProductionDeployment, + sslCATrustedFingerprint, + kibanaVersion, + downloadSource, + downloadSourceProxy, +}: { + platform: PLATFORM_TYPE; + esOutputHost: string; + esOutputProxy?: FleetProxy | undefined; + serviceToken: string; + policyId?: string; + fleetServerHost?: string; + isProductionDeployment?: boolean; + sslCATrustedFingerprint?: string; + kibanaVersion?: string; + downloadSource?: DownloadSource; + downloadSourceProxy?: FleetProxy; +}): string { const newLineSeparator = platform === 'windows' ? '`\n' : '\\\n'; - const artifact = getArtifact(platform, kibanaVersion ?? '', downloadSource); + const artifact = getArtifact(platform, kibanaVersion ?? '', downloadSource, downloadSourceProxy); const commandArguments = []; @@ -89,7 +111,7 @@ export function getInstallCommandForPlatform( commandArguments.push(['url', fleetServerHost]); } - commandArguments.push(['fleet-server-es', esHost]); + commandArguments.push(['fleet-server-es', esOutputHost]); commandArguments.push(['fleet-server-service-token', serviceToken]); if (policyId) { commandArguments.push(['fleet-server-policy', policyId]); @@ -110,7 +132,15 @@ export function getInstallCommandForPlatform( commandArguments.push(['fleet-server-port', '8220']); - const commandArgumentsStr = commandArguments + const enrollmentProxyArgs = []; + if (esOutputProxy) { + enrollmentProxyArgs.push(['proxy-url', esOutputProxy.url]); + Object.entries(esOutputProxy.proxy_headers || []).forEach(([key, value]) => { + enrollmentProxyArgs.push(['proxy-header', `"${key}=${value}"`]); + }); + } + + const commandArgumentsStr = [...commandArguments, ...enrollmentProxyArgs] .reduce((acc, [key, val]) => { if (acc === '' && key === 'url') { return `--${key}=${val}`; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/page_steps/install_agent/install_agent_standalone.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/page_steps/install_agent/install_agent_standalone.tsx index 0b9a6f6e85830..2802ac1319b15 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/page_steps/install_agent/install_agent_standalone.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/page_steps/install_agent/install_agent_standalone.tsx @@ -52,7 +52,7 @@ export const InstallElasticAgentStandalonePageStep: React.FC = ({ const { agentPolicyWithPackagePolicies } = useAgentPolicyWithPackagePolicies(selectedPolicyId); - const { fleetServerHost, fleetProxy, downloadSource, isLoadingInitialRequest } = - useFleetServerHostsForPolicy(agentPolicyWithPackagePolicies); + const { + fleetServerHost, + fleetProxy, + downloadSource, + isLoadingInitialRequest, + downloadSourceProxy, + } = useFleetServerHostsForPolicy(agentPolicyWithPackagePolicies); const selectedPolicy = agentPolicyWithPackagePolicies ? agentPolicyWithPackagePolicies @@ -196,6 +201,7 @@ export const AgentEnrollmentFlyout: React.FunctionComponent = ({ fleetServerHost={fleetServerHost} fleetProxy={fleetProxy} downloadSource={downloadSource} + downloadSourceProxy={downloadSourceProxy} setSelectedPolicyId={setSelectedPolicyId} agentPolicy={agentPolicy} selectedPolicy={selectedPolicy} diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx index ea31b163fb368..660aafa339b47 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx @@ -53,6 +53,8 @@ export const StandaloneSteps: React.FunctionComponent = ({ setSelectedAPIKeyId, isK8s, cloudSecurityIntegration, + downloadSource, + downloadSourceProxy, }) => { const { yaml, onCreateApiKey, isCreatingApiKey, apiKey, downloadYaml } = useFetchFullPolicy( selectedPolicy, @@ -62,7 +64,11 @@ export const StandaloneSteps: React.FunctionComponent = ({ const agentVersion = useAgentVersion(); const instructionsSteps = useMemo(() => { - const standaloneInstallCommands = StandaloneInstructions(agentVersion || ''); + const standaloneInstallCommands = StandaloneInstructions({ + agentVersion: agentVersion || '', + downloadSource, + downloadSourceProxy, + }); const steps: EuiContainedStepProps[] = !agentPolicy ? [ @@ -107,6 +113,8 @@ export const StandaloneSteps: React.FunctionComponent = ({ return steps; }, [ agentVersion, + downloadSource, + downloadSourceProxy, agentPolicy, selectedPolicy, agentPolicies, @@ -143,6 +151,7 @@ export const ManagedSteps: React.FunctionComponent = ({ fleetServerHost, fleetProxy, downloadSource, + downloadSourceProxy, refreshAgentPolicies, mode, setMode, @@ -173,6 +182,7 @@ export const ManagedSteps: React.FunctionComponent = ({ fleetServerHost, fleetProxy, downloadSource, + downloadSourceProxy, agentVersion: agentVersion || '', gcpProjectId, gcpOrganizationId, diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/types.ts b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/types.ts index 0eefe62229193..a58feeda65617 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/types.ts +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/types.ts @@ -83,4 +83,5 @@ export interface InstructionProps extends BaseProps { fleetServerHost: string; fleetProxy?: FleetProxy; downloadSource?: DownloadSource; + downloadSourceProxy?: FleetProxy; } diff --git a/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx b/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx index e5733983dd754..654b3a782649c 100644 --- a/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx +++ b/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import { DEFAULT_DOWNLOAD_SOURCE_URI } from '../../../../common/constants'; import type { DownloadSource, FleetProxy } from '../../../types'; function getfleetServerHostsEnrollArgs( @@ -14,7 +15,7 @@ function getfleetServerHostsEnrollArgs( ) { const proxyHeadersArgs = fleetProxy?.proxy_headers ? Object.entries(fleetProxy.proxy_headers).reduce((acc, [proxyKey, proyVal]) => { - acc += ` --proxy-header ${proxyKey}=${proyVal}`; + acc += ` --proxy-header "${proxyKey}=${proyVal}"`; return acc; }, '') @@ -23,11 +24,45 @@ function getfleetServerHostsEnrollArgs( return `--url=${fleetServerHost || `FLEET_SERVER_HOST`} --enrollment-token=${apiKey}${proxyArgs}`; } +export const getDownloadBaseUrl = (downloadSource?: DownloadSource) => { + const source = downloadSource?.host || DEFAULT_DOWNLOAD_SOURCE_URI; + return source.endsWith('/') ? source.substring(0, source.length - 1) : source; +}; + +export const getDownloadSourceProxyArgs = (downloadSourceProxy?: FleetProxy) => { + const windows = `${downloadSourceProxy?.url ? `-Proxy "${downloadSourceProxy.url}"` : ''} ${ + downloadSourceProxy?.proxy_headers + ? `-Headers @{${Object.entries(downloadSourceProxy.proxy_headers) + .reduce((acc, [proxyKey, proyVal]) => { + acc.push(`"${proxyKey}"="${proyVal}"`); + return acc; + }, [] as string[]) + .join('; ')}}` + : '' + }`.trim(); + const curl = `${downloadSourceProxy?.url ? `--proxy ${downloadSourceProxy.url}` : ''} ${ + downloadSourceProxy?.proxy_headers + ? Object.entries(downloadSourceProxy.proxy_headers) + .reduce((acc, [proxyKey, proyVal]) => { + acc.push(`--proxy-header "${proxyKey}=${proyVal}"`); + return acc; + }, [] as string[]) + .join(' ') + : '' + }`.trim(); + + return { + windows, + curl, + }; +}; + export const ManualInstructions = ({ apiKey, fleetServerHost, fleetProxy, downloadSource, + downloadSourceProxy, agentVersion: agentVersion, gcpProjectId = '', gcpOrganizationId = '', @@ -37,44 +72,44 @@ export const ManualInstructions = ({ fleetServerHost: string; fleetProxy?: FleetProxy; downloadSource?: DownloadSource; + downloadSourceProxy?: FleetProxy; agentVersion: string; gcpProjectId?: string; gcpOrganizationId?: string; gcpAccountType?: string; }) => { const enrollArgs = getfleetServerHostsEnrollArgs(apiKey, fleetServerHost, fleetProxy); - const downloadBaseUrl = downloadSource - ? downloadSource.host.endsWith('/') - ? downloadSource.host.substring(0, downloadSource.host.length - 1) - : downloadSource.host - : 'https://artifacts.elastic.co/downloads'; + const downloadBaseUrl = getDownloadBaseUrl(downloadSource); const fleetServerUrl = enrollArgs?.split('--url=')?.pop()?.split('--enrollment')[0]; const enrollmentToken = enrollArgs?.split('--enrollment-token=')[1]; const k8sCommand = 'kubectl apply -f elastic-agent-managed-kubernetes.yml'; - const linuxCommand = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-linux-x86_64.tar.gz + const { windows: windowsDownloadSourceProxyArgs, curl: curlDownloadSourceProxyArgs } = + getDownloadSourceProxyArgs(downloadSourceProxy); + + const linuxCommand = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-linux-x86_64.tar.gz ${curlDownloadSourceProxyArgs} tar xzvf elastic-agent-${agentVersion}-linux-x86_64.tar.gz cd elastic-agent-${agentVersion}-linux-x86_64 sudo ./elastic-agent install ${enrollArgs}`; - const macCommand = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-darwin-aarch64.tar.gz + const macCommand = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-darwin-aarch64.tar.gz ${curlDownloadSourceProxyArgs} tar xzvf elastic-agent-${agentVersion}-darwin-aarch64.tar.gz cd elastic-agent-${agentVersion}-darwin-aarch64 sudo ./elastic-agent install ${enrollArgs}`; const windowsCommand = `$ProgressPreference = 'SilentlyContinue' -Invoke-WebRequest -Uri ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-windows-x86_64.zip -OutFile elastic-agent-${agentVersion}-windows-x86_64.zip +Invoke-WebRequest -Uri ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-windows-x86_64.zip -OutFile elastic-agent-${agentVersion}-windows-x86_64.zip ${windowsDownloadSourceProxyArgs} Expand-Archive .\\elastic-agent-${agentVersion}-windows-x86_64.zip -DestinationPath . cd elastic-agent-${agentVersion}-windows-x86_64 .\\elastic-agent.exe install ${enrollArgs}`; - const linuxDebCommand = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-amd64.deb + const linuxDebCommand = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-amd64.deb ${curlDownloadSourceProxyArgs} sudo dpkg -i elastic-agent-${agentVersion}-amd64.deb sudo elastic-agent enroll ${enrollArgs} \nsudo systemctl enable elastic-agent \nsudo systemctl start elastic-agent`; - const linuxRpmCommand = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-x86_64.rpm + const linuxRpmCommand = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-x86_64.rpm ${curlDownloadSourceProxyArgs} sudo rpm -vi elastic-agent-${agentVersion}-x86_64.rpm sudo elastic-agent enroll ${enrollArgs} \nsudo systemctl enable elastic-agent \nsudo systemctl start elastic-agent`; diff --git a/x-pack/plugins/fleet/public/components/enrollment_instructions/standalone/index.tsx b/x-pack/plugins/fleet/public/components/enrollment_instructions/standalone/index.tsx index 21221fdaba79f..dd8eafec86ec4 100644 --- a/x-pack/plugins/fleet/public/components/enrollment_instructions/standalone/index.tsx +++ b/x-pack/plugins/fleet/public/components/enrollment_instructions/standalone/index.tsx @@ -4,27 +4,42 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import type { CommandsByPlatform } from '../../../applications/fleet/components/fleet_server_instructions/utils/install_command_utils'; +import type { DownloadSource, FleetProxy } from '../../../types'; +import { getDownloadBaseUrl, getDownloadSourceProxyArgs } from '../manual'; + +export const StandaloneInstructions = ({ + agentVersion, + downloadSource, + downloadSourceProxy, +}: { + agentVersion: string; + downloadSource?: DownloadSource; + downloadSourceProxy?: FleetProxy; +}): CommandsByPlatform => { + const downloadBaseUrl = getDownloadBaseUrl(downloadSource); + const { windows: windowsDownloadSourceProxyArgs, curl: curlDownloadSourceProxyArgs } = + getDownloadSourceProxyArgs(downloadSourceProxy); -export const StandaloneInstructions = (agentVersion: string): CommandsByPlatform => { - const linuxDebCommand = `curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-${agentVersion}-amd64.deb + const linuxDebCommand = `curl -L -O ${downloadBaseUrl}/downloads/beats/elastic-agent/elastic-agent-${agentVersion}-amd64.deb ${curlDownloadSourceProxyArgs} sudo dpkg -i elastic-agent-${agentVersion}-amd64.deb \nsudo systemctl enable elastic-agent \nsudo systemctl start elastic-agent`; - const linuxRpmCommand = `curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-${agentVersion}-x86_64.rpm + const linuxRpmCommand = `curl -L -O ${downloadBaseUrl}/downloads/beats/elastic-agent/elastic-agent-${agentVersion}-x86_64.rpm ${curlDownloadSourceProxyArgs} sudo rpm -vi elastic-agent-${agentVersion}-x86_64.rpm \nsudo systemctl enable elastic-agent \nsudo systemctl start elastic-agent`; - const linuxCommand = `curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-${agentVersion}-linux-x86_64.tar.gz + const linuxCommand = `curl -L -O ${downloadBaseUrl}/downloads/beats/elastic-agent/elastic-agent-${agentVersion}-linux-x86_64.tar.gz ${curlDownloadSourceProxyArgs} tar xzvf elastic-agent-${agentVersion}-linux-x86_64.tar.gz cd elastic-agent-${agentVersion}-linux-x86_64 sudo ./elastic-agent install`; - const macCommand = `curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-${agentVersion}-darwin-aarch64.tar.gz + const macCommand = `curl -L -O ${downloadBaseUrl}/downloads/beats/elastic-agent/elastic-agent-${agentVersion}-darwin-aarch64.tar.gz ${curlDownloadSourceProxyArgs} tar xzvf elastic-agent-${agentVersion}-darwin-aarch64.tar.gz cd elastic-agent-${agentVersion}-darwin-aarch64 sudo ./elastic-agent install`; const windowsCommand = `$ProgressPreference = 'SilentlyContinue' -Invoke-WebRequest -Uri https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-${agentVersion}-windows-x86_64.zip -OutFile elastic-agent-${agentVersion}-windows-x86_64.zip +Invoke-WebRequest -Uri ${downloadBaseUrl}/downloads/beats/elastic-agent/elastic-agent-${agentVersion}-windows-x86_64.zip -OutFile elastic-agent-${agentVersion}-windows-x86_64.zip ${windowsDownloadSourceProxyArgs} Expand-Archive .\elastic-agent-${agentVersion}-windows-x86_64.zip -DestinationPath . cd elastic-agent-${agentVersion}-windows-x86_64 .\\elastic-agent.exe install`; diff --git a/x-pack/plugins/fleet/public/hooks/use_fleet_server_hosts_for_policy.test.tsx b/x-pack/plugins/fleet/public/hooks/use_fleet_server_hosts_for_policy.test.tsx index 9e6c8ab5c62b1..6f9c96d130ebd 100644 --- a/x-pack/plugins/fleet/public/hooks/use_fleet_server_hosts_for_policy.test.tsx +++ b/x-pack/plugins/fleet/public/hooks/use_fleet_server_hosts_for_policy.test.tsx @@ -42,6 +42,23 @@ describe('useFleetServerHostsForPolicy', () => { is_preconfigured: false, }, has_active: true, + es_output: { + id: 'es-output', + name: 'es-output', + is_default: false, + is_default_monitoring: false, + type: 'elasticsearch', + hosts: ['https://elasticsearch:9200'], + }, + es_output_proxy: { + id: 'es-output-proxy', + name: 'es-output-proxy', + url: 'https://es-output-proxy', + proxy_headers: { + 'header-key': 'header-value', + }, + is_preconfigured: false, + }, }, download_source: { id: 'default-source', @@ -49,6 +66,15 @@ describe('useFleetServerHostsForPolicy', () => { host: 'https://defaultsource', is_default: false, }, + download_source_proxy: { + id: 'download-src-proxy', + name: 'download-src-proxy', + url: 'https://download-src-proxy', + proxy_headers: { + 'header-key': 'header-value', + }, + is_preconfigured: false, + }, }, }); }); @@ -64,12 +90,38 @@ describe('useFleetServerHostsForPolicy', () => { url: 'https://defaultproxy', is_preconfigured: false, }, + esOutput: { + id: 'es-output', + name: 'es-output', + is_default: false, + is_default_monitoring: false, + type: 'elasticsearch', + hosts: ['https://elasticsearch:9200'], + }, + esOutputProxy: { + id: 'es-output-proxy', + name: 'es-output-proxy', + url: 'https://es-output-proxy', + proxy_headers: { + 'header-key': 'header-value', + }, + is_preconfigured: false, + }, downloadSource: { id: 'default-source', name: 'default-source', host: 'https://defaultsource', is_default: false, }, + downloadSourceProxy: { + id: 'download-src-proxy', + name: 'download-src-proxy', + url: 'https://download-src-proxy', + proxy_headers: { + 'header-key': 'header-value', + }, + is_preconfigured: false, + }, }); }); }); diff --git a/x-pack/plugins/fleet/public/hooks/use_fleet_server_hosts_for_policy.ts b/x-pack/plugins/fleet/public/hooks/use_fleet_server_hosts_for_policy.ts index 8ca0d8a6871c3..12b8523f13028 100644 --- a/x-pack/plugins/fleet/public/hooks/use_fleet_server_hosts_for_policy.ts +++ b/x-pack/plugins/fleet/public/hooks/use_fleet_server_hosts_for_policy.ts @@ -14,7 +14,7 @@ import { useGetEnrollmentSettings } from './use_request'; /** * Return Fleet server hosts urls and proxy for a given agent policy */ -export function useFleetServerHostsForPolicy(agentPolicy?: AgentPolicy | null) { +export function useFleetServerHostsForPolicy(agentPolicy?: Pick | null) { const { isLoading, isInitialRequest, @@ -26,14 +26,20 @@ export function useFleetServerHostsForPolicy(agentPolicy?: AgentPolicy | null) { isLoadingInitialRequest: isLoading && isInitialRequest, fleetServerHost: enrollmentSettings?.fleet_server.host?.host_urls[0] || '', fleetProxy: enrollmentSettings?.fleet_server.host_proxy, + esOutput: enrollmentSettings?.fleet_server.es_output, + esOutputProxy: enrollmentSettings?.fleet_server.es_output_proxy, downloadSource: enrollmentSettings?.download_source, + downloadSourceProxy: enrollmentSettings?.download_source_proxy, }), [ isLoading, isInitialRequest, enrollmentSettings?.fleet_server.host, enrollmentSettings?.fleet_server.host_proxy, + enrollmentSettings?.fleet_server.es_output, + enrollmentSettings?.fleet_server.es_output_proxy, enrollmentSettings?.download_source, + enrollmentSettings?.download_source_proxy, ] ); } diff --git a/x-pack/plugins/fleet/server/routes/settings/enrollment_settings_handler.ts b/x-pack/plugins/fleet/server/routes/settings/enrollment_settings_handler.ts index 17cb27296d9e4..55a3d383433cc 100644 --- a/x-pack/plugins/fleet/server/routes/settings/enrollment_settings_handler.ts +++ b/x-pack/plugins/fleet/server/routes/settings/enrollment_settings_handler.ts @@ -22,6 +22,7 @@ import { agentPolicyService, appContextService, downloadSourceService } from '.. import { getFleetServerHostsForAgentPolicy } from '../../services/fleet_server_host'; import { getFleetProxy } from '../../services/fleet_proxies'; import { getFleetServerPolicies, hasFleetServersForPolicies } from '../../services/fleet_server'; +import { getDataOutputForAgentPolicy } from '../../services/agent_policies'; export const getEnrollmentSettingsHandler: FleetRequestHandler< undefined, @@ -46,6 +47,7 @@ export const getEnrollmentSettingsHandler: FleetRequestHandler< name: undefined, fleet_server_host_id: undefined, download_source_id: undefined, + data_output_id: undefined, }; // Check if there is any active fleet server enrolled into the fleet server policies policies @@ -70,6 +72,19 @@ export const getEnrollmentSettingsHandler: FleetRequestHandler< settingsResponse.download_source = undefined; } + // Get download source proxy + // ignore errors if the download source proxy is not found + try { + if (settingsResponse.download_source?.proxy_id) { + settingsResponse.download_source_proxy = await getFleetProxy( + soClient, + settingsResponse.download_source.proxy_id + ); + } + } catch (e) { + settingsResponse.download_source_proxy = undefined; + } + // Get associated fleet server host, or default one if it doesn't exist // `getFleetServerHostsForAgentPolicy` errors if there is no default, so catch it try { @@ -81,7 +96,7 @@ export const getEnrollmentSettingsHandler: FleetRequestHandler< settingsResponse.fleet_server.host = undefined; } - // if a fleet server host was found, get associated fleet server host proxy if any + // If a fleet server host was found, get associated fleet server host proxy if any // ignore errors if the proxy is not found try { if (settingsResponse.fleet_server.host?.proxy_id) { @@ -94,6 +109,25 @@ export const getEnrollmentSettingsHandler: FleetRequestHandler< settingsResponse.fleet_server.host_proxy = undefined; } + // Get associated output and proxy (if any) to use for Fleet Server enrollment + try { + if (settingsResponse.fleet_server.policies.length > 0) { + const dataOutput = await getDataOutputForAgentPolicy(soClient, scopedAgentPolicy); + if (dataOutput.type === 'elasticsearch' && dataOutput.hosts?.[0]) { + settingsResponse.fleet_server.es_output = dataOutput; + if (dataOutput.proxy_id) { + settingsResponse.fleet_server.es_output_proxy = await getFleetProxy( + soClient, + dataOutput.proxy_id + ); + } + } + } + } catch (e) { + settingsResponse.fleet_server.es_output = undefined; + settingsResponse.fleet_server.es_output_proxy = undefined; + } + return response.ok({ body: settingsResponse }); } catch (error) { return defaultFleetErrorHandler({ error, response }); @@ -116,6 +150,7 @@ export const getFleetServerOrAgentPolicies = async ( fleet_server_host_id: policy.fleet_server_host_id, download_source_id: policy.download_source_id, space_ids: policy.space_ids, + data_output_id: policy.data_output_id, }); // If an agent policy is specified, return only that policy diff --git a/x-pack/test/fleet_api_integration/apis/settings/enrollment.ts b/x-pack/test/fleet_api_integration/apis/settings/enrollment.ts index fc464ce0e3ded..d69051b6140a9 100644 --- a/x-pack/test/fleet_api_integration/apis/settings/enrollment.ts +++ b/x-pack/test/fleet_api_integration/apis/settings/enrollment.ts @@ -18,11 +18,8 @@ export default function (providerContext: FtrProviderContext) { describe('Enrollment settings - get', function () { skipIfNoDockerRegistry(providerContext); - before(async () => { - await fleetAndAgents.setup(); - }); - it('should respond with empty enrollment settings on empty cluster', async function () { + await fleetAndAgents.setup(); const response = await supertest .get(`/internal/fleet/settings/enrollment`) .set('kbn-xsrf', 'xxxx') @@ -51,6 +48,7 @@ export default function (providerContext: FtrProviderContext) { .set('kbn-xsrf', 'xxxx') .send({ force: true }) .expect(200); + await fleetAndAgents.setup(); }); after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/fleet/fleet_server'); @@ -92,12 +90,25 @@ export default function (providerContext: FtrProviderContext) { host_proxy: { id: 'my-proxy', name: 'my proxy', + proxy_headers: { + 'Accept-Encoding': 'gzip, deflate, br', + 'Accept-Language': 'en-US,en;q=0.5', + }, url: 'https://my-proxy', certificate: '', certificate_authorities: '', certificate_key: '', is_preconfigured: false, }, + es_output: { + hosts: ['http://localhost:9200'], + id: 'fleet-default-output', + is_default: true, + is_default_monitoring: true, + name: 'default', + preset: 'balanced', + type: 'elasticsearch', + }, }, download_source: { id: 'fleet-default-download-source', @@ -137,12 +148,25 @@ export default function (providerContext: FtrProviderContext) { host_proxy: { id: 'my-proxy', name: 'my proxy', + proxy_headers: { + 'Accept-Encoding': 'gzip, deflate, br', + 'Accept-Language': 'en-US,en;q=0.5', + }, url: 'https://my-proxy', certificate: '', certificate_authorities: '', certificate_key: '', is_preconfigured: false, }, + es_output: { + hosts: ['http://localhost:9200'], + id: 'fleet-default-output', + is_default: true, + is_default_monitoring: true, + name: 'default', + preset: 'balanced', + type: 'elasticsearch', + }, }, download_source: { id: 'fleet-default-download-source', @@ -178,6 +202,19 @@ export default function (providerContext: FtrProviderContext) { host: 'https://localhost:2222', proxy_id: 'my-proxy', }, + download_source_proxy: { + certificate: '', + certificate_authorities: '', + certificate_key: '', + id: 'my-proxy', + is_preconfigured: false, + name: 'my proxy', + proxy_headers: { + 'Accept-Encoding': 'gzip, deflate, br', + 'Accept-Language': 'en-US,en;q=0.5', + }, + url: 'https://my-proxy', + }, }); }); }); diff --git a/x-pack/test/functional/es_archives/fleet/fleet_server/data.json b/x-pack/test/functional/es_archives/fleet/fleet_server/data.json index a3729885c13e9..32e3735981802 100644 --- a/x-pack/test/functional/es_archives/fleet/fleet_server/data.json +++ b/x-pack/test/functional/es_archives/fleet/fleet_server/data.json @@ -435,12 +435,11 @@ "certificate_key": "", "is_preconfigured": false, "name": "my proxy", - "proxy_headers": null, + "proxy_headers": "{\"Accept-Language\":\"en-US,en;q=0.5\",\"Accept-Encoding\":\"gzip, deflate, br\"}", "url": "https://my-proxy" }, "managed": false, - "references": [ - ], + "references": [], "type": "fleet-proxy", "updated_at": "2024-04-22T22:07:16.226Z" }