Beats Management plugin: migrate server-side code (#70930)

* move all the legacy codebase to KP plugin

* fix imports

* add empty handler context & rename routes folder

* start migrating routes

* migrate rest of the routes

* migrate adapters

* remove beats from legacy xpack plugin

* use nullable + replace response.custom

* fix wrapRouteWithSecurity, remove incorrect header validation

* remove comment

* updating generated plugin list

* fix typos in doc

* adapt readme too.

* remove old commented routes from route files

* remove eslint disabling

* use camel case for plugin id

* update generated doc

Co-authored-by: Josh Dover <me@joshdover.com>
This commit is contained in:
Pierre Gayvallet 2020-08-18 12:00:39 +02:00 committed by GitHub
parent 198806baef
commit 890fc31dff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
127 changed files with 1573 additions and 1530 deletions

View file

@ -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]

View file

@ -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)];
};

View file

@ -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);
},
});
}

View file

@ -1,188 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { ResponseToolkit } from 'hapi';
import { PathReporter } from 'io-ts/lib/PathReporter';
import { get } from 'lodash';
import { isLeft } from 'fp-ts/lib/Either';
import { KibanaRequest, LegacyRequest } from '../../../../../../../../src/core/server';
// @ts-ignore
import { mirrorPluginStatus } from '../../../../../../server/lib/mirror_plugin_status';
import {
BackendFrameworkAdapter,
FrameworkInfo,
FrameworkRequest,
FrameworkResponse,
FrameworkRouteOptions,
internalAuthData,
internalUser,
KibanaLegacyServer,
KibanaServerRequest,
KibanaUser,
RuntimeFrameworkInfo,
RuntimeKibanaUser,
XpackInfo,
} from './adapter_types';
export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter {
public readonly internalUser = internalUser;
public info: null | FrameworkInfo = null;
constructor(
private readonly PLUGIN_ID: string,
private readonly server: KibanaLegacyServer,
private readonly CONFIG_PREFIX?: string
) {
const xpackMainPlugin = this.server.plugins.xpack_main;
const thisPlugin = this.server.plugins.beats_management;
mirrorPluginStatus(xpackMainPlugin, thisPlugin);
xpackMainPlugin.status.on('green', () => {
this.xpackInfoWasUpdatedHandler(xpackMainPlugin.info);
// Register a function that is called whenever the xpack info changes,
// to re-compute the license check results for this plugin
xpackMainPlugin.info
.feature(this.PLUGIN_ID)
.registerLicenseCheckResultsGenerator(this.xpackInfoWasUpdatedHandler);
});
}
public on(event: 'xpack.status.green' | 'elasticsearch.status.green', cb: () => void) {
switch (event) {
case 'xpack.status.green':
this.server.plugins.xpack_main.status.on('green', cb);
case 'elasticsearch.status.green':
this.server.plugins.elasticsearch.status.on('green', cb);
}
}
public getSetting(settingPath: string) {
return this.server.config().get(settingPath);
}
public log(text: string) {
this.server.log(text);
}
public registerRoute<
RouteRequest extends FrameworkRequest,
RouteResponse extends FrameworkResponse
>(route: FrameworkRouteOptions<RouteRequest, RouteResponse>) {
this.server.route({
handler: async (request: KibanaServerRequest, h: ResponseToolkit) => {
// Note, RuntimeKibanaServerRequest is avalaible to validate request, and its type *is* KibanaServerRequest
// but is not used here for perf reasons. It's value here is not high enough...
return await route.handler(await this.wrapRequest<RouteRequest>(request), h);
},
method: route.method,
path: route.path,
config: route.config,
});
}
private async wrapRequest<InternalRequest extends KibanaServerRequest>(
req: KibanaServerRequest
): Promise<FrameworkRequest<InternalRequest>> {
const { params, payload, query, headers, info } = req;
let isAuthenticated = headers.authorization != null;
let user;
if (isAuthenticated) {
user = await this.getUser(req);
if (!user) {
isAuthenticated = false;
}
}
return {
user:
isAuthenticated && user
? {
kind: 'authenticated',
[internalAuthData]: headers,
...user,
}
: {
kind: 'unauthenticated',
},
headers,
info,
params,
payload,
query,
};
}
private async getUser(request: KibanaServerRequest): Promise<KibanaUser | null> {
const user = this.server.newPlatform.setup.plugins.security?.authc.getCurrentUser(
KibanaRequest.from((request as unknown) as LegacyRequest)
);
if (!user) {
return null;
}
const assertKibanaUser = RuntimeKibanaUser.decode(user);
if (isLeft(assertKibanaUser)) {
throw new Error(
`Error parsing user info in ${this.PLUGIN_ID}, ${
PathReporter.report(assertKibanaUser)[0]
}`
);
}
return user;
}
private xpackInfoWasUpdatedHandler = (xpackInfo: XpackInfo) => {
let xpackInfoUnpacked: FrameworkInfo;
// If, for some reason, we cannot get the license information
// from Elasticsearch, assume worst case and disable
if (!xpackInfo || !xpackInfo.isAvailable()) {
this.info = null;
return;
}
try {
xpackInfoUnpacked = {
kibana: {
version: get(this.server, 'plugins.kibana.status.plugin.version', 'unknown'),
},
license: {
type: xpackInfo.license.getType(),
expired: !xpackInfo.license.isActive(),
expiry_date_in_millis:
xpackInfo.license.getExpiryDateInMillis() !== undefined
? xpackInfo.license.getExpiryDateInMillis()
: -1,
},
security: {
enabled: !!xpackInfo.feature('security') && xpackInfo.feature('security').isEnabled(),
available: !!xpackInfo.feature('security'),
},
watcher: {
enabled: !!xpackInfo.feature('watcher') && xpackInfo.feature('watcher').isEnabled(),
available: !!xpackInfo.feature('watcher'),
},
};
} catch (e) {
this.server.log(`Error accessing required xPackInfo in ${this.PLUGIN_ID} Kibana adapter`);
throw e;
}
const assertData = RuntimeFrameworkInfo.decode(xpackInfoUnpacked);
if (isLeft(assertData)) {
throw new Error(
`Error parsing xpack info in ${this.PLUGIN_ID}, ${PathReporter.report(assertData)[0]}`
);
}
this.info = xpackInfoUnpacked;
return {
security: xpackInfoUnpacked.security,
settings: this.getSetting(this.CONFIG_PREFIX || this.PLUGIN_ID),
};
};
}

