mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Fleet] Allow to configure proxy in kibana config file (#145737)
This commit is contained in:
parent
88be956d3d
commit
c1f1de73a7
6 changed files with 224 additions and 2 deletions
|
@ -7,7 +7,7 @@
|
|||
|
||||
import React, { useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { EuiBasicTable, EuiButtonIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { EuiBasicTable, EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui';
|
||||
import type { EuiBasicTableColumn } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
|
@ -43,6 +43,19 @@ export const FleetProxiesTable: React.FunctionComponent<FleetProxiesTableProps>
|
|||
{fleetProxy.name}
|
||||
</p>
|
||||
</NameFlexItemWithMaxWidth>
|
||||
{fleetProxy.is_preconfigured && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIconTip
|
||||
content={i18n.translate('xpack.fleet.settings.fleetProxiesTable.managedTooltip', {
|
||||
defaultMessage:
|
||||
'This proxy is managed outside of Fleet. Please refer to your kibana config file for more info.',
|
||||
})}
|
||||
type="lock"
|
||||
size="m"
|
||||
color="subdued"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
),
|
||||
width: '288px',
|
||||
|
@ -60,7 +73,7 @@ export const FleetProxiesTable: React.FunctionComponent<FleetProxiesTableProps>
|
|||
{
|
||||
width: '68px',
|
||||
render: (fleetProxy: FleetProxy) => {
|
||||
const isDeleteVisible = true;
|
||||
const isDeleteVisible = !fleetProxy.is_preconfigured;
|
||||
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="s" justifyContent="flexEnd">
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
PreconfiguredAgentPoliciesSchema,
|
||||
PreconfiguredOutputsSchema,
|
||||
PreconfiguredFleetServerHostsSchema,
|
||||
PreconfiguredFleetProxiesSchema,
|
||||
} from './types';
|
||||
|
||||
const DEFAULT_BUNDLED_PACKAGE_LOCATION = path.join(__dirname, '../target/bundled_packages');
|
||||
|
@ -117,6 +118,7 @@ export const config: PluginConfigDescriptor = {
|
|||
agentPolicies: PreconfiguredAgentPoliciesSchema,
|
||||
outputs: PreconfiguredOutputsSchema,
|
||||
fleetServerHosts: PreconfiguredFleetServerHostsSchema,
|
||||
proxies: PreconfiguredFleetProxiesSchema,
|
||||
agentIdVerificationEnabled: schema.boolean({ defaultValue: true }),
|
||||
developer: schema.object({
|
||||
disableRegistryVersionCheck: schema.boolean({ defaultValue: false }),
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import { isEqual } from 'lodash';
|
||||
import pMap from 'p-map';
|
||||
|
||||
import type { FleetConfigType } from '../../config';
|
||||
import type { FleetProxy } from '../../types';
|
||||
import {
|
||||
bulkGetFleetProxies,
|
||||
createFleetProxy,
|
||||
deleteFleetProxy,
|
||||
listFleetProxies,
|
||||
updateFleetProxy,
|
||||
} from '../fleet_proxies';
|
||||
import { listFleetServerHostsForProxyId } from '../fleet_server_host';
|
||||
import { agentPolicyService } from '../agent_policy';
|
||||
import { outputService } from '../output';
|
||||
|
||||
export function getPreconfiguredFleetProxiesFromConfig(config?: FleetConfigType) {
|
||||
const { proxies: fleetProxiesFromConfig } = config;
|
||||
|
||||
return fleetProxiesFromConfig.map((proxyConfig: any) => ({
|
||||
...proxyConfig,
|
||||
is_preconfigured: true,
|
||||
}));
|
||||
}
|
||||
|
||||
function hasChanged(existingProxy: FleetProxy, preconfiguredFleetProxy: FleetProxy) {
|
||||
return (
|
||||
(!existingProxy.is_preconfigured ||
|
||||
existingProxy.name !== existingProxy.name ||
|
||||
existingProxy.url !== preconfiguredFleetProxy.name ||
|
||||
!isEqual(
|
||||
existingProxy.proxy_headers ?? null,
|
||||
preconfiguredFleetProxy.proxy_headers ?? null
|
||||
) ||
|
||||
existingProxy.certificate_authorities) ??
|
||||
null !== preconfiguredFleetProxy.certificate_authorities ??
|
||||
(null || existingProxy.certificate) ??
|
||||
null !== preconfiguredFleetProxy.certificate ??
|
||||
(null || existingProxy.certificate_key) ??
|
||||
null !== preconfiguredFleetProxy.certificate_key ??
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
async function createOrUpdatePreconfiguredFleetProxies(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
preconfiguredFleetProxies: FleetProxy[]
|
||||
) {
|
||||
const existingFleetProxies = await bulkGetFleetProxies(
|
||||
soClient,
|
||||
preconfiguredFleetProxies.map(({ id }) => id),
|
||||
{ ignoreNotFound: true }
|
||||
);
|
||||
await Promise.all(
|
||||
preconfiguredFleetProxies.map(async (preconfiguredFleetProxy) => {
|
||||
const existingProxy = existingFleetProxies.find(
|
||||
(fleetProxy) => fleetProxy.id === preconfiguredFleetProxy.id
|
||||
);
|
||||
|
||||
const { id, ...data } = preconfiguredFleetProxy;
|
||||
|
||||
const isCreate = !existingProxy;
|
||||
const isUpdateWithNewData = existingProxy
|
||||
? hasChanged(existingProxy, preconfiguredFleetProxy)
|
||||
: false;
|
||||
|
||||
if (isCreate) {
|
||||
await createFleetProxy(
|
||||
soClient,
|
||||
{
|
||||
...data,
|
||||
is_preconfigured: true,
|
||||
},
|
||||
{ id, overwrite: true, fromPreconfiguration: true }
|
||||
);
|
||||
} else if (isUpdateWithNewData) {
|
||||
await updateFleetProxy(
|
||||
soClient,
|
||||
id,
|
||||
{
|
||||
...data,
|
||||
is_preconfigured: true,
|
||||
},
|
||||
{ fromPreconfiguration: true }
|
||||
);
|
||||
// Bump all the agent policy that use that proxy
|
||||
const [{ items: fleetServerHosts }, { items: outputs }] = await Promise.all([
|
||||
listFleetServerHostsForProxyId(soClient, id),
|
||||
outputService.listAllForProxyId(soClient, id),
|
||||
]);
|
||||
if (
|
||||
fleetServerHosts.some((host) => host.is_default) ||
|
||||
outputs.some((output) => output.is_default || output.is_default_monitoring)
|
||||
) {
|
||||
await agentPolicyService.bumpAllAgentPolicies(soClient, esClient);
|
||||
} else {
|
||||
await pMap(
|
||||
outputs,
|
||||
(output) =>
|
||||
agentPolicyService.bumpAllAgentPoliciesForOutput(soClient, esClient, output.id),
|
||||
{
|
||||
concurrency: 20,
|
||||
}
|
||||
);
|
||||
await pMap(
|
||||
fleetServerHosts,
|
||||
(fleetServerHost) =>
|
||||
agentPolicyService.bumpAllAgentPoliciesForFleetServerHosts(
|
||||
soClient,
|
||||
esClient,
|
||||
fleetServerHost.id
|
||||
),
|
||||
{
|
||||
concurrency: 20,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async function cleanPreconfiguredFleetProxies(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
preconfiguredFleetProxies: FleetProxy[]
|
||||
) {
|
||||
const existingFleetProxies = await listFleetProxies(soClient);
|
||||
const existingPreconfiguredFleetProxies = existingFleetProxies.items.filter(
|
||||
(o) => o.is_preconfigured === true
|
||||
);
|
||||
|
||||
for (const existingFleetProxy of existingPreconfiguredFleetProxies) {
|
||||
const hasBeenDelete = !preconfiguredFleetProxies.find(({ id }) => existingFleetProxy.id === id);
|
||||
if (!hasBeenDelete) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const [{ items: fleetServerHosts }, { items: outputs }] = await Promise.all([
|
||||
listFleetServerHostsForProxyId(soClient, existingFleetProxy.id),
|
||||
outputService.listAllForProxyId(soClient, existingFleetProxy.id),
|
||||
]);
|
||||
const isUsed = fleetServerHosts.length > 0 || outputs.length > 0;
|
||||
if (isUsed) {
|
||||
await updateFleetProxy(
|
||||
soClient,
|
||||
existingFleetProxy.id,
|
||||
{ is_preconfigured: false },
|
||||
{
|
||||
fromPreconfiguration: true,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
await deleteFleetProxy(soClient, existingFleetProxy.id, {
|
||||
fromPreconfiguration: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function ensurePreconfiguredFleetProxies(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
preconfiguredFleetProxies: FleetProxy[]
|
||||
) {
|
||||
await createOrUpdatePreconfiguredFleetProxies(soClient, esClient, preconfiguredFleetProxies);
|
||||
await cleanPreconfiguredFleetProxies(soClient, esClient, preconfiguredFleetProxies);
|
||||
}
|
|
@ -19,6 +19,7 @@ import { setupFleet } from './setup';
|
|||
|
||||
jest.mock('./preconfiguration');
|
||||
jest.mock('./preconfiguration/outputs');
|
||||
jest.mock('./preconfiguration/fleet_proxies');
|
||||
jest.mock('./settings');
|
||||
jest.mock('./output');
|
||||
jest.mock('./download_source');
|
||||
|
|
|
@ -29,6 +29,10 @@ import {
|
|||
ensurePreconfiguredOutputs,
|
||||
getPreconfiguredOutputFromConfig,
|
||||
} from './preconfiguration/outputs';
|
||||
import {
|
||||
ensurePreconfiguredFleetProxies,
|
||||
getPreconfiguredFleetProxiesFromConfig,
|
||||
} from './preconfiguration/fleet_proxies';
|
||||
import { outputService } from './output';
|
||||
import { downloadSourceService } from './download_source';
|
||||
|
||||
|
@ -86,6 +90,13 @@ async function createSetupSideEffects(
|
|||
await migrateSettingsToFleetServerHost(soClient);
|
||||
logger.debug('Setting up Fleet download source');
|
||||
const defaultDownloadSource = await downloadSourceService.ensureDefault(soClient);
|
||||
// Need to be done before outputs and fleet server hosts as these object can reference a proxy
|
||||
logger.debug('Setting up Proxy');
|
||||
await ensurePreconfiguredFleetProxies(
|
||||
soClient,
|
||||
esClient,
|
||||
getPreconfiguredFleetProxiesFromConfig(appContextService.getConfig())
|
||||
);
|
||||
|
||||
logger.debug('Setting up Fleet Sever Hosts');
|
||||
await ensurePreconfiguredFleetServerHosts(
|
||||
|
|
|
@ -95,6 +95,24 @@ export const PreconfiguredFleetServerHostsSchema = schema.arrayOf(
|
|||
{ defaultValue: [] }
|
||||
);
|
||||
|
||||
export const PreconfiguredFleetProxiesSchema = schema.arrayOf(
|
||||
schema.object({
|
||||
id: schema.string(),
|
||||
name: schema.string(),
|
||||
url: schema.string(),
|
||||
proxy_headers: schema.maybe(
|
||||
schema.recordOf(
|
||||
schema.string(),
|
||||
schema.oneOf([schema.string(), schema.boolean(), schema.number()])
|
||||
)
|
||||
),
|
||||
certificate_authorities: schema.maybe(schema.string()),
|
||||
certificate: schema.maybe(schema.string()),
|
||||
certificate_key: schema.maybe(schema.string()),
|
||||
}),
|
||||
{ defaultValue: [] }
|
||||
);
|
||||
|
||||
export const PreconfiguredAgentPoliciesSchema = schema.arrayOf(
|
||||
schema.object({
|
||||
...AgentPolicyBaseSchema,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue