diff --git a/docs/developer/architecture/code-exploration.asciidoc b/docs/developer/architecture/code-exploration.asciidoc index d9502e4cb47ee..6e814921d3f32 100644 --- a/docs/developer/architecture/code-exploration.asciidoc +++ b/docs/developer/architecture/code-exploration.asciidoc @@ -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] diff --git a/x-pack/index.js b/x-pack/index.js index 66fe05e8f035e..b984782df3986 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -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)]; }; diff --git a/x-pack/legacy/plugins/beats_management/index.ts b/x-pack/legacy/plugins/beats_management/index.ts deleted file mode 100644 index 1f04f342f9ca0..0000000000000 --- a/x-pack/legacy/plugins/beats_management/index.ts +++ /dev/null @@ -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); - }, - }); -} diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/legacy/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts deleted file mode 100644 index 3b29e50e4465b..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts +++ /dev/null @@ -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) { - 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(request), h); - }, - method: route.method, - path: route.path, - config: route.config, - }); - } - - private async wrapRequest( - req: KibanaServerRequest - ): Promise> { - 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 { - 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), - }; - }; -} diff --git a/x-pack/legacy/plugins/beats_management/server/lib/framework.ts b/x-pack/legacy/plugins/beats_management/server/lib/framework.ts deleted file mode 100644 index 96a06929073e5..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/lib/framework.ts +++ /dev/null @@ -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) => Promise; - 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) => Promise, - requiredLicense: string[], - requiredRoles?: string[] - ): (request: FrameworkRequest) => Promise { - 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) => Promise - ): (request: FrameworkRequest, h: ResponseToolkit) => Promise { - 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); - } - }; - } -} diff --git a/x-pack/legacy/plugins/beats_management/server/management_server.ts b/x-pack/legacy/plugins/beats_management/server/management_server.ts deleted file mode 100644 index 1073251949028..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/management_server.ts +++ /dev/null @@ -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)); -}; diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/configuration.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/beats/configuration.ts deleted file mode 100644 index f279a51b2bc1b..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/configuration.ts +++ /dev/null @@ -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> => { - 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, - }; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/enroll.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/beats/enroll.ts deleted file mode 100644 index 916cfad4102d0..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/enroll.ts +++ /dev/null @@ -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> => { - 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, - }; - } - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/events.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/beats/events.ts deleted file mode 100644 index 65d7e9979b9ca..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/events.ts +++ /dev/null @@ -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 => { - 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, - }; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/get.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/beats/get.ts deleted file mode 100644 index 874e66bb8a533..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/get.ts +++ /dev/null @@ -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> => { - 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, - }; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/list.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/beats/list.ts deleted file mode 100644 index 74fb98fc877cc..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/list.ts +++ /dev/null @@ -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> => { - 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 }; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/tag_assignment.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/beats/tag_assignment.ts deleted file mode 100644 index 974b2822fbd92..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/tag_assignment.ts +++ /dev/null @@ -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 => { - 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; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/tag_removal.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/beats/tag_removal.ts deleted file mode 100644 index 3bbc32dc5748b..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/tag_removal.ts +++ /dev/null @@ -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 => { - 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; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/update.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/beats/update.ts deleted file mode 100644 index 2859083e83386..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/beats/update.ts +++ /dev/null @@ -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> => { - 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, - }; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/configurations/delete.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/configurations/delete.ts deleted file mode 100644 index b7d430fb18c01..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/configurations/delete.ts +++ /dev/null @@ -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 => { - 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; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/configurations/get.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/configurations/get.ts deleted file mode 100644 index df534f74239ed..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/configurations/get.ts +++ /dev/null @@ -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> => { - 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 }; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/configurations/upsert.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/configurations/upsert.ts deleted file mode 100644 index fb62800594d0a..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/configurations/upsert.ts +++ /dev/null @@ -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 => { - const result = await Promise.all( - 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, - }; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/tags/assignable.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/tags/assignable.ts deleted file mode 100644 index 88a322c03790f..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/tags/assignable.ts +++ /dev/null @@ -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> => { - 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, - }; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/tags/delete.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/tags/delete.ts deleted file mode 100644 index 3e65f271c0fb0..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/tags/delete.ts +++ /dev/null @@ -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 => { - 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; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/tags/get.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/tags/get.ts deleted file mode 100644 index 37f8e1169fa6c..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/tags/get.ts +++ /dev/null @@ -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> => { - 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, - }; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/tags/list.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/tags/list.ts deleted file mode 100644 index eb5570273960f..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/tags/list.ts +++ /dev/null @@ -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> => { - 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 }; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/tags/set.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/tags/set.ts deleted file mode 100644 index f2c4b17007f10..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/tags/set.ts +++ /dev/null @@ -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> => { - 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' }; - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/server/rest_api/tokens/create.ts b/x-pack/legacy/plugins/beats_management/server/rest_api/tokens/create.ts deleted file mode 100644 index 571d2b4a4947c..0000000000000 --- a/x-pack/legacy/plugins/beats_management/server/rest_api/tokens/create.ts +++ /dev/null @@ -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> => { - 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, - }; - } - }, -}); diff --git a/x-pack/legacy/plugins/beats_management/tsconfig.json b/x-pack/legacy/plugins/beats_management/tsconfig.json deleted file mode 100644 index 7ade047bad32e..0000000000000 --- a/x-pack/legacy/plugins/beats_management/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - "exclude": ["**/node_modules/**"], - "paths": { - "react": ["../../../node_modules/@types/react"] - } -} diff --git a/x-pack/legacy/plugins/beats_management/common/config_schemas.ts b/x-pack/plugins/beats_management/common/config_schemas.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/common/config_schemas.ts rename to x-pack/plugins/beats_management/common/config_schemas.ts diff --git a/x-pack/legacy/plugins/beats_management/common/config_schemas_translations_map.ts b/x-pack/plugins/beats_management/common/config_schemas_translations_map.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/common/config_schemas_translations_map.ts rename to x-pack/plugins/beats_management/common/config_schemas_translations_map.ts diff --git a/x-pack/legacy/plugins/beats_management/common/constants/configuration_blocks.ts b/x-pack/plugins/beats_management/common/constants/configuration_blocks.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/common/constants/configuration_blocks.ts rename to x-pack/plugins/beats_management/common/constants/configuration_blocks.ts diff --git a/x-pack/legacy/plugins/beats_management/common/constants/index.ts b/x-pack/plugins/beats_management/common/constants/index.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/common/constants/index.ts rename to x-pack/plugins/beats_management/common/constants/index.ts diff --git a/x-pack/legacy/plugins/beats_management/common/constants/index_names.ts b/x-pack/plugins/beats_management/common/constants/index_names.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/common/constants/index_names.ts rename to x-pack/plugins/beats_management/common/constants/index_names.ts diff --git a/x-pack/legacy/plugins/beats_management/common/constants/plugin.ts b/x-pack/plugins/beats_management/common/constants/plugin.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/common/constants/plugin.ts rename to x-pack/plugins/beats_management/common/constants/plugin.ts diff --git a/x-pack/legacy/plugins/beats_management/common/constants/security.ts b/x-pack/plugins/beats_management/common/constants/security.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/common/constants/security.ts rename to x-pack/plugins/beats_management/common/constants/security.ts diff --git a/x-pack/legacy/plugins/beats_management/common/constants/table.ts b/x-pack/plugins/beats_management/common/constants/table.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/common/constants/table.ts rename to x-pack/plugins/beats_management/common/constants/table.ts diff --git a/x-pack/legacy/plugins/beats_management/common/domain_types.ts b/x-pack/plugins/beats_management/common/domain_types.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/common/domain_types.ts rename to x-pack/plugins/beats_management/common/domain_types.ts diff --git a/x-pack/legacy/plugins/beats_management/common/io_ts_types.ts b/x-pack/plugins/beats_management/common/io_ts_types.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/common/io_ts_types.ts rename to x-pack/plugins/beats_management/common/io_ts_types.ts diff --git a/x-pack/legacy/plugins/beats_management/common/return_types.ts b/x-pack/plugins/beats_management/common/return_types.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/common/return_types.ts rename to x-pack/plugins/beats_management/common/return_types.ts diff --git a/x-pack/plugins/beats_management/kibana.json b/x-pack/plugins/beats_management/kibana.json index 1b431216ef992..3fd1ab6fd8701 100644 --- a/x-pack/plugins/beats_management/kibana.json +++ b/x-pack/plugins/beats_management/kibana.json @@ -1,5 +1,5 @@ { - "id": "beats_management", + "id": "beatsManagement", "configPath": ["xpack", "beats_management"], "ui": true, "server": true, diff --git a/x-pack/plugins/beats_management/public/components/config_list.tsx b/x-pack/plugins/beats_management/public/components/config_list.tsx index 5f200df1e3c65..285ce0afdf2fc 100644 --- a/x-pack/plugins/beats_management/public/components/config_list.tsx +++ b/x-pack/plugins/beats_management/public/components/config_list.tsx @@ -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: { diff --git a/x-pack/plugins/beats_management/public/components/enroll_beats.tsx b/x-pack/plugins/beats_management/public/components/enroll_beats.tsx index 5bf0f51f48355..38f4a9a307014 100644 --- a/x-pack/plugins/beats_management/public/components/enroll_beats.tsx +++ b/x-pack/plugins/beats_management/public/components/enroll_beats.tsx @@ -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 */ diff --git a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/breadcrumb.tsx b/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/breadcrumb.tsx index c13ab69a19090..cd6435a52f294 100644 --- a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/breadcrumb.tsx +++ b/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/breadcrumb.tsx @@ -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'; diff --git a/x-pack/plugins/beats_management/public/components/table/controls/tag_badge_list.tsx b/x-pack/plugins/beats_management/public/components/table/controls/tag_badge_list.tsx index a99c8b9ef8f9f..550c57d11d79c 100644 --- a/x-pack/plugins/beats_management/public/components/table/controls/tag_badge_list.tsx +++ b/x-pack/plugins/beats_management/public/components/table/controls/tag_badge_list.tsx @@ -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'; diff --git a/x-pack/plugins/beats_management/public/components/table/table.tsx b/x-pack/plugins/beats_management/public/components/table/table.tsx index 997ad13246d39..eecba050766b5 100644 --- a/x-pack/plugins/beats_management/public/components/table/table.tsx +++ b/x-pack/plugins/beats_management/public/components/table/table.tsx @@ -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'; diff --git a/x-pack/plugins/beats_management/public/components/table/table_type_configs.tsx b/x-pack/plugins/beats_management/public/components/table/table_type_configs.tsx index 6bbf269711fbd..3c31a86ffd8c6 100644 --- a/x-pack/plugins/beats_management/public/components/table/table_type_configs.tsx +++ b/x-pack/plugins/beats_management/public/components/table/table_type_configs.tsx @@ -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'; diff --git a/x-pack/plugins/beats_management/public/components/tag/config_view/config_form.tsx b/x-pack/plugins/beats_management/public/components/tag/config_view/config_form.tsx index 30c4d79d4c6bc..de06e676355d8 100644 --- a/x-pack/plugins/beats_management/public/components/tag/config_view/config_form.tsx +++ b/x-pack/plugins/beats_management/public/components/tag/config_view/config_form.tsx @@ -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, diff --git a/x-pack/plugins/beats_management/public/components/tag/config_view/index.tsx b/x-pack/plugins/beats_management/public/components/tag/config_view/index.tsx index 773ca1719d5fa..183620dfa934f 100644 --- a/x-pack/plugins/beats_management/public/components/tag/config_view/index.tsx +++ b/x-pack/plugins/beats_management/public/components/tag/config_view/index.tsx @@ -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 { diff --git a/x-pack/plugins/beats_management/public/components/tag/tag_badge.tsx b/x-pack/plugins/beats_management/public/components/tag/tag_badge.tsx index 5880871da9f13..7fa0231cf3409 100644 --- a/x-pack/plugins/beats_management/public/components/tag/tag_badge.tsx +++ b/x-pack/plugins/beats_management/public/components/tag/tag_badge.tsx @@ -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; diff --git a/x-pack/plugins/beats_management/public/components/tag/tag_edit.tsx b/x-pack/plugins/beats_management/public/components/tag/tag_edit.tsx index 9fca9d3add5e7..d76d5fcd476d5 100644 --- a/x-pack/plugins/beats_management/public/components/tag/tag_edit.tsx +++ b/x-pack/plugins/beats_management/public/components/tag/tag_edit.tsx @@ -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'; diff --git a/x-pack/plugins/beats_management/public/containers/beats.ts b/x-pack/plugins/beats_management/public/containers/beats.ts index 874447deec321..1454dacbf2a0f 100644 --- a/x-pack/plugins/beats_management/public/containers/beats.ts +++ b/x-pack/plugins/beats_management/public/containers/beats.ts @@ -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 { diff --git a/x-pack/plugins/beats_management/public/containers/tags.ts b/x-pack/plugins/beats_management/public/containers/tags.ts index e7c73d26a1d02..56161f35c79e5 100644 --- a/x-pack/plugins/beats_management/public/containers/tags.ts +++ b/x-pack/plugins/beats_management/public/containers/tags.ts @@ -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 { diff --git a/x-pack/plugins/beats_management/public/lib/__tests__/config_blocks.test.ts b/x-pack/plugins/beats_management/public/lib/__tests__/config_blocks.test.ts index 6851020cdf97e..6776fb0b6f5ad 100644 --- a/x-pack/plugins/beats_management/public/lib/__tests__/config_blocks.test.ts +++ b/x-pack/plugins/beats_management/public/lib/__tests__/config_blocks.test.ts @@ -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'; diff --git a/x-pack/plugins/beats_management/public/lib/adapters/beats/adapter_types.ts b/x-pack/plugins/beats_management/public/lib/adapters/beats/adapter_types.ts index 1366894f78ddb..815b80e55fa11 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/beats/adapter_types.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/beats/adapter_types.ts @@ -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; diff --git a/x-pack/plugins/beats_management/public/lib/adapters/beats/memory_beats_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/beats/memory_beats_adapter.ts index 24a7e5c3af8fa..099c568b90f9e 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/beats/memory_beats_adapter.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/beats/memory_beats_adapter.ts @@ -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 { diff --git a/x-pack/plugins/beats_management/public/lib/adapters/beats/rest_beats_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/beats/rest_beats_adapter.ts index 880af83bfb3f2..d37ceeb5dfcdd 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/beats/rest_beats_adapter.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/beats/rest_beats_adapter.ts @@ -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) {} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/adapter_types.ts b/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/adapter_types.ts index 413cf32529b2f..e8e2d5cd6b430 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/adapter_types.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/adapter_types.ts @@ -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; diff --git a/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/memory_config_blocks_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/memory_config_blocks_adapter.ts index ccb1f27bf67eb..455a31a0b4659 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/memory_config_blocks_adapter.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/memory_config_blocks_adapter.ts @@ -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 { diff --git a/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/rest_config_blocks_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/rest_config_blocks_adapter.ts index 640da59ea572d..be501a5e951ba 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/rest_config_blocks_adapter.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/rest_config_blocks_adapter.ts @@ -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'; diff --git a/x-pack/plugins/beats_management/public/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/beats_management/public/lib/adapters/framework/adapter_types.ts index ce663650409fa..cb4fa830949bc 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/framework/adapter_types.ts @@ -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 { diff --git a/x-pack/plugins/beats_management/public/lib/adapters/tags/adapter_types.ts b/x-pack/plugins/beats_management/public/lib/adapters/tags/adapter_types.ts index b0ddf0309232a..5030b1704b1d7 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/tags/adapter_types.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/tags/adapter_types.ts @@ -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; diff --git a/x-pack/plugins/beats_management/public/lib/adapters/tags/memory_tags_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/tags/memory_tags_adapter.ts index 699880bd303ec..1e7cae5aed3d8 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/tags/memory_tags_adapter.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/tags/memory_tags_adapter.ts @@ -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 { diff --git a/x-pack/plugins/beats_management/public/lib/adapters/tags/rest_tags_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/tags/rest_tags_adapter.ts index a31f81b8e5ab4..9a2cebefc8f8f 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/tags/rest_tags_adapter.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/tags/rest_tags_adapter.ts @@ -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'; diff --git a/x-pack/plugins/beats_management/public/lib/adapters/tokens/rest_tokens_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/tokens/rest_tokens_adapter.ts index 4b2beabd35280..7b71d654d5e1f 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/tokens/rest_tokens_adapter.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/tokens/rest_tokens_adapter.ts @@ -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'; diff --git a/x-pack/plugins/beats_management/public/lib/beats.ts b/x-pack/plugins/beats_management/public/lib/beats.ts index a6cfe0b88dcf8..0dc9a241f2f07 100644 --- a/x-pack/plugins/beats_management/public/lib/beats.ts +++ b/x-pack/plugins/beats_management/public/lib/beats.ts @@ -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'; diff --git a/x-pack/plugins/beats_management/public/lib/compose/kibana.ts b/x-pack/plugins/beats_management/public/lib/compose/kibana.ts index d750417640f8c..68640469a7656 100644 --- a/x-pack/plugins/beats_management/public/lib/compose/kibana.ts +++ b/x-pack/plugins/beats_management/public/lib/compose/kibana.ts @@ -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'; diff --git a/x-pack/plugins/beats_management/public/lib/compose/scripts.ts b/x-pack/plugins/beats_management/public/lib/compose/scripts.ts index 093d618ba8d8b..83129384a77df 100644 --- a/x-pack/plugins/beats_management/public/lib/compose/scripts.ts +++ b/x-pack/plugins/beats_management/public/lib/compose/scripts.ts @@ -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'; diff --git a/x-pack/plugins/beats_management/public/lib/configuration_blocks.ts b/x-pack/plugins/beats_management/public/lib/configuration_blocks.ts index b486ba82689e8..09c079ea129e6 100644 --- a/x-pack/plugins/beats_management/public/lib/configuration_blocks.ts +++ b/x-pack/plugins/beats_management/public/lib/configuration_blocks.ts @@ -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 { diff --git a/x-pack/plugins/beats_management/public/lib/framework.ts b/x-pack/plugins/beats_management/public/lib/framework.ts index 63a81e0895348..33fa975a99493 100644 --- a/x-pack/plugins/beats_management/public/lib/framework.ts +++ b/x-pack/plugins/beats_management/public/lib/framework.ts @@ -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 { diff --git a/x-pack/plugins/beats_management/public/lib/tags.ts b/x-pack/plugins/beats_management/public/lib/tags.ts index 2d67edf7e347e..86562be3ff989 100644 --- a/x-pack/plugins/beats_management/public/lib/tags.ts +++ b/x-pack/plugins/beats_management/public/lib/tags.ts @@ -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'; diff --git a/x-pack/plugins/beats_management/public/pages/beat/details.tsx b/x-pack/plugins/beats_management/public/pages/beat/details.tsx index 4466a1ecba97d..cfe60aff67b1b 100644 --- a/x-pack/plugins/beats_management/public/pages/beat/details.tsx +++ b/x-pack/plugins/beats_management/public/pages/beat/details.tsx @@ -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'; diff --git a/x-pack/plugins/beats_management/public/pages/beat/index.tsx b/x-pack/plugins/beats_management/public/pages/beat/index.tsx index bea84377d2ab8..80590febc95be 100644 --- a/x-pack/plugins/beats_management/public/pages/beat/index.tsx +++ b/x-pack/plugins/beats_management/public/pages/beat/index.tsx @@ -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'; diff --git a/x-pack/plugins/beats_management/public/pages/beat/tags.tsx b/x-pack/plugins/beats_management/public/pages/beat/tags.tsx index 5a65473b25a24..672c0d89bb002 100644 --- a/x-pack/plugins/beats_management/public/pages/beat/tags.tsx +++ b/x-pack/plugins/beats_management/public/pages/beat/tags.tsx @@ -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'; diff --git a/x-pack/plugins/beats_management/public/pages/overview/enrolled_beats.tsx b/x-pack/plugins/beats_management/public/pages/overview/enrolled_beats.tsx index 7c26bb8de3f57..5e0bddbbe5411 100644 --- a/x-pack/plugins/beats_management/public/pages/overview/enrolled_beats.tsx +++ b/x-pack/plugins/beats_management/public/pages/overview/enrolled_beats.tsx @@ -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'; diff --git a/x-pack/plugins/beats_management/public/pages/overview/index.tsx b/x-pack/plugins/beats_management/public/pages/overview/index.tsx index 4df1a7d065469..57b007753491c 100644 --- a/x-pack/plugins/beats_management/public/pages/overview/index.tsx +++ b/x-pack/plugins/beats_management/public/pages/overview/index.tsx @@ -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'; diff --git a/x-pack/plugins/beats_management/public/pages/tag/create.tsx b/x-pack/plugins/beats_management/public/pages/tag/create.tsx index 881bb433b1d9a..34785e5dce51d 100644 --- a/x-pack/plugins/beats_management/public/pages/tag/create.tsx +++ b/x-pack/plugins/beats_management/public/pages/tag/create.tsx @@ -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'; diff --git a/x-pack/plugins/beats_management/public/pages/tag/edit.tsx b/x-pack/plugins/beats_management/public/pages/tag/edit.tsx index 10d7f7bbd7193..e3c2671061d99 100644 --- a/x-pack/plugins/beats_management/public/pages/tag/edit.tsx +++ b/x-pack/plugins/beats_management/public/pages/tag/edit.tsx @@ -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'; diff --git a/x-pack/plugins/beats_management/public/pages/walkthrough/initial/finish.tsx b/x-pack/plugins/beats_management/public/pages/walkthrough/initial/finish.tsx index 71f0b8161131f..93489f5223ef8 100644 --- a/x-pack/plugins/beats_management/public/pages/walkthrough/initial/finish.tsx +++ b/x-pack/plugins/beats_management/public/pages/walkthrough/initial/finish.tsx @@ -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 { diff --git a/x-pack/plugins/beats_management/public/pages/walkthrough/initial/tag.tsx b/x-pack/plugins/beats_management/public/pages/walkthrough/initial/tag.tsx index 8ecdf8bc5c663..01976633d14ea 100644 --- a/x-pack/plugins/beats_management/public/pages/walkthrough/initial/tag.tsx +++ b/x-pack/plugins/beats_management/public/pages/walkthrough/initial/tag.tsx @@ -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 { diff --git a/x-pack/legacy/plugins/beats_management/readme.md b/x-pack/plugins/beats_management/readme.md similarity index 88% rename from x-pack/legacy/plugins/beats_management/readme.md rename to x-pack/plugins/beats_management/readme.md index 3414f09deed46..36db612f7affd 100644 --- a/x-pack/legacy/plugins/beats_management/readme.md +++ b/x-pack/plugins/beats_management/readme.md @@ -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 diff --git a/x-pack/legacy/plugins/beats_management/scripts/enroll.js b/x-pack/plugins/beats_management/scripts/enroll.js similarity index 100% rename from x-pack/legacy/plugins/beats_management/scripts/enroll.js rename to x-pack/plugins/beats_management/scripts/enroll.js diff --git a/x-pack/legacy/plugins/beats_management/scripts/fake_env.ts b/x-pack/plugins/beats_management/scripts/fake_env.ts similarity index 96% rename from x-pack/legacy/plugins/beats_management/scripts/fake_env.ts rename to x-pack/plugins/beats_management/scripts/fake_env.ts index 65254d24863cd..b9eff4615cd42 100644 --- a/x-pack/legacy/plugins/beats_management/scripts/fake_env.ts +++ b/x-pack/plugins/beats_management/scripts/fake_env.ts @@ -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(); diff --git a/x-pack/legacy/plugins/beats_management/server/index_templates/beats_template.json b/x-pack/plugins/beats_management/server/index_templates/beats_template.json similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/index_templates/beats_template.json rename to x-pack/plugins/beats_management/server/index_templates/beats_template.json diff --git a/x-pack/legacy/plugins/beats_management/server/index_templates/events_template.json b/x-pack/plugins/beats_management/server/index_templates/events_template.json similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/index_templates/events_template.json rename to x-pack/plugins/beats_management/server/index_templates/events_template.json diff --git a/x-pack/legacy/plugins/beats_management/server/index_templates/index.ts b/x-pack/plugins/beats_management/server/index_templates/index.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/index_templates/index.ts rename to x-pack/plugins/beats_management/server/index_templates/index.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/beats/adapter_types.ts b/x-pack/plugins/beats_management/server/lib/adapters/beats/adapter_types.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/adapters/beats/adapter_types.ts rename to x-pack/plugins/beats_management/server/lib/adapters/beats/adapter_types.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/beats/elasticsearch_beats_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/beats/elasticsearch_beats_adapter.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/adapters/beats/elasticsearch_beats_adapter.ts rename to x-pack/plugins/beats_management/server/lib/adapters/beats/elasticsearch_beats_adapter.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/configuration_blocks/adapter_types.ts b/x-pack/plugins/beats_management/server/lib/adapters/configuration_blocks/adapter_types.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/adapters/configuration_blocks/adapter_types.ts rename to x-pack/plugins/beats_management/server/lib/adapters/configuration_blocks/adapter_types.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/configuration_blocks/elasticsearch_configuration_block_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/configuration_blocks/elasticsearch_configuration_block_adapter.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/adapters/configuration_blocks/elasticsearch_configuration_block_adapter.ts rename to x-pack/plugins/beats_management/server/lib/adapters/configuration_blocks/elasticsearch_configuration_block_adapter.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/database/adapter_types.ts b/x-pack/plugins/beats_management/server/lib/adapters/database/adapter_types.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/adapters/database/adapter_types.ts rename to x-pack/plugins/beats_management/server/lib/adapters/database/adapter_types.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts rename to x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts similarity index 57% rename from x-pack/legacy/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts rename to x-pack/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts index 85a8618be5d18..2ef3d98450ae4 100644 --- a/x-pack/legacy/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts @@ -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; 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( - route: FrameworkRouteOptions - ): 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; - config?: {}; -} - -export type FrameworkRouteHandler< - RouteRequest extends KibanaServerRequest, - RouteResponse extends FrameworkResponse -> = (request: FrameworkRequest, h: ResponseToolkit) => Promise; - -export type FrameworkResponse = Lifecycle.ReturnValue; diff --git a/x-pack/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts new file mode 100644 index 0000000000000..27387f269a9e4 --- /dev/null +++ b/x-pack/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -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 { + 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 }, + }; + }; +} diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/tags/adapter_types.ts b/x-pack/plugins/beats_management/server/lib/adapters/tags/adapter_types.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/adapters/tags/adapter_types.ts rename to x-pack/plugins/beats_management/server/lib/adapters/tags/adapter_types.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/tags/elasticsearch_tags_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/tags/elasticsearch_tags_adapter.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/adapters/tags/elasticsearch_tags_adapter.ts rename to x-pack/plugins/beats_management/server/lib/adapters/tags/elasticsearch_tags_adapter.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/tokens/adapter_types.ts b/x-pack/plugins/beats_management/server/lib/adapters/tokens/adapter_types.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/adapters/tokens/adapter_types.ts rename to x-pack/plugins/beats_management/server/lib/adapters/tokens/adapter_types.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/tokens/elasticsearch_tokens_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/tokens/elasticsearch_tokens_adapter.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/adapters/tokens/elasticsearch_tokens_adapter.ts rename to x-pack/plugins/beats_management/server/lib/adapters/tokens/elasticsearch_tokens_adapter.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/beat_events.ts b/x-pack/plugins/beats_management/server/lib/beat_events.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/beat_events.ts rename to x-pack/plugins/beats_management/server/lib/beat_events.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/beats.ts b/x-pack/plugins/beats_management/server/lib/beats.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/beats.ts rename to x-pack/plugins/beats_management/server/lib/beats.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/compose/kibana.ts b/x-pack/plugins/beats_management/server/lib/compose/kibana.ts similarity index 68% rename from x-pack/legacy/plugins/beats_management/server/lib/compose/kibana.ts rename to x-pack/plugins/beats_management/server/lib/compose/kibana.ts index b6a645ded8164..bdae4962bd471 100644 --- a/x-pack/legacy/plugins/beats_management/server/lib/compose/kibana.ts +++ b/x-pack/plugins/beats_management/server/lib/compose/kibana.ts @@ -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); diff --git a/x-pack/legacy/plugins/beats_management/server/lib/configuration_blocks.ts b/x-pack/plugins/beats_management/server/lib/configuration_blocks.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/configuration_blocks.ts rename to x-pack/plugins/beats_management/server/lib/configuration_blocks.ts diff --git a/x-pack/plugins/beats_management/server/lib/framework.ts b/x-pack/plugins/beats_management/server/lib/framework.ts new file mode 100644 index 0000000000000..abe41df1a279a --- /dev/null +++ b/x-pack/plugins/beats_management/server/lib/framework.ts @@ -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 { + 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' + ); + } + } +} diff --git a/x-pack/legacy/plugins/beats_management/server/lib/tags.ts b/x-pack/plugins/beats_management/server/lib/tags.ts similarity index 100% rename from x-pack/legacy/plugins/beats_management/server/lib/tags.ts rename to x-pack/plugins/beats_management/server/lib/tags.ts diff --git a/x-pack/legacy/plugins/beats_management/server/lib/tokens.ts b/x-pack/plugins/beats_management/server/lib/tokens.ts similarity index 92% rename from x-pack/legacy/plugins/beats_management/server/lib/tokens.ts rename to x-pack/plugins/beats_management/server/lib/tokens.ts index 759868810c0ce..366d3e8097980 100644 --- a/x-pack/legacy/plugins/beats_management/server/lib/tokens.ts +++ b/x-pack/plugins/beats_management/server/lib/tokens.ts @@ -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 { 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 = { diff --git a/x-pack/legacy/plugins/beats_management/server/lib/types.ts b/x-pack/plugins/beats_management/server/lib/types.ts similarity index 97% rename from x-pack/legacy/plugins/beats_management/server/lib/types.ts rename to x-pack/plugins/beats_management/server/lib/types.ts index 23894e3ffa6f7..d86aa8652fdbc 100644 --- a/x-pack/legacy/plugins/beats_management/server/lib/types.ts +++ b/x-pack/plugins/beats_management/server/lib/types.ts @@ -17,7 +17,7 @@ export type UserOrToken = FrameworkUser | string; export interface CMServerLibs { framework: BackendFrameworkLib; - database?: DatabaseAdapter; + database: DatabaseAdapter; beats: CMBeatsDomain; tags: CMTagsDomain; beatEvents: BeatEventsLib; diff --git a/x-pack/plugins/beats_management/server/plugin.ts b/x-pack/plugins/beats_management/server/plugin.ts index a82dbcb4a3a6e..92c2278148bc1 100644 --- a/x-pack/plugins/beats_management/server/plugin.ts +++ b/x-pack/plugins/beats_management/server/plugin.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { take } from 'rxjs/operators'; import { CoreSetup, CoreStart, @@ -13,6 +14,11 @@ import { import { SecurityPluginSetup } from '../../security/server'; import { LicensingPluginStart } from '../../licensing/server'; import { BeatsManagementConfigType } from '../common'; +import { CMServerLibs } from './lib/types'; +import { registerRoutes } from './routes'; +import { compose } from './lib/compose/kibana'; +import { INDEX_NAMES } from '../common/constants'; +import { beatsIndexTemplate } from './index_templates'; interface SetupDeps { security?: SecurityPluginSetup; @@ -22,18 +28,49 @@ interface StartDeps { licensing: LicensingPluginStart; } +declare module 'src/core/server' { + interface RequestHandlerContext { + beatsManagement?: CMServerLibs; + } +} + export class BeatsManagementPlugin implements Plugin<{}, {}, SetupDeps, StartDeps> { + private securitySetup?: SecurityPluginSetup; + private beatsLibs?: CMServerLibs; + constructor( private readonly initializerContext: PluginInitializerContext ) {} - public async setup(core: CoreSetup, plugins: SetupDeps) { - this.initializerContext.config.create(); + public async setup(core: CoreSetup, { security }: SetupDeps) { + this.securitySetup = security; + + const router = core.http.createRouter(); + registerRoutes(router); + + core.http.registerRouteHandlerContext('beatsManagement', (_, req) => { + return this.beatsLibs!; + }); return {}; } - public async start(core: CoreStart, { licensing }: StartDeps) { + public async start({ elasticsearch }: CoreStart, { licensing }: StartDeps) { + const config = await this.initializerContext.config.create().pipe(take(1)).toPromise(); + const logger = this.initializerContext.logger.get(); + const kibanaVersion = this.initializerContext.env.packageInfo.version; + + this.beatsLibs = compose({ + elasticsearch, + licensing, + security: this.securitySetup, + config, + logger, + kibanaVersion, + }); + + await this.beatsLibs.database.putTemplate(INDEX_NAMES.BEATS, beatsIndexTemplate); + return {}; } } diff --git a/x-pack/plugins/beats_management/server/routes/beats/configuration.ts b/x-pack/plugins/beats_management/server/routes/beats/configuration.ts new file mode 100644 index 0000000000000..1496e4bbfc99f --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/beats/configuration.ts @@ -0,0 +1,82 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'src/core/server'; +import { ConfigurationBlock } from '../../../common/domain_types'; +import { ReturnTypeList } from '../../../common/return_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerGetBeatConfigurationRoute = (router: IRouter) => { + router.get( + { + path: '/api/beats/agent/{beatId}/configuration', + validate: { + params: schema.object({ + beatId: schema.string(), + }), + }, + options: { + authRequired: false, + }, + }, + wrapRouteWithSecurity({}, async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const accessToken = request.headers['kbn-beats-access-token']; + if (!accessToken) { + return response.badRequest({ + body: 'beats access token required', + }); + } + const beatId = request.params.beatId; + + let configurationBlocks: ConfigurationBlock[]; + const beat = await beatsManagement.beats.getById( + beatsManagement.framework.internalUser, + beatId + ); + if (beat === null) { + return response.notFound({ + body: { + message: `Beat "${beatId}" not found`, + }, + }); + } + + const isAccessTokenValid = beat.access_token === accessToken; + if (!isAccessTokenValid) { + return response.unauthorized({ + body: { + message: 'Invalid access token', + }, + }); + } + + await beatsManagement.beats.update(beatsManagement.framework.internalUser, beat.id, { + last_checkin: new Date(), + }); + + if (beat.tags) { + const result = await beatsManagement.configurationBlocks.getForTags( + beatsManagement.framework.internalUser, + beat.tags, + -1 + ); + + configurationBlocks = result.blocks; + } else { + configurationBlocks = []; + } + + return response.ok({ + body: { + list: configurationBlocks, + success: true, + } as ReturnTypeList, + }); + }) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/enroll.ts b/x-pack/plugins/beats_management/server/routes/beats/enroll.ts new file mode 100644 index 0000000000000..be8fff3b7c437 --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/beats/enroll.ts @@ -0,0 +1,89 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'src/core/server'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ensureRawRequest } from '../../../../../../src/core/server/http/router'; +import { REQUIRED_LICENSES } from '../../../common/constants/security'; +import { BeatEnrollmentStatus } from '../../lib/types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerBeatEnrollmentRoute = (router: IRouter) => { + // TODO: write to Kibana audit log file https://github.com/elastic/kibana/issues/26024 + router.post( + { + path: '/api/beats/agent/{beatId}', + validate: { + params: schema.object({ + beatId: schema.string(), + }), + body: schema.object( + { + host_name: schema.string(), + name: schema.string(), + type: schema.string(), + version: schema.string(), + }, + { unknowns: 'ignore' } + ), + }, + options: { + authRequired: false, + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + + const { beatId } = request.params; + const enrollmentToken = request.headers['kbn-beats-enrollment-token'] as string; + if (!enrollmentToken) { + return response.badRequest({ + body: 'beats enrollment token required', + }); + } + + // TODO: fixme eventually, need to access `info.remoteAddress` from KibanaRequest. + const legacyRequest = ensureRawRequest(request); + + const { status, accessToken } = await beatsManagement.beats.enrollBeat( + enrollmentToken, + beatId, + legacyRequest.info.remoteAddress, + request.body + ); + + switch (status) { + case BeatEnrollmentStatus.ExpiredEnrollmentToken: + return response.badRequest({ + body: { + message: BeatEnrollmentStatus.ExpiredEnrollmentToken, + }, + }); + case BeatEnrollmentStatus.InvalidEnrollmentToken: + return response.badRequest({ + body: { + message: BeatEnrollmentStatus.InvalidEnrollmentToken, + }, + }); + case BeatEnrollmentStatus.Success: + default: + return response.ok({ + body: { + item: accessToken, + action: 'created', + success: true, + }, + }); + } + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/events.ts b/x-pack/plugins/beats_management/server/routes/beats/events.ts new file mode 100644 index 0000000000000..b87e6d684228a --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/beats/events.ts @@ -0,0 +1,66 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'kibana/server'; +import { ReturnTypeBulkAction } from '../../../common/return_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerBeatEventsRoute = (router: IRouter) => { + router.post( + { + path: '/api/beats/{beatId}/events', + validate: { + params: schema.object({ + beatId: schema.string(), + }), + body: schema.arrayOf(schema.any(), { defaultValue: [] }), + }, + options: { + authRequired: false, + }, + }, + wrapRouteWithSecurity({}, async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const accessToken = request.headers['kbn-beats-access-token']; + if (!accessToken) { + return response.badRequest({ + body: 'beats access token required', + }); + } + const beatId = request.params.beatId; + const events = request.body; + const internalUser = beatsManagement.framework.internalUser; + + const beat = await beatsManagement.beats.getById(internalUser, beatId); + if (beat === null) { + return response.badRequest({ + body: { + message: `Beat "${beatId}" not found`, + }, + }); + } + + const isAccessTokenValid = beat.access_token === accessToken; + if (!isAccessTokenValid) { + return response.unauthorized({ + body: { + message: `Invalid access token`, + }, + }); + } + + const results = await beatsManagement.beatEvents.log(internalUser, beat.id, events); + + return response.ok({ + body: { + results, + success: true, + } as ReturnTypeBulkAction, + }); + }) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/get.ts b/x-pack/plugins/beats_management/server/routes/beats/get.ts new file mode 100644 index 0000000000000..8762f325e7484 --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/beats/get.ts @@ -0,0 +1,59 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'kibana/server'; +import { CMBeat } from '../../../common/domain_types'; +import { ReturnTypeGet } from '../../../common/return_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerGetBeatRoute = (router: IRouter) => { + router.get( + { + path: '/api/beats/agent/{beatId}/{token?}', + validate: { + params: schema.object({ + beatId: schema.string(), + token: schema.string({ defaultValue: '' }), + }), + }, + }, + wrapRouteWithSecurity( + { requiredRoles: ['beats_admin'] }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const user = beatsManagement.framework.getUser(request); + const beatId = request.params.beatId; + + let beat: CMBeat | null; + if (beatId === 'unknown') { + beat = await beatsManagement.beats.getByEnrollmentToken(user, request.params.token); + if (beat === null) { + return response.ok({ body: { success: false } }); + } + } else { + beat = await beatsManagement.beats.getById(user, beatId); + if (beat === null) { + return response.notFound({ + body: { + message: 'Beat not found', + }, + }); + } + } + + delete beat.access_token; + + return response.ok({ + body: { + item: beat, + success: true, + } as ReturnTypeGet, + }); + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/index.ts b/x-pack/plugins/beats_management/server/routes/beats/index.ts new file mode 100644 index 0000000000000..0ebdc932142ae --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/beats/index.ts @@ -0,0 +1,14 @@ +/* + * 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. + */ + +export { registerGetBeatConfigurationRoute } from './configuration'; +export { registerBeatEnrollmentRoute } from './enroll'; +export { registerBeatEventsRoute } from './events'; +export { registerGetBeatRoute } from './get'; +export { registerListAgentsRoute } from './list'; +export { registerTagAssignmentsRoute } from './tag_assignment'; +export { registerTagRemovalsRoute } from './tag_removal'; +export { registerBeatUpdateRoute } from './update'; diff --git a/x-pack/plugins/beats_management/server/routes/beats/list.ts b/x-pack/plugins/beats_management/server/routes/beats/list.ts new file mode 100644 index 0000000000000..e4108238e3f2f --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/beats/list.ts @@ -0,0 +1,69 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'kibana/server'; +import { REQUIRED_LICENSES } from '../../../common/constants/security'; +import { CMBeat } from '../../../common/domain_types'; +import { ReturnTypeList } from '../../../common/return_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerListAgentsRoute = (router: IRouter) => { + router.get( + { + path: '/api/beats/agents/{listByAndValue*}', + validate: { + params: schema.object({ + listByAndValue: schema.maybe(schema.string()), + }), + query: schema.object( + { + ESQuery: schema.maybe(schema.string()), + }, + { defaultValue: {} } + ), + }, + }, + wrapRouteWithSecurity( + { + requiredRoles: ['beats_admin'], + requiredLicense: REQUIRED_LICENSES, + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const user = beatsManagement.framework.getUser(request); + + const listByAndValueParts = request.params.listByAndValue?.split('/') ?? []; + let listBy: string | 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 beatsManagement.beats.getAllWithTag(user, listByValue || ''); + break; + + default: + beats = await beatsManagement.beats.getAll( + user, + request.query.ESQuery ? JSON.parse(request.query.ESQuery) : undefined + ); + + break; + } + + return response.ok({ + body: { list: beats, success: true, page: -1, total: -1 } as ReturnTypeList, + }); + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/tag_assignment.ts b/x-pack/plugins/beats_management/server/routes/beats/tag_assignment.ts new file mode 100644 index 0000000000000..0397f8ec4398e --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/beats/tag_assignment.ts @@ -0,0 +1,68 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'kibana/server'; +import { REQUIRED_LICENSES } from '../../../common/constants/security'; +import { ReturnTypeBulkAction } from '../../../common/return_types'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import type { BeatsTagAssignment } from '../../../public/lib/adapters/beats/adapter_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerTagAssignmentsRoute = (router: IRouter) => { + // TODO: write to Kibana audit log file https://github.com/elastic/kibana/issues/26024 + router.post( + { + path: '/api/beats/agents_tags/assignments', + validate: { + body: schema.object({ + assignments: schema.arrayOf( + schema.object({ + beatId: schema.string(), + tag: schema.string(), + }), + { defaultValue: [] } + ), + }), + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + requiredRoles: ['beats_admin'], + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const user = beatsManagement.framework.getUser(request); + const { assignments }: { assignments: BeatsTagAssignment[] } = request.body; + + const result = await beatsManagement.beats.assignTagsToBeats(user, assignments); + + return response.ok({ + body: { + success: true, + results: result.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, + }); + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/tag_removal.ts b/x-pack/plugins/beats_management/server/routes/beats/tag_removal.ts new file mode 100644 index 0000000000000..a04ed81fb183b --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/beats/tag_removal.ts @@ -0,0 +1,66 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'kibana/server'; +import { REQUIRED_LICENSES } from '../../../common/constants/security'; +import { ReturnTypeBulkAction } from '../../../common/return_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerTagRemovalsRoute = (router: IRouter) => { + // TODO: write to Kibana audit log file https://github.com/elastic/kibana/issues/26024 + router.post( + { + path: '/api/beats/agents_tags/removals', + validate: { + body: schema.object({ + removals: schema.arrayOf( + schema.object({ + beatId: schema.string(), + tag: schema.string(), + }), + { defaultValue: [] } + ), + }), + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + requiredRoles: ['beats_admin'], + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const user = beatsManagement.framework.getUser(request); + const { removals } = request.body; + + const result = await beatsManagement.beats.removeTagsFromBeats(user, removals); + + return response.ok({ + body: { + success: true, + results: result.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, + }); + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/update.ts b/x-pack/plugins/beats_management/server/routes/beats/update.ts new file mode 100644 index 0000000000000..21bd6555b28dd --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/beats/update.ts @@ -0,0 +1,104 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'kibana/server'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ensureRawRequest } from '../../../../../../src/core/server/http/router'; +import { REQUIRED_LICENSES } from '../../../common/constants/security'; +import { CMBeat } from '../../../common/domain_types'; +import { ReturnTypeUpdate } from '../../../common/return_types'; +import { internalUser } from '../../lib/adapters/framework/adapter_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerBeatUpdateRoute = (router: IRouter) => { + // TODO: write to Kibana audit log file (include who did the verification as well) https://github.com/elastic/kibana/issues/26024 + router.put( + { + path: '/api/beats/agent/{beatId}', + validate: { + params: schema.object({ + beatId: schema.string(), + }), + body: schema.object( + { + active: schema.maybe(schema.boolean()), + ephemeral_id: schema.maybe(schema.string()), + host_name: schema.maybe(schema.string()), + local_configuration_yml: schema.maybe(schema.string()), + metadata: schema.maybe(schema.recordOf(schema.string(), schema.any())), + name: schema.maybe(schema.string()), + type: schema.maybe(schema.string()), + version: schema.maybe(schema.string()), + }, + { defaultValue: {} } + ), + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + requiredRoles: ['beats_admin'], + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const accessToken = request.headers['kbn-beats-access-token'] as string; + const { beatId } = request.params; + const user = beatsManagement.framework.getUser(request); + const userOrToken = accessToken || user; + + // TODO: fixme eventually, need to access `info.remoteAddress` from KibanaRequest. + const legacyRequest = ensureRawRequest(request); + const remoteAddress = legacyRequest.info.remoteAddress; + + if (user.kind === 'unauthenticated' && request.body.active !== undefined) { + return response.unauthorized({ + body: { + message: 'access-token is not a valid auth type to change beat status', + }, + }); + } + + const status = await beatsManagement.beats.update(userOrToken, beatId, { + ...request.body, + host_ip: remoteAddress, + }); + + switch (status) { + case 'beat-not-found': + return response.notFound({ + body: { + message: 'Beat not found', + }, + }); + case 'invalid-access-token': + return response.unauthorized({ + body: { + message: 'Invalid access token', + }, + }); + } + + const beat = await beatsManagement.beats.getById(internalUser, beatId); + if (!beat) { + return response.notFound({ + body: { + message: 'Beat not found', + }, + }); + } + + return response.ok({ + body: { + item: beat, + action: 'updated', + success: true, + } as ReturnTypeUpdate, + }); + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/configurations/delete.ts b/x-pack/plugins/beats_management/server/routes/configurations/delete.ts new file mode 100644 index 0000000000000..b60d3bd2d5a94 --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/configurations/delete.ts @@ -0,0 +1,47 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'src/core/server'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; +import { REQUIRED_LICENSES } from '../../../common/constants/security'; +import { ReturnTypeBulkDelete } from '../../../common/return_types'; + +export const registerDeleteConfigurationBlocksRoute = (router: IRouter) => { + router.delete( + { + path: '/api/beats/configurations/{ids}', + validate: { + params: schema.object({ + ids: schema.string(), + }), + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + requiredRoles: ['beats_admin'], + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const ids = request.params.ids.split(',').filter((id) => id.length > 0); + const user = beatsManagement.framework.getUser(request); + + const results = await beatsManagement.configurationBlocks.delete(user, ids); + return response.ok({ + body: { + success: true, + results: results.map((result) => ({ + success: result.success, + action: 'deleted', + error: result.success ? undefined : { message: result.reason }, + })), + } as ReturnTypeBulkDelete, + }); + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/configurations/get.ts b/x-pack/plugins/beats_management/server/routes/configurations/get.ts new file mode 100644 index 0000000000000..6f422ca9ca8bd --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/configurations/get.ts @@ -0,0 +1,52 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'src/core/server'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; +import { REQUIRED_LICENSES } from '../../../common/constants/security'; +import { ConfigurationBlock } from '../../../common/domain_types'; +import { ReturnTypeList } from '../../../common/return_types'; + +export const registerGetConfigurationBlocksRoute = (router: IRouter) => { + router.get( + { + path: '/api/beats/configurations/{tagIds}/{page?}', + validate: { + params: schema.object({ + tagIds: schema.string(), + page: schema.maybe(schema.number()), + }), + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + requiredRoles: ['beats_admin'], + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const tagIds = request.params.tagIds.split(',').filter((id) => id.length > 0); + const user = beatsManagement.framework.getUser(request); + const result = await beatsManagement.configurationBlocks.getForTags( + user, + tagIds, + request.params.page, + 5 + ); + + return response.ok({ + body: { + page: result.page, + total: result.total, + list: result.blocks, + success: true, + } as ReturnTypeList, + }); + } + ) + ); +}; diff --git a/x-pack/legacy/plugins/beats_management/server/kibana.index.ts b/x-pack/plugins/beats_management/server/routes/configurations/index.ts similarity index 50% rename from x-pack/legacy/plugins/beats_management/server/kibana.index.ts rename to x-pack/plugins/beats_management/server/routes/configurations/index.ts index dd7bc443bc603..490d4a7cd7328 100644 --- a/x-pack/legacy/plugins/beats_management/server/kibana.index.ts +++ b/x-pack/plugins/beats_management/server/routes/configurations/index.ts @@ -4,10 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { compose } from './lib/compose/kibana'; -import { initManagementServer } from './management_server'; - -export const initServerWithKibana = (hapiServer: any) => { - const libs = compose(hapiServer); - initManagementServer(libs); -}; +export { registerGetConfigurationBlocksRoute } from './get'; +export { registerDeleteConfigurationBlocksRoute } from './delete'; +export { registerUpsertConfigurationBlocksRoute } from './upsert'; diff --git a/x-pack/plugins/beats_management/server/routes/configurations/upsert.ts b/x-pack/plugins/beats_management/server/routes/configurations/upsert.ts new file mode 100644 index 0000000000000..e235b172e7d0b --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/configurations/upsert.ts @@ -0,0 +1,72 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'src/core/server'; +import { REQUIRED_LICENSES } from '../../../common/constants'; +import { + ConfigurationBlock, + createConfigurationBlockInterface, +} from '../../../common/domain_types'; +import { ReturnTypeBulkUpsert } from '../../../common/return_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerUpsertConfigurationBlocksRoute = (router: IRouter) => { + // TODO: write to Kibana audit log file + router.put( + { + path: '/api/beats/configurations', + validate: { + body: schema.arrayOf(schema.recordOf(schema.string(), schema.any()), { defaultValue: [] }), + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + requiredRoles: ['beats_admin'], + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const user = beatsManagement.framework.getUser(request); + const input = request.body as ConfigurationBlock[]; + + const result = await Promise.all( + input.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 beatsManagement.configurationBlocks.save( + user, + block + ); + if (error) { + return { success, error }; + } + + return { success, blockID }; + }) + ); + + return response.ok({ + body: { + 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, + } as ReturnTypeBulkUpsert, + }); + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/index.ts b/x-pack/plugins/beats_management/server/routes/index.ts new file mode 100644 index 0000000000000..423ecc85a5798 --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/index.ts @@ -0,0 +1,54 @@ +/* + * 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 { IRouter } from 'src/core/server'; +import { + registerDeleteConfigurationBlocksRoute, + registerGetConfigurationBlocksRoute, + registerUpsertConfigurationBlocksRoute, +} from './configurations'; +import { registerCreateTokenRoute } from './tokens'; +import { + registerSetTagRoute, + registerListTagsRoute, + registerGetTagsWithIdsRoute, + registerDeleteTagsWithIdsRoute, + registerAssignableTagsRoute, +} from './tags'; +import { + registerBeatUpdateRoute, + registerTagRemovalsRoute, + registerTagAssignmentsRoute, + registerListAgentsRoute, + registerGetBeatRoute, + registerBeatEventsRoute, + registerBeatEnrollmentRoute, + registerGetBeatConfigurationRoute, +} from './beats'; + +export const registerRoutes = (router: IRouter) => { + // configurations + registerGetConfigurationBlocksRoute(router); + registerDeleteConfigurationBlocksRoute(router); + registerUpsertConfigurationBlocksRoute(router); + // beats + registerBeatUpdateRoute(router); + registerTagRemovalsRoute(router); + registerTagAssignmentsRoute(router); + registerListAgentsRoute(router); + registerGetBeatRoute(router); + registerBeatEventsRoute(router); + registerBeatEnrollmentRoute(router); + registerGetBeatConfigurationRoute(router); + // tags + registerSetTagRoute(router); + registerListTagsRoute(router); + registerGetTagsWithIdsRoute(router); + registerDeleteTagsWithIdsRoute(router); + registerAssignableTagsRoute(router); + // tokens + registerCreateTokenRoute(router); +}; diff --git a/x-pack/plugins/beats_management/server/routes/tags/assignable.ts b/x-pack/plugins/beats_management/server/routes/tags/assignable.ts new file mode 100644 index 0000000000000..60d4748bf1fa6 --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/tags/assignable.ts @@ -0,0 +1,50 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'src/core/server'; +import { flatten } from 'lodash'; +import { REQUIRED_LICENSES } from '../../../common/constants/security'; +import { BeatTag } from '../../../common/domain_types'; +import { ReturnTypeBulkGet } from '../../../common/return_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerAssignableTagsRoute = (router: IRouter) => { + router.get( + { + path: '/api/beats/tags/assignable/{beatIds}', + validate: { + params: schema.object({ + beatIds: schema.string(), + }), + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + requiredRoles: ['beats_admin'], + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const user = beatsManagement.framework.getUser(request); + const beatIds = request.params.beatIds.split(',').filter((id) => id.length > 0); + + const beats = await beatsManagement.beats.getByIds(user, beatIds); + const tags = await beatsManagement.tags.getNonConflictingTags( + user, + flatten(beats.map((beat) => beat.tags)) + ); + + return response.ok({ + body: { + items: tags, + success: true, + } as ReturnTypeBulkGet, + }); + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/tags/delete.ts b/x-pack/plugins/beats_management/server/routes/tags/delete.ts new file mode 100644 index 0000000000000..78d0c80d42060 --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/tags/delete.ts @@ -0,0 +1,47 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'kibana/server'; +import { REQUIRED_LICENSES } from '../../../common/constants/security'; +import { ReturnTypeBulkDelete } from '../../../common/return_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerDeleteTagsWithIdsRoute = (router: IRouter) => { + router.delete( + { + path: '/api/beats/tags/{tagIds}', + validate: { + params: schema.object({ + tagIds: schema.string(), + }), + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + requiredRoles: ['beats_admin'], + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const user = beatsManagement.framework.getUser(request); + const tagIds = request.params.tagIds.split(',').filter((id) => id.length > 0); + + const success = await beatsManagement.tags.delete(user, tagIds); + + return response.ok({ + body: { + results: tagIds.map(() => ({ + success, + action: 'deleted', + })), + success, + } as ReturnTypeBulkDelete, + }); + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/tags/get.ts b/x-pack/plugins/beats_management/server/routes/tags/get.ts new file mode 100644 index 0000000000000..48da829aa09e5 --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/tags/get.ts @@ -0,0 +1,45 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'src/core/server'; +import { REQUIRED_LICENSES } from '../../../common/constants/security'; +import { BeatTag } from '../../../common/domain_types'; +import { ReturnTypeBulkGet } from '../../../common/return_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerGetTagsWithIdsRoute = (router: IRouter) => { + router.get( + { + path: '/api/beats/tags/{tagIds}', + validate: { + params: schema.object({ + tagIds: schema.string(), + }), + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + requiredRoles: ['beats_admin'], + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const user = beatsManagement.framework.getUser(request); + const tagIds = request.params.tagIds.split(',').filter((id) => id.length > 0); + + const tags = await beatsManagement.tags.getWithIds(user, tagIds); + + return response.ok({ + body: { + items: tags, + success: true, + } as ReturnTypeBulkGet, + }); + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/tags/index.ts b/x-pack/plugins/beats_management/server/routes/tags/index.ts new file mode 100644 index 0000000000000..2f0590026ca7e --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/tags/index.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export { registerAssignableTagsRoute } from './assignable'; +export { registerDeleteTagsWithIdsRoute } from './delete'; +export { registerGetTagsWithIdsRoute } from './get'; +export { registerListTagsRoute } from './list'; +export { registerSetTagRoute } from './set'; diff --git a/x-pack/plugins/beats_management/server/routes/tags/list.ts b/x-pack/plugins/beats_management/server/routes/tags/list.ts new file mode 100644 index 0000000000000..ce913cda337c5 --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/tags/list.ts @@ -0,0 +1,52 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'kibana/server'; +import { REQUIRED_LICENSES } from '../../../common/constants/security'; +import { BeatTag } from '../../../common/domain_types'; +import { ReturnTypeList } from '../../../common/return_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerListTagsRoute = (router: IRouter) => { + router.get( + { + path: '/api/beats/tags', + validate: { + query: schema.object( + { + ESQuery: schema.maybe(schema.string()), + }, + { defaultValue: {} } + ), + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + requiredRoles: ['beats_admin'], + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const user = beatsManagement.framework.getUser(request); + + const tags = await beatsManagement.tags.getAll( + user, + request.query && request.query.ESQuery ? JSON.parse(request.query.ESQuery) : undefined + ); + + return response.ok({ + body: { + list: tags, + success: true, + page: -1, + total: -1, + } as ReturnTypeList, + }); + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/tags/set.ts b/x-pack/plugins/beats_management/server/routes/tags/set.ts new file mode 100644 index 0000000000000..ef9e181514a55 --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/tags/set.ts @@ -0,0 +1,62 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'src/core/server'; +import { REQUIRED_LICENSES } from '../../../common/constants'; +import { BeatTag } from '../../../common/domain_types'; +import { ReturnTypeUpsert } from '../../../common/return_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +export const registerSetTagRoute = (router: IRouter) => { + // TODO: write to Kibana audit log file + router.put( + { + path: '/api/beats/tag/{tagId}', + validate: { + params: schema.object({ + tagId: schema.string(), + }), + body: schema.object( + { + color: schema.maybe(schema.string()), + name: schema.maybe(schema.string()), + }, + { defaultValue: {} } + ), + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + requiredRoles: ['beats_admin'], + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const user = beatsManagement.framework.getUser(request); + + const config = { + id: request.params.tagId, + name: request.params.tagId, + color: '#DD0A73', + hasConfigurationBlocksTypes: [], + ...request.body, + }; + const id = await beatsManagement.tags.upsertTag(user, config); + const tag = await beatsManagement.tags.getWithIds(user, [id]); + + // TODO the action needs to be surfaced + return response.ok({ + body: { + success: true, + item: tag[0], + action: 'created', + } as ReturnTypeUpsert, + }); + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/tokens/create.ts b/x-pack/plugins/beats_management/server/routes/tokens/create.ts new file mode 100644 index 0000000000000..2fd7d4614c570 --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/tokens/create.ts @@ -0,0 +1,61 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'src/core/server'; +import { REQUIRED_LICENSES } from '../../../common/constants/security'; +import { ReturnTypeBulkCreate } from '../../../common/return_types'; +import { wrapRouteWithSecurity } from '../wrap_route_with_security'; + +const DEFAULT_NUM_TOKENS = 1; + +export const registerCreateTokenRoute = (router: IRouter) => { + // TODO: write to Kibana audit log file + router.post( + { + path: '/api/beats/enrollment_tokens', + validate: { + body: schema.nullable( + schema.object({ + num_tokens: schema.number({ defaultValue: DEFAULT_NUM_TOKENS, min: 1 }), + }) + ), + }, + }, + wrapRouteWithSecurity( + { + requiredLicense: REQUIRED_LICENSES, + requiredRoles: ['beats_admin'], + }, + async (context, request, response) => { + const beatsManagement = context.beatsManagement!; + const user = beatsManagement.framework.getUser(request); + + const numTokens = request.body?.num_tokens ?? DEFAULT_NUM_TOKENS; + try { + const tokens = await beatsManagement.tokens.createEnrollmentTokens(user, numTokens); + return response.ok({ + body: { + results: tokens.map((token) => ({ + item: token, + success: true, + action: 'created', + })), + success: true, + } as ReturnTypeBulkCreate, + }); + } catch (err) { + beatsManagement.framework.log(err.message); + return response.internalError({ + body: { + message: 'An error occurred, please check your Kibana logs', + }, + }); + } + } + ) + ); +}; diff --git a/x-pack/plugins/beats_management/server/routes/tokens/index.ts b/x-pack/plugins/beats_management/server/routes/tokens/index.ts new file mode 100644 index 0000000000000..3e34fff0a6c6b --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/tokens/index.ts @@ -0,0 +1,7 @@ +/* + * 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. + */ + +export { registerCreateTokenRoute } from './create'; diff --git a/x-pack/plugins/beats_management/server/routes/wrap_route_with_security.ts b/x-pack/plugins/beats_management/server/routes/wrap_route_with_security.ts new file mode 100644 index 0000000000000..ad4f8080127b2 --- /dev/null +++ b/x-pack/plugins/beats_management/server/routes/wrap_route_with_security.ts @@ -0,0 +1,69 @@ +/* + * 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 { + KibanaRequest, + KibanaResponseFactory, + RequestHandler, + RequestHandlerContext, + RouteMethod, +} from 'src/core/server'; +import { difference } from 'lodash'; + +export function wrapRouteWithSecurity( + { + requiredLicense = [], + requiredRoles = [], + }: { requiredLicense?: string[]; requiredRoles?: string[] }, + handler: RequestHandler +): RequestHandler { + return async ( + context: RequestHandlerContext, + request: KibanaRequest, + response: KibanaResponseFactory + ) => { + const beatsManagement = context.beatsManagement!; + const license = beatsManagement.framework.license; + const user = beatsManagement.framework.getUser(request); + + if ( + requiredLicense.length > 0 && + (license.expired || !requiredLicense.includes(license.type)) + ) { + return response.forbidden({ + body: { + message: `Your ${license.type} license does not support this API or is expired. Please upgrade your license.`, + }, + }); + } + + if (requiredRoles.length > 0) { + if (user.kind !== 'authenticated') { + return response.forbidden({ + body: { + message: `Request must be authenticated`, + }, + }); + } + + if ( + user.kind === 'authenticated' && + !user.roles.includes('superuser') && + difference(requiredRoles, user.roles).length !== 0 + ) { + return response.forbidden({ + body: { + message: `Request must be authenticated by a user with one of the following user roles: ${requiredRoles.join( + ',' + )}`, + }, + }); + } + } + + return handler(context, request, response); + }; +} diff --git a/x-pack/test/api_integration/apis/beats/enroll_beat.js b/x-pack/test/api_integration/apis/beats/enroll_beat.js index 305322e766e3c..18e0b250a91b5 100644 --- a/x-pack/test/api_integration/apis/beats/enroll_beat.js +++ b/x-pack/test/api_integration/apis/beats/enroll_beat.js @@ -97,8 +97,9 @@ export default function ({ getService }) { .expect(400); expect(apiResponse).to.eql({ - success: false, - error: { code: 400, message: 'Invalid enrollment token' }, + statusCode: 400, + error: 'Bad Request', + message: 'Invalid enrollment token', }); }); @@ -128,8 +129,9 @@ export default function ({ getService }) { .expect(400); expect(apiResponse).to.eql({ - success: false, - error: { code: 400, message: 'Expired enrollment token' }, + statusCode: 400, + error: 'Bad Request', + message: 'Expired enrollment token', }); }); diff --git a/x-pack/test/api_integration/apis/beats/update_beat.js b/x-pack/test/api_integration/apis/beats/update_beat.js index dff9c2a0ec072..dc4afe88353e1 100644 --- a/x-pack/test/api_integration/apis/beats/update_beat.js +++ b/x-pack/test/api_integration/apis/beats/update_beat.js @@ -92,7 +92,7 @@ export default function ({ getService }) { .send(beat) .expect(401); - expect(body.error.message).to.be('Invalid access token'); + expect(body.message).to.be('Invalid access token'); const beatInEs = await es.get({ index: ES_INDEX_NAME, @@ -115,7 +115,7 @@ export default function ({ getService }) { .send(beat) .expect(404); - expect(body.error.message).to.be('Beat not found'); + expect(body.message).to.be('Beat not found'); }); }); }