View file

@ -1,174 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { ResponseObject, ResponseToolkit } from 'hapi';
import { difference } from 'lodash';
import { BaseReturnType } from '../../common/return_types';
import {
BackendFrameworkAdapter,
FrameworkRequest,
FrameworkResponse,
} from './adapters/framework/adapter_types';
export class BackendFrameworkLib {
public log = this.adapter.log;
public on = this.adapter.on.bind(this.adapter);
public internalUser = this.adapter.internalUser;
constructor(private readonly adapter: BackendFrameworkAdapter) {
this.validateConfig();
}
public registerRoute<
RouteRequest extends FrameworkRequest,
RouteResponse extends FrameworkResponse
>(route: {
path: string;
method: string | string[];
licenseRequired?: string[];
requiredRoles?: string[];
handler: (request: FrameworkRequest<RouteRequest>) => Promise<BaseReturnType>;
config?: {};
}) {
this.adapter.registerRoute({
...route,
handler: this.wrapErrors(
this.wrapRouteWithSecurity(route.handler, route.licenseRequired || [], route.requiredRoles)
),
});
}
public getSetting(setting: 'encryptionKey'): string;
public getSetting(setting: 'enrollmentTokensTtlInSeconds'): number;
public getSetting(setting: 'defaultUserRoles'): string[];
public getSetting(
setting: 'encryptionKey' | 'enrollmentTokensTtlInSeconds' | 'defaultUserRoles'
) {
return this.adapter.getSetting(`xpack.beats.${setting}`);
}
/**
* Expired `null` happens when we have no xpack info
*/
public get license() {
return {
type: this.adapter.info ? this.adapter.info.license.type : 'unknown',
expired: this.adapter.info ? this.adapter.info.license.expired : null,
};
}
public get securityIsEnabled() {
return this.adapter.info ? this.adapter.info.security.enabled : false;
}
private validateConfig() {
const encryptionKey = this.adapter.getSetting('xpack.beats.encryptionKey');
if (!encryptionKey) {
this.adapter.log(
'Using a default encryption key for xpack.beats.encryptionKey. It is recommended that you set xpack.beats.encryptionKey in kibana.yml with a unique token'
);
}
}
private wrapRouteWithSecurity(
handler: (request: FrameworkRequest<any>) => Promise<BaseReturnType>,
requiredLicense: string[],
requiredRoles?: string[]
): (request: FrameworkRequest) => Promise<BaseReturnType> {
return async (request: FrameworkRequest) => {
if (
requiredLicense.length > 0 &&
(this.license.expired || !requiredLicense.includes(this.license.type))
) {
return {
error: {
message: `Your ${this.license.type} license does not support this API or is expired. Please upgrade your license.`,
code: 403,
},
success: false,
};
}
if (requiredRoles) {
if (request.user.kind !== 'authenticated') {
return {
error: {
message: `Request must be authenticated`,
code: 403,
},
success: false,
};
}
if (
request.user.kind === 'authenticated' &&
!request.user.roles.includes('superuser') &&
difference(requiredRoles, request.user.roles).length !== 0
) {
return {
error: {
message: `Request must be authenticated by a user with one of the following user roles: ${requiredRoles.join(
','
)}`,
code: 403,
},
success: false,
};
}
}
return await handler(request);
};
}
private wrapErrors(
handler: (request: FrameworkRequest<any>) => Promise<BaseReturnType>
): (request: FrameworkRequest, h: ResponseToolkit) => Promise<ResponseObject> {
return async (request: FrameworkRequest, h: ResponseToolkit) => {
try {
const result = await handler(request);
if (!result.error) {
return h.response(result);
}
return h
.response({
error: result.error,
success: false,
})
.code(result.error.code || 400);
} catch (err) {
let statusCode = err.statusCode;
// This is the only known non-status code error in the system, but just in case we have an else
if (!statusCode && (err.message as string).includes('Invalid user type')) {
statusCode = 403;
} else {
statusCode = 500;
}
if (statusCode === 403) {
return h
.response({
error: {
message: 'Insufficient user permissions for managing Beats configuration',
code: 403,
},
success: false,
})
.code(403);
}
return h
.response({
error: {
message: err.message,
code: statusCode,
},
success: false,
})
.code(statusCode);
}
};
}
}

