mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Changed alerting wrong param name for help xpack.encrypted_saved_objects.encryptionKey to xpack.encryptedSavedObjects.encryptionKey (#63307) (#63310)
# Conflicts: # rfcs/text/0002_encrypted_attributes.md
This commit is contained in:
parent
6794371f13
commit
10b1c8bdb3
5 changed files with 257 additions and 5 deletions
|
@ -9,7 +9,7 @@ Alerts and actions are enabled by default in {kib}, but require you configure th
|
|||
|
||||
. <<using-kibana-with-security,Set up {kib} to work with {stack} {security-features}>>.
|
||||
. <<configuring-tls-kib-es,Set up TLS encryption between {kib} and {es}>>.
|
||||
. <<general-alert-action-settings,Specify a value for `xpack.encrypted_saved_objects.encryptionKey`>>.
|
||||
. <<general-alert-action-settings,Specify a value for `xpack.encryptedSavedObjects.encryptionKey`>>.
|
||||
|
||||
You can configure the following settings in the `kibana.yml` file.
|
||||
|
||||
|
@ -18,7 +18,7 @@ You can configure the following settings in the `kibana.yml` file.
|
|||
[[general-alert-action-settings]]
|
||||
==== General settings
|
||||
|
||||
`xpack.encrypted_saved_objects.encryptionKey`::
|
||||
`xpack.encryptedSavedObjects.encryptionKey`::
|
||||
|
||||
A string of 32 or more characters used to encrypt sensitive properties on alerts and actions before they're stored in {es}. Third party credentials — such as the username and password used to connect to an SMTP service — are an example of encrypted properties.
|
||||
+
|
||||
|
|
|
@ -157,7 +157,7 @@ Pre-packaged *alert types* simplify setup, hide the details complex domain-speci
|
|||
If you are using an *on-premises* Elastic Stack deployment with <<using-kibana-with-security, *security*>>:
|
||||
|
||||
* TLS must be configured for communication <<configuring-tls-kib-es, between {es} and {kib}>>. {kib} alerting uses <<api-keys, API keys>> to secure background alert checks and actions, and API keys require {ref}/configuring-tls.html#tls-http[TLS on the HTTP interface].
|
||||
* In the kibana.yml configuration file, add the <<alert-action-settings-kb,`xpack.encrypted_saved_objects.encryptionKey` setting>>
|
||||
* In the kibana.yml configuration file, add the <<alert-action-settings-kb,`xpack.encryptedSavedObjects.encryptionKey` setting>>
|
||||
|
||||
[float]
|
||||
[[alerting-security]]
|
||||
|
|
252
rfcs/text/0002_encrypted_attributes.md
Normal file
252
rfcs/text/0002_encrypted_attributes.md
Normal file
|
@ -0,0 +1,252 @@
|
|||
- Start Date: 2019-03-22
|
||||
- RFC PR: [#33740](https://github.com/elastic/kibana/pull/33740)
|
||||
- Kibana Issue: (leave this empty)
|
||||
|
||||
# Summary
|
||||
|
||||
In order to support the action service we need a way to encrypt/decrypt
|
||||
attributes on saved objects that works with security and spaces filtering as
|
||||
well as performing audit logging. Sufficiently hides the private key used and
|
||||
removes encrypted attributes from being exposed through regular means.
|
||||
|
||||
# Basic example
|
||||
|
||||
Register saved object type with the `encrypted_saved_objects` plugin:
|
||||
|
||||
```typescript
|
||||
server.plugins.encrypted_saved_objects.registerType({
|
||||
type: 'server-action',
|
||||
attributesToEncrypt: new Set(['credentials', 'apiKey']),
|
||||
});
|
||||
```
|
||||
|
||||
Use the same API to create saved objects with encrypted attributes as for any other saved object type:
|
||||
|
||||
```typescript
|
||||
const savedObject = await server.savedObjects
|
||||
.getScopedSavedObjectsClient(request)
|
||||
.create('server-action', {
|
||||
name: 'my-server-action',
|
||||
data: { location: 'BBOX (100.0, ..., 0.0)', email: '<html>...</html>' },
|
||||
credentials: { username: 'some-user', password: 'some-password' },
|
||||
apiKey: 'dGhpcyBpcyBub3QgYSByZWFsIHRva2VuIGJ1dCBpdCBpcyBvb'
|
||||
});
|
||||
|
||||
// savedObject = {
|
||||
// id: 'dd9750b9-ef0a-444c-8405-4dfcc2e9d670',
|
||||
// type: 'server-action',
|
||||
// name: 'my-server-action',
|
||||
// data: { location: 'BBOX (100.0, ..., 0.0)', email: '<html>...</html>' },
|
||||
// };
|
||||
|
||||
```
|
||||
|
||||
Use dedicated method to retrieve saved object with decrypted attributes on behalf of Kibana internal user:
|
||||
|
||||
```typescript
|
||||
const savedObject = await server.plugins.encrypted_saved_objects.getDecryptedAsInternalUser(
|
||||
'server-action',
|
||||
'dd9750b9-ef0a-444c-8405-4dfcc2e9d670'
|
||||
);
|
||||
|
||||
// savedObject = {
|
||||
// id: 'dd9750b9-ef0a-444c-8405-4dfcc2e9d670',
|
||||
// type: 'server-action',
|
||||
// name: 'my-server-action',
|
||||
// data: { location: 'BBOX (100.0, ..., 0.0)', email: '<html>...</html>' },
|
||||
// credentials: { username: 'some-user', password: 'some-password' },
|
||||
// apiKey: 'dGhpcyBpcyBub3QgYSByZWFsIHRva2VuIGJ1dCBpdCBpcyBvb',
|
||||
// };
|
||||
```
|
||||
|
||||
# Motivation
|
||||
|
||||
Main motivation is the storage and usage of third-party credentials for use with
|
||||
the action service to do notifications. Also perform other types integrations,
|
||||
call webhooks using tokens.
|
||||
|
||||
# Detailed design
|
||||
|
||||
In order for this to be in basic it needs to be done as a wrapper around the
|
||||
saved object client. This can be added from the `x-pack` plugin.
|
||||
|
||||
## General
|
||||
|
||||
To be able to manage saved objects with encrypted attributes from any plugin one should
|
||||
do the following:
|
||||
|
||||
1. Define `encrypted_saved_objects` plugin as a dependency.
|
||||
2. Add attributes to be encrypted in `mappings.json` file for the respective saved object type. These attributes should
|
||||
always have a `binary` type since they'll contain encrypted content as a `Base64` encoded string and should never be
|
||||
searchable or analyzed. This makes defining of attributes that require encryption explicit and auditable, and significantly
|
||||
simplifies implementation:
|
||||
```json
|
||||
{
|
||||
"server-action": {
|
||||
"properties": {
|
||||
"name": { "type": "keyword" },
|
||||
"data": {
|
||||
"properties": {
|
||||
"location": { "type": "geo_shape" },
|
||||
"email": { "type": "text" }
|
||||
}
|
||||
},
|
||||
"credentials": { "type": "binary" },
|
||||
"apiKey": { "type": "binary" }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
3. Register saved object type and attributes that should be encrypted with `encrypted_saved_objects` plugin:
|
||||
```typescript
|
||||
server.plugins.encrypted_saved_objects.registerType({
|
||||
type: 'server-action',
|
||||
attributesToEncrypt: new Set(['credentials', 'apiKey']),
|
||||
attributesToExcludeFromAAD: new Set(['data']),
|
||||
});
|
||||
```
|
||||
|
||||
Notice the optional `attributesToExcludeFromAAD` property, it allows one to exclude some of the saved object attributes
|
||||
from Additional authenticated data (AAD), read more about that below in `Encryption and decryption` section.
|
||||
|
||||
Since `encrypted_saved_objects` adds its own wrapper (`EncryptedSavedObjectsClientWrapper`) into `SavedObjectsClient`
|
||||
wrapper chain consumers will be able to create, update, delete and retrieve saved objects using standard Saved Objects API.
|
||||
Two main responsibilities of the wrapper are:
|
||||
|
||||
* It encrypts attributes that are supposed to be encrypted during `create`, `bulkCreate` and `update` operations
|
||||
* It strips encrypted attributes from **any** saved object returned from the Saved Objects API
|
||||
|
||||
As noted above the wrapper is stripping encrypted attributes from saved objects returned from the API methods, that means
|
||||
that there is no way at all to retrieve encrypted attributes using standard Saved Objects API unless `encrypted_saved_objects`
|
||||
plugin is disabled. This potentially can lead to the situation when consumer retrieves saved object, updates its non-encrypted
|
||||
properties and passes that same object to the `update` Saved Objects API method without re-defining encrypted attributes. In
|
||||
this case only specified attributes will be updated and encrypted attributes will stay untouched. And if these updated
|
||||
attributes are included into AAD, that is true by default for all attributes unless they are specifically excluded via
|
||||
`attributesToExcludeFromAAD`, then it will be no longer possible to decrypt encrypted attributes. At this stage we consider
|
||||
this as a developer mistake and don't prevent it from happening in any way apart from logging this type of event. Partial
|
||||
update of only attributes that are not the part of AAD will not cause this issue.
|
||||
|
||||
Saved object ID is an essential part of AAD used during encryption process and hence should be as hard to guess as possible.
|
||||
To fulfil this requirement wrapper generates highly random IDs (UUIDv4) for the saved objects that contain encrypted
|
||||
attributes and hence consumers are not allowed to specify ID when calling `create` or `bulkCreate` method and if they try
|
||||
to do so the error will be thrown.
|
||||
|
||||
To reduce the risk of unintentional decryption and consequent leaking of the sensitive information there is only one way
|
||||
to retrieve saved object and decrypt its encrypted attributes and it's exposed only through `encrypted_saved_objects` plugin:
|
||||
|
||||
```typescript
|
||||
const savedObject = await server.plugins.encrypted_saved_objects.getDecryptedAsInternalUser(
|
||||
'server-action',
|
||||
'dd9750b9-ef0a-444c-8405-4dfcc2e9d670'
|
||||
);
|
||||
|
||||
// savedObject = {
|
||||
// id: 'dd9750b9-ef0a-444c-8405-4dfcc2e9d670',
|
||||
// type: 'server-action',
|
||||
// name: 'my-server-action',
|
||||
// data: { location: 'BBOX (100.0, ..., 0.0)', email: '<html>...</html>' },
|
||||
// credentials: { username: 'some-user', password: 'some-password' },
|
||||
// apiKey: 'dGhpcyBpcyBub3QgYSByZWFsIHRva2VuIGJ1dCBpdCBpcyBvb',
|
||||
// };
|
||||
```
|
||||
|
||||
As can be seen from the method name, the request to retrieve saved object and decrypt its attributes is performed on
|
||||
behalf of the internal Kibana user and hence isn't supposed to be called within user request context.
|
||||
|
||||
**Note:** the fact that saved object with encrypted attributes is created using standard Saved Objects API within a
|
||||
particular user and space context, but retrieved out of any context makes it unclear how consumers are supposed to
|
||||
provide that context and retrieve saved object from a particular space. Current plan for `getDecryptedAsInternalUser`
|
||||
method is to accept a third `BaseOptions` argument that allows consumers to specify `namespace` that they can retrieve
|
||||
from the request using public `spaces` plugin API.
|
||||
|
||||
## Encryption and decryption
|
||||
|
||||
Saved object attributes are encrypted using [@elastic/node-crypto](https://github.com/elastic/node-crypto) library. Please
|
||||
take a look at the source code of this library to know how encryption is performed exactly, what algorithm and encryption
|
||||
parameters are used, but in short it's AES Encryption with AES-256-GCM that uses random initialization vector and salt.
|
||||
|
||||
As with encryption key for Kibana's session cookie, master encryption key used by `encrypted_saved_objects` plugin can be
|
||||
defined as a configuration value (`xpack.encryptedSavedObjects.encryptionKey`) via `kibana.yml`, but it's **highly
|
||||
recommended** to define this key in the [Kibana Keystore](https://www.elastic.co/guide/en/kibana/current/secure-settings.html)
|
||||
instead. The master key should be cryptographically safe and be equal or greater than 32 bytes.
|
||||
|
||||
To prevent certain vectors of attacks where raw content of encrypted attributes of one saved object is copied to another
|
||||
saved object which would unintentionally allow it to decrypt content that was not supposed to be decrypted we rely on Additional
|
||||
authenticated data (AAD) during encryption and decryption. AAD consists of the following components:
|
||||
|
||||
* Saved object ID
|
||||
* Saved object type
|
||||
* Saved object attributes
|
||||
|
||||
AAD does not include encrypted attributes themselves and attributes defined in optional `attributesToExcludeFromAAD`
|
||||
parameter provided during saved object type registration with `encrypted_saved_objects` plugin. There are a number of
|
||||
reasons why one would want to exclude certain attributes from AAD:
|
||||
|
||||
* if attribute contains large amount of data that can significantly slow down encryption and decryption, especially during
|
||||
bulk operations (e.g. large geo shape or arbitrary HTML document)
|
||||
* if attribute contains data that is supposed to be updated separately from encrypted attributes or attributes included
|
||||
into AAD (e.g some user defined content associated with the email action or alert)
|
||||
|
||||
## Audit
|
||||
|
||||
Encrypted attributes will most likely contain sensitive information and any attempt to access these should be properly
|
||||
logged to allow any further audit procedures. The following events will be logged with Kibana audit log functionality:
|
||||
|
||||
* Successful attempt to encrypt attributes (incl. saved object ID, type and attributes names)
|
||||
* Failed attempt to encrypt attribute (incl. saved object ID, type and attribute name)
|
||||
* Successful attempt to decrypt attributes (incl. saved object ID, type and attributes names)
|
||||
* Failed attempt to decrypt attribute (incl. saved object ID, type and attribute name)
|
||||
|
||||
In addition to audit log events we'll issue ordinary log events for any attempts to save, update or decrypt saved objects
|
||||
with missing attributes that were supposed to be encrypted/decrypted based on the registration parameters.
|
||||
|
||||
# Benefits
|
||||
|
||||
* None of the registered types will expose their encrypted details. The saved
|
||||
objects with their unencrypted attributes could still be obtained and searched
|
||||
on. The wrapper will follow all the security and spaces filtering of saved
|
||||
objects so that only users with appropriate permissions will be able to obtain
|
||||
the scrubbed objects or _save_ objects with encrypted attributes.
|
||||
|
||||
* No explicit access to a method that takes in an encrypted string exists. If the
|
||||
type was not registered no decryption is possible. No need to handle the saved object
|
||||
with the encrypted attributes reducing the risk of accidentally returning it in a
|
||||
handler.
|
||||
|
||||
# Drawbacks
|
||||
|
||||
* It isn't possible to decrypt existing encrypted attributes once encryption key changes
|
||||
* Possibly have a performance impact on Saved Objects API operations that require encryption/decryption
|
||||
* Will require non trivial tests to test functionality along with spaces and security
|
||||
* The attributes that are encrypted have to be defined and if they change they need to be migrated
|
||||
|
||||
# Out of scope
|
||||
|
||||
* Encryption key rotation mechanism, either regular or emergency
|
||||
* Mechanism that would detect and warn when Kibana does not use keystore to store encryption key
|
||||
|
||||
# Alternatives
|
||||
|
||||
Only allow this to be used within the Actions service itself where the details
|
||||
of the saved object are handled there directly. And the saved objects are
|
||||
`hidden` but still use the security and spaces wrappers.
|
||||
|
||||
# Adoption strategy
|
||||
|
||||
Integration should be pretty easy which would include depending on the plugin, registering the desired saved object type
|
||||
with it and defining encrypted attributes in the `mappings.json`.
|
||||
|
||||
# How we teach this
|
||||
|
||||
The `encrypted_saved_objects` as the name of the `thing` where it's seen as a separate
|
||||
extension on top of the saved object service.
|
||||
|
||||
Provide a README.md in the plugin directory with the usage examples.
|
||||
|
||||
# Unresolved questions
|
||||
|
||||
* Is it acceptable to have this plugin in Basic?
|
||||
* Are there any other use-cases that are not served with that interface?
|
||||
* How would this work with Saved Objects Export\Import API?
|
||||
* How would this work with migrations, if the attribute names wanted to be
|
||||
changed, a decrypt context would need to be created for migration?
|
|
@ -91,7 +91,7 @@ describe('health check', () => {
|
|||
|
||||
const description = queryByRole(/banner/i);
|
||||
expect(description!.textContent).toMatchInlineSnapshot(
|
||||
`"To create an alert, set a value for xpack.encrypted_saved_objects.encryptionKey in your kibana.yml file. Learn how."`
|
||||
`"To create an alert, set a value for xpack.encryptedSavedObjects.encryptionKey in your kibana.yml file. Learn how."`
|
||||
);
|
||||
|
||||
const action = queryByText(/Learn/i);
|
||||
|
|
|
@ -132,7 +132,7 @@ const EncryptionError = ({
|
|||
defaultMessage: 'To create an alert, set a value for ',
|
||||
}
|
||||
)}
|
||||
<EuiCode>{'xpack.encrypted_saved_objects.encryptionKey'}</EuiCode>
|
||||
<EuiCode>{'xpack.encryptedSavedObjects.encryptionKey'}</EuiCode>
|
||||
{i18n.translate(
|
||||
'xpack.triggersActionsUI.components.healthCheck.encryptionErrorAfterKey',
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue