From d2c9a62e15335f191e2ac2a8f445e59df01c348e Mon Sep 17 00:00:00 2001 From: "Lucas F. da Costa" Date: Wed, 9 Mar 2022 15:51:39 +0000 Subject: [PATCH] Enable local mtls (#127116) * [Uptime] register synthetics service locations on startup * [Uptime] Enable mTLS through a devUrl for the synthetics service * [Uptime] deprecate basic auth for synthetics service * [Uptime] move the registration of the synthetics service location to the service constructor * re-enable basic authentication for environments other than production * only return monitor errors if the error array is not empty * fix: add missing username prop to ServiceAPIClient * use UUID for the monitors in tests to prevent name conflicts * adjust tests * Update x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts Co-authored-by: Dominique Clarke * do not surface edit errors from the service * do not surface delete errors from the service Co-authored-by: Dominique Clarke Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Dominique Clarke --- x-pack/plugins/uptime/e2e/config.ts | 6 +++++- .../journeys/monitor_management.journey.ts | 11 +++++----- .../action_bar/action_bar.tsx | 4 ++-- .../action_bar/action_bar_errors.test.tsx | 12 +++++++---- .../public/state/api/monitor_management.ts | 2 +- .../get_service_locations.ts | 14 ++++++++++++- .../synthetics_service/service_api_client.ts | 21 ++++++++++--------- .../synthetics_service/synthetics_service.ts | 16 +++++++++----- .../synthetics_service/add_monitor.ts | 8 ++++--- .../synthetics_service/delete_monitor.ts | 6 ++++-- .../synthetics_service/edit_monitor.ts | 6 ++++-- 11 files changed, 70 insertions(+), 36 deletions(-) diff --git a/x-pack/plugins/uptime/e2e/config.ts b/x-pack/plugins/uptime/e2e/config.ts index 48b4e048000f2..08cc1d960d044 100644 --- a/x-pack/plugins/uptime/e2e/config.ts +++ b/x-pack/plugins/uptime/e2e/config.ts @@ -57,7 +57,11 @@ async function config({ readConfigFile }: FtrConfigProviderContext) { `--elasticsearch.password=changeme`, '--xpack.reporting.enabled=false', `--xpack.uptime.service.manifestUrl=${manifestUrl}`, - `--xpack.uptime.service.username=${serviceUsername}`, + `--xpack.uptime.service.username=${ + process.env.SYNTHETICS_REMOTE_ENABLED + ? serviceUsername + : 'localKibanaIntegrationTestsUser' + }`, `--xpack.uptime.service.password=${servicPassword}`, '--xpack.uptime.ui.monitorManagement.enabled=true', ], diff --git a/x-pack/plugins/uptime/e2e/journeys/monitor_management.journey.ts b/x-pack/plugins/uptime/e2e/journeys/monitor_management.journey.ts index d89c9da043e4f..1d6270c00df65 100644 --- a/x-pack/plugins/uptime/e2e/journeys/monitor_management.journey.ts +++ b/x-pack/plugins/uptime/e2e/journeys/monitor_management.journey.ts @@ -5,6 +5,7 @@ * 2.0. */ +import uuid from 'uuid'; import { journey, step, expect, before, after, Page } from '@elastic/synthetics'; import { monitorManagementPageProvider } from '../page_objects/monitor_management'; import { DataStream } from '../../common/runtime_types/monitor_management'; @@ -16,10 +17,10 @@ const basicMonitorDetails = { location: customLocation || 'US Central', schedule: '3', }; -const httpName = 'http monitor'; -const icmpName = 'icmp monitor'; -const tcpName = 'tcp monitor'; -const browserName = 'browser monitor'; +const httpName = `http monitor ${uuid.v4()}`; +const icmpName = `icmp monitor ${uuid.v4()}`; +const tcpName = `tcp monitor ${uuid.v4()}`; +const browserName = `browser monitor ${uuid.v4()}`; const configuration = { [DataStream.HTTP]: { @@ -156,7 +157,7 @@ Object.keys(configuration).forEach((type) => { journey('Monitor Management breadcrumbs', async ({ page, params }: { page: Page; params: any }) => { const uptime = monitorManagementPageProvider({ page, kibanaUrl: params.kibanaUrl }); const defaultMonitorDetails = { - name: 'Sample monitor', + name: `Sample monitor ${uuid.v4()}`, location: 'US Central', schedule: '3', apmServiceName: 'service', diff --git a/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar.tsx b/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar.tsx index f54031766be8e..8a2e669129114 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar.tsx @@ -69,7 +69,7 @@ export const ActionBar = ({ }); }, [monitor, monitorId, isValid, isSaving]); - const hasErrors = data && Object.keys(data).length; + const hasErrors = data && 'attributes' in data && data.attributes.errors?.length > 0; const loading = status === FETCH_STATUS.LOADING; const handleOnSave = useCallback(() => { @@ -103,7 +103,7 @@ export const ActionBar = ({ }); setIsSuccessful(true); } else if (hasErrors && !loading) { - Object.values(data!).forEach((location) => { + Object.values(data.attributes.errors!).forEach((location) => { const { status: responseStatus, reason } = location.error || {}; kibanaService.toasts.addWarning({ title: i18n.translate('xpack.uptime.monitorManagement.service.error.title', { diff --git a/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar_errors.test.tsx b/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar_errors.test.tsx index 1a882e5027313..88520b8761ae7 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar_errors.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar_errors.test.tsx @@ -52,10 +52,14 @@ describe(' Service Errors', () => { it('Handles service errors', async () => { jest.spyOn(kibana.kibanaService.toasts, 'addWarning').mockImplementation(toast); useFetcher.mockReturnValue({ - data: [ - { locationId: 'us_central', error: { reason: 'Invalid config', status: 400 } }, - { locationId: 'us_central', error: { reason: 'Cannot schedule', status: 500 } }, - ], + data: { + attributes: { + errors: [ + { locationId: 'us_central', error: { reason: 'Invalid config', status: 400 } }, + { locationId: 'us_central', error: { reason: 'Cannot schedule', status: 500 } }, + ], + }, + }, status: FETCH_STATUS.SUCCESS, refetch: () => {}, }); diff --git a/x-pack/plugins/uptime/public/state/api/monitor_management.ts b/x-pack/plugins/uptime/public/state/api/monitor_management.ts index 206ba07dc4c23..00a033ec51b7a 100644 --- a/x-pack/plugins/uptime/public/state/api/monitor_management.ts +++ b/x-pack/plugins/uptime/public/state/api/monitor_management.ts @@ -24,7 +24,7 @@ export const setMonitor = async ({ }: { monitor: SyntheticsMonitor; id?: string; -}): Promise => { +}): Promise<{ attributes: { errors: ServiceLocationErrors } } | SyntheticsMonitor> => { if (id) { return await apiService.put(`${API_URLS.SYNTHETICS_MONITORS}/${id}`, monitor); } else { diff --git a/x-pack/plugins/uptime/server/lib/synthetics_service/get_service_locations.ts b/x-pack/plugins/uptime/server/lib/synthetics_service/get_service_locations.ts index e746dafdb55d5..f1af840aac72f 100644 --- a/x-pack/plugins/uptime/server/lib/synthetics_service/get_service_locations.ts +++ b/x-pack/plugins/uptime/server/lib/synthetics_service/get_service_locations.ts @@ -8,13 +8,25 @@ import axios from 'axios'; import { ManifestLocation, + ServiceLocation, Locations, ServiceLocationsApiResponse, } from '../../../common/runtime_types'; import { UptimeServerSetup } from '../adapters/framework'; +export const getDevLocation = (devUrl: string): ServiceLocation => ({ + id: 'localhost', + label: 'Local Synthetics Service', + geo: { lat: 0, lon: 0 }, + url: devUrl, +}); + export async function getServiceLocations(server: UptimeServerSetup) { - const locations: Locations = []; + let locations: Locations = []; + + if (process.env.NODE_ENV !== 'production' && server.config.service?.devUrl) { + locations = [getDevLocation(server.config.service.devUrl)]; + } if (!server.config.service?.manifestUrl) { return { locations }; diff --git a/x-pack/plugins/uptime/server/lib/synthetics_service/service_api_client.ts b/x-pack/plugins/uptime/server/lib/synthetics_service/service_api_client.ts index 1e82ef77e083b..14c5a2ebb5959 100644 --- a/x-pack/plugins/uptime/server/lib/synthetics_service/service_api_client.ts +++ b/x-pack/plugins/uptime/server/lib/synthetics_service/service_api_client.ts @@ -32,7 +32,6 @@ export interface ServiceData { export class ServiceAPIClient { private readonly username?: string; - private readonly devUrl?: string; private readonly authorization: string; public locations: ServiceLocations; private logger: Logger; @@ -41,9 +40,8 @@ export class ServiceAPIClient { constructor(logger: Logger, config: ServiceConfig, kibanaVersion: string) { this.config = config; - const { username, password, devUrl } = config; + const { username, password } = config; this.username = username; - this.devUrl = devUrl; this.kibanaVersion = kibanaVersion; if (username && password) { @@ -61,8 +59,10 @@ export class ServiceAPIClient { if (config.tls && config.tls.certificate && config.tls.key) { const tlsConfig = new SslConfig(config.tls); + const rejectUnauthorized = process.env.NODE_ENV === 'production'; + return new https.Agent({ - rejectUnauthorized: true, // (NOTE: this will disable client verification) + rejectUnauthorized, cert: tlsConfig.certificate, key: tlsConfig.key, }); @@ -102,13 +102,14 @@ export class ServiceAPIClient { return axios({ method, - url: (this.devUrl ?? url) + (runOnce ? '/run' : '/monitors'), + url: url + (runOnce ? '/run' : '/monitors'), data: { monitors: monitorsStreams, output, stack_version: this.kibanaVersion }, - headers: this.authorization - ? { - Authorization: this.authorization, - } - : undefined, + headers: + process.env.NODE_ENV !== 'production' && this.authorization + ? { + Authorization: this.authorization, + } + : undefined, httpsAgent: this.getHttpsAgent(), }); }; diff --git a/x-pack/plugins/uptime/server/lib/synthetics_service/synthetics_service.ts b/x-pack/plugins/uptime/server/lib/synthetics_service/synthetics_service.ts index acf3c0df49164..11dcf1973b41c 100644 --- a/x-pack/plugins/uptime/server/lib/synthetics_service/synthetics_service.ts +++ b/x-pack/plugins/uptime/server/lib/synthetics_service/synthetics_service.ts @@ -64,6 +64,8 @@ export class SyntheticsService { this.esHosts = getEsHosts({ config: this.config, cloud: server.cloud }); this.locations = []; + + this.registerServiceLocations(); } public init() { @@ -103,6 +105,14 @@ export class SyntheticsService { } } + public registerServiceLocations() { + const service = this; + getServiceLocations(service.server).then((result) => { + service.locations = result.locations; + service.apiClient.locations = result.locations; + }); + } + public registerSyncTask(taskManager: TaskManagerSetupContract) { const service = this; @@ -121,11 +131,7 @@ export class SyntheticsService { const { state } = taskInstance; service.setupIndexTemplates(); - - getServiceLocations(service.server).then((result) => { - service.locations = result.locations; - service.apiClient.locations = result.locations; - }); + service.registerServiceLocations(); await service.pushConfigs(); diff --git a/x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts b/x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts index 29c2210efd20a..ee3ef1fe6380c 100644 --- a/x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts +++ b/x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts @@ -54,10 +54,12 @@ export const addSyntheticsMonitorRoute: UMRestApiRouteFactory = () => ({ formatTelemetryEvent({ monitor: newMonitor, errors, kibanaVersion: server.kibanaVersion }) ); - if (errors) { - return errors; + if (errors && errors.length > 0) { + return response.ok({ + body: { message: 'error pushing monitor to the service', attributes: { errors } }, + }); } - return newMonitor; + return response.ok({ body: newMonitor }); }, }); diff --git a/x-pack/plugins/uptime/server/rest_api/synthetics_service/delete_monitor.ts b/x-pack/plugins/uptime/server/rest_api/synthetics_service/delete_monitor.ts index bbdb6818b3f6a..6d744a7a1a406 100644 --- a/x-pack/plugins/uptime/server/rest_api/synthetics_service/delete_monitor.ts +++ b/x-pack/plugins/uptime/server/rest_api/synthetics_service/delete_monitor.ts @@ -46,8 +46,10 @@ export const deleteSyntheticsMonitorRoute: UMRestApiRouteFactory = () => ({ formatTelemetryDeleteEvent(monitor, server.kibanaVersion, new Date().toISOString(), errors) ); - if (errors) { - return errors; + if (errors && errors.length > 0) { + return response.ok({ + body: { message: 'error pushing monitor to the service', attributes: { errors } }, + }); } return monitorId; diff --git a/x-pack/plugins/uptime/server/rest_api/synthetics_service/edit_monitor.ts b/x-pack/plugins/uptime/server/rest_api/synthetics_service/edit_monitor.ts index d8a6ec85e770e..6170bdd72ac36 100644 --- a/x-pack/plugins/uptime/server/rest_api/synthetics_service/edit_monitor.ts +++ b/x-pack/plugins/uptime/server/rest_api/synthetics_service/edit_monitor.ts @@ -78,8 +78,10 @@ export const editSyntheticsMonitorRoute: UMRestApiRouteFactory = () => ({ ); // Return service sync errors in OK response - if (errors) { - return errors; + if (errors && errors.length > 0) { + return response.ok({ + body: { message: 'error pushing monitor to the service', attributes: { errors } }, + }); } return editMonitor;