View file

@ -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));
};

View file

@ -1,61 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { ConfigurationBlock } from '../../../common/domain_types';
import { BaseReturnType, ReturnTypeList } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
export const createGetBeatConfigurationRoute = (libs: CMServerLibs) => ({
method: 'GET',
path: '/api/beats/agent/{beatId}/configuration',
config: {
validate: {
headers: Joi.object({
'kbn-beats-access-token': Joi.string().required(),
}).options({ allowUnknown: true }),
},
auth: false,
},
handler: async (
request: FrameworkRequest
): Promise<BaseReturnType | ReturnTypeList<ConfigurationBlock>> => {
const beatId = request.params.beatId;
const accessToken = request.headers['kbn-beats-access-token'];
let configurationBlocks: ConfigurationBlock[];
const beat = await libs.beats.getById(libs.framework.internalUser, beatId);
if (beat === null) {
return { error: { message: `Beat "${beatId}" not found`, code: 404 }, success: false };
}
const isAccessTokenValid = beat.access_token === accessToken;
if (!isAccessTokenValid) {
return { error: { message: 'Invalid access token', code: 401 }, success: false };
}
await libs.beats.update(libs.framework.internalUser, beat.id, {
last_checkin: new Date(),
});
if (beat.tags) {
const result = await libs.configurationBlocks.getForTags(
libs.framework.internalUser,
beat.tags,
-1
);
configurationBlocks = result.blocks;
} else {
configurationBlocks = [];
}
return {
list: configurationBlocks,
success: true,
};
},
});

View file

@ -1,68 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { omit } from 'lodash';
import { REQUIRED_LICENSES } from '../../../common/constants/security';
import { BaseReturnType, ReturnTypeCreate } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { BeatEnrollmentStatus, CMServerLibs } from '../../lib/types';
// TODO: write to Kibana audit log file https://github.com/elastic/kibana/issues/26024
export const createBeatEnrollmentRoute = (libs: CMServerLibs) => ({
method: 'POST',
path: '/api/beats/agent/{beatId}',
licenseRequired: REQUIRED_LICENSES,
config: {
auth: false,
validate: {
headers: Joi.object({
'kbn-beats-enrollment-token': Joi.string().required(),
}).options({
allowUnknown: true,
}),
payload: Joi.object({
host_name: Joi.string().required(),
name: Joi.string().required(),
type: Joi.string().required(),
version: Joi.string().required(),
}).required(),
},
},
handler: async (
request: FrameworkRequest
): Promise<BaseReturnType | ReturnTypeCreate<string>> => {
const { beatId } = request.params;
const enrollmentToken = request.headers['kbn-beats-enrollment-token'];
const { status, accessToken } = await libs.beats.enrollBeat(
enrollmentToken,
beatId,
request.info.remoteAddress,
omit(request.payload, 'enrollment_token')
);
switch (status) {
case BeatEnrollmentStatus.ExpiredEnrollmentToken:
return {
error: { message: BeatEnrollmentStatus.ExpiredEnrollmentToken, code: 400 },
success: false,
};
case BeatEnrollmentStatus.InvalidEnrollmentToken:
return {
error: { message: BeatEnrollmentStatus.InvalidEnrollmentToken, code: 400 },
success: false,
};
case BeatEnrollmentStatus.Success:
default:
return {
item: accessToken,
action: 'created',
success: true,
};
}
},
});

View file

@ -1,44 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { BaseReturnType, ReturnTypeBulkAction } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
export const beatEventsRoute = (libs: CMServerLibs) => ({
method: 'POST',
path: '/api/beats/{beatId}/events',
config: {
validate: {
headers: Joi.object({
'kbn-beats-access-token': Joi.string().required(),
}).options({ allowUnknown: true }),
},
auth: false,
},
handler: async (request: FrameworkRequest): Promise<BaseReturnType | ReturnTypeBulkAction> => {
const beatId = request.params.beatId;
const events = request.payload;
const accessToken = request.headers['kbn-beats-access-token'];
const beat = await libs.beats.getById(libs.framework.internalUser, beatId);
if (beat === null) {
return { error: { message: `Beat "${beatId}" not found`, code: 400 }, success: false };
}
const isAccessTokenValid = beat.access_token === accessToken;
if (!isAccessTokenValid) {
return { error: { message: `Invalid access token`, code: 401 }, success: false };
}
const results = await libs.beatEvents.log(libs.framework.internalUser, beat.id, events);
return {
results,
success: true,
};
},
});

View file

@ -1,39 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { CMBeat } from '../../../common/domain_types';
import { BaseReturnType, ReturnTypeGet } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
export const createGetBeatRoute = (libs: CMServerLibs) => ({
method: 'GET',
path: '/api/beats/agent/{beatId}/{token?}',
requiredRoles: ['beats_admin'],
handler: async (request: FrameworkRequest): Promise<BaseReturnType | ReturnTypeGet<CMBeat>> => {
const beatId = request.params.beatId;
let beat: CMBeat | null;
if (beatId === 'unknown') {
beat = await libs.beats.getByEnrollmentToken(request.user, request.params.token);
if (beat === null) {
return { success: false };
}
} else {
beat = await libs.beats.getById(request.user, beatId);
if (beat === null) {
return { error: { message: 'Beat not found', code: 404 }, success: false };
}
}
delete beat.access_token;
return {
item: beat,
success: true,
};
},
});

