[Rule Migration] Add audit logging for SIEM Migration tasks. (#207831)

## Summary

Adds audit logging for successful calls to these API routes:
- Start/Stop migration
- Create migration
- Update Rule
- Install Rule
- Retrieve migration results.
- Uploaded Macro/Lookup
- Retrieved Macro/Lookup

Tested it manually by going through the workflow with audit logging
enabled:

Enable:
`xpack.security.audit.enabled: true`

Results:
```
{"event":{"action":"siem_migration_created","category":["database"],"type":["creation"],"outcome":"success"},"user":{"name":"elastic","roles":["superuser"]},"kibana":{"space_id":"default"},"trace":{"id":"00885dd4-7fd9-45fe-9a0b-2173adcac4ad"},"client":{"ip":"127.0.0.1"},"service":{"node":{"roles":["background_tasks","ui"]}},"ecs":{"version":"8.11.0"},"@timestamp":"2025-01-22T15:05:12.875+01:00","message":"User created a new SIEM migration with [id=cd9552ce-05c8-4893-b659-b5a5ed9325d9","log":{"level":"INFO","logger":"plugins.security.audit.ecs"},"process":{"pid":91324,"uptime":540.063456227},"transaction":{"id":"ee4606116856393c"}}
{"event":{"action":"siem_migration_started","category":["database"],"type":["start"],"outcome":"success"},"user":{"name":"elastic","roles":["superuser"]},"kibana":{"space_id":"default"},"trace":{"id":"e852b328-9e53-4c4d-b8ca-b8fa2b76383d"},"client":{"ip":"127.0.0.1"},"service":{"node":{"roles":["background_tasks","ui"]}},"ecs":{"version":"8.11.0"},"@timestamp":"2025-01-22T15:11:36.569+01:00","message":"User started an existing SIEM migration with [id=3805f79e-123c-4962-b22b-8ddf365cdd89]","log":{"level":"INFO","logger":"plugins.security.audit.ecs"},"process":{"pid":5438,"uptime":62.828177986},"transaction":{"id":"0ac652c8f722f1c4"}}
{"event":{"action":"siem_migration_stopped","category":["database"],"type":["end"],"outcome":"success"},"user":{"name":"elastic","roles":["superuser"]},"kibana":{"space_id":"default"},"trace":{"id":"136f3a38-d47d-455d-bca2-aaf38559b20a"},"client":{"ip":"127.0.0.1"},"service":{"node":{"roles":["background_tasks","ui"]}},"ecs":{"version":"8.11.0"},"@timestamp":"2025-01-22T15:11:05.871+01:00","message":"User stopped an existing SIEM migration with [id=3805f79e-123c-4962-b22b-8ddf365cdd89]","log":{"level":"INFO","logger":"plugins.security.audit.ecs"},"process":{"pid":5438,"uptime":32.12840553},"transaction":{"id":"be379686654f4bdf"}}
{"event":{"action":"siem_migration_updated_rule","category":["database"],"type":["change"],"outcome":"success"},"user":{"id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0","name":"elastic","roles":["superuser"]},"kibana":{"space_id":"default","session_id":"IPgQ3+R8DW9uxx4RQqUx9eZj+D5Es7SGQdcDoM/02l4="},"trace":{"id":"368b31e7-812d-464b-83d8-0e635c7fe5ed"},"client":{"ip":"127.0.0.1"},"service":{"node":{"roles":["background_tasks","ui"]}},"ecs":{"version":"8.11.0"},"@timestamp":"2025-01-22T15:13:15.827+01:00","message":"User updated a translated detection rule with [id=29pWjpQB_LGnD_bEV66u]","log":{"level":"INFO","logger":"plugins.security.audit.ecs"},"process":{"pid":5438,"uptime":162.09338085},"transaction":{"id":"404b3cb31be3c94f"}}
{"event":{"action":"siem_migration_installed_rule","category":["database"],"type":["creation"],"outcome":"success"},"user":{"id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0","name":"elastic","roles":["superuser"]},"kibana":{"space_id":"default","session_id":"IPgQ3+R8DW9uxx4RQqUx9eZj+D5Es7SGQdcDoM/02l4="},"trace":{"id":"d90396dc-a0d3-4308-b07e-54761b562803"},"client":{"ip":"127.0.0.1"},"service":{"node":{"roles":["background_tasks","ui"]}},"ecs":{"version":"8.11.0"},"@timestamp":"2025-01-22T15:13:46.709+01:00","message":"User installed a new detection rule through SIEM migration with [id=3805f79e-123c-4962-b22b-8ddf365cdd89]","log":{"level":"INFO","logger":"plugins.security.audit.ecs"},"process":{"pid":5438,"uptime":192.977728866},"transaction":{"id":"4b17bafb9fbf48a4"}}
{"event":{"action":"siem_migration_uploaded_macro","category":["database"],"type":["creation"],"outcome":"success"},"user":{"name":"elastic","roles":["superuser"]},"kibana":{"space_id":"default"},"trace":{"id":"e5fcb9cc-9d27-41cf-a171-13b9faf6078e"},"client":{"ip":"127.0.0.1"},"service":{"node":{"roles":["background_tasks","ui"]}},"ecs":{"version":"8.11.0"},"@timestamp":"2025-01-23T13:45:18.639+01:00","message":"User uploaded a new macro through SIEM migration with [id=2fc199ef-5bc7-4d87-a349-baeaea662273]","log":{"level":"INFO","logger":"plugins.security.audit.ecs"},"process":{"pid":89625,"uptime":106.911700803},"transaction":{"id":"fc95c131e86b0284"}}
```
This commit is contained in:
Marius Iversen 2025-02-05 14:43:13 +01:00 committed by GitHub
parent aa4ce832f8
commit 06f3c30f60
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 285 additions and 17 deletions

View file

@ -8,15 +8,16 @@
import type { IKibanaResponse, Logger } from '@kbn/core/server';
import { buildRouteValidationWithZod } from '@kbn/zod-helpers';
import { v4 as uuidV4 } from 'uuid';
import { ResourceIdentifier } from '../../../../../common/siem_migrations/rules/resources';
import { SIEM_RULE_MIGRATION_CREATE_PATH } from '../../../../../common/siem_migrations/constants';
import {
CreateRuleMigrationRequestBody,
CreateRuleMigrationRequestParams,
type CreateRuleMigrationResponse,
} from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import { ResourceIdentifier } from '../../../../../common/siem_migrations/rules/resources';
import type { SecuritySolutionPluginRouter } from '../../../../types';
import type { CreateRuleMigrationInput } from '../data/rule_migrations_data_rules_client';
import { SiemMigrationAuditLogger, SiemMigrationsAuditActions } from './util/audit';
import { withLicense } from './util/with_license';
export const registerSiemRuleMigrationsCreateRoute = (
@ -43,6 +44,7 @@ export const registerSiemRuleMigrationsCreateRoute = (
async (context, req, res): Promise<IKibanaResponse<CreateRuleMigrationResponse>> => {
const originalRules = req.body;
const migrationId = req.params.migration_id ?? uuidV4();
let siemMigrationAuditLogger: SiemMigrationAuditLogger | undefined;
try {
const [firstOriginalRule] = originalRules;
if (!firstOriginalRule) {
@ -51,7 +53,14 @@ export const registerSiemRuleMigrationsCreateRoute = (
const ctx = await context.resolve(['securitySolution']);
const ruleMigrationsClient = ctx.securitySolution.getSiemRuleMigrationsClient();
const auditLogger = ctx.securitySolution.getAuditLogger();
if (auditLogger) {
siemMigrationAuditLogger = new SiemMigrationAuditLogger(auditLogger);
}
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_CREATED,
id: migrationId,
});
const ruleMigrations = originalRules.map<CreateRuleMigrationInput>((originalRule) => ({
migration_id: migrationId,
original_rule: originalRule,
@ -72,6 +81,11 @@ export const registerSiemRuleMigrationsCreateRoute = (
return res.ok({ body: { migration_id: migrationId } });
} catch (err) {
logger.error(err);
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_CREATED,
error: err,
id: migrationId,
});
return res.badRequest({ body: err.message });
}
}

View file

@ -7,14 +7,15 @@
import type { IKibanaResponse, Logger } from '@kbn/core/server';
import { buildRouteValidationWithZod } from '@kbn/zod-helpers';
import { SIEM_RULE_MIGRATION_PATH } from '../../../../../common/siem_migrations/constants';
import {
GetRuleMigrationRequestParams,
GetRuleMigrationRequestQuery,
type GetRuleMigrationResponse,
} from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import { SIEM_RULE_MIGRATION_PATH } from '../../../../../common/siem_migrations/constants';
import type { SecuritySolutionPluginRouter } from '../../../../types';
import type { RuleMigrationGetOptions } from '../data/rule_migrations_data_rules_client';
import { SiemMigrationAuditLogger, SiemMigrationsAuditActions } from './util/audit';
import { withLicense } from './util/with_license';
export const registerSiemRuleMigrationsGetRoute = (
@ -53,8 +54,13 @@ export const registerSiemRuleMigrationsGetRoute = (
is_untranslatable: isUntranslatable,
is_failed: isFailed,
} = req.query;
let siemMigrationAuditLogger: SiemMigrationAuditLogger | undefined;
try {
const ctx = await context.resolve(['securitySolution']);
const auditLogger = ctx.securitySolution.getAuditLogger();
if (auditLogger) {
siemMigrationAuditLogger = new SiemMigrationAuditLogger(auditLogger);
}
const ruleMigrationsClient = ctx.securitySolution.getSiemRuleMigrationsClient();
const options: RuleMigrationGetOptions = {
@ -75,9 +81,18 @@ export const registerSiemRuleMigrationsGetRoute = (
const result = await ruleMigrationsClient.data.rules.get(migrationId, options);
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_RETRIEVED,
id: migrationId,
});
return res.ok({ body: result });
} catch (err) {
logger.error(err);
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_RETRIEVED,
error: err,
id: migrationId,
});
return res.badRequest({ body: err.message });
}
})

View file

@ -14,8 +14,9 @@ import {
InstallMigrationRulesRequestParams,
} from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import type { SecuritySolutionPluginRouter } from '../../../../types';
import { withLicense } from './util/with_license';
import { SiemMigrationAuditLogger, SiemMigrationsAuditActions } from './util/audit';
import { installTranslated } from './util/installation';
import { withLicense } from './util/with_license';
export const registerSiemRuleMigrationsInstallRoute = (
router: SecuritySolutionPluginRouter,
@ -41,6 +42,7 @@ export const registerSiemRuleMigrationsInstallRoute = (
async (context, req, res): Promise<IKibanaResponse<InstallMigrationRulesResponse>> => {
const { migration_id: migrationId } = req.params;
const { ids, enabled = false } = req.body;
let siemMigrationAuditLogger: SiemMigrationAuditLogger | undefined;
try {
const ctx = await context.resolve(['core', 'alerting', 'securitySolution']);
@ -48,7 +50,14 @@ export const registerSiemRuleMigrationsInstallRoute = (
const securitySolutionContext = ctx.securitySolution;
const savedObjectsClient = ctx.core.savedObjects.client;
const rulesClient = await ctx.alerting.getRulesClient();
const auditLogger = ctx.securitySolution.getAuditLogger();
if (auditLogger) {
siemMigrationAuditLogger = new SiemMigrationAuditLogger(auditLogger);
}
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_INSTALLED_RULE,
id: migrationId,
});
const installed = await installTranslated({
migrationId,
ids,
@ -61,6 +70,11 @@ export const registerSiemRuleMigrationsInstallRoute = (
return res.ok({ body: { installed } });
} catch (err) {
logger.error(err);
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_INSTALLED_RULE,
error: err,
id: migrationId,
});
return res.badRequest({ body: err.message });
}
}

View file

@ -7,13 +7,14 @@
import type { IKibanaResponse, Logger } from '@kbn/core/server';
import { buildRouteValidationWithZod } from '@kbn/zod-helpers';
import { SIEM_RULE_MIGRATION_RESOURCES_PATH } from '../../../../../../common/siem_migrations/constants';
import {
GetRuleMigrationResourcesRequestParams,
GetRuleMigrationResourcesRequestQuery,
type GetRuleMigrationResourcesResponse,
} from '../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import { SIEM_RULE_MIGRATION_RESOURCES_PATH } from '../../../../../../common/siem_migrations/constants';
import type { SecuritySolutionPluginRouter } from '../../../../../types';
import { SiemMigrationAuditLogger, SiemMigrationsAuditActions } from '../util/audit';
import { withLicense } from '../util/with_license';
export const registerSiemRuleMigrationsResourceGetRoute = (
@ -40,16 +41,47 @@ export const registerSiemRuleMigrationsResourceGetRoute = (
async (context, req, res): Promise<IKibanaResponse<GetRuleMigrationResourcesResponse>> => {
const migrationId = req.params.migration_id;
const { type, names, from, size } = req.query;
let siemMigrationAuditLogger: SiemMigrationAuditLogger | undefined;
try {
const ctx = await context.resolve(['securitySolution']);
const ruleMigrationsClient = ctx.securitySolution.getSiemRuleMigrationsClient();
const auditLogger = ctx.securitySolution.getAuditLogger();
if (auditLogger) {
siemMigrationAuditLogger = new SiemMigrationAuditLogger(auditLogger);
}
const options = { filters: { type, names }, from, size };
const resources = await ruleMigrationsClient.data.resources.get(migrationId, options);
if (type && type === 'macro') {
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_RETRIEVED_MACRO,
id: migrationId,
});
}
if (type && type === 'lookup') {
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_RETRIEVED_LOOKUP,
id: migrationId,
});
}
return res.ok({ body: resources });
} catch (err) {
logger.error(err);
if (type && type === 'macro') {
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_RETRIEVED_MACRO,
error: err,
id: migrationId,
});
}
if (type && type === 'lookup') {
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_RETRIEVED_LOOKUP,
error: err,
id: migrationId,
});
}
return res.badRequest({ body: err.message });
}
}

