-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implements Encrypted Saved Objects Model Version API (#166302)
Closes #161002 Closes #170073 ## Summary This PR implements a createModelVersion API in the Encrypted Saved Objects plugin to support upward migrations for model version encrypted saved objects. Much like how the `createMigration` API provided a way to wrap migration functions to support migration of encrypted saved objects prior to the model version paradigm, the new `createModelVersion` API provides a way to wrap a model version definition for the same purpose. `createModelVersion` manipulates the changes defined for a model version ('unsafe_transform', 'data_backfill', 'data_removal'), merging them into a single transform function in which the saved object document is decrypted, transformed, and then encrypted again. The document is decrypted with the `encrypted saved object type registration` provided by the required `inputType` parameter. Similarly, the document is by encrypted with the `encrypted saved object type registration` provided by the required `outputType` parameter. An example plugin (`examples/eso_model_version_example`) provides a demonstration of how the createModelVersion API should be used. The UI of the example plugin gives an idea of what the encrypted saved objects look like before and after the model version changes are applied. ## Testing ### Manual Testing - Modify the example plugin implementation in `examples/eso_model_version_example` to include different changes or additional model versions. ### Unit Tests - `x-pack/plugins/encrypted_saved_objects/server/create_model_version.test.ts` ### Functional Tests - `x-pack/test/encrypted_saved_objects_api_integration/tests/encrypted_saved_objects_api.ts` - `x-pack/test/encrypted_saved_objects_api_integration/tests/encrypted_saved_objects_decryption.ts` --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
- Loading branch information
1 parent
f684005
commit 835d4af
Showing
37 changed files
with
2,216 additions
and
50 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
## Encrypted Saved Object Model Version Example | ||
|
||
This plugin provides a simple use case demonstration of: | ||
- How to organize versioned saved object and encryption registration definitions | ||
- How to use the createModelVersion wrapper function of the Encrypted Saved Objects plugin | ||
- How/when encrypted model versions are migrated and what to expect when they are queried | ||
|
||
This is an example plugin to demonstrate implementation of an encrypted saved object with model versions using the new encryptedSavedObjectsPlugin.createModelVersion API. | ||
|
||
A good place to start is by reviewing the definitions in `examples/eso_model_version_example/server/types`. This is where the interfaces and constants that for the example saved object are defined. | ||
|
||
In `examples/eso_model_version_example/server/plugin.ts` the model versions are defined, which include typical changes you might see in a saved object over time only in this case the model version definitions are wrapped by the new createModelVersion API. | ||
|
||
Lastly, use the plugin UI to get a sense for how the objects are migrated - you can query the raw documents and then decrypted the migrated objects. | ||
|
||
To run this example, use the command `yarn start --run-examples`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
* 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 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
export const PLUGIN_ID = 'esoModelVersionExample'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"type": "plugin", | ||
"id": "@kbn/eso-model-version-example", | ||
"owner": "@elastic/kibana-security", | ||
"description": "ESO Model Version Example", | ||
"plugin": { | ||
"id": "esoModelVersionExample", | ||
"server": true, | ||
"browser": true, | ||
"requiredBundles": ["kibanaReact"], | ||
"requiredPlugins": ["developerExamples", "security", "spaces", "encryptedSavedObjects"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
/* | ||
* 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 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import { | ||
EuiAccordion, | ||
EuiButton, | ||
EuiCodeBlock, | ||
EuiPageTemplate, | ||
EuiSpacer, | ||
EuiText, | ||
EuiTextColor, | ||
EuiTitle, | ||
} from '@elastic/eui'; | ||
import React, { useState } from 'react'; | ||
|
||
export const MyPluginComponent: React.FC = () => { | ||
const [generated, setGenerated] = useState(''); | ||
const [rawDocs, setRawDocs] = useState(''); | ||
const [objects, setObjects] = useState(''); | ||
const [decrypted, setDecrypted] = useState(''); | ||
|
||
const handler = async ( | ||
endpoint: string, | ||
setter: (value: React.SetStateAction<string>) => void | ||
) => { | ||
const response = await fetch(endpoint); | ||
const data = await response.json(); | ||
setter(JSON.stringify(data, null, 2)); | ||
}; | ||
|
||
return ( | ||
<EuiPageTemplate> | ||
<EuiPageTemplate.Section grow={false} color="subdued" bottomBorder="extended"> | ||
<EuiTitle size="l"> | ||
<h1>Encrypted Saved Object Model Version Example</h1> | ||
</EuiTitle> | ||
<EuiText> | ||
This is a demonstration to show the results of the implementation found in | ||
<EuiTextColor color="accent">examples/eso_model_version_example</EuiTextColor> | ||
</EuiText> | ||
</EuiPageTemplate.Section> | ||
<EuiPageTemplate.Section | ||
grow={false} | ||
color="subdued" | ||
bottomBorder="extended" | ||
title="Create Objects" | ||
> | ||
<EuiText> | ||
1. This will create three objects - one for each model version definition (see | ||
<EuiTextColor color="accent"> | ||
examples/eso_model_version_example/server/types | ||
</EuiTextColor> | ||
). | ||
</EuiText> | ||
<EuiButton | ||
onClick={() => { | ||
handler('/internal/eso_mv_example/generate', setGenerated); | ||
}} | ||
> | ||
Create Objects | ||
</EuiButton> | ||
<EuiSpacer /> | ||
<EuiAccordion | ||
id="createdObjectsAccordion" | ||
buttonContent="Created Objects" | ||
initialIsOpen={true} | ||
> | ||
<EuiCodeBlock language="json" fontSize="s" paddingSize="s" isCopyable> | ||
{generated} | ||
</EuiCodeBlock> | ||
</EuiAccordion> | ||
</EuiPageTemplate.Section> | ||
<EuiPageTemplate.Section grow={false} color="subdued" bottomBorder="extended"> | ||
<EuiText> | ||
2. This will read the raw documents of the objects with an Elasticsearch client. Note that | ||
the | ||
<EuiTextColor color="accent">typeMigrationVersion </EuiTextColor> | ||
(10.n.0) will correspond to the model version (n). | ||
</EuiText> | ||
<EuiButton | ||
onClick={() => { | ||
handler('/internal/eso_mv_example/read_raw', setRawDocs); | ||
}} | ||
> | ||
Read Raw Documents | ||
</EuiButton> | ||
<EuiSpacer /> | ||
<EuiAccordion | ||
id="rawDocumentsAccordion" | ||
buttonContent="Raw Object Documents" | ||
initialIsOpen={true} | ||
> | ||
<EuiCodeBlock language="json" fontSize="s" paddingSize="s" isCopyable> | ||
{rawDocs} | ||
</EuiCodeBlock> | ||
</EuiAccordion> | ||
</EuiPageTemplate.Section> | ||
<EuiPageTemplate.Section grow={false} color="subdued" bottomBorder="extended"> | ||
<EuiText> | ||
3. This will read the saved objects with a Kibana saved object client. Note that the | ||
objects have been migrated on read to the latest model version, and the encrypted fields | ||
have been stripped. | ||
</EuiText> | ||
<EuiButton | ||
onClick={() => { | ||
handler('/internal/eso_mv_example/get_objects', setObjects); | ||
}} | ||
> | ||
Read Saved Objects | ||
</EuiButton> | ||
<EuiSpacer /> | ||
<EuiAccordion | ||
id="migratedObjectsAccordion" | ||
buttonContent="Migrated Objects" | ||
initialIsOpen={true} | ||
> | ||
<EuiCodeBlock language="json" fontSize="s" paddingSize="s" isCopyable> | ||
{objects} | ||
</EuiCodeBlock> | ||
</EuiAccordion> | ||
</EuiPageTemplate.Section> | ||
<EuiPageTemplate.Section grow={false} color="subdued" bottomBorder="extended"> | ||
<EuiText>4. This will decrypt the saved objects.</EuiText> | ||
<EuiButton | ||
onClick={() => { | ||
handler('/internal/eso_mv_example/get_decrypted', setDecrypted); | ||
}} | ||
> | ||
Decrypt Secrets | ||
</EuiButton> | ||
<EuiSpacer /> | ||
<EuiAccordion | ||
id="decryptedAccordion" | ||
buttonContent="Decrypted Secrets" | ||
initialIsOpen={true} | ||
> | ||
<EuiCodeBlock language="json" fontSize="s" paddingSize="s" isCopyable> | ||
{decrypted} | ||
</EuiCodeBlock> | ||
</EuiAccordion> | ||
</EuiPageTemplate.Section> | ||
</EuiPageTemplate> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* 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 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; | ||
import { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public'; | ||
import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/public'; | ||
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; | ||
import type { FeaturesPluginSetup } from '@kbn/features-plugin/public'; | ||
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; | ||
import { MyPluginComponent } from './app'; | ||
|
||
interface SetupDeps { | ||
developerExamples: DeveloperExamplesSetup; | ||
security: SecurityPluginSetup; | ||
features: FeaturesPluginSetup; | ||
} | ||
|
||
interface StartDeps { | ||
security: SecurityPluginStart; | ||
} | ||
|
||
export class EsoModelVersionExample implements Plugin<void, void, SetupDeps, StartDeps> { | ||
public setup(coreSetup: CoreSetup<StartDeps>, deps: SetupDeps) { | ||
coreSetup.application.register({ | ||
id: 'esoModelVersionExample', | ||
title: 'ESO Model Version Example', | ||
async mount({ element }: AppMountParameters) { | ||
const [coreStart] = await coreSetup.getStartServices(); | ||
ReactDOM.render( | ||
<KibanaPageTemplate> | ||
<KibanaContextProvider services={{ ...coreStart, ...deps }}> | ||
<MyPluginComponent /> | ||
</KibanaContextProvider> | ||
</KibanaPageTemplate>, | ||
element | ||
); | ||
return () => ReactDOM.unmountComponentAtNode(element); | ||
}, | ||
}); | ||
deps.developerExamples.register({ | ||
appId: 'esoModelVersionExample', | ||
title: 'ESO Model Version Example', | ||
description: 'Example of encrypted saved object with model version implementation', | ||
}); | ||
} | ||
|
||
public start(core: CoreStart, deps: StartDeps) { | ||
return {}; | ||
} | ||
|
||
public stop() {} | ||
} | ||
export const plugin = () => new EsoModelVersionExample(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/* | ||
* 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 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
import { PluginInitializer } from '@kbn/core/server'; | ||
import { EsoModelVersionExample } from './plugin'; | ||
|
||
export const plugin: PluginInitializer<void, void> = async () => new EsoModelVersionExample(); |
Oops, something went wrong.