View file

@ -1,60 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as Joi from 'joi';
import { REQUIRED_LICENSES } from '../../../common/constants/security';
import { CMBeat } from '../../../common/domain_types';
import { ReturnTypeList } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
export const createListAgentsRoute = (libs: CMServerLibs) => ({
method: 'GET',
path: '/api/beats/agents/{listByAndValue*}',
requiredRoles: ['beats_admin'],
licenseRequired: REQUIRED_LICENSES,
validate: {
headers: Joi.object({
'kbn-beats-enrollment-token': Joi.string().required(),
}).options({
allowUnknown: true,
}),
query: Joi.object({
ESQuery: Joi.string(),
}),
},
handler: async (request: FrameworkRequest): Promise<ReturnTypeList<CMBeat>> => {
const listByAndValueParts = request.params.listByAndValue
? request.params.listByAndValue.split('/')
: [];
let listBy: 'tag' | null = null;
let listByValue: string | null = null;
if (listByAndValueParts.length === 2) {
listBy = listByAndValueParts[0];
listByValue = listByAndValueParts[1];
}
let beats: CMBeat[];
switch (listBy) {
case 'tag':
beats = await libs.beats.getAllWithTag(request.user, listByValue || '');
break;
default:
beats = await libs.beats.getAll(
request.user,
request.query && request.query.ESQuery ? JSON.parse(request.query.ESQuery) : undefined
);
break;
}
return { list: beats, success: true, page: -1, total: -1 };
},
});

View file

@ -1,58 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { REQUIRED_LICENSES } from '../../../common/constants/security';
import { ReturnTypeBulkAction } from '../../../common/return_types';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { BeatsTagAssignment } from '../../../../../../plugins/beats_management/public/lib/adapters/beats/adapter_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
// TODO: write to Kibana audit log file https://github.com/elastic/kibana/issues/26024
export const createTagAssignmentsRoute = (libs: CMServerLibs) => ({
method: 'POST',
path: '/api/beats/agents_tags/assignments',
licenseRequired: REQUIRED_LICENSES,
requiredRoles: ['beats_admin'],
config: {
validate: {
payload: Joi.object({
assignments: Joi.array().items(
Joi.object({
beatId: Joi.string().required(),
tag: Joi.string().required(),
})
),
}).required(),
},
},
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkAction> => {
const { assignments }: { assignments: BeatsTagAssignment[] } = request.payload;
const response = await libs.beats.assignTagsToBeats(request.user, assignments);
return {
success: true,
results: response.assignments.map((assignment) => ({
success: assignment.status && assignment.status >= 200 && assignment.status < 300,
error:
!assignment.status || assignment.status >= 300
? {
code: assignment.status || 400,
message: assignment.result,
}
: undefined,
result:
assignment.status && assignment.status >= 200 && assignment.status < 300
? {
message: assignment.result,
}
: undefined,
})),
} as ReturnTypeBulkAction;
},
});

View file

@ -1,56 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { REQUIRED_LICENSES } from '../../../common/constants/security';
import { ReturnTypeBulkAction } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
// TODO: write to Kibana audit log file https://github.com/elastic/kibana/issues/26024
export const createTagRemovalsRoute = (libs: CMServerLibs) => ({
method: 'POST',
path: '/api/beats/agents_tags/removals',
licenseRequired: REQUIRED_LICENSES,
requiredRoles: ['beats_admin'],
config: {
validate: {
payload: Joi.object({
removals: Joi.array().items(
Joi.object({
beatId: Joi.string().required(),
tag: Joi.string().required(),
})
),
}).required(),
},
},
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkAction> => {
const { removals } = request.payload;
const response = await libs.beats.removeTagsFromBeats(request.user, removals);
return {
success: true,
results: response.removals.map((removal) => ({
success: removal.status && removal.status >= 200 && removal.status < 300,
error:
!removal.status || removal.status >= 300
? {
code: removal.status || 400,
message: removal.result,
}
: undefined,
result:
removal.status && removal.status >= 200 && removal.status < 300
? {
message: removal.result,
}
: undefined,
})),
} as ReturnTypeBulkAction;
},
});

View file