View file

@ -8,17 +8,18 @@
import type { IKibanaResponse, Logger } from '@kbn/core/server';
import { buildRouteValidationWithZod } from '@kbn/zod-helpers';
import partition from 'lodash/partition';
import { ResourceIdentifier } from '../../../../../../common/siem_migrations/rules/resources';
import { SIEM_RULE_MIGRATION_RESOURCES_PATH } from '../../../../../../common/siem_migrations/constants';
import {
UpsertRuleMigrationResourcesRequestBody,
UpsertRuleMigrationResourcesRequestParams,
type UpsertRuleMigrationResourcesResponse,
} from '../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import { SIEM_RULE_MIGRATION_RESOURCES_PATH } from '../../../../../../common/siem_migrations/constants';
import { ResourceIdentifier } from '../../../../../../common/siem_migrations/rules/resources';
import type { SecuritySolutionPluginRouter } from '../../../../../types';
import type { CreateRuleMigrationResourceInput } from '../../data/rule_migrations_data_resources_client';
import { withLicense } from '../util/with_license';
import { SiemMigrationAuditLogger, SiemMigrationsAuditActions } from '../util/audit';
import { processLookups } from '../util/lookups';
import { withLicense } from '../util/with_license';
export const registerSiemRuleMigrationsResourceUpsertRoute = (
router: SecuritySolutionPluginRouter,
@ -49,9 +50,29 @@ export const registerSiemRuleMigrationsResourceUpsertRoute = (
): Promise<IKibanaResponse<UpsertRuleMigrationResourcesResponse>> => {
const resources = req.body;
const migrationId = req.params.migration_id;
let siemMigrationAuditLogger: SiemMigrationAuditLogger | undefined;
try {
const ctx = await context.resolve(['securitySolution']);
const ruleMigrationsClient = ctx.securitySolution.getSiemRuleMigrationsClient();
const auditLogger = ctx.securitySolution.getAuditLogger();
if (auditLogger) {
siemMigrationAuditLogger = new SiemMigrationAuditLogger(auditLogger);
}
for (const resource of resources) {
if (resource.type === 'macro') {
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_UPLOADED_MACRO,
id: migrationId,
});
}
if (resource.type === 'lookup') {
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_UPLOADED_LOOKUP,
id: migrationId,
});
}
}
// Check if the migration exists
const { data } = await ruleMigrationsClient.data.rules.get(migrationId, { size: 1 });
@ -83,6 +104,22 @@ export const registerSiemRuleMigrationsResourceUpsertRoute = (
return res.ok({ body: { acknowledged: true } });
} catch (err) {
logger.error(err);
for (const resource of resources) {
if (resource.type === 'macro') {
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_UPLOADED_MACRO,
error: err,
id: migrationId,
});
}
if (resource.type === 'lookup') {
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_UPLOADED_LOOKUP,
error: err,
id: migrationId,
});
}
}
return res.badRequest({ body: err.message });
}
}

View file

@ -18,8 +18,9 @@ import {
type StartRuleMigrationResponse,
} from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import type { SecuritySolutionPluginRouter } from '../../../../types';
import { withLicense } from './util/with_license';
import { SiemMigrationAuditLogger, SiemMigrationsAuditActions } from './util/audit';
import { getRetryFilter } from './util/retry';
import { withLicense } from './util/with_license';
export const registerSiemRuleMigrationsStartRoute = (
router: SecuritySolutionPluginRouter,
@ -49,12 +50,15 @@ export const registerSiemRuleMigrationsStartRoute = (
connector_id: connectorId,
retry,
} = req.body;
let siemMigrationAuditLogger: SiemMigrationAuditLogger | undefined;
try {
const ctx = await context.resolve(['core', 'actions', 'alerting', 'securitySolution']);
const ruleMigrationsClient = ctx.securitySolution.getSiemRuleMigrationsClient();
const auditLogger = ctx.securitySolution.getAuditLogger();
if (auditLogger) {
siemMigrationAuditLogger = new SiemMigrationAuditLogger(auditLogger);
}
if (retry) {
const { updated } = await ruleMigrationsClient.task.updateToRetry(
migrationId,
@ -76,9 +80,19 @@ export const registerSiemRuleMigrationsStartRoute = (
if (!exists) {
return res.noContent();
}
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_STARTED,
id: migrationId,
});
return res.ok({ body: { started } });
} catch (err) {
logger.error(err);
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_STARTED,
error: err,
id: migrationId,
});
return res.badRequest({ body: err.message });
}
}

