[Security Solution][Upgrade] Add tag for disabled rules on upgrade (#125448)

* Add tag for disabled rules on upgrade

* Resiliency

* Restore 8.0 AAD migration and add 8.0.1 migration for auto-disabled tags

* Add integration test for migration

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Madison Caldwell 2022-02-16 22:08:56 -05:00 committed by GitHub
parent 485ab50302
commit 8f03c791e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 413 additions and 15 deletions

View file

@ -2063,31 +2063,172 @@ describe('successful migrations', () => {
{ params: { outputIndex: 'output-index', type: 'query' }, alertTypeId: 'not.siem.signals' },
true
);
expect(migration800(alert, migrationContext).attributes.alertTypeId).toEqual(
'not.siem.signals'
);
expect(migration800(alert, migrationContext).attributes.enabled).toEqual(true);
expect(migration800(alert, migrationContext).attributes.params.outputIndex).toEqual(
'output-index'
);
const migratedAlert = migration800(alert, migrationContext);
expect(migratedAlert.attributes.alertTypeId).toEqual('not.siem.signals');
expect(migratedAlert.attributes.enabled).toEqual(true);
expect(migratedAlert.attributes.tags).toEqual(['foo']);
expect(migratedAlert.attributes.params.outputIndex).toEqual('output-index');
});
test.each(Object.keys(ruleTypeMappings) as RuleType[])(
'Changes AAD rule params accordingly if rule is a siem.signals %p rule',
'changes AAD rule params accordingly if rule is a siem.signals %p rule',
(ruleType) => {
const migration800 = getMigrations(encryptedSavedObjectsSetup, isPreconfigured)['8.0.0'];
const alert = getMockData(
{ params: { outputIndex: 'output-index', type: ruleType }, alertTypeId: 'siem.signals' },
true
);
expect(migration800(alert, migrationContext).attributes.alertTypeId).toEqual(
ruleTypeMappings[ruleType]
);
expect(migration800(alert, migrationContext).attributes.enabled).toEqual(false);
expect(migration800(alert, migrationContext).attributes.params.outputIndex).toEqual('');
const migratedAlert = migration800(alert, migrationContext);
expect(migratedAlert.attributes.alertTypeId).toEqual(ruleTypeMappings[ruleType]);
expect(migratedAlert.attributes.enabled).toEqual(false);
expect(migratedAlert.attributes.tags).toEqual(['foo']);
expect(migratedAlert.attributes.params.outputIndex).toEqual('');
}
);
describe('8.0.1', () => {
describe.each(Object.keys(ruleTypeMappings) as RuleType[])(
'auto_disabled %p rule tags',
(ruleType) => {
const alert717Enabled = getMockData(
{
params: { outputIndex: 'output-index', type: ruleType },
alertTypeId: 'siem.signals',
enabled: true,
scheduledTaskId: 'abcd',
},
true
);
const alert717Disabled = getMockData(
{
params: { outputIndex: 'output-index', type: ruleType },
alertTypeId: 'siem.signals',
enabled: false,
},
true
);
const alert800 = getMockData(
{
params: { outputIndex: '', type: ruleType },
alertTypeId: ruleTypeMappings[ruleType],
enabled: false,
scheduledTaskId: 'abcd',
},
true
);
test('Does not update rule tags if rule has already been enabled', () => {
const migrations = getMigrations(encryptedSavedObjectsSetup, isPreconfigured);
const migration800 = migrations['8.0.0'];
const migration801 = migrations['8.0.1'];
// migrate to 8.0.0
const migratedAlert800 = migration800(alert717Enabled, migrationContext);
expect(migratedAlert800.attributes.enabled).toEqual(false);
// reenable rule
migratedAlert800.attributes.enabled = true;
// migrate to 8.0.1
const migratedAlert801 = migration801(migratedAlert800, migrationContext);
expect(migratedAlert801.attributes.alertTypeId).toEqual(ruleTypeMappings[ruleType]);
expect(migratedAlert801.attributes.enabled).toEqual(true);
expect(migratedAlert801.attributes.params.outputIndex).toEqual('');
// tags not updated
expect(migratedAlert801.attributes.tags).toEqual(['foo']);
});
test('Does not update rule tags if rule was already disabled before upgrading to 8.0', () => {
const migrations = getMigrations(encryptedSavedObjectsSetup, isPreconfigured);
const migration800 = migrations['8.0.0'];
const migration801 = migrations['8.0.1'];
// migrate to 8.0.0
const migratedAlert800 = migration800(alert717Disabled, migrationContext);
expect(migratedAlert800.attributes.enabled).toEqual(false);
// migrate to 8.0.1
const migratedAlert801 = migration801(migratedAlert800, migrationContext);
expect(migratedAlert801.attributes.alertTypeId).toEqual(ruleTypeMappings[ruleType]);
expect(migratedAlert801.attributes.enabled).toEqual(false);
expect(migratedAlert801.attributes.params.outputIndex).toEqual('');
// tags not updated
expect(migratedAlert801.attributes.tags).toEqual(['foo']);
});
test('Updates rule tags if rule was auto-disabled in 8.0 upgrade and not reenabled', () => {
const migrations = getMigrations(encryptedSavedObjectsSetup, isPreconfigured);
const migration800 = migrations['8.0.0'];
const migration801 = migrations['8.0.1'];
// migrate to 8.0.0
const migratedAlert800 = migration800(alert717Enabled, migrationContext);
expect(migratedAlert800.attributes.enabled).toEqual(false);
// migrate to 8.0.1
const migratedAlert801 = migration801(migratedAlert800, migrationContext);
expect(migratedAlert801.attributes.alertTypeId).toEqual(ruleTypeMappings[ruleType]);
expect(migratedAlert801.attributes.enabled).toEqual(false);
expect(migratedAlert801.attributes.params.outputIndex).toEqual('');
// tags updated
expect(migratedAlert801.attributes.tags).toEqual(['foo', 'auto_disabled_8.0']);
});
test('Updates rule tags correctly if tags are undefined', () => {
const migrations = getMigrations(encryptedSavedObjectsSetup, isPreconfigured);
const migration801 = migrations['8.0.1'];
const alert = {
...alert800,
attributes: {
...alert800.attributes,
tags: undefined,
},
};
// migrate to 8.0.1
const migratedAlert801 = migration801(alert, migrationContext);
expect(migratedAlert801.attributes.alertTypeId).toEqual(ruleTypeMappings[ruleType]);
expect(migratedAlert801.attributes.enabled).toEqual(false);
expect(migratedAlert801.attributes.params.outputIndex).toEqual('');
// tags updated
expect(migratedAlert801.attributes.tags).toEqual(['auto_disabled_8.0']);
});
test('Updates rule tags correctly if tags are null', () => {
const migrations = getMigrations(encryptedSavedObjectsSetup, isPreconfigured);
const migration801 = migrations['8.0.1'];
const alert = {
...alert800,
attributes: {
...alert800.attributes,
tags: null,
},
};
// migrate to 8.0.1
const migratedAlert801 = migration801(alert, migrationContext);
expect(migratedAlert801.attributes.alertTypeId).toEqual(ruleTypeMappings[ruleType]);
expect(migratedAlert801.attributes.enabled).toEqual(false);
expect(migratedAlert801.attributes.params.outputIndex).toEqual('');
// tags updated
expect(migratedAlert801.attributes.tags).toEqual(['auto_disabled_8.0']);
});
}
);
});
describe('Metrics Inventory Threshold rule', () => {
test('Migrates incorrect action group spelling', () => {
const migration800 = getMigrations(encryptedSavedObjectsSetup, isPreconfigured)['8.0.0'];

View file

@ -58,6 +58,9 @@ export const isAnyActionSupportIncidents = (doc: SavedObjectUnsanitizedDoc<RawRu
export const isSiemSignalsRuleType = (doc: SavedObjectUnsanitizedDoc<RawRule>): boolean =>
doc.attributes.alertTypeId === 'siem.signals';
export const isDetectionEngineAADRuleType = (doc: SavedObjectUnsanitizedDoc<RawRule>): boolean =>
(Object.values(ruleTypeMappings) as string[]).includes(doc.attributes.alertTypeId);
/**
* Returns true if the alert type is that of "siem.notifications" which is a legacy notification system that was deprecated in 7.16.0
* in favor of using the newer alerting notifications system.
@ -136,6 +139,12 @@ export function getMigrations(
)
);
const migrationRules801 = createEsoMigration(
encryptedSavedObjects,
(doc: SavedObjectUnsanitizedDoc<RawRule>): doc is SavedObjectUnsanitizedDoc<RawRule> => true,
pipeMigrations(addSecuritySolutionAADRuleTypeTags)
);
return {
'7.10.0': executeMigrationWithErrorHandling(migrationWhenRBACWasIntroduced, '7.10.0'),
'7.11.0': executeMigrationWithErrorHandling(migrationAlertUpdatedAtAndNotifyWhen, '7.11.0'),
@ -145,6 +154,7 @@ export function getMigrations(
'7.15.0': executeMigrationWithErrorHandling(migrationSecurityRules715, '7.15.0'),
'7.16.0': executeMigrationWithErrorHandling(migrateRules716, '7.16.0'),
'8.0.0': executeMigrationWithErrorHandling(migrationRules800, '8.0.0'),
'8.0.1': executeMigrationWithErrorHandling(migrationRules801, '8.0.1'),
};
}
@ -672,6 +682,28 @@ function addSecuritySolutionAADRuleTypes(
: doc;
}
function addSecuritySolutionAADRuleTypeTags(
doc: SavedObjectUnsanitizedDoc<RawRule>
): SavedObjectUnsanitizedDoc<RawRule> {
const ruleType = doc.attributes.params.type;
return isDetectionEngineAADRuleType(doc) && isRuleType(ruleType)
? {
...doc,
attributes: {
...doc.attributes,
// If the rule is disabled at this point, then the rule has not been re-enabled after
// running the 8.0.0 migrations. If `doc.attributes.scheduledTaskId` exists, then the
// rule was enabled prior to running the migration. Thus we know we should add the
// tag to indicate it was auto-disabled.
tags:
!doc.attributes.enabled && doc.attributes.scheduledTaskId
? [...(doc.attributes.tags ?? []), 'auto_disabled_8.0']
: doc.attributes.tags ?? [],
},
}
: doc;
}
function addThreatIndicatorPathToThreatMatchRules(
doc: SavedObjectUnsanitizedDoc<RawRule>
): SavedObjectUnsanitizedDoc<RawRule> {

View file

@ -181,7 +181,7 @@ export default function createGetTests({ getService }: FtrProviderContext) {
});
it('7.15.0 migrates security_solution alerts with exceptionLists to be saved object references', async () => {
// NOTE: We hae to use elastic search directly against the ".kibana" index because alerts do not expose the references which we want to test exists
// NOTE: We have to use elasticsearch directly against the ".kibana" index because alerts do not expose the references which we want to test exists
const response = await es.get<{ references: [{}] }>(
{
index: '.kibana',
@ -373,5 +373,39 @@ export default function createGetTests({ getService }: FtrProviderContext) {
expect(response.body._source?.alert?.alertTypeId).to.be('siem.queryRule');
expect(response.body._source?.alert?.enabled).to.be(false);
});
it('8.0.1 migrates and adds tags to disabled rules in 8.0', async () => {
const responseEnabledBeforeMigration = await es.get<{ alert: RawRule }>(
{
index: '.kibana',
id: 'alert:1efdfa40-8ec7-11ec-a700-5524407a7653',
},
{ meta: true }
);
expect(responseEnabledBeforeMigration.statusCode).to.eql(200);
const responseDisabledBeforeMigration = await es.get<{ alert: RawRule }>(
{
index: '.kibana',
id: 'alert:13fdfa40-8ec7-11ec-a700-5524407a7667',
},
{ meta: true }
);
expect(responseDisabledBeforeMigration.statusCode).to.eql(200);
// Both should be disabled
expect(responseEnabledBeforeMigration.body._source?.alert?.enabled).to.be(false);
expect(responseDisabledBeforeMigration.body._source?.alert?.enabled).to.be(false);
// Only the rule that was enabled should be tagged
expect(responseEnabledBeforeMigration.body._source?.alert?.tags).to.eql([
'__internal_rule_id:064e3fed-6328-416b-bb85-c08265088f41',
'__internal_immutable:false',
'auto_disabled_8.0',
]);
expect(responseDisabledBeforeMigration.body._source?.alert?.tags).to.eql([
'__internal_rule_id:364e3fed-6328-416b-bb85-c08265088f41',
'__internal_immutable:false',
]);
});
});
}

View file

@ -663,3 +663,194 @@
}
}
{
"type":"doc",
"value":{
"id":"alert:1efdfa40-8ec7-11ec-a700-5524407a7653",
"index":".kibana_1",
"source":{
"alert":{
"name":"enabled 7.16.1 query rule",
"tags":[
"__internal_rule_id:064e3fed-6328-416b-bb85-c08265088f41",
"__internal_immutable:false"
],
"alertTypeId":"siem.signals",
"consumer":"siem",
"params":{
"author":[
],
"description":"enabled 7.16.1 query rule",
"ruleId":"064e3fed-6328-416b-bb85-c08265088f41",
"falsePositives":[
],
"from":"now-36000060s",
"immutable":false,
"license":"",
"outputIndex":".siem-signals-default",
"meta":{
"from":"10000h"
},
"maxSignals":100,
"riskScore":21,
"riskScoreMapping":[
],
"severity":"low",
"severityMapping":[
],
"threat":[
],
"to":"now",
"references":[
],
"version":4,
"exceptionsList":[
],
"type":"query",
"language":"kuery",
"index":[
"apm-*-transaction*",
"traces-apm*",
"auditbeat-*",
"endgame-*",
"filebeat-*",
"logs-*",
"packetbeat-*",
"winlogbeat-*",
"test-index-3"
],
"query":"*:*",
"filters":[
]
},
"schedule":{
"interval":"1m"
},
"enabled":true,
"actions":[
],
"throttle":null,
"apiKeyOwner":"3270256467",
"apiKey":"UnFCyd4CthfIw6Mv5SRRbhYC7NPD2Jn8L+aCT/JfPQ5/poIsrwkh0plDAllpBYjFYhGXTQPtSPgu9yAwsuuaUhXxtFcnFHPleQeLvmu8VICueSxgMnK25Oqku8hfSQw9ETf9WZ3yXQOwvD9i8fkIUx84zt5q2LMuZv826fY9433/seVoCWspTj5qm2DchMDgTWzMKQaR2zbvRA==",
"createdBy":"3270256467",
"updatedBy":"3270256467",
"createdAt":"2022-02-16T01:24:02.121Z",
"muteAll":true,
"mutedInstanceIds":[
],
"scheduledTaskId":"2030ade0-8ec7-11ec-a700-5524407a7653"
},
"type":"alert",
"references":[],
"migrationVersion":{
"alert":"7.16.0"
},
"updated_at":"2022-02-16T16:20:19.375Z"
}
}
}
{
"type":"doc",
"value":{
"id":"alert:13fdfa40-8ec7-11ec-a700-5524407a7667",
"index":".kibana_1",
"source":{
"alert":{
"name":"disabled 7.16.1 query rule",
"tags":[
"__internal_rule_id:364e3fed-6328-416b-bb85-c08265088f41",
"__internal_immutable:false"
],
"alertTypeId":"siem.signals",
"consumer":"siem",
"params":{
"author":[
],
"description":"disabled 7.16.1 query rule",
"ruleId":"364e3fed-6328-416b-bb85-c08265088f41",
"falsePositives":[
],
"from":"now-36000060s",
"immutable":false,
"license":"",
"outputIndex":".siem-signals-default",
"meta":{
"from":"10000h"
},
"maxSignals":100,
"riskScore":21,
"riskScoreMapping":[
],
"severity":"low",
"severityMapping":[
],
"threat":[
],
"to":"now",
"references":[
],
"version":4,
"exceptionsList":[
],
"type":"query",
"language":"kuery",
"index":[
"apm-*-transaction*",
"traces-apm*",
"auditbeat-*",
"endgame-*",
"filebeat-*",
"logs-*",
"packetbeat-*",
"winlogbeat-*",
"test-index-3"
],
"query":"*:*",
"filters":[
]
},
"schedule":{
"interval":"1m"
},
"enabled":true,
"actions":[
],
"throttle":null,
"apiKeyOwner":"3270256467",
"apiKey":"UnFCyd4CthfIw6Mv5SRRbhYC7NPD2Jn8L+aCT/JfPQ5/poIsrwkh0plDAllpBYjFYhGXTQPtSPgu9yAwsuuaUhXxtFcnFHPleQeLvmu8VICueSxgMnK25Oqku8hfSQw9ETf9WZ3yXQOwvD9i8fkIUx84zt5q2LMuZv826fY9433/seVoCWspTj5qm2DchMDgTWzMKQaR2zbvRA==",
"createdBy":"3270256467",
"updatedBy":"3270256467",
"createdAt":"2022-02-16T01:25:02.121Z",
"muteAll":true,
"mutedInstanceIds":[
],
"scheduledTaskId":null
},
"type":"alert",
"references":[],
"migrationVersion":{
"alert":"7.16.0"
},
"updated_at":"2022-02-16T16:21:19.375Z"
}
}
}

View file

@ -341,4 +341,4 @@
}
}
}
}
}