@ -1,102 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { REQUIRED_LICENSES } from '../../../common/constants/security';
import { CMBeat } from '../../../common/domain_types';
import { BaseReturnType, ReturnTypeUpdate } from '../../../common/return_types';
import { FrameworkRequest, internalUser } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
// TODO: write to Kibana audit log file (include who did the verification as well) https://github.com/elastic/kibana/issues/26024
export const createBeatUpdateRoute = (libs: CMServerLibs) => ({
method: 'PUT',
path: '/api/beats/agent/{beatId}',
licenseRequired: REQUIRED_LICENSES,
requiredRoles: ['beats_admin'],
config: {
validate: {
headers: Joi.object({
'kbn-beats-access-token': Joi.string(),
}).options({
allowUnknown: true,
}),
params: Joi.object({
beatId: Joi.string(),
}),
payload: Joi.object({
active: Joi.bool(),
ephemeral_id: Joi.string(),
host_name: Joi.string(),
local_configuration_yml: Joi.string(),
metadata: Joi.object(),
name: Joi.string(),
type: Joi.string(),
version: Joi.string(),
}),
},
},
handler: async (
request: FrameworkRequest
): Promise<BaseReturnType | ReturnTypeUpdate<CMBeat>> => {
const { beatId } = request.params;
const accessToken = request.headers['kbn-beats-access-token'];
const remoteAddress = request.info.remoteAddress;
const userOrToken = accessToken || request.user;
if (request.user.kind === 'unauthenticated' && request.payload.active !== undefined) {
return {
error: {
message: 'access-token is not a valid auth type to change beat status',
code: 401,
},
success: false,
};
}
const status = await libs.beats.update(userOrToken, beatId, {
...request.payload,
host_ip: remoteAddress,
});
switch (status) {
case 'beat-not-found':
return {
error: {
message: 'Beat not found',
code: 404,
},
success: false,
};
case 'invalid-access-token':
return {
error: {
message: 'Invalid access token',
code: 401,
},
success: false,
};
}
const beat = await libs.beats.getById(internalUser, beatId);
if (!beat) {
return {
error: {
message: 'Beat not found',
code: 404,
},
success: false,
};
}
return {
item: beat,
action: 'updated',
success: true,
};
},
});

View file

@ -1,32 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { REQUIRED_LICENSES } from '../../../common/constants/security';
import { ReturnTypeBulkDelete } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
export const createDeleteConfidurationsRoute = (libs: CMServerLibs) => ({
method: 'DELETE',
path: '/api/beats/configurations/{ids}',
requiredRoles: ['beats_admin'],
licenseRequired: REQUIRED_LICENSES,
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkDelete> => {
const idString: string = request.params.ids;
const ids = idString.split(',').filter((id: string) => id.length > 0);
const results = await libs.configurationBlocks.delete(request.user, ids);
return {
success: true,
results: results.map((result) => ({
success: result.success,
action: 'deleted',
error: result.success ? undefined : { message: result.reason },
})),
} as ReturnTypeBulkDelete;
},
});

View file

@ -1,31 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { REQUIRED_LICENSES } from '../../../common/constants/security';
import { ConfigurationBlock } from '../../../common/domain_types';
import { ReturnTypeList } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
export const createGetConfigurationBlocksRoute = (libs: CMServerLibs) => ({
method: 'GET',
path: '/api/beats/configurations/{tagIds}/{page?}',
requiredRoles: ['beats_admin'],
licenseRequired: REQUIRED_LICENSES,
handler: async (request: FrameworkRequest): Promise<ReturnTypeList<ConfigurationBlock>> => {
const tagIdString: string = request.params.tagIds;
const tagIds = tagIdString.split(',').filter((id: string) => id.length > 0);
const result = await libs.configurationBlocks.getForTags(
request.user,
tagIds,
parseInt(request.params.page, 10),
5
);
return { page: result.page, total: result.total, list: result.blocks, success: true };
},
});

View file

@ -1,66 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { PathReporter } from 'io-ts/lib/PathReporter';
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { isLeft } from 'fp-ts/lib/Either';
import { REQUIRED_LICENSES } from '../../../common/constants';
import {
ConfigurationBlock,
createConfigurationBlockInterface,
} from '../../../common/domain_types';
import { ReturnTypeBulkUpsert } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
// TODO: write to Kibana audit log file
export const upsertConfigurationRoute = (libs: CMServerLibs) => ({
method: 'PUT',
path: '/api/beats/configurations',
licenseRequired: REQUIRED_LICENSES,
requiredRoles: ['beats_admin'],
config: {
validate: {
payload: Joi.array().items(Joi.object({}).unknown(true)),
},
},
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkUpsert> => {
const result = await Promise.all<any>(
request.payload.map(async (block: ConfigurationBlock) => {
const assertData = createConfigurationBlockInterface().decode(block);
if (isLeft(assertData)) {
return {
error: `Error parsing block info, ${PathReporter.report(assertData)[0]}`,
};
}
const { blockID, success, error } = await libs.configurationBlocks.save(
request.user,
block
);
if (error) {
return { success, error };
}
return { success, blockID };
})
);
return {
results: result.map((r) => ({
success: r.success as boolean,
// TODO: we need to surface this data, not hard coded
action: 'created' as 'created' | 'updated',
})),
success: true,
};
},
});

View file

@ -1,34 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { flatten } from 'lodash';
import { REQUIRED_LICENSES } from '../../../common/constants/security';
import { BeatTag } from '../../../common/domain_types';
import { ReturnTypeBulkGet } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
export const createAssignableTagsRoute = (libs: CMServerLibs) => ({
method: 'GET',
path: '/api/beats/tags/assignable/{beatIds}',
requiredRoles: ['beats_admin'],
licenseRequired: REQUIRED_LICENSES,
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkGet<BeatTag>> => {
const beatIdString: string = request.params.beatIds;
const beatIds = beatIdString.split(',').filter((id: string) => id.length > 0);
const beats = await libs.beats.getByIds(request.user, beatIds);
const tags = await libs.tags.getNonConflictingTags(
request.user,
flatten(beats.map((beat) => beat.tags))
);
return {
items: tags,
success: true,
};
},
});

View file