View file

@ -7,12 +7,13 @@
import type { IKibanaResponse, Logger } from '@kbn/core/server';
import { buildRouteValidationWithZod } from '@kbn/zod-helpers';
import { SIEM_RULE_MIGRATION_STOP_PATH } from '../../../../../common/siem_migrations/constants';
import {
StopRuleMigrationRequestParams,
type StopRuleMigrationResponse,
} from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import { SIEM_RULE_MIGRATION_STOP_PATH } from '../../../../../common/siem_migrations/constants';
import type { SecuritySolutionPluginRouter } from '../../../../types';
import { SiemMigrationAuditLogger, SiemMigrationsAuditActions } from './util/audit';
import { withLicense } from './util/with_license';
export const registerSiemRuleMigrationsStopRoute = (
@ -35,8 +36,13 @@ export const registerSiemRuleMigrationsStopRoute = (
withLicense(
async (context, req, res): Promise<IKibanaResponse<StopRuleMigrationResponse>> => {
const migrationId = req.params.migration_id;
let siemMigrationAuditLogger: SiemMigrationAuditLogger | undefined;
try {
const ctx = await context.resolve(['securitySolution']);
const auditLogger = ctx.securitySolution.getAuditLogger();
if (auditLogger) {
siemMigrationAuditLogger = new SiemMigrationAuditLogger(auditLogger);
}
const ruleMigrationsClient = ctx.securitySolution.getSiemRuleMigrationsClient();
const { exists, stopped } = await ruleMigrationsClient.task.stop(migrationId);
@ -44,9 +50,19 @@ export const registerSiemRuleMigrationsStopRoute = (
if (!exists) {
return res.noContent();
}
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_STOPPED,
id: migrationId,
});
return res.ok({ body: { stopped } });
} catch (err) {
logger.error(err);
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_STOPPED,
error: err,
id: migrationId,
});
return res.badRequest({ body: err.message });
}
}

View file

@ -7,14 +7,15 @@
import type { IKibanaResponse, Logger } from '@kbn/core/server';
import { buildRouteValidationWithZod } from '@kbn/zod-helpers';
import { SIEM_RULE_MIGRATIONS_PATH } from '../../../../../common/siem_migrations/constants';
import {
UpdateRuleMigrationRequestBody,
type UpdateRuleMigrationResponse,
} from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import { SIEM_RULE_MIGRATIONS_PATH } from '../../../../../common/siem_migrations/constants';
import type { SecuritySolutionPluginRouter } from '../../../../types';
import { withLicense } from './util/with_license';
import { SiemMigrationAuditLogger, SiemMigrationsAuditActions } from './util/audit';
import { transformToInternalUpdateRuleMigrationData } from './util/update_rules';
import { withLicense } from './util/with_license';
export const registerSiemRuleMigrationsUpdateRoute = (
router: SecuritySolutionPluginRouter,
@ -36,10 +37,20 @@ export const registerSiemRuleMigrationsUpdateRoute = (
withLicense(
async (context, req, res): Promise<IKibanaResponse<UpdateRuleMigrationResponse>> => {
const rulesToUpdate = req.body;
let siemMigrationAuditLogger: SiemMigrationAuditLogger | undefined;
try {
const ctx = await context.resolve(['securitySolution']);
const ruleMigrationsClient = ctx.securitySolution.getSiemRuleMigrationsClient();
const auditLogger = ctx.securitySolution.getAuditLogger();
if (auditLogger) {
siemMigrationAuditLogger = new SiemMigrationAuditLogger(auditLogger);
}
for (const rule of rulesToUpdate) {
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_UPDATED_RULE,
id: rule.id,
});
}
const transformedRuleToUpdate = rulesToUpdate.map(
transformToInternalUpdateRuleMigrationData
);
@ -48,6 +59,13 @@ export const registerSiemRuleMigrationsUpdateRoute = (
return res.ok({ body: { updated: true } });
} catch (err) {
logger.error(err);
for (const rule of rulesToUpdate) {
siemMigrationAuditLogger?.log({
action: SiemMigrationsAuditActions.SIEM_MIGRATION_UPDATED_RULE,
error: err,
id: rule.id,
});
}
return res.badRequest({ body: err.message });
}
}

View file

@ -0,0 +1,108 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { AuditLogger, EcsEvent } from '@kbn/core/server';
import type { ArrayElement } from '@kbn/utility-types';
export enum SiemMigrationsAuditActions {
SIEM_MIGRATION_STARTED = 'siem_migration_started',
SIEM_MIGRATION_STOPPED = 'siem_migration_stopped',
SIEM_MIGRATION_CREATED = 'siem_migration_created',
SIEM_MIGRATION_UPDATED = 'siem_migration_updated',
SIEM_MIGRATION_RETRIEVED = 'siem_migration_retrieved',
SIEM_MIGRATION_INSTALLED_RULE = 'siem_migration_installed_rule',
SIEM_MIGRATION_UPDATED_RULE = 'siem_migration_updated_rule',
SIEM_MIGRATION_UPLOADED_MACRO = 'siem_migration_uploaded_macro',
SIEM_MIGRATION_RETRIEVED_MACRO = 'siem_migration_retrieved_macro',
SIEM_MIGRATION_UPLOADED_LOOKUP = 'siem_migration_uploaded_lookup',
SIEM_MIGRATION_RETRIEVED_LOOKUP = 'siem_migration_retrieved_lookup',
}
export enum AUDIT_TYPE {
CHANGE = 'change',
START = 'start',
END = 'end',
ACCESS = 'access',
CREATION = 'creation',
}
export enum AUDIT_CATEGORY {
API = 'api',
AUTHENTICATION = 'authentication',
DATABASE = 'database',
WEB = 'web',
}
export enum AUDIT_OUTCOME {
FAILURE = 'failure',
SUCCESS = 'success',
UNKNOWN = 'unknown',
}
export const siemMigrationAuditEventType: Record<
SiemMigrationsAuditActions,
ArrayElement<EcsEvent['type']>
> = {
siem_migration_started: AUDIT_TYPE.START,
siem_migration_stopped: AUDIT_TYPE.END,
siem_migration_created: AUDIT_TYPE.CREATION,
siem_migration_updated: AUDIT_TYPE.CHANGE,
siem_migration_retrieved: AUDIT_TYPE.ACCESS,
siem_migration_installed_rule: AUDIT_TYPE.CREATION,
siem_migration_updated_rule: AUDIT_TYPE.CHANGE,
siem_migration_uploaded_macro: AUDIT_TYPE.CREATION,
siem_migration_retrieved_macro: AUDIT_TYPE.ACCESS,
siem_migration_uploaded_lookup: AUDIT_TYPE.CREATION,
siem_migration_retrieved_lookup: AUDIT_TYPE.ACCESS,
};
export const siemMigrationAuditEventMessage: Record<SiemMigrationsAuditActions, string> = {
siem_migration_started: 'User started an existing SIEM migration',
siem_migration_stopped: 'User stopped an existing SIEM migration',
siem_migration_created: 'User created a new SIEM migration',
siem_migration_updated: 'User updated an existing SIEM migration',
siem_migration_retrieved: 'User retrieved rules from an existing SIEM migration',
siem_migration_installed_rule: 'User installed a new detection rule through SIEM migration',
siem_migration_updated_rule: 'User updated a translated detection rule',
siem_migration_uploaded_macro: 'User uploaded a new macro through SIEM migration',
siem_migration_retrieved_macro: 'User retrieved a SIEM migration macro',
siem_migration_uploaded_lookup: 'User uploaded a new lookup list through SIEM migration',
siem_migration_retrieved_lookup: 'User retrieved a SIEM migration lookup list',
};
export interface SiemMigrationAuditEvent {
action: SiemMigrationsAuditActions;
error?: Error;
id?: string;
}
export class SiemMigrationAuditLogger {
constructor(private readonly auditLogger: AuditLogger) {}
public log({ action, error, id }: SiemMigrationAuditEvent): void {
const type = siemMigrationAuditEventType[action];
let message = siemMigrationAuditEventMessage[action];
if (id) {
message += ` with [id=${id}]`;
}
this.auditLogger.log({
message,
event: {
action,
category: [AUDIT_CATEGORY.DATABASE],
type: type ? [type] : undefined,
outcome: error ? AUDIT_OUTCOME.FAILURE : AUDIT_OUTCOME.SUCCESS,
},
error: error && {
code: error.name,
message: error.message,
},
});
}
}