Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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 { CoreSetup, Logger } from '@kbn/core/server';
import type { ConfigType } from '../config';

import { getSignalsMigrationDeprecationsInfo } from './signals_migration';

export const registerDeprecations = ({
core,
config,
logger,
}: {
core: CoreSetup;
config: ConfigType;
logger: Logger;
}) => {
core.deprecations.registerDeprecations({
getDeprecations: async (ctx) => {
return [...(await getSignalsMigrationDeprecationsInfo(ctx, config, logger, core.docLinks))];
},
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* 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 {
DeprecationsDetails,
GetDeprecationsContext,
Logger,
DocLinksServiceSetup,
} from '@kbn/core/server';

import { i18n } from '@kbn/i18n';
import { DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL } from '../../common/constants';
import type { ConfigType } from '../config';

import { getNonMigratedSignalsInfo } from '../lib/detection_engine/migrations/get_non_migrated_signals_info';

const constructMigrationApiCall = (space: string, range: string) =>
`GET <kibana host>:<port>${
space === 'default' ? '' : `/s/${space}`
}${DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL}?from=${range}`;

export const getSignalsMigrationDeprecationsInfo = async (
ctx: GetDeprecationsContext,
config: ConfigType,
logger: Logger,
docLinks: DocLinksServiceSetup
): Promise<DeprecationsDetails[]> => {
const esClient = ctx.esClient.asInternalUser;
const { isMigrationRequired, spaces } = await getNonMigratedSignalsInfo({
esClient,
signalsIndex: config.signalsIndex,
logger,
});
// Deprecation API requires time range to be part of request (https://www.elastic.co/guide/en/security/current/signals-migration-api.html#migration-1)
// Return the earliest date, so it would capture the oldest possible signals
const fromRange = new Date(0).toISOString();

if (isMigrationRequired) {
return [
{
deprecationType: 'feature',
title: i18n.translate('xpack.securitySolution.deprecations.signalsMigrationTitle', {
defaultMessage: 'Found not migrated detection alerts',
}),
level: 'warning',
message: i18n.translate('xpack.securitySolution.deprecations.signalsMigrationMessage', {
defaultMessage: `After upgrading Kibana, the latest Elastic Security features will be available for any newly generated detection alerts. However, in order to enable new features for existing detection alerts, migration may be necessary.`,
}),
documentationUrl: docLinks.links.securitySolution.signalsMigrationApi,
correctiveActions: {
manualSteps: [
i18n.translate(
'xpack.securitySolution.deprecations.migrateIndexIlmPolicy.signalsMigrationManualStepOne',
{
defaultMessage: `Visit "Learn more" link for instructions how to migrate detection alerts. Migrate indices for each space.`,
}
),
i18n.translate(
'xpack.securitySolution.deprecations.migrateIndexIlmPolicy.signalsMigrationManualStepTwo',
{
defaultMessage: 'Spaces with at least one non-migrated signals index: {spaces}.',
values: {
spaces: spaces.join(', '),
},
}
),
i18n.translate(
'xpack.securitySolution.deprecations.migrateIndexIlmPolicy.signalsMigrationManualStepFour',
{
defaultMessage: 'Example of migration API calls:',
}
),
...spaces.map((space) => constructMigrationApiCall(space, fromRange)),
],
},
},
];
}

return [];
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ export const createMigrationIndex = async ({
},
},
},
mappings: {
_meta: {
version,
},
},
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
import { elasticsearchServiceMock } from '@kbn/core/server/mocks';
import { loggerMock } from '@kbn/logging-mocks';

import { getNonMigratedSignalsInfo } from './get_non_migrated_signals_info';
import {
getNonMigratedSignalsInfo,
checkIfMigratedIndexOutdated,
} from './get_non_migrated_signals_info';
import { getIndexVersionsByIndex } from './get_index_versions_by_index';
import { getSignalVersionsByIndex } from './get_signal_versions_by_index';
import { getLatestIndexTemplateVersion } from './get_latest_index_template_version';
Expand Down Expand Up @@ -132,6 +135,39 @@ describe('getNonMigratedSignalsInfo', () => {
spaces: ['default'],
});
});
it('return empty result for migrated in v8 index', async () => {
getIndexAliasPerSpaceMock.mockReturnValue({
'.reindexed-v8-siem-signals-another-1-000001': {
alias: '.siem-signals-another-1',
indexName: '.reindexed-v8-siem-signals-another-1-000001',
space: 'another-1-000001',
},
'.siem-signals-another-1-000002': {
alias: '.siem-signals-another-1',
indexName: '.siem-signals-another-1-000002',
space: 'another-1',
},
});

getIndexVersionsByIndexMock.mockReturnValue({
'.reindexed-v8-siem-signals-another-1-000001': 57,
'.siem-signals-another-1-000002': TEMPLATE_VERSION,
'.reindexed-v8-siem-signals-another-1-000001-r000077': TEMPLATE_VERSION, // outdated .reindexed-v8-siem-signals-another-1-000001 is already migrated
});
getSignalVersionsByIndexMock.mockReturnValue({});

const result = await getNonMigratedSignalsInfo({
esClient,
signalsIndex: 'siem-signals',
logger,
});

expect(result).toEqual({
indices: [],
isMigrationRequired: false,
spaces: [],
});
});
it('returns results for outdated signals in index', async () => {
getIndexVersionsByIndexMock.mockReturnValue({
'.siem-signals-another-1-legacy': TEMPLATE_VERSION,
Expand Down Expand Up @@ -175,3 +211,49 @@ describe('getNonMigratedSignalsInfo', () => {
});
});
});

describe('checkIfMigratedIndexOutdated', () => {
const indexVersionsByIndex = {
'.siem-signals-default-000001': 57,
'.siem-signals-another-6-000001': 57,
'.siem-signals-default-000002': 77,
'.siem-signals-another-5-000001': 57,
'.reindexed-v8-siem-signals-another-1-000001': 57,
'.siem-signals-another-7-000001': 57,
'.reindexed-v8-siem-signals-another-2-000001': 57,
'.siem-signals-another-3-000001': 57,
'.reindexed-v8-siem-signals-another-4-000001': 57,
'.siem-signals-another-3-000002': 77,
'.siem-signals-another-9-000001': 57,
'.siem-signals-another-8-000001': 57,
'.siem-signals-another-2-000002': 77,
'.siem-signals-another-10-000001': 57,
'.siem-signals-another-1-000002': 77,
'.siem-signals-another-2-000001-r000077': 77,
'.reindexed-v8-siem-signals-another-1-000001-r000077': 77,
};

const migratedIndices = [
'.reindexed-v8-siem-signals-another-1-000001',
'.reindexed-v8-siem-signals-another-2-000001',
'.reindexed-v8-siem-signals-another-1-000001-r000077',
];

migratedIndices.forEach((index) => {
it(`should correctly find index "${index}" is migrated`, () => {
expect(checkIfMigratedIndexOutdated(index, indexVersionsByIndex, TEMPLATE_VERSION)).toBe(
false
);
});
});

it('should find non migrated index', () => {
expect(
checkIfMigratedIndexOutdated(
'.reindexed-v8-siem-signals-another-4-000001',
indexVersionsByIndex,
TEMPLATE_VERSION
)
).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,41 @@ import { isOutdated as getIsOutdated, signalsAreOutdated } from './helpers';
import { getLatestIndexTemplateVersion } from './get_latest_index_template_version';
import { getIndexAliasPerSpace } from './get_index_alias_per_space';

const REINDEXED_PREFIX = '.reindexed-v8-';

export const checkIfMigratedIndexOutdated = (
indexName: string,
indexVersionsByIndex: IndexVersionsByIndex,
latestTemplateVersion: number
) => {
const isIndexOutdated = getIsOutdated({
current: indexVersionsByIndex[indexName] ?? 0,
target: latestTemplateVersion,
});

if (!isIndexOutdated) {
return false;
}

const nameWithoutPrefix = indexName.replace(REINDEXED_PREFIX, '.');

const hasOutdatedMigratedIndices = Object.entries(indexVersionsByIndex).every(
([index, version]) => {
if (index === indexName) {
return true;
}

if (index.startsWith(nameWithoutPrefix) || index.startsWith(indexName)) {
return getIsOutdated({ current: version ?? 0, target: latestTemplateVersion });
}

return true;
}
);

return hasOutdatedMigratedIndices;
};

interface OutdatedSpaces {
isMigrationRequired: boolean;
spaces: string[];
Expand Down Expand Up @@ -85,6 +120,14 @@ export const getNonMigratedSignalsInfo = async ({
const version = indexVersionsByIndex[indexName] ?? 0;
const signalVersions = signalVersionsByIndex[indexName] ?? [];

// filter out migrated from 7.x to 8 indices
if (
indexName.startsWith(REINDEXED_PREFIX) &&
!checkIfMigratedIndexOutdated(indexName, indexVersionsByIndex, latestTemplateVersion)
) {
return acc;
}

const isOutdated =
getIsOutdated({ current: version, target: latestTemplateVersion }) ||
signalsAreOutdated({ signalVersions, target: latestTemplateVersion });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { AppClientFactory } from './client';
import type { ConfigType } from './config';
import { createConfig } from './config';
import { initUiSettings } from './ui_settings';
import { registerDeprecations } from './deprecations';
import {
APP_ID,
APP_UI_ID,
Expand Down Expand Up @@ -212,6 +213,8 @@ export class Plugin implements ISecuritySolutionPlugin {

this.ruleMonitoringService.setup(core, plugins);

registerDeprecations({ core, config: this.config, logger: this.logger });

if (experimentalFeatures.riskScoringPersistence) {
registerRiskScoringTask({
getStartServices: core.getStartServices,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"type": "doc",
"value": {
"id": "1",
"index": ".siem-signals-another-space-legacy",
"source": {
"@timestamp": "2020-10-10T00:00:00.000Z",
"signal": {}
},
"type": "_doc"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"type": "index",
"value": {
"aliases": {
".siem-signals-another-space": {
"is_write_index": false
}
},
"index": ".siem-signals-another-space-legacy",
"mappings": {
"_meta": {
"version": 1
},
"properties": {
"@timestamp": {
"type": "date"
},
"signal": { "type": "object" }
}
},
"settings": {
"index": {
"lifecycle": {
"indexing_complete": true
}
}
}
}
}
Loading