@ -1,31 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { REQUIRED_LICENSES } from '../../../common/constants/security';
import { ReturnTypeBulkDelete } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
export const createDeleteTagsWithIdsRoute = (libs: CMServerLibs) => ({
method: 'DELETE',
path: '/api/beats/tags/{tagIds}',
requiredRoles: ['beats_admin'],
licenseRequired: REQUIRED_LICENSES,
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkDelete> => {
const tagIdString: string = request.params.tagIds;
const tagIds = tagIdString.split(',').filter((id: string) => id.length > 0);
const success = await libs.tags.delete(request.user, tagIds);
return {
results: tagIds.map(() => ({
success,
action: 'deleted',
})),
success,
} as ReturnTypeBulkDelete;
},
});

View file

@ -1,29 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { REQUIRED_LICENSES } from '../../../common/constants/security';
import { BeatTag } from '../../../common/domain_types';
import { ReturnTypeBulkGet } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
export const createGetTagsWithIdsRoute = (libs: CMServerLibs) => ({
method: 'GET',
path: '/api/beats/tags/{tagIds}',
requiredRoles: ['beats_admin'],
licenseRequired: REQUIRED_LICENSES,
handler: async (request: FrameworkRequest): Promise<ReturnTypeBulkGet<BeatTag>> => {
const tagIdString: string = request.params.tagIds;
const tagIds = tagIdString.split(',').filter((id: string) => id.length > 0);
const tags = await libs.tags.getWithIds(request.user, tagIds);
return {
items: tags,
success: true,
};
},
});

View file

@ -1,37 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as Joi from 'joi';
import { REQUIRED_LICENSES } from '../../../common/constants/security';
import { BeatTag } from '../../../common/domain_types';
import { ReturnTypeList } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
export const createListTagsRoute = (libs: CMServerLibs) => ({
method: 'GET',
path: '/api/beats/tags',
requiredRoles: ['beats_admin'],
licenseRequired: REQUIRED_LICENSES,
validate: {
headers: Joi.object({
'kbn-beats-enrollment-token': Joi.string().required(),
}).options({
allowUnknown: true,
}),
query: Joi.object({
ESQuery: Joi.string(),
}),
},
handler: async (request: FrameworkRequest): Promise<ReturnTypeList<BeatTag>> => {
const tags = await libs.tags.getAll(
request.user,
request.query && request.query.ESQuery ? JSON.parse(request.query.ESQuery) : undefined
);
return { list: tags, success: true, page: -1, total: -1 };
},
});

View file

@ -1,47 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { get } from 'lodash';
import { REQUIRED_LICENSES } from '../../../common/constants';
import { BeatTag } from '../../../common/domain_types';
import { ReturnTypeUpsert } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
// TODO: write to Kibana audit log file
export const createSetTagRoute = (libs: CMServerLibs) => ({
method: 'PUT',
path: '/api/beats/tag/{tagId}',
licenseRequired: REQUIRED_LICENSES,
requiredRoles: ['beats_admin'],
config: {
validate: {
params: Joi.object({
tagId: Joi.string(),
}),
payload: Joi.object({
color: Joi.string(),
name: Joi.string(),
}),
},
},
handler: async (request: FrameworkRequest): Promise<ReturnTypeUpsert<BeatTag>> => {
const defaultConfig = {
id: request.params.tagId,
name: request.params.tagId,
color: '#DD0A73',
hasConfigurationBlocksTypes: [],
};
const config = { ...defaultConfig, ...get(request, 'payload', {}) };
const id = await libs.tags.upsertTag(request.user, config);
const tag = await libs.tags.getWithIds(request.user, [id]);
// TODO the action needs to be surfaced
return { success: true, item: tag[0], action: 'created' };
},
});

View file

@ -1,54 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { get } from 'lodash';
import { REQUIRED_LICENSES } from '../../../common/constants/security';
import { BaseReturnType, ReturnTypeBulkCreate } from '../../../common/return_types';
import { FrameworkRequest } from '../../lib/adapters/framework/adapter_types';
import { CMServerLibs } from '../../lib/types';
// TODO: write to Kibana audit log file
const DEFAULT_NUM_TOKENS = 1;
export const createTokensRoute = (libs: CMServerLibs) => ({
method: 'POST',
path: '/api/beats/enrollment_tokens',
licenseRequired: REQUIRED_LICENSES,
requiredRoles: ['beats_admin'],
config: {
validate: {
payload: Joi.object({
num_tokens: Joi.number().optional().default(DEFAULT_NUM_TOKENS).min(1),
}).allow(null),
},
},
handler: async (
request: FrameworkRequest
): Promise<BaseReturnType | ReturnTypeBulkCreate<string>> => {
const numTokens = get(request, 'payload.num_tokens', DEFAULT_NUM_TOKENS);
try {
const tokens = await libs.tokens.createEnrollmentTokens(request.user, numTokens);
return {
results: tokens.map((token) => ({
item: token,
success: true,
action: 'created',
})),
success: true,
};
} catch (err) {
libs.framework.log(err.message);
return {
error: {
message: 'An error occured, please check your Kibana logs',
code: 500,
},
success: false,
};
}
},
});

View file

@ -1,7 +0,0 @@
{
"extends": "../../../tsconfig.json",
"exclude": ["**/node_modules/**"],
"paths": {
"react": ["../../../node_modules/@types/react"]
}
}

View file

