Beats Management plugin: migrate server-side code (#70930)
* move all the legacy codebase to KP plugin * fix imports * add empty handler context & rename routes folder * start migrating routes * migrate rest of the routes * migrate adapters * remove beats from legacy xpack plugin * use nullable + replace response.custom * fix wrapRouteWithSecurity, remove incorrect header validation * remove comment * updating generated plugin list * fix typos in doc * adapt readme too. * remove old commented routes from route files * remove eslint disabling * use camel case for plugin id * update generated doc Co-authored-by: Josh Dover <me@joshdover.com>
This commit is contained in:
parent
198806baef
commit
890fc31dff
|
@ -313,9 +313,10 @@ To access an elasticsearch instance that has live data you have two options:
|
|||
WARNING: Missing README.
|
||||
|
||||
|
||||
- {kib-repo}blob/{branch}/x-pack/plugins/beats_management[beats_management]
|
||||
- {kib-repo}blob/{branch}/x-pack/plugins/beats_management/readme.md[beatsManagement]
|
||||
|
||||
WARNING: Missing README.
|
||||
Notes:
|
||||
Failure to have auth enabled in Kibana will make for a broken UI. UI-based errors not yet in place
|
||||
|
||||
|
||||
- {kib-repo}blob/{branch}/x-pack/plugins/canvas/README.md[canvas]
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
import { xpackMain } from './legacy/plugins/xpack_main';
|
||||
import { monitoring } from './legacy/plugins/monitoring';
|
||||
import { security } from './legacy/plugins/security';
|
||||
import { beats } from './legacy/plugins/beats_management';
|
||||
import { spaces } from './legacy/plugins/spaces';
|
||||
|
||||
module.exports = function (kibana) {
|
||||
return [xpackMain(kibana), monitoring(kibana), spaces(kibana), security(kibana), beats(kibana)];
|
||||
return [xpackMain(kibana), monitoring(kibana), spaces(kibana), security(kibana)];
|
||||
};
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import Joi from 'joi';
|
||||
import { PLUGIN } from './common/constants';
|
||||
import { CONFIG_PREFIX } from './common/constants/plugin';
|
||||
import { initServerWithKibana } from './server/kibana.index';
|
||||
import { KibanaLegacyServer } from './server/lib/adapters/framework/adapter_types';
|
||||
|
||||
const DEFAULT_ENROLLMENT_TOKENS_TTL_S = 10 * 60; // 10 minutes
|
||||
|
||||
export const config = Joi.object({
|
||||
enabled: Joi.boolean().default(true),
|
||||
defaultUserRoles: Joi.array().items(Joi.string()).default(['superuser']),
|
||||
encryptionKey: Joi.string().default('xpack_beats_default_encryptionKey'),
|
||||
enrollmentTokensTtlInSeconds: Joi.number()
|
||||
.integer()
|
||||
.min(1)
|
||||
.max(10 * 60 * 14) // No more then 2 weeks for security reasons
|
||||
.default(DEFAULT_ENROLLMENT_TOKENS_TTL_S),
|
||||
}).default();
|
||||
|
||||
export function beats(kibana: any) {
|
||||
return new kibana.Plugin({
|
||||
id: PLUGIN.ID,
|
||||
require: ['kibana', 'elasticsearch', 'xpack_main'],
|
||||
config: () => config,
|
||||
configPrefix: CONFIG_PREFIX,
|
||||
init(server: KibanaLegacyServer) {
|
||||
initServerWithKibana(server);
|
||||
},
|
||||
});
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ResponseToolkit } from 'hapi';
|
||||
import { PathReporter } from 'io-ts/lib/PathReporter';
|
||||
import { get } from 'lodash';
|
||||
import { isLeft } from 'fp-ts/lib/Either';
|
||||
import { KibanaRequest, LegacyRequest } from '../../../../../../../../src/core/server';
|
||||
// @ts-ignore
|
||||
import { mirrorPluginStatus } from '../../../../../../server/lib/mirror_plugin_status';
|
||||
import {
|
||||
BackendFrameworkAdapter,
|
||||
FrameworkInfo,
|
||||
FrameworkRequest,
|
||||
FrameworkResponse,
|
||||
FrameworkRouteOptions,
|
||||
internalAuthData,
|
||||
internalUser,
|
||||
KibanaLegacyServer,
|
||||
KibanaServerRequest,
|
||||
KibanaUser,
|
||||
RuntimeFrameworkInfo,
|
||||
RuntimeKibanaUser,
|
||||
XpackInfo,
|
||||
} from './adapter_types';
|
||||
|
||||
export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter {
|
||||
public readonly internalUser = internalUser;
|
||||
public info: null | FrameworkInfo = null;
|
||||
|
||||
constructor(
|
||||
private readonly PLUGIN_ID: string,
|
||||
private readonly server: KibanaLegacyServer,
|
||||
private readonly CONFIG_PREFIX?: string
|
||||
) {
|
||||
const xpackMainPlugin = this.server.plugins.xpack_main;
|
||||
const thisPlugin = this.server.plugins.beats_management;
|
||||
|
||||
mirrorPluginStatus(xpackMainPlugin, thisPlugin);
|
||||
|
||||
xpackMainPlugin.status.on('green', () => {
|
||||
this.xpackInfoWasUpdatedHandler(xpackMainPlugin.info);
|
||||
// Register a function that is called whenever the xpack info changes,
|
||||
// to re-compute the license check results for this plugin
|
||||
xpackMainPlugin.info
|
||||
.feature(this.PLUGIN_ID)
|
||||
.registerLicenseCheckResultsGenerator(this.xpackInfoWasUpdatedHandler);
|
||||
});
|
||||
}
|
||||
|
||||
public on(event: 'xpack.status.green' | 'elasticsearch.status.green', cb: () => void) {
|
||||
switch (event) {
|
||||
case 'xpack.status.green':
|
||||
this.server.plugins.xpack_main.status.on('green', cb);
|
||||
case 'elasticsearch.status.green':
|
||||
this.server.plugins.elasticsearch.status.on('green', cb);
|
||||
}
|
||||
}
|
||||
|
||||
public getSetting(settingPath: string) {
|
||||
return this.server.config().get(settingPath);
|
||||
}
|
||||
|
||||
public log(text: string) {
|
||||
this.server.log(text);
|
||||
}
|
||||
|
||||
public registerRoute<
|
||||
RouteRequest extends FrameworkRequest,
|
||||
RouteResponse extends FrameworkResponse
|
||||
>(route: FrameworkRouteOptions<RouteRequest, RouteResponse>) {
|
||||
this.server.route({
|
||||
handler: async (request: KibanaServerRequest, h: ResponseToolkit) => {
|
||||
// Note, RuntimeKibanaServerRequest is avalaible to validate request, and its type *is* KibanaServerRequest
|
||||
// but is not used here for perf reasons. It's value here is not high enough...
|
||||
return await route.handler(await this.wrapRequest<RouteRequest>(request), h);
|
||||
},
|
||||
method: route.method,
|
||||
path: route.path,
|
||||
config: route.config,
|
||||
});
|
||||
}
|
||||
|
||||
private async wrapRequest<InternalRequest extends KibanaServerRequest>(
|
||||
req: KibanaServerRequest
|
||||
): Promise<FrameworkRequest<InternalRequest>> {
|
||||
const { params, payload, query, headers, info } = req;
|
||||
|
||||
let isAuthenticated = headers.authorization != null;
|
||||
let user;
|
||||
if (isAuthenticated) {
|
||||
user = await this.getUser(req);
|
||||
if (!user) {
|
||||
isAuthenticated = false;
|
||||
}
|
||||
}
|
||||
return {
|
||||
user:
|
||||
isAuthenticated && user
|
||||
? {
|
||||
kind: 'authenticated',
|
||||
[internalAuthData]: headers,
|
||||
...user,
|
||||
}
|
||||
: {
|
||||
kind: 'unauthenticated',
|
||||
},
|
||||
headers,
|
||||
info,
|
||||
params,
|
||||
payload,
|
||||
query,
|
||||
};
|
||||
}
|
||||
|
||||
private async getUser(request: KibanaServerRequest): Promise<KibanaUser | null> {
|
||||
const user = this.server.newPlatform.setup.plugins.security?.authc.getCurrentUser(
|
||||
KibanaRequest.from((request as unknown) as LegacyRequest)
|
||||
);
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
const assertKibanaUser = RuntimeKibanaUser.decode(user);
|
||||
if (isLeft(assertKibanaUser)) {
|
||||
throw new Error(
|
||||
`Error parsing user info in ${this.PLUGIN_ID}, ${
|
||||
PathReporter.report(assertKibanaUser)[0]
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
private xpackInfoWasUpdatedHandler = (xpackInfo: XpackInfo) => {
|
||||
let xpackInfoUnpacked: FrameworkInfo;
|
||||
|
||||
// If, for some reason, we cannot get the license information
|
||||
// from Elasticsearch, assume worst case and disable
|
||||
if (!xpackInfo || !xpackInfo.isAvailable()) {
|
||||
this.info = null;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
xpackInfoUnpacked = {
|
||||
kibana: {
|
||||
version: get(this.server, 'plugins.kibana.status.plugin.version', 'unknown'),
|
||||
},
|
||||
license: {
|
||||
type: xpackInfo.license.getType(),
|
||||
expired: !xpackInfo.license.isActive(),
|
||||
expiry_date_in_millis:
|
||||
xpackInfo.license.getExpiryDateInMillis() !== undefined
|
||||
? xpackInfo.license.getExpiryDateInMillis()
|
||||
: -1,
|
||||
},
|
||||
security: {
|
||||
enabled: !!xpackInfo.feature('security') && xpackInfo.feature('security').isEnabled(),
|
||||
available: !!xpackInfo.feature('security'),
|
||||
},
|
||||
watcher: {
|
||||
enabled: !!xpackInfo.feature('watcher') && xpackInfo.feature('watcher').isEnabled(),
|
||||
available: !!xpackInfo.feature('watcher'),
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
this.server.log(`Error accessing required xPackInfo in ${this.PLUGIN_ID} Kibana adapter`);
|
||||
throw e;
|
||||
}
|
||||
|
||||
const assertData = RuntimeFrameworkInfo.decode(xpackInfoUnpacked);
|
||||
if (isLeft(assertData)) {
|
||||
throw new Error(
|
||||
`Error parsing xpack info in ${this.PLUGIN_ID}, ${PathReporter.report(assertData)[0]}`
|
||||
);
|
||||
}
|
||||
this.info = xpackInfoUnpacked;
|
||||
|
||||
return {
|
||||
security: xpackInfoUnpacked.security,
|
||||
settings: this.getSetting(this.CONFIG_PREFIX || this.PLUGIN_ID),
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ResponseObject, ResponseToolkit } from 'hapi';
|
||||
import { difference } from 'lodash';
|
||||
import { BaseReturnType } from '../../common/return_types';
|
||||
import {
|
||||
BackendFrameworkAdapter,
|
||||
FrameworkRequest,
|
||||
FrameworkResponse,
|
||||
} from './adapters/framework/adapter_types';
|
||||
|
||||
export class BackendFrameworkLib {
|
||||
public log = this.adapter.log;
|
||||
public on = this.adapter.on.bind(this.adapter);
|
||||
public internalUser = this.adapter.internalUser;
|
||||
constructor(private readonly adapter: BackendFrameworkAdapter) {
|
||||
this.validateConfig();
|
||||
}
|
||||
|
||||
public registerRoute<
|
||||
RouteRequest extends FrameworkRequest,
|
||||
RouteResponse extends FrameworkResponse
|
||||
>(route: {
|
||||
path: string;
|
||||
method: string | string[];
|
||||
licenseRequired?: string[];
|
||||
requiredRoles?: string[];
|
||||
handler: (request: FrameworkRequest<RouteRequest>) => Promise<BaseReturnType>;
|
||||
config?: {};
|
||||
}) {
|
||||
this.adapter.registerRoute({
|
||||
...route,
|
||||
handler: this.wrapErrors(
|
||||
this.wrapRouteWithSecurity(route.handler, route.licenseRequired || [], route.requiredRoles)
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
public getSetting(setting: 'encryptionKey'): string;
|
||||
public getSetting(setting: 'enrollmentTokensTtlInSeconds'): number;
|
||||
public getSetting(setting: 'defaultUserRoles'): string[];
|
||||
public getSetting(
|
||||
setting: 'encryptionKey' | 'enrollmentTokensTtlInSeconds' | 'defaultUserRoles'
|
||||
) {
|
||||
return this.adapter.getSetting(`xpack.beats.${setting}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expired `null` happens when we have no xpack info
|
||||
*/
|
||||
public get license() {
|
||||
return {
|
||||
type: this.adapter.info ? this.adapter.info.license.type : 'unknown',
|
||||
expired: this.adapter.info ? this.adapter.info.license.expired : null,
|
||||
};
|
||||
}
|
||||
|
||||
public get securityIsEnabled() {
|
||||
return this.adapter.info ? this.adapter.info.security.enabled : false;
|
||||
}
|
||||
|
||||
private validateConfig() {
|
||||
const encryptionKey = this.adapter.getSetting('xpack.beats.encryptionKey');
|
||||
|
||||
if (!encryptionKey) {
|
||||
this.adapter.log(
|
||||
'Using a default encryption key for xpack.beats.encryptionKey. It is recommended that you set xpack.beats.encryptionKey in kibana.yml with a unique token'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private wrapRouteWithSecurity(
|
||||
handler: (request: FrameworkRequest<any>) => Promise<BaseReturnType>,
|
||||
requiredLicense: string[],
|
||||
requiredRoles?: string[]
|
||||
): (request: FrameworkRequest) => Promise<BaseReturnType> {
|
||||
return async (request: FrameworkRequest) => {
|
||||
if (
|
||||
requiredLicense.length > 0 &&
|
||||
(this.license.expired || !requiredLicense.includes(this.license.type))
|
||||
) {
|
||||
return {
|
||||
error: {
|
||||
message: `Your ${this.license.type} license does not support this API or is expired. Please upgrade your license.`,
|
||||
code: 403,
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (requiredRoles) {
|
||||
if (request.user.kind !== 'authenticated') {
|
||||
return {
|
||||
error: {
|
||||
message: `Request must be authenticated`,
|
||||
code: 403,
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
request.user.kind === 'authenticated' &&
|
||||
!request.user.roles.includes('superuser') &&
|
||||
difference(requiredRoles, request.user.roles).length !== 0
|
||||
) {
|
||||
return {
|
||||
error: {
|
||||
message: `Request must be authenticated by a user with one of the following user roles: ${requiredRoles.join(
|
||||
','
|
||||
)}`,
|
||||
code: 403,
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
return await handler(request);
|
||||
};
|
||||
}
|
||||
private wrapErrors(
|
||||
handler: (request: FrameworkRequest<any>) => Promise<BaseReturnType>
|
||||
): (request: FrameworkRequest, h: ResponseToolkit) => Promise<ResponseObject> {
|
||||
return async (request: FrameworkRequest, h: ResponseToolkit) => {
|
||||
try {
|
||||
const result = await handler(request);
|
||||
if (!result.error) {
|
||||
return h.response(result);
|
||||
}
|
||||
return h
|
||||
.response({
|
||||
error: result.error,
|
||||
success: false,
|
||||
})
|
||||
.code(result.error.code || 400);
|
||||
} catch (err) {
|
||||
let statusCode = err.statusCode;
|
||||
|
||||
// This is the only known non-status code error in the system, but just in case we have an else
|
||||
if (!statusCode && (err.message as string).includes('Invalid user type')) {
|
||||
statusCode = 403;
|
||||
} else {
|
||||
statusCode = 500;
|
||||
}
|
||||
|
||||
if (statusCode === 403) {
|
||||
return h
|
||||
.response({
|
||||
error: {
|
||||
message: 'Insufficient user permissions for managing Beats configuration',
|
||||
code: 403,
|
||||
},
|
||||
success: false,
|
||||
})
|
||||
.code(403);
|
||||
}
|
||||
|
||||
return h
|
||||
.response({
|
||||
error: {
|
||||
message: err.message,
|
||||
code: statusCode,
|
||||
},
|
||||
success: false,
|
||||
})
|
||||
.code(statusCode);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { INDEX_NAMES } from '../common/constants/index_names';
|
||||
import { beatsIndexTemplate } from './index_templates';
|
||||
import { CMServerLibs } from './lib/types';
|
||||
import { createGetBeatConfigurationRoute } from './rest_api/beats/configuration';
|
||||
import { createBeatEnrollmentRoute } from './rest_api/beats/enroll';
|
||||
import { beatEventsRoute } from './rest_api/beats/events';
|
||||
import { createGetBeatRoute } from './rest_api/beats/get';
|
||||
import { createListAgentsRoute } from './rest_api/beats/list';
|
||||
import { createTagAssignmentsRoute } from './rest_api/beats/tag_assignment';
|
||||
import { createTagRemovalsRoute } from './rest_api/beats/tag_removal';
|
||||
import { createBeatUpdateRoute } from './rest_api/beats/update';
|
||||
import { createDeleteConfidurationsRoute } from './rest_api/configurations/delete';
|
||||
import { createGetConfigurationBlocksRoute } from './rest_api/configurations/get';
|
||||
import { upsertConfigurationRoute } from './rest_api/configurations/upsert';
|
||||
import { createAssignableTagsRoute } from './rest_api/tags/assignable';
|
||||
import { createDeleteTagsWithIdsRoute } from './rest_api/tags/delete';
|
||||
import { createGetTagsWithIdsRoute } from './rest_api/tags/get';
|
||||
import { createListTagsRoute } from './rest_api/tags/list';
|
||||
import { createSetTagRoute } from './rest_api/tags/set';
|
||||
import { createTokensRoute } from './rest_api/tokens/create';
|
||||
|
||||
export const initManagementServer = (libs: CMServerLibs) => {
|
||||
if (libs.database) {
|
||||
libs.framework.on('elasticsearch.status.green', async () => {
|
||||
await libs.database!.putTemplate(INDEX_NAMES.BEATS, beatsIndexTemplate);
|
||||
});
|
||||
}
|
||||
|
||||
libs.framework.registerRoute(createGetBeatRoute(libs));
|
||||
libs.framework.registerRoute(createGetTagsWithIdsRoute(libs));
|
||||
libs.framework.registerRoute(createListTagsRoute(libs));
|
||||
libs.framework.registerRoute(createDeleteTagsWithIdsRoute(libs));
|
||||
libs.framework.registerRoute(createGetBeatConfigurationRoute(libs));
|
||||
libs.framework.registerRoute(createTagAssignmentsRoute(libs));
|
||||
libs.framework.registerRoute(createListAgentsRoute(libs));
|
||||
libs.framework.registerRoute(createTagRemovalsRoute(libs));
|
||||
libs.framework.registerRoute(createBeatEnrollmentRoute(libs));
|
||||
libs.framework.registerRoute(createSetTagRoute(libs));
|
||||
libs.framework.registerRoute(createTokensRoute(libs));
|
||||
libs.framework.registerRoute(createBeatUpdateRoute(libs));
|
||||
libs.framework.registerRoute(createDeleteConfidurationsRoute(libs));
|
||||
libs.framework.registerRoute(createGetConfigurationBlocksRoute(libs));
|
||||
libs.framework.registerRoute(upsertConfigurationRoute(libs));
|
||||
libs.framework.registerRoute(createAssignableTagsRoute(libs));
|
||||
libs.framework.registerRoute(beatEventsRoute(libs));
|
||||
};
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import Joi from 'joi';
|
||||
import { ConfigurationBlock } from '../../../common/domain_types';
|
||||
import { BaseReturnType, ReturnTypeList } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
export const createGetBeatConfigurationRoute = (libs: CMServerLibs) => ({
|
||||
method: 'GET',
|
||||
path: '/api/beats/agent/{beatId}/configuration',
|
||||
config: {
|
||||
validate: {
|
||||
headers: Joi.object({
|
||||
'kbn-beats-access-token': Joi.string().required(),
|
||||
}).options({ allowUnknown: true }),
|
||||
},
|
||||
auth: false,
|
||||
},
|
||||
handler: async (
|
||||
request: FrameworkRequest
|
||||
): Promise<BaseReturnType | ReturnTypeList<ConfigurationBlock>> => {
|
||||
const beatId = request.params.beatId;
|
||||
const accessToken = request.headers['kbn-beats-access-token'];
|
||||
|
||||
let configurationBlocks: ConfigurationBlock[];
|
||||
const beat = await libs.beats.getById(libs.framework.internalUser, beatId);
|
||||
if (beat === null) {
|
||||
return { error: { message: `Beat "${beatId}" not found`, code: 404 }, success: false };
|
||||
}
|
||||
|
||||
const isAccessTokenValid = beat.access_token === accessToken;
|
||||
if (!isAccessTokenValid) {
|
||||
return { error: { message: 'Invalid access token', code: 401 }, success: false };
|
||||
}
|
||||
|
||||
await libs.beats.update(libs.framework.internalUser, beat.id, {
|
||||
last_checkin: new Date(),
|
||||
});
|
||||
|
||||
if (beat.tags) {
|
||||
const result = await libs.configurationBlocks.getForTags(
|
||||
libs.framework.internalUser,
|
||||
beat.tags,
|
||||
-1
|
||||
);
|
||||
|
||||
configurationBlocks = result.blocks;
|
||||
} else {
|
||||
configurationBlocks = [];
|
||||
}
|
||||
|
||||
return {
|
||||
list: configurationBlocks,
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
});
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import Joi from 'joi';
|
||||
import { omit } from 'lodash';
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants/security';
|
||||
import { BaseReturnType, ReturnTypeCreate } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { BeatEnrollmentStatus, CMServerLibs } from '../../lib/types';
|
||||
|
||||
// TODO: write to Kibana audit log file https://github.com/elastic/kibana/issues/26024
|
||||
export const createBeatEnrollmentRoute = (libs: CMServerLibs) => ({
|
||||
method: 'POST',
|
||||
path: '/api/beats/agent/{beatId}',
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
config: {
|
||||
auth: false,
|
||||
validate: {
|
||||
headers: Joi.object({
|
||||
'kbn-beats-enrollment-token': Joi.string().required(),
|
||||
}).options({
|
||||
allowUnknown: true,
|
||||
}),
|
||||
payload: Joi.object({
|
||||
host_name: Joi.string().required(),
|
||||
name: Joi.string().required(),
|
||||
type: Joi.string().required(),
|
||||
version: Joi.string().required(),
|
||||
}).required(),
|
||||
},
|
||||
},
|
||||
handler: async (
|
||||
request: FrameworkRequest
|
||||
): Promise<BaseReturnType | ReturnTypeCreate<string>> => {
|
||||
const { beatId } = request.params;
|
||||
const enrollmentToken = request.headers['kbn-beats-enrollment-token'];
|
||||
|
||||
const { status, accessToken } = await libs.beats.enrollBeat(
|
||||
enrollmentToken,
|
||||
beatId,
|
||||
request.info.remoteAddress,
|
||||
omit(request.payload, 'enrollment_token')
|
||||
);
|
||||
|
||||
switch (status) {
|
||||
case BeatEnrollmentStatus.ExpiredEnrollmentToken:
|
||||
return {
|
||||
error: { message: BeatEnrollmentStatus.ExpiredEnrollmentToken, code: 400 },
|
||||
success: false,
|
||||
};
|
||||
|
||||
case BeatEnrollmentStatus.InvalidEnrollmentToken:
|
||||
return {
|
||||
error: { message: BeatEnrollmentStatus.InvalidEnrollmentToken, code: 400 },
|
||||
success: false,
|
||||
};
|
||||
case BeatEnrollmentStatus.Success:
|
||||
default:
|
||||
return {
|
||||
item: accessToken,
|
||||
action: 'created',
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import Joi from 'joi';
|
||||
import { BaseReturnType, ReturnTypeBulkAction } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
export const beatEventsRoute = (libs: CMServerLibs) => ({
|
||||
method: 'POST',
|
||||
path: '/api/beats/{beatId}/events',
|
||||
config: {
|
||||
validate: {
|
||||
headers: Joi.object({
|
||||
'kbn-beats-access-token': Joi.string().required(),
|
||||
}).options({ allowUnknown: true }),
|
||||
},
|
||||
auth: false,
|
||||
},
|
||||
handler: async (request: FrameworkRequest): Promise<BaseReturnType | ReturnTypeBulkAction> => {
|
||||
const beatId = request.params.beatId;
|
||||
const events = request.payload;
|
||||
const accessToken = request.headers['kbn-beats-access-token'];
|
||||
|
||||
const beat = await libs.beats.getById(libs.framework.internalUser, beatId);
|
||||
if (beat === null) {
|
||||
return { error: { message: `Beat "${beatId}" not found`, code: 400 }, success: false };
|
||||
}
|
||||
|
||||
const isAccessTokenValid = beat.access_token === accessToken;
|
||||
if (!isAccessTokenValid) {
|
||||
return { error: { message: `Invalid access token`, code: 401 }, success: false };
|
||||
}
|
||||
|
||||
const results = await libs.beatEvents.log(libs.framework.internalUser, beat.id, events);
|
||||
|
||||
return {
|
||||
results,
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
});
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { CMBeat } from '../../../common/domain_types';
|
||||
import { BaseReturnType, ReturnTypeGet } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
export const createGetBeatRoute = (libs: CMServerLibs) => ({
|
||||
method: 'GET',
|
||||
path: '/api/beats/agent/{beatId}/{token?}',
|
||||
requiredRoles: ['beats_admin'],
|
||||
handler: async (request: FrameworkRequest): Promise<BaseReturnType | ReturnTypeGet<CMBeat>> => {
|
||||
const beatId = request.params.beatId;
|
||||
|
||||
let beat: CMBeat | null;
|
||||
if (beatId === 'unknown') {
|
||||
beat = await libs.beats.getByEnrollmentToken(request.user, request.params.token);
|
||||
if (beat === null) {
|
||||
return { success: false };
|
||||
}
|
||||
} else {
|
||||
beat = await libs.beats.getById(request.user, beatId);
|
||||
if (beat === null) {
|
||||
return { error: { message: 'Beat not found', code: 404 }, success: false };
|
||||
}
|
||||
}
|
||||
|
||||
delete beat.access_token;
|
||||
|
||||
return {
|
||||
item: beat,
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
});
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import * as Joi from 'joi';
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants/security';
|
||||
import { CMBeat } from '../../../common/domain_types';
|
||||
import { ReturnTypeList } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
export const createListAgentsRoute = (libs: CMServerLibs) => ({
|
||||
method: 'GET',
|
||||
path: '/api/beats/agents/{listByAndValue*}',
|
||||
requiredRoles: ['beats_admin'],
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
|
||||
validate: {
|
||||
headers: Joi.object({
|
||||
'kbn-beats-enrollment-token': Joi.string().required(),
|
||||
}).options({
|
||||
allowUnknown: true,
|
||||
}),
|
||||
query: Joi.object({
|
||||
ESQuery: Joi.string(),
|
||||
}),
|
||||
},
|
||||
handler: async (request: FrameworkRequest): Promise<ReturnTypeList<CMBeat>> => {
|
||||
const listByAndValueParts = request.params.listByAndValue
|
||||
? request.params.listByAndValue.split('/')
|
||||
: [];
|
||||
let listBy: 'tag' | null = null;
|
||||
let listByValue: string | null = null;
|
||||
|
||||
if (listByAndValueParts.length === 2) {
|
||||
listBy = listByAndValueParts[0];
|
||||
listByValue = listByAndValueParts[1];
|
||||
}
|
||||
|
||||
let beats: CMBeat[];
|
||||
|
||||
switch (listBy) {
|
||||
case 'tag':
|
||||
beats = await libs.beats.getAllWithTag(request.user, listByValue || '');
|
||||
break;
|
||||
|
||||
default:
|
||||
beats = await libs.beats.getAll(
|
||||
request.user,
|
||||
request.query && request.query.ESQuery ? JSON.parse(request.query.ESQuery) : undefined
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return { list: beats, success: true, page: -1, total: -1 };
|
||||
},
|
||||
});
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Joi from 'joi';
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants/security';
|
||||
import { ReturnTypeBulkAction } from '../../../common/return_types';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { BeatsTagAssignment } from '../../../../../../plugins/beats_management/public/lib/adapters/beats/adapter_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
// TODO: write to Kibana audit log file https://github.com/elastic/kibana/issues/26024
|
||||
export const createTagAssignmentsRoute = (libs: CMServerLibs) => ({
|
||||
method: 'POST',
|
||||
path: '/api/beats/agents_tags/assignments',
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
requiredRoles: ['beats_admin'],
|
||||
config: {
|
||||
validate: {
|
||||
payload: Joi.object({
|
||||
assignments: Joi.array().items(
|
||||
Joi.object({
|
||||
beatId: Joi.string().required(),
|
||||
tag: Joi.string().required(),
|
||||
})
|
||||
),
|
||||
}).required(),
|
||||
},
|
||||
},
|
||||
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkAction> => {
|
||||
const { assignments }: { assignments: BeatsTagAssignment[] } = request.payload;
|
||||
|
||||
const response = await libs.beats.assignTagsToBeats(request.user, assignments);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
results: response.assignments.map((assignment) => ({
|
||||
success: assignment.status && assignment.status >= 200 && assignment.status < 300,
|
||||
error:
|
||||
!assignment.status || assignment.status >= 300
|
||||
? {
|
||||
code: assignment.status || 400,
|
||||
message: assignment.result,
|
||||
}
|
||||
: undefined,
|
||||
result:
|
||||
assignment.status && assignment.status >= 200 && assignment.status < 300
|
||||
? {
|
||||
message: assignment.result,
|
||||
}
|
||||
: undefined,
|
||||
})),
|
||||
} as ReturnTypeBulkAction;
|
||||
},
|
||||
});
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Joi from 'joi';
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants/security';
|
||||
import { ReturnTypeBulkAction } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
// TODO: write to Kibana audit log file https://github.com/elastic/kibana/issues/26024
|
||||
export const createTagRemovalsRoute = (libs: CMServerLibs) => ({
|
||||
method: 'POST',
|
||||
path: '/api/beats/agents_tags/removals',
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
requiredRoles: ['beats_admin'],
|
||||
config: {
|
||||
validate: {
|
||||
payload: Joi.object({
|
||||
removals: Joi.array().items(
|
||||
Joi.object({
|
||||
beatId: Joi.string().required(),
|
||||
tag: Joi.string().required(),
|
||||
})
|
||||
),
|
||||
}).required(),
|
||||
},
|
||||
},
|
||||
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkAction> => {
|
||||
const { removals } = request.payload;
|
||||
|
||||
const response = await libs.beats.removeTagsFromBeats(request.user, removals);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
results: response.removals.map((removal) => ({
|
||||
success: removal.status && removal.status >= 200 && removal.status < 300,
|
||||
error:
|
||||
!removal.status || removal.status >= 300
|
||||
? {
|
||||
code: removal.status || 400,
|
||||
message: removal.result,
|
||||
}
|
||||
: undefined,
|
||||
result:
|
||||
removal.status && removal.status >= 200 && removal.status < 300
|
||||
? {
|
||||
message: removal.result,
|
||||
}
|
||||
: undefined,
|
||||
})),
|
||||
} as ReturnTypeBulkAction;
|
||||
},
|
||||
});
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Joi from 'joi';
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants/security';
|
||||
import { CMBeat } from '../../../common/domain_types';
|
||||
import { BaseReturnType, ReturnTypeUpdate } from '../../../common/return_types';
|
||||
import { FrameworkRequest, internalUser } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
// TODO: write to Kibana audit log file (include who did the verification as well) https://github.com/elastic/kibana/issues/26024
|
||||
export const createBeatUpdateRoute = (libs: CMServerLibs) => ({
|
||||
method: 'PUT',
|
||||
path: '/api/beats/agent/{beatId}',
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
requiredRoles: ['beats_admin'],
|
||||
config: {
|
||||
validate: {
|
||||
headers: Joi.object({
|
||||
'kbn-beats-access-token': Joi.string(),
|
||||
}).options({
|
||||
allowUnknown: true,
|
||||
}),
|
||||
params: Joi.object({
|
||||
beatId: Joi.string(),
|
||||
}),
|
||||
payload: Joi.object({
|
||||
active: Joi.bool(),
|
||||
ephemeral_id: Joi.string(),
|
||||
host_name: Joi.string(),
|
||||
local_configuration_yml: Joi.string(),
|
||||
metadata: Joi.object(),
|
||||
name: Joi.string(),
|
||||
type: Joi.string(),
|
||||
version: Joi.string(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
handler: async (
|
||||
request: FrameworkRequest
|
||||
): Promise<BaseReturnType | ReturnTypeUpdate<CMBeat>> => {
|
||||
const { beatId } = request.params;
|
||||
const accessToken = request.headers['kbn-beats-access-token'];
|
||||
const remoteAddress = request.info.remoteAddress;
|
||||
const userOrToken = accessToken || request.user;
|
||||
|
||||
if (request.user.kind === 'unauthenticated' && request.payload.active !== undefined) {
|
||||
return {
|
||||
error: {
|
||||
message: 'access-token is not a valid auth type to change beat status',
|
||||
code: 401,
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
const status = await libs.beats.update(userOrToken, beatId, {
|
||||
...request.payload,
|
||||
host_ip: remoteAddress,
|
||||
});
|
||||
|
||||
switch (status) {
|
||||
case 'beat-not-found':
|
||||
return {
|
||||
error: {
|
||||
message: 'Beat not found',
|
||||
code: 404,
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
case 'invalid-access-token':
|
||||
return {
|
||||
error: {
|
||||
message: 'Invalid access token',
|
||||
code: 401,
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
const beat = await libs.beats.getById(internalUser, beatId);
|
||||
|
||||
if (!beat) {
|
||||
return {
|
||||
error: {
|
||||
message: 'Beat not found',
|
||||
code: 404,
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
item: beat,
|
||||
action: 'updated',
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
});
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants/security';
|
||||
import { ReturnTypeBulkDelete } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
export const createDeleteConfidurationsRoute = (libs: CMServerLibs) => ({
|
||||
method: 'DELETE',
|
||||
path: '/api/beats/configurations/{ids}',
|
||||
requiredRoles: ['beats_admin'],
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkDelete> => {
|
||||
const idString: string = request.params.ids;
|
||||
const ids = idString.split(',').filter((id: string) => id.length > 0);
|
||||
|
||||
const results = await libs.configurationBlocks.delete(request.user, ids);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
results: results.map((result) => ({
|
||||
success: result.success,
|
||||
action: 'deleted',
|
||||
error: result.success ? undefined : { message: result.reason },
|
||||
})),
|
||||
} as ReturnTypeBulkDelete;
|
||||
},
|
||||
});
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants/security';
|
||||
import { ConfigurationBlock } from '../../../common/domain_types';
|
||||
import { ReturnTypeList } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
export const createGetConfigurationBlocksRoute = (libs: CMServerLibs) => ({
|
||||
method: 'GET',
|
||||
path: '/api/beats/configurations/{tagIds}/{page?}',
|
||||
requiredRoles: ['beats_admin'],
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
handler: async (request: FrameworkRequest): Promise<ReturnTypeList<ConfigurationBlock>> => {
|
||||
const tagIdString: string = request.params.tagIds;
|
||||
const tagIds = tagIdString.split(',').filter((id: string) => id.length > 0);
|
||||
|
||||
const result = await libs.configurationBlocks.getForTags(
|
||||
request.user,
|
||||
tagIds,
|
||||
parseInt(request.params.page, 10),
|
||||
5
|
||||
);
|
||||
|
||||
return { page: result.page, total: result.total, list: result.blocks, success: true };
|
||||
},
|
||||
});
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { PathReporter } from 'io-ts/lib/PathReporter';
|
||||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import Joi from 'joi';
|
||||
import { isLeft } from 'fp-ts/lib/Either';
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants';
|
||||
import {
|
||||
ConfigurationBlock,
|
||||
createConfigurationBlockInterface,
|
||||
} from '../../../common/domain_types';
|
||||
import { ReturnTypeBulkUpsert } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
// TODO: write to Kibana audit log file
|
||||
export const upsertConfigurationRoute = (libs: CMServerLibs) => ({
|
||||
method: 'PUT',
|
||||
path: '/api/beats/configurations',
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
requiredRoles: ['beats_admin'],
|
||||
config: {
|
||||
validate: {
|
||||
payload: Joi.array().items(Joi.object({}).unknown(true)),
|
||||
},
|
||||
},
|
||||
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkUpsert> => {
|
||||
const result = await Promise.all<any>(
|
||||
request.payload.map(async (block: ConfigurationBlock) => {
|
||||
const assertData = createConfigurationBlockInterface().decode(block);
|
||||
if (isLeft(assertData)) {
|
||||
return {
|
||||
error: `Error parsing block info, ${PathReporter.report(assertData)[0]}`,
|
||||
};
|
||||
}
|
||||
|
||||
const { blockID, success, error } = await libs.configurationBlocks.save(
|
||||
request.user,
|
||||
block
|
||||
);
|
||||
if (error) {
|
||||
return { success, error };
|
||||
}
|
||||
|
||||
return { success, blockID };
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
results: result.map((r) => ({
|
||||
success: r.success as boolean,
|
||||
// TODO: we need to surface this data, not hard coded
|
||||
action: 'created' as 'created' | 'updated',
|
||||
})),
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
});
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { flatten } from 'lodash';
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants/security';
|
||||
import { BeatTag } from '../../../common/domain_types';
|
||||
import { ReturnTypeBulkGet } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
export const createAssignableTagsRoute = (libs: CMServerLibs) => ({
|
||||
method: 'GET',
|
||||
path: '/api/beats/tags/assignable/{beatIds}',
|
||||
requiredRoles: ['beats_admin'],
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkGet<BeatTag>> => {
|
||||
const beatIdString: string = request.params.beatIds;
|
||||
const beatIds = beatIdString.split(',').filter((id: string) => id.length > 0);
|
||||
|
||||
const beats = await libs.beats.getByIds(request.user, beatIds);
|
||||
const tags = await libs.tags.getNonConflictingTags(
|
||||
request.user,
|
||||
flatten(beats.map((beat) => beat.tags))
|
||||
);
|
||||
|
||||
return {
|
||||
items: tags,
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
});
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants/security';
|
||||
import { ReturnTypeBulkDelete } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
export const createDeleteTagsWithIdsRoute = (libs: CMServerLibs) => ({
|
||||
method: 'DELETE',
|
||||
path: '/api/beats/tags/{tagIds}',
|
||||
requiredRoles: ['beats_admin'],
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkDelete> => {
|
||||
const tagIdString: string = request.params.tagIds;
|
||||
const tagIds = tagIdString.split(',').filter((id: string) => id.length > 0);
|
||||
|
||||
const success = await libs.tags.delete(request.user, tagIds);
|
||||
|
||||
return {
|
||||
results: tagIds.map(() => ({
|
||||
success,
|
||||
action: 'deleted',
|
||||
})),
|
||||
success,
|
||||
} as ReturnTypeBulkDelete;
|
||||
},
|
||||
});
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants/security';
|
||||
import { BeatTag } from '../../../common/domain_types';
|
||||
import { ReturnTypeBulkGet } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
export const createGetTagsWithIdsRoute = (libs: CMServerLibs) => ({
|
||||
method: 'GET',
|
||||
path: '/api/beats/tags/{tagIds}',
|
||||
requiredRoles: ['beats_admin'],
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkGet<BeatTag>> => {
|
||||
const tagIdString: string = request.params.tagIds;
|
||||
const tagIds = tagIdString.split(',').filter((id: string) => id.length > 0);
|
||||
|
||||
const tags = await libs.tags.getWithIds(request.user, tagIds);
|
||||
|
||||
return {
|
||||
items: tags,
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
});
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import * as Joi from 'joi';
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants/security';
|
||||
import { BeatTag } from '../../../common/domain_types';
|
||||
import { ReturnTypeList } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
export const createListTagsRoute = (libs: CMServerLibs) => ({
|
||||
method: 'GET',
|
||||
path: '/api/beats/tags',
|
||||
requiredRoles: ['beats_admin'],
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
validate: {
|
||||
headers: Joi.object({
|
||||
'kbn-beats-enrollment-token': Joi.string().required(),
|
||||
}).options({
|
||||
allowUnknown: true,
|
||||
}),
|
||||
query: Joi.object({
|
||||
ESQuery: Joi.string(),
|
||||
}),
|
||||
},
|
||||
handler: async (request: FrameworkRequest): Promise<ReturnTypeList<BeatTag>> => {
|
||||
const tags = await libs.tags.getAll(
|
||||
request.user,
|
||||
request.query && request.query.ESQuery ? JSON.parse(request.query.ESQuery) : undefined
|
||||
);
|
||||
|
||||
return { list: tags, success: true, page: -1, total: -1 };
|
||||
},
|
||||
});
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Joi from 'joi';
|
||||
import { get } from 'lodash';
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants';
|
||||
import { BeatTag } from '../../../common/domain_types';
|
||||
import { ReturnTypeUpsert } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
// TODO: write to Kibana audit log file
|
||||
export const createSetTagRoute = (libs: CMServerLibs) => ({
|
||||
method: 'PUT',
|
||||
path: '/api/beats/tag/{tagId}',
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
requiredRoles: ['beats_admin'],
|
||||
config: {
|
||||
validate: {
|
||||
params: Joi.object({
|
||||
tagId: Joi.string(),
|
||||
}),
|
||||
payload: Joi.object({
|
||||
color: Joi.string(),
|
||||
name: Joi.string(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
handler: async (request: FrameworkRequest): Promise<ReturnTypeUpsert<BeatTag>> => {
|
||||
const defaultConfig = {
|
||||
id: request.params.tagId,
|
||||
name: request.params.tagId,
|
||||
color: '#DD0A73',
|
||||
hasConfigurationBlocksTypes: [],
|
||||
};
|
||||
const config = { ...defaultConfig, ...get(request, 'payload', {}) };
|
||||
|
||||
const id = await libs.tags.upsertTag(request.user, config);
|
||||
const tag = await libs.tags.getWithIds(request.user, [id]);
|
||||
|
||||
// TODO the action needs to be surfaced
|
||||
return { success: true, item: tag[0], action: 'created' };
|
||||
},
|
||||
});
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Joi from 'joi';
|
||||
import { get } from 'lodash';
|
||||
import { REQUIRED_LICENSES } from '../../../common/constants/security';
|
||||
import { BaseReturnType, ReturnTypeBulkCreate } from '../../../common/return_types';
|
||||
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
|
||||
import { CMServerLibs } from '../../lib/types';
|
||||
|
||||
// TODO: write to Kibana audit log file
|
||||
const DEFAULT_NUM_TOKENS = 1;
|
||||
export const createTokensRoute = (libs: CMServerLibs) => ({
|
||||
method: 'POST',
|
||||
path: '/api/beats/enrollment_tokens',
|
||||
licenseRequired: REQUIRED_LICENSES,
|
||||
requiredRoles: ['beats_admin'],
|
||||
config: {
|
||||
validate: {
|
||||
payload: Joi.object({
|
||||
num_tokens: Joi.number().optional().default(DEFAULT_NUM_TOKENS).min(1),
|
||||
}).allow(null),
|
||||
},
|
||||
},
|
||||
handler: async (
|
||||
request: FrameworkRequest
|
||||
): Promise<BaseReturnType | ReturnTypeBulkCreate<string>> => {
|
||||
const numTokens = get(request, 'payload.num_tokens', DEFAULT_NUM_TOKENS);
|
||||
|
||||
try {
|
||||
const tokens = await libs.tokens.createEnrollmentTokens(request.user, numTokens);
|
||||
return {
|
||||
results: tokens.map((token) => ({
|
||||
item: token,
|
||||
success: true,
|
||||
action: 'created',
|
||||
})),
|
||||
success: true,
|
||||
};
|
||||
} catch (err) {
|
||||
libs.framework.log(err.message);
|
||||
return {
|
||||
error: {
|
||||
message: 'An error occured, please check your Kibana logs',
|
||||
code: 500,
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"exclude": ["**/node_modules/**"],
|
||||
"paths": {
|
||||
"react": ["../../../node_modules/@types/react"]
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"id": "beats_management",
|
||||
"id": "beatsManagement",
|
||||
"configPath": ["xpack", "beats_management"],
|
||||
"ui": true,
|
||||
"server": true,
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
import { EuiBasicTable, EuiLink } from '@elastic/eui';
|
||||
import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
|
||||
import React from 'react';
|
||||
import { configBlockSchemas } from '../../../../legacy/plugins/beats_management/common/config_schemas';
|
||||
import { translateConfigSchema } from '../../../../legacy/plugins/beats_management/common/config_schemas_translations_map';
|
||||
import { ConfigurationBlock } from '../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { configBlockSchemas } from '../../common/config_schemas';
|
||||
import { translateConfigSchema } from '../../common/config_schemas_translations_map';
|
||||
import { ConfigurationBlock } from '../../common/domain_types';
|
||||
|
||||
interface ComponentProps {
|
||||
configs: {
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { upperFirst } from 'lodash';
|
||||
import React from 'react';
|
||||
import { CMBeat } from '../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { CMBeat } from '../../common/domain_types';
|
||||
|
||||
interface ComponentProps {
|
||||
/** Such as kibanas basePath, for use to generate command */
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
import React, { Component } from 'react';
|
||||
import { RouteProps } from 'react-router-dom';
|
||||
import { BASE_PATH } from '../../../../../../legacy/plugins/beats_management/common/constants';
|
||||
import { BASE_PATH } from '../../../../common/constants';
|
||||
import { BreadcrumbConsumer } from './consumer';
|
||||
import { Breadcrumb as BreadcrumbData, BreadcrumbContext } from './types';
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
EuiPopover,
|
||||
} from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { TABLE_CONFIG } from '../../../../../../legacy/plugins/beats_management/common/constants/table';
|
||||
import { TABLE_CONFIG } from '../../../../common/constants/table';
|
||||
import { TagBadge } from '../../tag/tag_badge';
|
||||
import { AssignmentActionType } from '../index';
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { QuerySuggestion } from '../../../../../../src/plugins/data/public';
|
||||
import { TABLE_CONFIG } from '../../../../../legacy/plugins/beats_management/common/constants';
|
||||
import { TABLE_CONFIG } from '../../../common/constants';
|
||||
import { AutocompleteField } from '../autocomplete_field/index';
|
||||
import { ControlSchema } from './action_schema';
|
||||
import { OptionControl } from './controls/option_control';
|
||||
|
|
|
@ -9,10 +9,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { sortBy, uniqBy } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import {
|
||||
BeatTag,
|
||||
CMBeat,
|
||||
} from '../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { BeatTag, CMBeat } from '../../../common/domain_types';
|
||||
import { ConnectedLink } from '../navigation/connected_link';
|
||||
import { TagBadge } from '../tag';
|
||||
|
||||
|
|
|
@ -8,10 +8,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import Formsy from 'formsy-react';
|
||||
import { get } from 'lodash';
|
||||
import React from 'react';
|
||||
import {
|
||||
ConfigBlockSchema,
|
||||
ConfigurationBlock,
|
||||
} from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { ConfigBlockSchema, ConfigurationBlock } from '../../../../common/domain_types';
|
||||
import {
|
||||
FormsyEuiCodeEditor,
|
||||
FormsyEuiFieldText,
|
||||
|
|
|
@ -22,9 +22,9 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { configBlockSchemas } from '../../../../../../legacy/plugins/beats_management/common/config_schemas';
|
||||
import { translateConfigSchema } from '../../../../../../legacy/plugins/beats_management/common/config_schemas_translations_map';
|
||||
import { ConfigurationBlock } from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { configBlockSchemas } from '../../../../common/config_schemas';
|
||||
import { translateConfigSchema } from '../../../../common/config_schemas_translations_map';
|
||||
import { ConfigurationBlock } from '../../../../common/domain_types';
|
||||
import { ConfigForm } from './config_form';
|
||||
|
||||
interface ComponentProps {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { EuiBadge, EuiBadgeProps } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { TABLE_CONFIG } from '../../../../../legacy/plugins/beats_management/common/constants';
|
||||
import { TABLE_CONFIG } from '../../../common/constants';
|
||||
|
||||
type TagBadgeProps = EuiBadgeProps & {
|
||||
maxIdRenderSize?: number;
|
||||
|
|
|
@ -24,11 +24,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
import 'brace/mode/yaml';
|
||||
import 'brace/theme/github';
|
||||
import React from 'react';
|
||||
import {
|
||||
BeatTag,
|
||||
CMBeat,
|
||||
ConfigurationBlock,
|
||||
} from '../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { BeatTag, CMBeat, ConfigurationBlock } from '../../../common/domain_types';
|
||||
import { ConfigList } from '../config_list';
|
||||
import { AssignmentActionType, BeatsTableType, Table, tagConfigActions } from '../table';
|
||||
import { ConfigView } from './config_view';
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { Container } from 'unstated';
|
||||
import { CMBeat } from '../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { BeatsTagAssignment } from '../../../../legacy/plugins/beats_management/server/lib/adapters/beats/adapter_types';
|
||||
import { CMBeat } from '../../common/domain_types';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import type { BeatsTagAssignment } from '../../server/lib/adapters/beats/adapter_types';
|
||||
import { FrontendLibs } from './../lib/types';
|
||||
|
||||
interface ContainerState {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { Container } from 'unstated';
|
||||
import { BeatTag } from '../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { BeatTag } from '../../common/domain_types';
|
||||
import { FrontendLibs } from '../lib/types';
|
||||
|
||||
interface ContainerState {
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { configBlockSchemas } from '../../../../../legacy/plugins/beats_management/common/config_schemas';
|
||||
import { translateConfigSchema } from '../../../../../legacy/plugins/beats_management/common/config_schemas_translations_map';
|
||||
import { configBlockSchemas } from '../../../common/config_schemas';
|
||||
import { translateConfigSchema } from '../../../common/config_schemas_translations_map';
|
||||
import { ConfigBlocksLib } from '../configuration_blocks';
|
||||
import { MemoryConfigBlocksAdapter } from './../adapters/configuration_blocks/memory_config_blocks_adapter';
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { CMBeat } from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { ReturnTypeBulkAction } from '../../../../../../legacy/plugins/beats_management/common/return_types';
|
||||
import { CMBeat } from '../../../../common/domain_types';
|
||||
import { ReturnTypeBulkAction } from '../../../../common/return_types';
|
||||
|
||||
export interface CMBeatsAdapter {
|
||||
get(id: string): Promise<CMBeat | null>;
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
|
||||
import { omit } from 'lodash';
|
||||
import { CMBeat } from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { ReturnTypeBulkAction } from '../../../../../../legacy/plugins/beats_management/common/return_types';
|
||||
import { CMBeat } from '../../../../common/domain_types';
|
||||
import { ReturnTypeBulkAction } from '../../../../common/return_types';
|
||||
import { BeatsTagAssignment, CMBeatsAdapter } from './adapter_types';
|
||||
|
||||
export class MemoryBeatsAdapter implements CMBeatsAdapter {
|
||||
|
|
|
@ -4,15 +4,16 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { CMBeat } from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { CMBeat } from '../../../../common/domain_types';
|
||||
import {
|
||||
ReturnTypeBulkAction,
|
||||
ReturnTypeGet,
|
||||
ReturnTypeList,
|
||||
ReturnTypeUpdate,
|
||||
} from '../../../../../../legacy/plugins/beats_management/common/return_types';
|
||||
} from '../../../../common/return_types';
|
||||
import { RestAPIAdapter } from '../rest_api/adapter_types';
|
||||
import { BeatsTagAssignment, CMBeatsAdapter } from './adapter_types';
|
||||
|
||||
export class RestBeatsAdapter implements CMBeatsAdapter {
|
||||
constructor(private readonly REST: RestAPIAdapter) {}
|
||||
|
||||
|
|
|
@ -3,11 +3,8 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { ConfigurationBlock } from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import {
|
||||
ReturnTypeBulkUpsert,
|
||||
ReturnTypeList,
|
||||
} from '../../../../../../legacy/plugins/beats_management/common/return_types';
|
||||
import { ConfigurationBlock } from '../../../../common/domain_types';
|
||||
import { ReturnTypeBulkUpsert, ReturnTypeList } from '../../../../common/return_types';
|
||||
|
||||
export interface FrontendConfigBlocksAdapter {
|
||||
upsert(blocks: ConfigurationBlock[]): Promise<ReturnTypeBulkUpsert>;
|
||||
|
|
|
@ -4,11 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ConfigurationBlock } from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import {
|
||||
ReturnTypeBulkUpsert,
|
||||
ReturnTypeList,
|
||||
} from '../../../../../../legacy/plugins/beats_management/common/return_types';
|
||||
import { ConfigurationBlock } from '../../../../common/domain_types';
|
||||
import { ReturnTypeBulkUpsert, ReturnTypeList } from '../../../../common/return_types';
|
||||
import { FrontendConfigBlocksAdapter } from './adapter_types';
|
||||
|
||||
export class MemoryConfigBlocksAdapter implements FrontendConfigBlocksAdapter {
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ConfigurationBlock } from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { ConfigurationBlock } from '../../../../common/domain_types';
|
||||
import {
|
||||
ReturnTypeBulkDelete,
|
||||
ReturnTypeBulkUpsert,
|
||||
ReturnTypeList,
|
||||
} from '../../../../../../legacy/plugins/beats_management/common/return_types';
|
||||
} from '../../../../common/return_types';
|
||||
import { RestAPIAdapter } from '../rest_api/adapter_types';
|
||||
import { FrontendConfigBlocksAdapter } from './adapter_types';
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { LICENSES } from '../../../../../../legacy/plugins/beats_management/common/constants/security';
|
||||
import { LICENSES } from '../../../../common/constants/security';
|
||||
import { RegisterManagementAppArgs } from '../../../../../../../src/plugins/management/public';
|
||||
|
||||
export interface FrameworkAdapter {
|
||||
|
|
|
@ -3,10 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import {
|
||||
BeatTag,
|
||||
CMBeat,
|
||||
} from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { BeatTag, CMBeat } from '../../../../common/domain_types';
|
||||
|
||||
export interface CMTagsAdapter {
|
||||
getTagsWithIds(tagIds: string[]): Promise<BeatTag[]>;
|
||||
|
|
|
@ -4,10 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import {
|
||||
BeatTag,
|
||||
CMBeat,
|
||||
} from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { BeatTag, CMBeat } from '../../../../common/domain_types';
|
||||
import { CMTagsAdapter } from './adapter_types';
|
||||
|
||||
export class MemoryTagsAdapter implements CMTagsAdapter {
|
||||
|
|
|
@ -5,16 +5,13 @@
|
|||
*/
|
||||
|
||||
import { uniq } from 'lodash';
|
||||
import {
|
||||
BeatTag,
|
||||
CMBeat,
|
||||
} from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { BeatTag, CMBeat } from '../../../../common/domain_types';
|
||||
import {
|
||||
ReturnTypeBulkDelete,
|
||||
ReturnTypeBulkGet,
|
||||
ReturnTypeList,
|
||||
ReturnTypeUpsert,
|
||||
} from '../../../../../../legacy/plugins/beats_management/common/return_types';
|
||||
} from '../../../../common/return_types';
|
||||
import { RestAPIAdapter } from '../rest_api/adapter_types';
|
||||
import { CMTagsAdapter } from './adapter_types';
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ReturnTypeBulkCreate } from '../../../../../../legacy/plugins/beats_management/common/return_types';
|
||||
import { ReturnTypeBulkCreate } from '../../../../common/return_types';
|
||||
import { RestAPIAdapter } from '../rest_api/adapter_types';
|
||||
import { CMTokensAdapter } from './adapter_types';
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ReturnTypeBulkAction } from '../../../../legacy/plugins/beats_management/common/return_types';
|
||||
import { CMBeat } from '../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { ReturnTypeBulkAction } from '../../common/return_types';
|
||||
import { CMBeat } from '../../common/domain_types';
|
||||
import { BeatsTagAssignment, CMBeatsAdapter } from './adapters/beats/adapter_types';
|
||||
import { ElasticsearchLib } from './elasticsearch';
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
*/
|
||||
|
||||
import { camelCase } from 'lodash';
|
||||
import { configBlockSchemas } from '../../../../../legacy/plugins/beats_management/common/config_schemas';
|
||||
import { translateConfigSchema } from '../../../../../legacy/plugins/beats_management/common/config_schemas_translations_map';
|
||||
import { INDEX_NAMES } from '../../../../../legacy/plugins/beats_management/common/constants/index_names';
|
||||
import { configBlockSchemas } from '../../../common/config_schemas';
|
||||
import { translateConfigSchema } from '../../../common/config_schemas_translations_map';
|
||||
import { INDEX_NAMES } from '../../../common/constants/index_names';
|
||||
import { RestBeatsAdapter } from '../adapters/beats/rest_beats_adapter';
|
||||
import { RestConfigBlocksAdapter } from '../adapters/configuration_blocks/rest_config_blocks_adapter';
|
||||
import { RestElasticsearchAdapter } from '../adapters/elasticsearch/rest';
|
||||
|
@ -20,7 +20,7 @@ import { ConfigBlocksLib } from '../configuration_blocks';
|
|||
import { ElasticsearchLib } from '../elasticsearch';
|
||||
import { TagsLib } from '../tags';
|
||||
import { FrontendLibs } from '../types';
|
||||
import { PLUGIN } from '../../../../../legacy/plugins/beats_management/common/constants/plugin';
|
||||
import { PLUGIN } from '../../../common/constants/plugin';
|
||||
import { FrameworkLib } from './../framework';
|
||||
import { ManagementSetup } from '../../../../../../src/plugins/management/public';
|
||||
import { SecurityPluginSetup } from '../../../../security/public';
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { configBlockSchemas } from '../../../../../legacy/plugins/beats_management/common/config_schemas';
|
||||
import { translateConfigSchema } from '../../../../../legacy/plugins/beats_management/common/config_schemas_translations_map';
|
||||
import { configBlockSchemas } from '../../../common/config_schemas';
|
||||
import { translateConfigSchema } from '../../../common/config_schemas_translations_map';
|
||||
import { RestBeatsAdapter } from '../adapters/beats/rest_beats_adapter';
|
||||
import { RestConfigBlocksAdapter } from '../adapters/configuration_blocks/rest_config_blocks_adapter';
|
||||
import { MemoryElasticsearchAdapter } from '../adapters/elasticsearch/memory';
|
||||
|
|
|
@ -7,10 +7,7 @@
|
|||
import yaml from 'js-yaml';
|
||||
import { set } from '@elastic/safer-lodash-set';
|
||||
import { get, has, omit } from 'lodash';
|
||||
import {
|
||||
ConfigBlockSchema,
|
||||
ConfigurationBlock,
|
||||
} from '../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { ConfigBlockSchema, ConfigurationBlock } from '../../common/domain_types';
|
||||
import { FrontendConfigBlocksAdapter } from './adapters/configuration_blocks/adapter_types';
|
||||
|
||||
export class ConfigBlocksLib {
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
*/
|
||||
|
||||
import { difference, get } from 'lodash';
|
||||
import {
|
||||
LICENSES,
|
||||
LicenseType,
|
||||
} from '../../../../legacy/plugins/beats_management/common/constants/security';
|
||||
import { LICENSES, LicenseType } from '../../common/constants/security';
|
||||
import { FrameworkAdapter } from './adapters/framework/adapter_types';
|
||||
|
||||
export class FrameworkLib {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import uuidv4 from 'uuid/v4';
|
||||
import { BeatTag, CMBeat } from '../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { BeatTag, CMBeat } from '../../common/domain_types';
|
||||
import { CMTagsAdapter } from './adapters/tags/adapter_types';
|
||||
import { ElasticsearchLib } from './elasticsearch';
|
||||
|
||||
|
|
|
@ -19,14 +19,10 @@ import { i18n } from '@kbn/i18n';
|
|||
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
|
||||
import { get } from 'lodash';
|
||||
import React from 'react';
|
||||
import { configBlockSchemas } from '../../../../../legacy/plugins/beats_management/common/config_schemas';
|
||||
import { translateConfigSchema } from '../../../../../legacy/plugins/beats_management/common/config_schemas_translations_map';
|
||||
import { TABLE_CONFIG } from '../../../../../legacy/plugins/beats_management/common/constants';
|
||||
import {
|
||||
BeatTag,
|
||||
CMBeat,
|
||||
ConfigurationBlock,
|
||||
} from '../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { configBlockSchemas } from '../../../common/config_schemas';
|
||||
import { translateConfigSchema } from '../../../common/config_schemas_translations_map';
|
||||
import { TABLE_CONFIG } from '../../../common/constants';
|
||||
import { BeatTag, CMBeat, ConfigurationBlock } from '../../../common/domain_types';
|
||||
import { Breadcrumb } from '../../components/navigation/breadcrumb';
|
||||
import { ConnectedLink } from '../../components/navigation/connected_link';
|
||||
import { TagBadge } from '../../components/tag';
|
||||
|
|
|
@ -17,7 +17,7 @@ import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
|
|||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { Redirect, Route, Switch } from 'react-router-dom';
|
||||
import { CMBeat } from '../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { CMBeat } from '../../../common/domain_types';
|
||||
import { PrimaryLayout } from '../../components/layouts/primary';
|
||||
import { Breadcrumb } from '../../components/navigation/breadcrumb';
|
||||
import { ChildRoutes } from '../../components/navigation/child_routes';
|
||||
|
|
|
@ -7,10 +7,7 @@
|
|||
import { EuiGlobalToastList } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import {
|
||||
BeatTag,
|
||||
CMBeat,
|
||||
} from '../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { BeatTag, CMBeat } from '../../../common/domain_types';
|
||||
import { Breadcrumb } from '../../components/navigation/breadcrumb';
|
||||
import { BeatDetailTagsTable, Table } from '../../components/table';
|
||||
import { FrontendLibs } from '../../lib/types';
|
||||
|
|
|
@ -19,10 +19,7 @@ import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
|
|||
import { flatten, sortBy } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import {
|
||||
BeatTag,
|
||||
CMBeat,
|
||||
} from '../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { BeatTag, CMBeat } from '../../../common/domain_types';
|
||||
import { EnrollBeat } from '../../components/enroll_beats';
|
||||
import { Breadcrumb } from '../../components/navigation/breadcrumb';
|
||||
import { BeatsTableType, Table } from '../../components/table';
|
||||
|
|
|
@ -16,7 +16,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React from 'react';
|
||||
import { Subscribe } from 'unstated';
|
||||
import { CMBeat } from '../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { CMBeat } from '../../../common/domain_types';
|
||||
import { PrimaryLayout } from '../../components/layouts/primary';
|
||||
import { ChildRoutes } from '../../components/navigation/child_routes';
|
||||
import { BeatsContainer } from '../../containers/beats';
|
||||
|
|
|
@ -12,11 +12,8 @@ import 'brace/mode/yaml';
|
|||
import 'brace/theme/github';
|
||||
import { isEqual } from 'lodash';
|
||||
import React from 'react';
|
||||
import { UNIQUENESS_ENFORCING_TYPES } from '../../../../../legacy/plugins/beats_management/common/constants/configuration_blocks';
|
||||
import {
|
||||
BeatTag,
|
||||
ConfigurationBlock,
|
||||
} from '../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { UNIQUENESS_ENFORCING_TYPES } from '../../../common/constants/configuration_blocks';
|
||||
import { BeatTag, ConfigurationBlock } from '../../../common/domain_types';
|
||||
import { PrimaryLayout } from '../../components/layouts/primary';
|
||||
import { TagEdit } from '../../components/tag';
|
||||
import { AppPageProps } from '../../frontend_types';
|
||||
|
|
|
@ -10,12 +10,8 @@ import 'brace/mode/yaml';
|
|||
import 'brace/theme/github';
|
||||
import { flatten } from 'lodash';
|
||||
import React from 'react';
|
||||
import { UNIQUENESS_ENFORCING_TYPES } from '../../../../../legacy/plugins/beats_management/common/constants';
|
||||
import {
|
||||
BeatTag,
|
||||
CMBeat,
|
||||
ConfigurationBlock,
|
||||
} from '../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { UNIQUENESS_ENFORCING_TYPES } from '../../../common/constants';
|
||||
import { BeatTag, CMBeat, ConfigurationBlock } from '../../../common/domain_types';
|
||||
import { PrimaryLayout } from '../../components/layouts/primary';
|
||||
import { TagEdit } from '../../components/tag';
|
||||
import { AppPageProps } from '../../frontend_types';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiPageContent } from '@elastic/eui';
|
||||
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
|
||||
import React from 'react';
|
||||
import { CMBeat } from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { CMBeat } from '../../../../common/domain_types';
|
||||
import { AppPageProps } from '../../../frontend_types';
|
||||
|
||||
interface PageState {
|
||||
|
|
|
@ -9,10 +9,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
import { isEqual } from 'lodash';
|
||||
import React, { Component } from 'react';
|
||||
import uuidv4 from 'uuid/v4';
|
||||
import {
|
||||
BeatTag,
|
||||
ConfigurationBlock,
|
||||
} from '../../../../../../legacy/plugins/beats_management/common/domain_types';
|
||||
import { BeatTag, ConfigurationBlock } from '../../../../common/domain_types';
|
||||
import { TagEdit } from '../../../components/tag/tag_edit';
|
||||
import { AppPageProps } from '../../../frontend_types';
|
||||
interface PageState {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Beats CM
|
||||
|
||||
Notes:
|
||||
Falure to have auth enabled in Kibana will make for a broken UI. UI based errors not yet in place
|
||||
Failure to have auth enabled in Kibana will make for a broken UI. UI-based errors not yet in place
|
||||
|
||||
## Testing
|
||||
|
|
@ -9,8 +9,7 @@ import request from 'request';
|
|||
import uuidv4 from 'uuid/v4';
|
||||
import { configBlockSchemas } from '../common/config_schemas';
|
||||
import { BeatTag } from '../common/domain_types';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { compose } from '../../../../plugins/beats_management/public/lib/compose/scripts';
|
||||
import { compose } from '../public/lib/compose/scripts';
|
||||
const args = process.argv.slice(2);
|
||||
const chance = new Chance();
|
||||
|
|
@ -6,74 +6,19 @@
|
|||
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
|
||||
import { Lifecycle, ResponseToolkit } from 'hapi';
|
||||
import * as t from 'io-ts';
|
||||
import { CoreSetup, CoreStart } from 'src/core/server';
|
||||
import { SecurityPluginSetup } from '../../../../../../../plugins/security/server';
|
||||
import { LicenseType } from '../../../../common/constants/security';
|
||||
import { Headers, KibanaRequest } from 'src/core/server';
|
||||
|
||||
export const internalAuthData = Symbol('internalAuthData');
|
||||
export const internalUser: FrameworkInternalUser = {
|
||||
kind: 'internal',
|
||||
};
|
||||
|
||||
export interface XpackInfo {
|
||||
license: {
|
||||
getType: () => LicenseType;
|
||||
/** Is the license expired */
|
||||
isActive: () => boolean;
|
||||
getExpiryDateInMillis: () => number;
|
||||
};
|
||||
feature: (pluginId: string) => any;
|
||||
isAvailable: () => boolean;
|
||||
}
|
||||
|
||||
export interface BackendFrameworkAdapter {
|
||||
getUser(request: KibanaRequest): FrameworkUser<Headers>;
|
||||
internalUser: FrameworkInternalUser;
|
||||
info: null | FrameworkInfo;
|
||||
log(text: string): void;
|
||||
on(event: 'xpack.status.green' | 'elasticsearch.status.green', cb: () => void): void;
|
||||
getSetting(settingPath: string): any;
|
||||
registerRoute<RouteRequest extends FrameworkRequest, RouteResponse extends FrameworkResponse>(
|
||||
route: FrameworkRouteOptions<RouteRequest, RouteResponse>
|
||||
): void;
|
||||
}
|
||||
|
||||
export interface KibanaLegacyServer {
|
||||
newPlatform: {
|
||||
setup: {
|
||||
core: CoreSetup;
|
||||
plugins: { security: SecurityPluginSetup };
|
||||
};
|
||||
start: {
|
||||
core: CoreStart;
|
||||
};
|
||||
};
|
||||
plugins: {
|
||||
xpack_main: {
|
||||
status: {
|
||||
on: (status: 'green' | 'yellow' | 'red', callback: () => void) => void;
|
||||
};
|
||||
info: XpackInfo;
|
||||
};
|
||||
kibana: {
|
||||
status: {
|
||||
plugin: {
|
||||
version: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
elasticsearch: {
|
||||
status: {
|
||||
on: (status: 'green' | 'yellow' | 'red', callback: () => void) => void;
|
||||
};
|
||||
getCluster: () => any;
|
||||
};
|
||||
beats_management: {};
|
||||
};
|
||||
config: () => any;
|
||||
route: (routeConfig: any) => void;
|
||||
log: (message: string) => void;
|
||||
}
|
||||
|
||||
export const RuntimeFrameworkInfo = t.interface(
|
||||
|
@ -167,23 +112,3 @@ export interface FrameworkRequest<
|
|||
params: KibanaServerRequestGenaric['params'];
|
||||
query: KibanaServerRequestGenaric['query'];
|
||||
}
|
||||
|
||||
export interface FrameworkRouteOptions<
|
||||
RouteRequest extends FrameworkRequest = FrameworkRequest,
|
||||
RouteResponse extends FrameworkResponse = any
|
||||
> {
|
||||
path: string;
|
||||
method: string | string[];
|
||||
vhost?: string;
|
||||
licenseRequired?: string[];
|
||||
requiredRoles?: string[];
|
||||
handler: FrameworkRouteHandler<RouteRequest, RouteResponse>;
|
||||
config?: {};
|
||||
}
|
||||
|
||||
export type FrameworkRouteHandler<
|
||||
RouteRequest extends KibanaServerRequest,
|
||||
RouteResponse extends FrameworkResponse
|
||||
> = (request: FrameworkRequest<RouteRequest>, h: ResponseToolkit) => Promise<RouteResponse>;
|
||||
|
||||
export type FrameworkResponse = Lifecycle.ReturnValue;
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { PathReporter } from 'io-ts/lib/PathReporter';
|
||||
import { isLeft } from 'fp-ts/lib/Either';
|
||||
import { KibanaRequest, Headers, Logger } from 'src/core/server';
|
||||
import {
|
||||
BackendFrameworkAdapter,
|
||||
FrameworkInfo,
|
||||
FrameworkUser,
|
||||
internalAuthData,
|
||||
internalUser,
|
||||
RuntimeFrameworkInfo,
|
||||
RuntimeKibanaUser,
|
||||
} from './adapter_types';
|
||||
import { BeatsManagementConfigType } from '../../../../common';
|
||||
import { ILicense, LicensingPluginStart } from '../../../../../licensing/server';
|
||||
import { SecurityPluginSetup } from '../../../../../security/server';
|
||||
|
||||
export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter {
|
||||
public readonly internalUser = internalUser;
|
||||
public info: null | FrameworkInfo = null;
|
||||
|
||||
constructor(
|
||||
private readonly PLUGIN_ID: string,
|
||||
private readonly kibanaVersion: string,
|
||||
private readonly config: BeatsManagementConfigType,
|
||||
private readonly logger: Logger,
|
||||
private readonly licensing: LicensingPluginStart,
|
||||
private readonly security?: SecurityPluginSetup
|
||||
) {
|
||||
this.licensing.license$.subscribe((license) => this.licenseUpdateHandler(license));
|
||||
}
|
||||
|
||||
public log(text: string) {
|
||||
this.logger.info(text);
|
||||
}
|
||||
|
||||
getUser(request: KibanaRequest): FrameworkUser<Headers> {
|
||||
const user = this.security?.authc.getCurrentUser(request);
|
||||
if (!user) {
|
||||
return {
|
||||
kind: 'unauthenticated',
|
||||
};
|
||||
}
|
||||
const assertKibanaUser = RuntimeKibanaUser.decode(user);
|
||||
if (isLeft(assertKibanaUser)) {
|
||||
throw new Error(
|
||||
`Error parsing user info in ${this.PLUGIN_ID}, ${
|
||||
PathReporter.report(assertKibanaUser)[0]
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
kind: 'authenticated',
|
||||
[internalAuthData]: request.headers,
|
||||
...user,
|
||||
};
|
||||
}
|
||||
|
||||
private licenseUpdateHandler = (license: ILicense) => {
|
||||
let xpackInfoUnpacked: FrameworkInfo;
|
||||
|
||||
// If, for some reason, we cannot get the license information
|
||||
// from Elasticsearch, assume worst case and disable
|
||||
if (!license.isAvailable) {
|
||||
this.info = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const securityFeature = license.getFeature('security');
|
||||
const watcherFeature = license.getFeature('watcher');
|
||||
|
||||
try {
|
||||
xpackInfoUnpacked = {
|
||||
kibana: {
|
||||
version: this.kibanaVersion,
|
||||
},
|
||||
license: {
|
||||
type: license.type!,
|
||||
expired: !license.isActive,
|
||||
expiry_date_in_millis: license.expiryDateInMillis ?? -1,
|
||||
},
|
||||
security: {
|
||||
enabled: securityFeature.isEnabled,
|
||||
available: securityFeature.isAvailable,
|
||||
},
|
||||
watcher: {
|
||||
enabled: watcherFeature.isEnabled,
|
||||
available: watcherFeature.isAvailable,
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
this.logger.error(`Error accessing required xPackInfo in ${this.PLUGIN_ID} Kibana adapter`);
|
||||
throw e;
|
||||
}
|
||||
|
||||
const assertData = RuntimeFrameworkInfo.decode(xpackInfoUnpacked);
|
||||
if (isLeft(assertData)) {
|
||||
throw new Error(
|
||||
`Error parsing xpack info in ${this.PLUGIN_ID}, ${PathReporter.report(assertData)[0]}`
|
||||
);
|
||||
}
|
||||
this.info = xpackInfoUnpacked;
|
||||
|
||||
return {
|
||||
security: xpackInfoUnpacked.security,
|
||||
settings: { ...this.config },
|
||||
};
|
||||
};
|
||||
}
|
|
@ -5,12 +5,14 @@
|
|||
*/
|
||||
|
||||
import { camelCase } from 'lodash';
|
||||
import type { ElasticsearchServiceStart, Logger } from 'src/core/server';
|
||||
import { SecurityPluginSetup } from '../../../../security/server';
|
||||
import { LicensingPluginStart } from '../../../../licensing/server';
|
||||
import { PLUGIN } from '../../../common/constants';
|
||||
import { CONFIG_PREFIX } from '../../../common/constants/plugin';
|
||||
import { BeatsManagementConfigType } from '../../../common';
|
||||
import { ElasticsearchBeatsAdapter } from '../adapters/beats/elasticsearch_beats_adapter';
|
||||
import { ElasticsearchConfigurationBlockAdapter } from '../adapters/configuration_blocks/elasticsearch_configuration_block_adapter';
|
||||
import { KibanaDatabaseAdapter } from '../adapters/database/kibana_database_adapter';
|
||||
import { KibanaLegacyServer } from '../adapters/framework/adapter_types';
|
||||
import { KibanaBackendFrameworkAdapter } from '../adapters/framework/kibana_framework_adapter';
|
||||
import { ElasticsearchTagsAdapter } from '../adapters/tags/elasticsearch_tags_adapter';
|
||||
import { ElasticsearchTokensAdapter } from '../adapters/tokens/elasticsearch_tokens_adapter';
|
||||
|
@ -22,11 +24,33 @@ import { CMTokensDomain } from '../tokens';
|
|||
import { CMServerLibs } from '../types';
|
||||
import { BackendFrameworkLib } from './../framework';
|
||||
|
||||
export function compose(server: KibanaLegacyServer): CMServerLibs {
|
||||
const framework = new BackendFrameworkLib(
|
||||
new KibanaBackendFrameworkAdapter(camelCase(PLUGIN.ID), server, CONFIG_PREFIX)
|
||||
interface ComposeOptions {
|
||||
elasticsearch: ElasticsearchServiceStart;
|
||||
licensing: LicensingPluginStart;
|
||||
security?: SecurityPluginSetup;
|
||||
config: BeatsManagementConfigType;
|
||||
logger: Logger;
|
||||
kibanaVersion: string;
|
||||
}
|
||||
|
||||
export function compose({
|
||||
elasticsearch,
|
||||
config,
|
||||
kibanaVersion,
|
||||
logger,
|
||||
licensing,
|
||||
security,
|
||||
}: ComposeOptions): CMServerLibs {
|
||||
const backendAdapter = new KibanaBackendFrameworkAdapter(
|
||||
camelCase(PLUGIN.ID),
|
||||
kibanaVersion,
|
||||
config,
|
||||
logger,
|
||||
licensing,
|
||||
security
|
||||
);
|
||||
const database = new KibanaDatabaseAdapter(server.newPlatform.start.core.elasticsearch);
|
||||
const framework = new BackendFrameworkLib(backendAdapter, config);
|
||||
const database = new KibanaDatabaseAdapter(elasticsearch);
|
||||
const beatsAdapter = new ElasticsearchBeatsAdapter(database);
|
||||
const configAdapter = new ElasticsearchConfigurationBlockAdapter(database);
|
||||
|
53
x-pack/plugins/beats_management/server/lib/framework.ts
Normal file
53
x-pack/plugins/beats_management/server/lib/framework.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { Headers, KibanaRequest } from 'kibana/server';
|
||||
import { BackendFrameworkAdapter, FrameworkUser } from './adapters/framework/adapter_types';
|
||||
import { BeatsManagementConfigType } from '../../common';
|
||||
|
||||
export class BackendFrameworkLib {
|
||||
public log = this.adapter.log;
|
||||
public internalUser = this.adapter.internalUser;
|
||||
|
||||
constructor(
|
||||
private readonly adapter: BackendFrameworkAdapter,
|
||||
private readonly config: BeatsManagementConfigType
|
||||
) {
|
||||
this.validateConfig();
|
||||
}
|
||||
|
||||
public getConfig(): BeatsManagementConfigType {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public getUser(request: KibanaRequest): FrameworkUser<Headers> {
|
||||
return this.adapter.getUser(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expired `null` happens when we have no xpack info
|
||||
*/
|
||||
public get license() {
|
||||
return {
|
||||
type: this.adapter.info ? this.adapter.info.license.type : 'unknown',
|
||||
expired: this.adapter.info ? this.adapter.info.license.expired : null,
|
||||
};
|
||||
}
|
||||
|
||||
public get securityIsEnabled() {
|
||||
return this.adapter.info ? this.adapter.info.security.enabled : false;
|
||||
}
|
||||
|
||||
private validateConfig() {
|
||||
const encryptionKey = this.config.encryptionKey;
|
||||
|
||||
if (!encryptionKey) {
|
||||
this.adapter.log(
|
||||
'Using a default encryption key for xpack.beats.encryptionKey. It is recommended that you set xpack.beats.encryptionKey in kibana.yml with a unique token'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,7 +58,7 @@ export class CMTokensDomain {
|
|||
let expired = false;
|
||||
|
||||
if (decode) {
|
||||
const enrollmentTokenSecret = this.framework.getSetting('encryptionKey');
|
||||
const enrollmentTokenSecret = this.framework.getConfig().encryptionKey;
|
||||
|
||||
try {
|
||||
verifyToken(recivedToken, enrollmentTokenSecret);
|
||||
|
@ -98,7 +98,7 @@ export class CMTokensDomain {
|
|||
}
|
||||
|
||||
public generateAccessToken() {
|
||||
const enrollmentTokenSecret = this.framework.getSetting('encryptionKey');
|
||||
const enrollmentTokenSecret = this.framework.getConfig().encryptionKey;
|
||||
|
||||
const tokenData = {
|
||||
created: moment().toJSON(),
|
||||
|
@ -113,12 +113,12 @@ export class CMTokensDomain {
|
|||
numTokens: number = 1
|
||||
): Promise<string[]> {
|
||||
const tokens = [];
|
||||
const enrollmentTokensTtlInSeconds = this.framework.getSetting('enrollmentTokensTtlInSeconds');
|
||||
const enrollmentTokensTtlInSeconds = this.framework.getConfig().enrollmentTokensTtlInSeconds;
|
||||
|
||||
const enrollmentTokenExpiration = moment()
|
||||
.add(enrollmentTokensTtlInSeconds, 'seconds')
|
||||
.toJSON();
|
||||
const enrollmentTokenSecret = this.framework.getSetting('encryptionKey');
|
||||
const enrollmentTokenSecret = this.framework.getConfig().encryptionKey;
|
||||
|
||||
while (tokens.length < numTokens) {
|
||||
const tokenData = {
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue