[Security Solution] Correct the license_uuid reference name in the Endpoint Policy (#167194)

## Summary

Correct the `license_uuid` field name in the Endpoint Policy. Before, it
was named `license_uid`, but the Endpoint expects `license_uuid`.

This PR in intended to be backported to `8.10.3` which brings up an
interesting problem since we already have a migration added to `main`
for the `8.11` release.

After talking with the kibana-core team, my approach is to add the
migration for this bug fix to this PR. Then, to keep the `modelVersions`
consistent, I will backport all `modelVersions` to `8.10.3` to keep the
migrations consistent. Keeping these consistent is important so that
both users upgrading from `8.10.x` in ESS and the Serverless line all
remain in sync. The end result is that the policies inside of of
`8.10.3` will have an extra field that will be unused until `8.11.0`

The following `8.10.3` backport for this will include the extra
migration and I will request reviews for it since it will be more than a
normal backport.

Policy:

![image](888e364b-e835-4a76-8ee3-68d8ed1f055b)

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Kevin Logan 2023-09-28 12:37:15 -04:00 committed by GitHub
parent 2edc13c2c1
commit 9d6ec1a7cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 261 additions and 13 deletions

View file

@ -106,7 +106,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"ingest-agent-policies": "f11cc19275f4c3e4ee7c5cd6423b6706b21b989d",
"ingest-download-sources": "279a68147e62e4d8858c09ad1cf03bd5551ce58d",
"ingest-outputs": "b4e636b13a5d0f89f0400fb67811d4cca4736eb0",
"ingest-package-policies": "af9e8d523a6f3ae5b8c9adcfba391ff405dfa374",
"ingest-package-policies": "8ec637429836f80f1fcc798bcee7c5916eceaed5",
"ingest_manager_settings": "64955ef1b7a9ffa894d4bb9cf863b5602bfa6885",
"inventory-view": "b8683c8e352a286b4aca1ab21003115a4800af83",
"kql-telemetry": "93c1d16c1a0dfca9c8842062cf5ef8f62ae401ad",

View file

@ -36,6 +36,11 @@ import { migrateSyntheticsPackagePolicyToV8100 } from './migrations/synthetics/t
import { migratePackagePolicyEvictionsFromV8100 } from './migrations/security_solution/to_v8_10_0';
import {
migratePackagePolicyEvictionsFromV81102,
migratePackagePolicyToV81102,
} from './migrations/security_solution/to_v8_11_0_2';
import {
migrateAgentPolicyToV7100,
migratePackagePolicyToV7100,
@ -335,6 +340,17 @@ const getSavedObjectTypes = (): { [key: string]: SavedObjectsType } => ({
forwardCompatibility: migratePackagePolicyEvictionsFromV8110,
},
},
'3': {
changes: [
{
type: 'data_backfill',
backfillFn: migratePackagePolicyToV81102,
},
],
schemas: {
forwardCompatibility: migratePackagePolicyEvictionsFromV81102,
},
},
},
migrations: {
'7.10.0': migratePackagePolicyToV7100,

View file

@ -0,0 +1,167 @@
/*
* 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 { SavedObjectUnsanitizedDoc } from '@kbn/core/server';
import type { SavedObjectModelTransformationContext } from '@kbn/core-saved-objects-server';
import type { PackagePolicy } from '../../../../common';
import { migratePackagePolicyToV81102 as migration } from './to_v8_11_0_2';
import { migratePackagePolicyEvictionsFromV81102 as eviction } from './to_v8_11_0_2';
describe('8.11.0-2 Endpoint Package Policy migration', () => {
const policyDoc = ({ meta = {} }) => {
return {
id: 'mock-saved-object-id',
attributes: {
name: 'Some Policy Name',
package: {
name: 'endpoint',
title: '',
version: '',
},
id: 'endpoint',
policy_id: '',
enabled: true,
namespace: '',
revision: 0,
updated_at: '',
updated_by: '',
created_at: '',
created_by: '',
inputs: [
{
type: 'endpoint',
enabled: true,
streams: [],
config: {
policy: {
value: {
meta: {
license: '',
cloud: false,
cluster_uuid: 'qwe',
cluster_name: 'clusterName',
...meta,
},
windows: {},
mac: {},
linux: {},
},
},
},
},
],
},
type: ' nested',
};
};
it('adds a new field `license_uuid` that takes the value of `license_uid` if it exists', () => {
const initialDoc = policyDoc({ meta: { license_uid: 'existing_uuid' } });
const migratedDoc = policyDoc({
meta: { license_uid: 'existing_uuid', license_uuid: 'existing_uuid' },
});
expect(migration(initialDoc, {} as SavedObjectModelTransformationContext)).toEqual({
attributes: {
inputs: migratedDoc.attributes.inputs,
},
});
});
it('adds a new field `license_uuid` that takes an empty value if `existing_uid` does not exist', () => {
const initialDoc = policyDoc({});
const migratedDoc = policyDoc({
meta: { license_uuid: '' },
});
expect(migration(initialDoc, {} as SavedObjectModelTransformationContext)).toEqual({
attributes: {
inputs: migratedDoc.attributes.inputs,
},
});
});
it('removes `license_uuid` for backwards compatibility', () => {
const initialDoc = policyDoc({
meta: { license_uuid: 'existing_uuid' },
});
const migratedDoc = policyDoc({});
expect(eviction(initialDoc.attributes)).toEqual(migratedDoc.attributes);
});
it('does not modify non-endpoint package policies', () => {
const doc: SavedObjectUnsanitizedDoc<PackagePolicy> = {
id: 'mock-saved-object-id',
attributes: {
name: 'Some Policy Name',
package: {
name: 'notEndpoint',
title: '',
version: '',
},
id: 'notEndpoint',
policy_id: '',
enabled: true,
namespace: '',
revision: 0,
updated_at: '',
updated_by: '',
created_at: '',
created_by: '',
inputs: [
{
type: 'notEndpoint',
enabled: true,
streams: [],
config: {},
},
],
},
type: ' nested',
};
expect(
migration(
doc,
{} as SavedObjectModelTransformationContext
) as SavedObjectUnsanitizedDoc<PackagePolicy>
).toEqual({
attributes: {
name: 'Some Policy Name',
package: {
name: 'notEndpoint',
title: '',
version: '',
},
id: 'notEndpoint',
policy_id: '',
enabled: true,
namespace: '',
revision: 0,
updated_at: '',
updated_by: '',
created_at: '',
created_by: '',
inputs: [
{
type: 'notEndpoint',
enabled: true,
streams: [],
config: {},
},
],
},
});
});
});

View file

@ -0,0 +1,65 @@
/*
* 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 { SavedObjectUnsanitizedDoc } from '@kbn/core/server';
import type { SavedObjectModelDataBackfillFn } from '@kbn/core-saved-objects-server';
import { omit } from 'lodash';
import type { SavedObjectModelVersionForwardCompatibilityFn } from '@kbn/core-saved-objects-server';
import type { PackagePolicy } from '../../../../common';
export const migratePackagePolicyToV81102: SavedObjectModelDataBackfillFn<
PackagePolicy,
PackagePolicy
> = (packagePolicyDoc) => {
if (packagePolicyDoc.attributes.package?.name !== 'endpoint') {
return { attributes: packagePolicyDoc.attributes };
}
const updatedPackagePolicyDoc: SavedObjectUnsanitizedDoc<PackagePolicy> = packagePolicyDoc;
const input = updatedPackagePolicyDoc.attributes.inputs[0];
if (input && input.config) {
const policy = input.config.policy.value;
const newMetaValues = {
license_uuid: policy?.meta?.license_uid ? policy.meta.license_uid : '',
};
policy.meta = policy?.meta ? { ...policy.meta, ...newMetaValues } : newMetaValues;
}
return {
attributes: {
inputs: updatedPackagePolicyDoc.attributes.inputs,
},
};
};
export const migratePackagePolicyEvictionsFromV81102: SavedObjectModelVersionForwardCompatibilityFn =
(unknownAttributes) => {
const attributes = unknownAttributes as PackagePolicy;
if (attributes.package?.name !== 'endpoint') {
return attributes;
}
const updatedAttributes = attributes;
const input = updatedAttributes.inputs[0];
if (input && input.config) {
const policy = input.config.policy.value;
policy.meta = omit(policy.meta, ['license_uuid']);
}
return updatedAttributes;
};

View file

@ -22,7 +22,7 @@ export const policyFactory = (
return {
meta: {
license,
license_uid: licenseUid,
license_uuid: licenseUid,
cluster_uuid: clusterUuid,
cluster_name: clusterName,
cloud,

View file

@ -196,7 +196,7 @@ export const eventsOnlyPolicy = (): PolicyConfig => ({
meta: {
license: '',
cloud: false,
license_uid: '',
license_uuid: '',
cluster_name: '',
cluster_uuid: '',
serverless: false,

View file

@ -942,7 +942,7 @@ export interface PolicyConfig {
meta: {
license: string;
cloud: boolean;
license_uid: string;
license_uuid: string;
cluster_uuid: string;
cluster_name: string;
serverless: boolean;

View file

@ -273,7 +273,7 @@ describe('policy details: ', () => {
meta: {
license: '',
cloud: false,
license_uid: '',
license_uuid: '',
cluster_name: '',
cluster_uuid: '',
serverless: false,

View file

@ -574,7 +574,7 @@ describe('ingest_integration tests ', () => {
const infoResponse = {
cluster_name: 'updated-name',
cluster_uuid: 'updated-uuid',
license_uid: 'updated-uid',
license_uuid: 'updated-uuid',
name: 'name',
tagline: 'tagline',
version: {
@ -602,7 +602,7 @@ describe('ingest_integration tests ', () => {
mockPolicy.meta.license = 'platinum'; // license is set to emit platinum
mockPolicy.meta.cluster_name = 'updated-name';
mockPolicy.meta.cluster_uuid = 'updated-uuid';
mockPolicy.meta.license_uid = 'updated-uid';
mockPolicy.meta.license_uuid = 'updated-uid';
mockPolicy.meta.serverless = false;
const logger = loggingSystemMock.create().get('ingest_integration.test');
const callback = getPackagePolicyUpdateCallback(
@ -621,7 +621,7 @@ describe('ingest_integration tests ', () => {
policyConfig.inputs[0]!.config!.policy.value.meta.license = 'gold';
policyConfig.inputs[0]!.config!.policy.value.meta.cluster_name = 'original-name';
policyConfig.inputs[0]!.config!.policy.value.meta.cluster_uuid = 'original-uuid';
policyConfig.inputs[0]!.config!.policy.value.meta.license_uid = 'original-uid';
policyConfig.inputs[0]!.config!.policy.value.meta.license_uuid = 'original-uid';
policyConfig.inputs[0]!.config!.policy.value.meta.serverless = true;
const updatedPolicyConfig = await callback(
policyConfig,
@ -639,7 +639,7 @@ describe('ingest_integration tests ', () => {
mockPolicy.meta.license = 'platinum'; // license is set to emit platinum
mockPolicy.meta.cluster_name = 'updated-name';
mockPolicy.meta.cluster_uuid = 'updated-uuid';
mockPolicy.meta.license_uid = 'updated-uid';
mockPolicy.meta.license_uuid = 'updated-uid';
mockPolicy.meta.serverless = false;
const logger = loggingSystemMock.create().get('ingest_integration.test');
const callback = getPackagePolicyUpdateCallback(
@ -657,7 +657,7 @@ describe('ingest_integration tests ', () => {
policyConfig.inputs[0]!.config!.policy.value.meta.license = 'platinum';
policyConfig.inputs[0]!.config!.policy.value.meta.cluster_name = 'updated-name';
policyConfig.inputs[0]!.config!.policy.value.meta.cluster_uuid = 'updated-uuid';
policyConfig.inputs[0]!.config!.policy.value.meta.license_uid = 'updated-uid';
policyConfig.inputs[0]!.config!.policy.value.meta.license_uuid = 'updated-uid';
policyConfig.inputs[0]!.config!.policy.value.meta.serverless = false;
const updatedPolicyConfig = await callback(
policyConfig,

View file

@ -59,7 +59,7 @@ const shouldUpdateMetaValues = (
currentCloudInfo: boolean,
currentClusterName: string,
currentClusterUUID: string,
currentLicenseUID: string,
currentLicenseUUID: string,
currentIsServerlessEnabled: boolean
) => {
return (
@ -67,7 +67,7 @@ const shouldUpdateMetaValues = (
endpointPackagePolicy.meta.cloud !== currentCloudInfo ||
endpointPackagePolicy.meta.cluster_name !== currentClusterName ||
endpointPackagePolicy.meta.cluster_uuid !== currentClusterUUID ||
endpointPackagePolicy.meta.license_uid !== currentLicenseUID ||
endpointPackagePolicy.meta.license_uuid !== currentLicenseUUID ||
endpointPackagePolicy.meta.serverless !== currentIsServerlessEnabled
);
};
@ -238,7 +238,7 @@ export const getPackagePolicyUpdateCallback = (
newEndpointPackagePolicy.meta.cloud = cloud?.isCloudEnabled;
newEndpointPackagePolicy.meta.cluster_name = esClientInfo.cluster_name;
newEndpointPackagePolicy.meta.cluster_uuid = esClientInfo.cluster_uuid;
newEndpointPackagePolicy.meta.license_uid = licenseService.getLicenseUID();
newEndpointPackagePolicy.meta.license_uuid = licenseService.getLicenseUID();
newEndpointPackagePolicy.meta.serverless = cloud?.isServerlessEnabled;
endpointIntegrationData.inputs[0].config.policy.value = newEndpointPackagePolicy;