@ -1,5 +1,5 @@
{
"id": "beats_management",
"id": "beatsManagement",
"configPath": ["xpack", "beats_management"],
"ui": true,
"server": true,

View file

@ -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: {

View file

@ -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 */

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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,

View file

@ -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 {

View file

@ -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;

View file

@ -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';

View file

@ -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 {

View file

@ -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 {

View file

@ -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';

View file

@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { CMBeat } from '../../../../../../legacy/plugins/beats_management/common/domain_types';
import { ReturnTypeBulkAction } from '../../../../../../legacy/plugins/beats_management/common/return_types';
import { CMBeat } from '../../../../common/domain_types';
import { ReturnTypeBulkAction } from '../../../../common/return_types';
export interface CMBeatsAdapter {
get(id: string): Promise<CMBeat | null>;

View file

@ -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 {

View file

@ -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) {}

View file

@ -3,11 +3,8 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { ConfigurationBlock } from '../../../../../../legacy/plugins/beats_management/common/domain_types';
import {
ReturnTypeBulkUpsert,
ReturnTypeList,
} from '../../../../../../legacy/plugins/beats_management/common/return_types';
import { ConfigurationBlock } from '../../../../common/domain_types';
import { ReturnTypeBulkUpsert, ReturnTypeList } from '../../../../common/return_types';
export interface FrontendConfigBlocksAdapter {
upsert(blocks: ConfigurationBlock[]): Promise<ReturnTypeBulkUpsert>;

View file

@ -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 {

View file

@ -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';

View file

@ -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 {

View file

@ -3,10 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import {
BeatTag,
CMBeat,
} from '../../../../../../legacy/plugins/beats_management/common/domain_types';
import { BeatTag, CMBeat } from '../../../../common/domain_types';
export interface CMTagsAdapter {
getTagsWithIds(tagIds: string[]): Promise<BeatTag[]>;

View file

@ -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 {

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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 {

View file

@ -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 {

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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 {

View file

@ -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 {

View file

@ -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

View file

@ -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();

View file

@ -6,74 +6,19 @@
/* eslint-disable @typescript-eslint/no-empty-interface */
import { Lifecycle, ResponseToolkit } from 'hapi';
import * as t from 'io-ts';
import { CoreSetup, CoreStart } from 'src/core/server';
import { SecurityPluginSetup } from '../../../../../../../plugins/security/server';
import { LicenseType } from '../../../../common/constants/security';
import { Headers, KibanaRequest } from 'src/core/server';
export const internalAuthData = Symbol('internalAuthData');
export const internalUser: FrameworkInternalUser = {
kind: 'internal',
};
export interface XpackInfo {
license: {
getType: () => LicenseType;
/** Is the license expired */
isActive: () => boolean;
getExpiryDateInMillis: () => number;
};
feature: (pluginId: string) => any;
isAvailable: () => boolean;
}
export interface BackendFrameworkAdapter {
getUser(request: KibanaRequest): FrameworkUser<Headers>;
internalUser: FrameworkInternalUser;
info: null | FrameworkInfo;
log(text: string): void;
on(event: 'xpack.status.green' | 'elasticsearch.status.green', cb: () => void): void;
getSetting(settingPath: string): any;
registerRoute<RouteRequest extends FrameworkRequest, RouteResponse extends FrameworkResponse>(
route: FrameworkRouteOptions<RouteRequest, RouteResponse>
): void;
}
export interface KibanaLegacyServer {
newPlatform: {
setup: {
core: CoreSetup;
plugins: { security: SecurityPluginSetup };
};
start: {
core: CoreStart;
};
};
plugins: {
xpack_main: {
status: {
on: (status: 'green' | 'yellow' | 'red', callback: () => void) => void;
};
info: XpackInfo;
};
kibana: {
status: {
plugin: {
version: string;
};
};
};
elasticsearch: {
status: {
on: (status: 'green' | 'yellow' | 'red', callback: () => void) => void;
};
getCluster: () => any;
};
beats_management: {};
};
config: () => any;
route: (routeConfig: any) => void;
log: (message: string) => void;
}
export const RuntimeFrameworkInfo = t.interface(
@ -167,23 +112,3 @@ export interface FrameworkRequest<
params: KibanaServerRequestGenaric['params'];
query: KibanaServerRequestGenaric['query'];
}
export interface FrameworkRouteOptions<
RouteRequest extends FrameworkRequest = FrameworkRequest,
RouteResponse extends FrameworkResponse = any
> {
path: string;
method: string | string[];
vhost?: string;
licenseRequired?: string[];
requiredRoles?: string[];
handler: FrameworkRouteHandler<RouteRequest, RouteResponse>;
config?: {};
}
export type FrameworkRouteHandler<
RouteRequest extends KibanaServerRequest,
RouteResponse extends FrameworkResponse
> = (request: FrameworkRequest<RouteRequest>, h: ResponseToolkit) => Promise<RouteResponse>;
export type FrameworkResponse = Lifecycle.ReturnValue;

View file

@ -0,0 +1,115 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { PathReporter } from 'io-ts/lib/PathReporter';
import { isLeft } from 'fp-ts/lib/Either';
import { KibanaRequest, Headers, Logger } from 'src/core/server';
import {
BackendFrameworkAdapter,
FrameworkInfo,
FrameworkUser,
internalAuthData,
internalUser,
RuntimeFrameworkInfo,
RuntimeKibanaUser,
} from './adapter_types';
import { BeatsManagementConfigType } from '../../../../common';
import { ILicense, LicensingPluginStart } from '../../../../../licensing/server';
import { SecurityPluginSetup } from '../../../../../security/server';
export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter {
public readonly internalUser = internalUser;
public info: null | FrameworkInfo = null;
constructor(
private readonly PLUGIN_ID: string,
private readonly kibanaVersion: string,
private readonly config: BeatsManagementConfigType,
private readonly logger: Logger,
private readonly licensing: LicensingPluginStart,
private readonly security?: SecurityPluginSetup
) {
this.licensing.license$.subscribe((license) => this.licenseUpdateHandler(license));
}
public log(text: string) {
this.logger.info(text);
}
getUser(request: KibanaRequest): FrameworkUser<Headers> {
const user = this.security?.authc.getCurrentUser(request);
if (!user) {
return {
kind: 'unauthenticated',
};
}
const assertKibanaUser = RuntimeKibanaUser.decode(user);
if (isLeft(assertKibanaUser)) {
throw new Error(
`Error parsing user info in ${this.PLUGIN_ID}, ${
PathReporter.report(assertKibanaUser)[0]
}`
);
}
return {
kind: 'authenticated',
[internalAuthData]: request.headers,
...user,
};
}
private licenseUpdateHandler = (license: ILicense) => {
let xpackInfoUnpacked: FrameworkInfo;
// If, for some reason, we cannot get the license information
// from Elasticsearch, assume worst case and disable
if (!license.isAvailable) {
this.info = null;
return;
}
const securityFeature = license.getFeature('security');
const watcherFeature = license.getFeature('watcher');
try {
xpackInfoUnpacked = {
kibana: {
version: this.kibanaVersion,
},
license: {
type: license.type!,
expired: !license.isActive,
expiry_date_in_millis: license.expiryDateInMillis ?? -1,
},
security: {
enabled: securityFeature.isEnabled,
available: securityFeature.isAvailable,
},
watcher: {
enabled: watcherFeature.isEnabled,
available: watcherFeature.isAvailable,
},
};
} catch (e) {
this.logger.error(`Error accessing required xPackInfo in ${this.PLUGIN_ID} Kibana adapter`);
throw e;
}
const assertData = RuntimeFrameworkInfo.decode(xpackInfoUnpacked);
if (isLeft(assertData)) {
throw new Error(
`Error parsing xpack info in ${this.PLUGIN_ID}, ${PathReporter.report(assertData)[0]}`
);
}
this.info = xpackInfoUnpacked;
return {
security: xpackInfoUnpacked.security,
settings: { ...this.config },
};
};
}

View file

@ -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);

View file

@ -0,0 +1,53 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { Headers, KibanaRequest } from 'kibana/server';
import { BackendFrameworkAdapter, FrameworkUser } from './adapters/framework/adapter_types';
import { BeatsManagementConfigType } from '../../common';
export class BackendFrameworkLib {
public log = this.adapter.log;
public internalUser = this.adapter.internalUser;
constructor(
private readonly adapter: BackendFrameworkAdapter,
private readonly config: BeatsManagementConfigType
) {
this.validateConfig();
}
public getConfig(): BeatsManagementConfigType {
return this.config;
}
public getUser(request: KibanaRequest): FrameworkUser<Headers> {
return this.adapter.getUser(request);
}
/**
* Expired `null` happens when we have no xpack info
*/
public get license() {
return {
type: this.adapter.info ? this.adapter.info.license.type : 'unknown',
expired: this.adapter.info ? this.adapter.info.license.expired : null,
};
}
public get securityIsEnabled() {
return this.adapter.info ? this.adapter.info.security.enabled : false;
}
private validateConfig() {
const encryptionKey = this.config.encryptionKey;
if (!encryptionKey) {
this.adapter.log(
'Using a default encryption key for xpack.beats.encryptionKey. It is recommended that you set xpack.beats.encryptionKey in kibana.yml with a unique token'
);
}
}
}

View file

@ -58,7 +58,7 @@ export class CMTokensDomain {
let expired = false;
if (decode) {
const enrollmentTokenSecret = this.framework.getSetting('encryptionKey');
const enrollmentTokenSecret = this.framework.getConfig().encryptionKey;
try {
verifyToken(recivedToken, enrollmentTokenSecret);
@ -98,7 +98,7 @@ export class CMTokensDomain {
}
public generateAccessToken() {
const enrollmentTokenSecret = this.framework.getSetting('encryptionKey');
const enrollmentTokenSecret = this.framework.getConfig().encryptionKey;
const tokenData = {
created: moment().toJSON(),
@ -113,12 +113,12 @@ export class CMTokensDomain {
numTokens: number = 1
): Promise<string[]> {
const tokens = [];
const enrollmentTokensTtlInSeconds = this.framework.getSetting('enrollmentTokensTtlInSeconds');
const enrollmentTokensTtlInSeconds = this.framework.getConfig().enrollmentTokensTtlInSeconds;
const enrollmentTokenExpiration = moment()
.add(enrollmentTokensTtlInSeconds, 'seconds')
.toJSON();
const enrollmentTokenSecret = this.framework.getSetting('encryptionKey');
const enrollmentTokenSecret = this.framework.getConfig().encryptionKey;
while (tokens.length < numTokens) {
const tokenData = {

Some files were not shown because too many files have changed in this diff Show more