diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/index.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/index.ts index 4f5590938be970..9574c4b5757706 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/index.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/index.ts @@ -14,6 +14,3 @@ export * from './list_asset_criticality.gen'; export * from './create_asset_criticality.gen'; export * from './get_asset_criticality.gen'; export * from './delete_asset_criticality.gen'; -export * from './internal_create_asset_criticality.gen'; -export * from './internal_get_asset_criticality.gen'; -export * from './internal_delete_asset_criticality.gen'; diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_create_asset_criticality.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_create_asset_criticality.gen.ts deleted file mode 100644 index 44ea824720cb62..00000000000000 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_create_asset_criticality.gen.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Internal Asset Criticality Create Record Schema - * version: 1 - */ - -import { z } from 'zod'; - -import { CreateAssetCriticalityRecord, AssetCriticalityRecord } from './common.gen'; - -export type InternalCreateAssetCriticalityRecordRequestBody = z.infer< - typeof InternalCreateAssetCriticalityRecordRequestBody ->; -export const InternalCreateAssetCriticalityRecordRequestBody = CreateAssetCriticalityRecord.merge( - z.object({ - /** - * If 'wait_for' the request will wait for the index refresh. - */ - refresh: z.literal('wait_for').optional(), - }) -); -export type InternalCreateAssetCriticalityRecordRequestBodyInput = z.input< - typeof InternalCreateAssetCriticalityRecordRequestBody ->; - -export type InternalCreateAssetCriticalityRecordResponse = z.infer< - typeof InternalCreateAssetCriticalityRecordResponse ->; -export const InternalCreateAssetCriticalityRecordResponse = AssetCriticalityRecord; diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_create_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_create_asset_criticality.schema.yaml deleted file mode 100644 index 89bf56b71056c4..00000000000000 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_create_asset_criticality.schema.yaml +++ /dev/null @@ -1,35 +0,0 @@ -openapi: 3.0.0 -info: - version: '1' - title: Internal Asset Criticality Create Record Schema -paths: - /internal/asset_criticality: - post: - x-labels: [ess, serverless] - x-internal: true - x-codegen-enabled: true - operationId: InternalCreateAssetCriticalityRecord - summary: Deprecated Internal Create Criticality Record - deprecated: true - requestBody: - required: true - content: - application/json: - schema: - allOf: - - $ref: './common.schema.yaml#/components/schemas/CreateAssetCriticalityRecord' - - type: object - properties: - refresh: - type: string - enum: [wait_for] - description: If 'wait_for' the request will wait for the index refresh. - responses: - '200': - description: Successful response - content: - application/json: - schema: - $ref: './common.schema.yaml#/components/schemas/AssetCriticalityRecord' - '400': - description: Invalid request diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_delete_asset_criticality.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_delete_asset_criticality.gen.ts deleted file mode 100644 index ca5d2b06251c79..00000000000000 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_delete_asset_criticality.gen.ts +++ /dev/null @@ -1,40 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Internal Asset Criticality Delete Record Schema - * version: 1 - */ - -import { z } from 'zod'; - -import { IdField } from './common.gen'; - -export type InternalDeleteAssetCriticalityRecordRequestQuery = z.infer< - typeof InternalDeleteAssetCriticalityRecordRequestQuery ->; -export const InternalDeleteAssetCriticalityRecordRequestQuery = z.object({ - /** - * The ID value of the asset. - */ - id_value: z.string(), - /** - * The field representing the ID. - */ - id_field: IdField, - /** - * If 'wait_for' the request will wait for the index refresh. - */ - refresh: z.literal('wait_for').optional(), -}); -export type InternalDeleteAssetCriticalityRecordRequestQueryInput = z.input< - typeof InternalDeleteAssetCriticalityRecordRequestQuery ->; diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_delete_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_delete_asset_criticality.schema.yaml deleted file mode 100644 index 2fa847315cbdca..00000000000000 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_delete_asset_criticality.schema.yaml +++ /dev/null @@ -1,39 +0,0 @@ -openapi: 3.0.0 -info: - version: '1' - title: Internal Asset Criticality Delete Record Schema -paths: - /internal/asset_criticality: - delete: - x-labels: [ess, serverless] - x-internal: true - x-codegen-enabled: true - operationId: InternalDeleteAssetCriticalityRecord - summary: Deprecated Internal Delete Criticality Record - deprecated: true - parameters: - - name: id_value - in: query - required: true - schema: - type: string - description: The ID value of the asset. - - name: id_field - in: query - required: true - schema: - $ref: './common.schema.yaml#/components/schemas/IdField' - example: 'host.name' - description: The field representing the ID. - - name: refresh - in: query - required: false - schema: - type: string - enum: [wait_for] - description: If 'wait_for' the request will wait for the index refresh. - responses: - '200': - description: Successful response - '400': - description: Invalid request diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_get_asset_criticality.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_get_asset_criticality.gen.ts deleted file mode 100644 index 1edf38c55ee0d3..00000000000000 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_get_asset_criticality.gen.ts +++ /dev/null @@ -1,41 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Internal Asset Criticality Get Record Schema - * version: 1 - */ - -import { z } from 'zod'; - -import { IdField, AssetCriticalityRecord } from './common.gen'; - -export type InternalGetAssetCriticalityRecordRequestQuery = z.infer< - typeof InternalGetAssetCriticalityRecordRequestQuery ->; -export const InternalGetAssetCriticalityRecordRequestQuery = z.object({ - /** - * The ID value of the asset. - */ - id_value: z.string(), - /** - * The field representing the ID. - */ - id_field: IdField, -}); -export type InternalGetAssetCriticalityRecordRequestQueryInput = z.input< - typeof InternalGetAssetCriticalityRecordRequestQuery ->; - -export type InternalGetAssetCriticalityRecordResponse = z.infer< - typeof InternalGetAssetCriticalityRecordResponse ->; -export const InternalGetAssetCriticalityRecordResponse = AssetCriticalityRecord; diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_get_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_get_asset_criticality.schema.yaml deleted file mode 100644 index d528fc391d6844..00000000000000 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/internal_get_asset_criticality.schema.yaml +++ /dev/null @@ -1,38 +0,0 @@ -openapi: 3.0.0 -info: - version: '1' - title: Internal Asset Criticality Get Record Schema -paths: - /internal/asset_criticality: - get: - x-labels: [ess, serverless] - x-internal: true - x-codegen-enabled: true - operationId: InternalGetAssetCriticalityRecord - summary: Deprecated Internal Get Criticality Record - deprecated: true - parameters: - - name: id_value - in: query - required: true - schema: - type: string - description: The ID value of the asset. - - name: id_field - in: query - required: true - schema: - $ref: './common.schema.yaml#/components/schemas/IdField' - example: 'host.name' - description: The field representing the ID. - responses: - '200': - description: Successful response - content: - application/json: - schema: - $ref: './common.schema.yaml#/components/schemas/AssetCriticalityRecord' - '400': - description: Invalid request - '404': - description: Criticality record not found diff --git a/x-pack/plugins/security_solution/common/entity_analytics/asset_criticality/constants.ts b/x-pack/plugins/security_solution/common/entity_analytics/asset_criticality/constants.ts index 2abc0120df67c3..d089a52f4cc300 100644 --- a/x-pack/plugins/security_solution/common/entity_analytics/asset_criticality/constants.ts +++ b/x-pack/plugins/security_solution/common/entity_analytics/asset_criticality/constants.ts @@ -5,13 +5,11 @@ * 2.0. */ -export const ASSET_CRITICALITY_INTERNAL_URL = `/internal/asset_criticality` as const; +const ASSET_CRITICALITY_INTERNAL_URL = `/internal/asset_criticality` as const; export const ASSET_CRITICALITY_INTERNAL_PRIVILEGES_URL = `${ASSET_CRITICALITY_INTERNAL_URL}/privileges` as const; export const ASSET_CRITICALITY_INTERNAL_STATUS_URL = `${ASSET_CRITICALITY_INTERNAL_URL}/status` as const; -export const ASSET_CRITICALITY_INTERNAL_CSV_UPLOAD_URL = - `${ASSET_CRITICALITY_INTERNAL_URL}/upload_csv` as const; export const ASSET_CRITICALITY_PUBLIC_URL = `/api/asset_criticality` as const; export const ASSET_CRITICALITY_PUBLIC_CSV_UPLOAD_URL = diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts index 6fb6ef7488b271..4da6d719e701eb 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts @@ -4,18 +4,13 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server'; +import type { Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; -import { - DeleteAssetCriticalityRecordRequestQuery, - InternalDeleteAssetCriticalityRecordRequestQuery, -} from '../../../../../common/api/entity_analytics'; -import type { SecuritySolutionRequestHandlerContext } from '../../../../types'; +import { DeleteAssetCriticalityRecordRequestQuery } from '../../../../../common/api/entity_analytics'; import { ASSET_CRITICALITY_PUBLIC_URL, - ASSET_CRITICALITY_INTERNAL_URL, APP_ID, ENABLE_ASSET_CRITICALITY_SETTING, API_VERSIONS, @@ -26,79 +21,6 @@ import type { EntityAnalyticsRoutesDeps } from '../../types'; import { AssetCriticalityAuditActions } from '../audit'; import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../../audit'; -type DeleteHandler = ( - context: SecuritySolutionRequestHandlerContext, - request: { - query: DeleteAssetCriticalityRecordRequestQuery; - }, - response: KibanaResponseFactory -) => Promise; - -const handler: (logger: Logger) => DeleteHandler = - (logger) => async (context, request, response) => { - const securitySolution = await context.securitySolution; - - securitySolution.getAuditLogger()?.log({ - message: 'User attempted to un-assign asset criticality from an entity', - event: { - action: AssetCriticalityAuditActions.ASSET_CRITICALITY_UNASSIGN, - category: AUDIT_CATEGORY.DATABASE, - type: AUDIT_TYPE.DELETION, - outcome: AUDIT_OUTCOME.UNKNOWN, - }, - }); - - const siemResponse = buildSiemResponse(response); - try { - await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); - await checkAndInitAssetCriticalityResources(context, logger); - - const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); - await assetCriticalityClient.delete( - { - idField: request.query.id_field, - idValue: request.query.id_value, - }, - request.query.refresh - ); - - return response.ok(); - } catch (e) { - const error = transformError(e); - - return siemResponse.error({ - statusCode: error.statusCode, - body: { message: error.message, full_error: JSON.stringify(e) }, - bypassErrorFormat: true, - }); - } - }; - -export const assetCriticalityInternalDeleteRoute = ( - router: EntityAnalyticsRoutesDeps['router'], - logger: Logger -) => { - router.versioned - .delete({ - access: 'internal', - path: ASSET_CRITICALITY_INTERNAL_URL, - options: { - tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], - }, - }) - .addVersion( - { - version: API_VERSIONS.internal.v1, - validate: { - request: { - query: buildRouteValidationWithZod(InternalDeleteAssetCriticalityRecordRequestQuery), - }, - }, - }, - handler(logger) - ); -}; - export const assetCriticalityPublicDeleteRoute = ( router: EntityAnalyticsRoutesDeps['router'], logger: Logger @@ -120,6 +42,43 @@ export const assetCriticalityPublicDeleteRoute = ( }, }, }, - handler(logger) + async (context, request, response) => { + const securitySolution = await context.securitySolution; + + securitySolution.getAuditLogger()?.log({ + message: 'User attempted to un-assign asset criticality from an entity', + event: { + action: AssetCriticalityAuditActions.ASSET_CRITICALITY_UNASSIGN, + category: AUDIT_CATEGORY.DATABASE, + type: AUDIT_TYPE.DELETION, + outcome: AUDIT_OUTCOME.UNKNOWN, + }, + }); + + const siemResponse = buildSiemResponse(response); + try { + await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); + await checkAndInitAssetCriticalityResources(context, logger); + + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + await assetCriticalityClient.delete( + { + idField: request.query.id_field, + idValue: request.query.id_value, + }, + request.query.refresh + ); + + return response.ok(); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } + } ); }; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts index 9e5203bd24741a..99f7d3ff97ae44 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts @@ -4,14 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server'; +import type { Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { GetAssetCriticalityRecordRequestQuery } from '../../../../../common/api/entity_analytics'; -import type { SecuritySolutionRequestHandlerContext } from '../../../../types'; import { - ASSET_CRITICALITY_INTERNAL_URL, ASSET_CRITICALITY_PUBLIC_URL, APP_ID, ENABLE_ASSET_CRITICALITY_SETTING, @@ -22,77 +20,6 @@ import { assertAdvancedSettingsEnabled } from '../../utils/assert_advanced_setti import type { EntityAnalyticsRoutesDeps } from '../../types'; import { AssetCriticalityAuditActions } from '../audit'; import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../../audit'; -type GetHandler = ( - context: SecuritySolutionRequestHandlerContext, - request: { - query: GetAssetCriticalityRecordRequestQuery; - }, - response: KibanaResponseFactory -) => Promise; - -const handler: (logger: Logger) => GetHandler = (logger) => async (context, request, response) => { - const siemResponse = buildSiemResponse(response); - try { - await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); - await checkAndInitAssetCriticalityResources(context, logger); - - const securitySolution = await context.securitySolution; - const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); - const record = await assetCriticalityClient.get({ - idField: request.query.id_field, - idValue: request.query.id_value, - }); - - if (!record) { - return response.notFound(); - } - - securitySolution.getAuditLogger()?.log({ - message: 'User accessed the criticality level for an entity', - event: { - action: AssetCriticalityAuditActions.ASSET_CRITICALITY_GET, - category: AUDIT_CATEGORY.DATABASE, - type: AUDIT_TYPE.ACCESS, - outcome: AUDIT_OUTCOME.SUCCESS, - }, - }); - - return response.ok({ body: record }); - } catch (e) { - const error = transformError(e); - - return siemResponse.error({ - statusCode: error.statusCode, - body: { message: error.message, full_error: JSON.stringify(e) }, - bypassErrorFormat: true, - }); - } -}; - -export const assetCriticalityInternalGetRoute = ( - router: EntityAnalyticsRoutesDeps['router'], - logger: Logger -) => { - router.versioned - .get({ - access: 'internal', - path: ASSET_CRITICALITY_INTERNAL_URL, - options: { - tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], - }, - }) - .addVersion( - { - version: API_VERSIONS.internal.v1, - validate: { - request: { - query: buildRouteValidationWithZod(GetAssetCriticalityRecordRequestQuery), - }, - }, - }, - handler(logger) - ); -}; export const assetCriticalityPublicGetRoute = ( router: EntityAnalyticsRoutesDeps['router'], @@ -115,6 +42,43 @@ export const assetCriticalityPublicGetRoute = ( }, }, }, - handler(logger) + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + try { + await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); + await checkAndInitAssetCriticalityResources(context, logger); + + const securitySolution = await context.securitySolution; + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + const record = await assetCriticalityClient.get({ + idField: request.query.id_field, + idValue: request.query.id_value, + }); + + if (!record) { + return response.notFound(); + } + + securitySolution.getAuditLogger()?.log({ + message: 'User accessed the criticality level for an entity', + event: { + action: AssetCriticalityAuditActions.ASSET_CRITICALITY_GET, + category: AUDIT_CATEGORY.DATABASE, + type: AUDIT_TYPE.ACCESS, + outcome: AUDIT_OUTCOME.SUCCESS, + }, + }); + + return response.ok({ body: record }); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } + } ); }; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/register_asset_criticality_routes.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/register_asset_criticality_routes.ts index 07899be6b91758..c7134ee0eafb6d 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/register_asset_criticality_routes.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/register_asset_criticality_routes.ts @@ -5,14 +5,11 @@ * 2.0. */ import { assetCriticalityInternalStatusRoute } from './status'; -import { assetCriticalityPublicUpsertRoute, assetCriticalityInternalUpsertRoute } from './upsert'; -import { assetCriticalityInternalGetRoute, assetCriticalityPublicGetRoute } from './get'; -import { assetCriticalityPublicDeleteRoute, assetCriticalityInternalDeleteRoute } from './delete'; +import { assetCriticalityPublicUpsertRoute } from './upsert'; +import { assetCriticalityPublicGetRoute } from './get'; +import { assetCriticalityPublicDeleteRoute } from './delete'; import { assetCriticalityInternalPrivilegesRoute } from './privileges'; -import { - assetCriticalityInternalCSVUploadRoute, - assetCriticalityPublicCSVUploadRoute, -} from './upload_csv'; +import { assetCriticalityPublicCSVUploadRoute } from './upload_csv'; import { assetCriticalityPublicListRoute } from './list'; import type { EntityAnalyticsRoutesDeps } from '../../types'; import { assetCriticalityPublicBulkUploadRoute } from './bulk_upload'; @@ -24,13 +21,8 @@ export const registerAssetCriticalityRoutes = ({ getStartServices, }: EntityAnalyticsRoutesDeps) => { // Internal routes - assetCriticalityInternalCSVUploadRoute(router, logger, config, getStartServices); - assetCriticalityInternalDeleteRoute(router, logger); - assetCriticalityInternalGetRoute(router, logger); assetCriticalityInternalPrivilegesRoute(router, logger, getStartServices); assetCriticalityInternalStatusRoute(router, logger); - assetCriticalityInternalUpsertRoute(router, logger); - // Public routes assetCriticalityPublicCSVUploadRoute(router, logger, config, getStartServices); assetCriticalityPublicBulkUploadRoute(router, logger, config); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts index 98d9ae6c75a968..6f69695f20a74e 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts @@ -4,18 +4,16 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server'; +import type { Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { schema } from '@kbn/config-schema'; import Papa from 'papaparse'; import { transformError } from '@kbn/securitysolution-es-utils'; -import type internal from 'stream'; import type { UploadAssetCriticalityRecordsResponse } from '../../../../../common/api/entity_analytics'; import { CRITICALITY_CSV_MAX_SIZE_BYTES_WITH_TOLERANCE } from '../../../../../common/entity_analytics/asset_criticality'; import type { ConfigType } from '../../../../config'; -import type { HapiReadableStream, SecuritySolutionRequestHandlerContext } from '../../../../types'; +import type { HapiReadableStream } from '../../../../types'; import { - ASSET_CRITICALITY_INTERNAL_CSV_UPLOAD_URL, ASSET_CRITICALITY_PUBLIC_CSV_UPLOAD_URL, APP_ID, ENABLE_ASSET_CRITICALITY_SETTING, @@ -29,135 +27,6 @@ import type { EntityAnalyticsRoutesDeps } from '../../types'; import { AssetCriticalityAuditActions } from '../audit'; import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../../audit'; -type CSVUploadHandler = ( - context: SecuritySolutionRequestHandlerContext, - request: { - body: { file: internal.Stream }; - }, - response: KibanaResponseFactory -) => Promise; - -const handler: ( - logger: Logger, - getStartServices: EntityAnalyticsRoutesDeps['getStartServices'], - config: ConfigType -) => CSVUploadHandler = - (logger, getStartServices, config) => async (context, request, response) => { - const { errorRetries, maxBulkRequestBodySizeBytes } = - config.entityAnalytics.assetCriticality.csvUpload; - - const securitySolution = await context.securitySolution; - securitySolution.getAuditLogger()?.log({ - message: 'User attempted to assign many asset criticalities via file upload', - event: { - action: AssetCriticalityAuditActions.ASSET_CRITICALITY_BULK_UPDATE, - category: AUDIT_CATEGORY.DATABASE, - type: AUDIT_TYPE.CREATION, - outcome: AUDIT_OUTCOME.UNKNOWN, - }, - }); - - const start = new Date(); - const siemResponse = buildSiemResponse(response); - const [coreStart] = await getStartServices(); - const telemetry = coreStart.analytics; - - try { - await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); - await checkAndInitAssetCriticalityResources(context, logger); - const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); - const fileStream = request.body.file as HapiReadableStream; - - logger.debug(`Parsing asset criticality CSV file ${fileStream.hapi.filename}`); - - const csvStream = Papa.parse(Papa.NODE_STREAM_INPUT, { - header: false, - dynamicTyping: true, - skipEmptyLines: true, - }); - - const recordsStream = fileStream.pipe(csvStream).pipe(transformCSVToUpsertRecords()); - - const { errors, stats } = await assetCriticalityClient.bulkUpsertFromStream({ - recordsStream, - retries: errorRetries, - flushBytes: maxBulkRequestBodySizeBytes, - }); - const end = new Date(); - - const tookMs = end.getTime() - start.getTime(); - logger.debug( - () => `Asset criticality CSV upload completed in ${tookMs}ms ${JSON.stringify(stats)}` - ); - - // type assignment here to ensure that the response body stays in sync with the API schema - const resBody: UploadAssetCriticalityRecordsResponse = { errors, stats }; - - const [eventType, event] = createAssetCriticalityProcessedFileEvent({ - startTime: start, - endTime: end, - result: stats, - }); - - telemetry.reportEvent(eventType, event); - - return response.ok({ body: resBody }); - } catch (e) { - logger.error(`Error during asset criticality csv upload: ${e}`); - try { - const end = new Date(); - - const [eventType, event] = createAssetCriticalityProcessedFileEvent({ - startTime: start, - endTime: end, - }); - - telemetry.reportEvent(eventType, event); - } catch (error) { - logger.error(`Error reporting telemetry event: ${error}`); - } - - const error = transformError(e); - return siemResponse.error({ - statusCode: error.statusCode, - body: error.message, - }); - } - }; - -export const assetCriticalityInternalCSVUploadRoute = ( - router: EntityAnalyticsRoutesDeps['router'], - logger: Logger, - config: ConfigType, - getStartServices: EntityAnalyticsRoutesDeps['getStartServices'] -) => { - router.versioned - .post({ - access: 'internal', - path: ASSET_CRITICALITY_INTERNAL_CSV_UPLOAD_URL, - options: { - tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], - body: { - output: 'stream', - accepts: 'multipart/form-data', - maxBytes: CRITICALITY_CSV_MAX_SIZE_BYTES_WITH_TOLERANCE, - }, - }, - }) - .addVersion( - { - version: API_VERSIONS.internal.v1, - validate: { - request: { - body: schema.object({ - file: schema.stream(), - }), - }, - }, - }, - handler(logger, getStartServices, config) - ); -}; export const assetCriticalityPublicCSVUploadRoute = ( router: EntityAnalyticsRoutesDeps['router'], logger: Logger, @@ -188,6 +57,87 @@ export const assetCriticalityPublicCSVUploadRoute = ( }, }, }, - handler(logger, getStartServices, config) + async (context, request, response) => { + const { errorRetries, maxBulkRequestBodySizeBytes } = + config.entityAnalytics.assetCriticality.csvUpload; + + const securitySolution = await context.securitySolution; + securitySolution.getAuditLogger()?.log({ + message: 'User attempted to assign many asset criticalities via file upload', + event: { + action: AssetCriticalityAuditActions.ASSET_CRITICALITY_BULK_UPDATE, + category: AUDIT_CATEGORY.DATABASE, + type: AUDIT_TYPE.CREATION, + outcome: AUDIT_OUTCOME.UNKNOWN, + }, + }); + + const start = new Date(); + const siemResponse = buildSiemResponse(response); + const [coreStart] = await getStartServices(); + const telemetry = coreStart.analytics; + + try { + await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); + await checkAndInitAssetCriticalityResources(context, logger); + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + const fileStream = request.body.file as HapiReadableStream; + + logger.debug(`Parsing asset criticality CSV file ${fileStream.hapi.filename}`); + + const csvStream = Papa.parse(Papa.NODE_STREAM_INPUT, { + header: false, + dynamicTyping: true, + skipEmptyLines: true, + }); + + const recordsStream = fileStream.pipe(csvStream).pipe(transformCSVToUpsertRecords()); + + const { errors, stats } = await assetCriticalityClient.bulkUpsertFromStream({ + recordsStream, + retries: errorRetries, + flushBytes: maxBulkRequestBodySizeBytes, + }); + const end = new Date(); + + const tookMs = end.getTime() - start.getTime(); + logger.debug( + () => `Asset criticality CSV upload completed in ${tookMs}ms ${JSON.stringify(stats)}` + ); + + // type assignment here to ensure that the response body stays in sync with the API schema + const resBody: UploadAssetCriticalityRecordsResponse = { errors, stats }; + + const [eventType, event] = createAssetCriticalityProcessedFileEvent({ + startTime: start, + endTime: end, + result: stats, + }); + + telemetry.reportEvent(eventType, event); + + return response.ok({ body: resBody }); + } catch (e) { + logger.error(`Error during asset criticality csv upload: ${e}`); + try { + const end = new Date(); + + const [eventType, event] = createAssetCriticalityProcessedFileEvent({ + startTime: start, + endTime: end, + }); + + telemetry.reportEvent(eventType, event); + } catch (error) { + logger.error(`Error reporting telemetry event: ${error}`); + } + + const error = transformError(e); + return siemResponse.error({ + statusCode: error.statusCode, + body: error.message, + }); + } + } ); }; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts index 59da04beff8553..02ff12b1b91d3b 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts @@ -4,18 +4,13 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server'; +import type { Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; -import { - CreateAssetCriticalityRecordRequestBody, - InternalCreateAssetCriticalityRecordRequestBody, -} from '../../../../../common/api/entity_analytics'; -import type { SecuritySolutionRequestHandlerContext } from '../../../../types'; +import { CreateAssetCriticalityRecordRequestBody } from '../../../../../common/api/entity_analytics'; import { ASSET_CRITICALITY_PUBLIC_URL, - ASSET_CRITICALITY_INTERNAL_URL, APP_ID, ENABLE_ASSET_CRITICALITY_SETTING, API_VERSIONS, @@ -26,84 +21,6 @@ import { AssetCriticalityAuditActions } from '../audit'; import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../../audit'; import { assertAdvancedSettingsEnabled } from '../../utils/assert_advanced_setting_enabled'; -type UpsertHandler = ( - context: SecuritySolutionRequestHandlerContext, - request: { - body: CreateAssetCriticalityRecordRequestBody; - }, - response: KibanaResponseFactory -) => Promise; - -const handler: (logger: Logger) => UpsertHandler = - (logger) => async (context, request, response) => { - const siemResponse = buildSiemResponse(response); - try { - await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); - await checkAndInitAssetCriticalityResources(context, logger); - - const securitySolution = await context.securitySolution; - const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); - - const assetCriticalityRecord = { - idField: request.body.id_field, - idValue: request.body.id_value, - criticalityLevel: request.body.criticality_level, - }; - - const result = await assetCriticalityClient.upsert( - assetCriticalityRecord, - request.body.refresh - ); - - securitySolution.getAuditLogger()?.log({ - message: 'User attempted to assign the asset criticality level for an entity', - event: { - action: AssetCriticalityAuditActions.ASSET_CRITICALITY_UPDATE, - category: AUDIT_CATEGORY.DATABASE, - type: AUDIT_TYPE.CREATION, - outcome: AUDIT_OUTCOME.UNKNOWN, - }, - }); - - return response.ok({ - body: result, - }); - } catch (e) { - const error = transformError(e); - - return siemResponse.error({ - statusCode: error.statusCode, - body: { message: error.message, full_error: JSON.stringify(e) }, - bypassErrorFormat: true, - }); - } - }; - -export const assetCriticalityInternalUpsertRoute = ( - router: EntityAnalyticsRoutesDeps['router'], - logger: Logger -) => { - router.versioned - .post({ - access: 'internal', - path: ASSET_CRITICALITY_INTERNAL_URL, - options: { - tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], - }, - }) - .addVersion( - { - version: API_VERSIONS.internal.v1, - validate: { - request: { - body: buildRouteValidationWithZod(InternalCreateAssetCriticalityRecordRequestBody), - }, - }, - }, - handler(logger) - ); -}; - export const assetCriticalityPublicUpsertRoute = ( router: EntityAnalyticsRoutesDeps['router'], logger: Logger @@ -125,6 +42,48 @@ export const assetCriticalityPublicUpsertRoute = ( }, }, }, - handler(logger) + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + try { + await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); + await checkAndInitAssetCriticalityResources(context, logger); + + const securitySolution = await context.securitySolution; + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + + const assetCriticalityRecord = { + idField: request.body.id_field, + idValue: request.body.id_value, + criticalityLevel: request.body.criticality_level, + }; + + const result = await assetCriticalityClient.upsert( + assetCriticalityRecord, + request.body.refresh + ); + + securitySolution.getAuditLogger()?.log({ + message: 'User attempted to assign the asset criticality level for an entity', + event: { + action: AssetCriticalityAuditActions.ASSET_CRITICALITY_UPDATE, + category: AUDIT_CATEGORY.DATABASE, + type: AUDIT_TYPE.CREATION, + outcome: AUDIT_OUTCOME.UNKNOWN, + }, + }); + + return response.ok({ + body: result, + }); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } + } ); }; diff --git a/x-pack/test/api_integration/services/security_solution_api.gen.ts b/x-pack/test/api_integration/services/security_solution_api.gen.ts index c4f914183b2eb9..3877bb3faa6dd1 100644 --- a/x-pack/test/api_integration/services/security_solution_api.gen.ts +++ b/x-pack/test/api_integration/services/security_solution_api.gen.ts @@ -78,9 +78,6 @@ import { GetTimelinesRequestQueryInput } from '@kbn/security-solution-plugin/com import { ImportRulesRequestQueryInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/import_rules/import_rules_route.gen'; import { ImportTimelinesRequestBodyInput } from '@kbn/security-solution-plugin/common/api/timeline/import_timelines/import_timelines_route.gen'; import { InstallPrepackedTimelinesRequestBodyInput } from '@kbn/security-solution-plugin/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.gen'; -import { InternalCreateAssetCriticalityRecordRequestBodyInput } from '@kbn/security-solution-plugin/common/api/entity_analytics/asset_criticality/internal_create_asset_criticality.gen'; -import { InternalDeleteAssetCriticalityRecordRequestQueryInput } from '@kbn/security-solution-plugin/common/api/entity_analytics/asset_criticality/internal_delete_asset_criticality.gen'; -import { InternalGetAssetCriticalityRecordRequestQueryInput } from '@kbn/security-solution-plugin/common/api/entity_analytics/asset_criticality/internal_get_asset_criticality.gen'; import { ManageAlertTagsRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.gen'; import { PatchRuleRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.gen'; import { PatchTimelineRequestBodyInput } from '@kbn/security-solution-plugin/common/api/timeline/patch_timelines/patch_timeline_route.gen'; @@ -607,30 +604,6 @@ detection engine rules. .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(props.body as object); }, - internalCreateAssetCriticalityRecord(props: InternalCreateAssetCriticalityRecordProps) { - return supertest - .post('/internal/asset_criticality') - .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send(props.body as object); - }, - internalDeleteAssetCriticalityRecord(props: InternalDeleteAssetCriticalityRecordProps) { - return supertest - .delete('/internal/asset_criticality') - .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .query(props.query); - }, - internalGetAssetCriticalityRecord(props: InternalGetAssetCriticalityRecordProps) { - return supertest - .get('/internal/asset_criticality') - .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .query(props.query); - }, internalUploadAssetCriticalityRecords() { return supertest .post('/internal/asset_criticality/upload_csv') @@ -973,15 +946,6 @@ export interface ImportTimelinesProps { export interface InstallPrepackedTimelinesProps { body: InstallPrepackedTimelinesRequestBodyInput; } -export interface InternalCreateAssetCriticalityRecordProps { - body: InternalCreateAssetCriticalityRecordRequestBodyInput; -} -export interface InternalDeleteAssetCriticalityRecordProps { - query: InternalDeleteAssetCriticalityRecordRequestQueryInput; -} -export interface InternalGetAssetCriticalityRecordProps { - query: InternalGetAssetCriticalityRecordRequestQueryInput; -} export interface ManageAlertTagsProps { body: ManageAlertTagsRequestBodyInput; }