Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/improvement/ARSN-430/KMS-client'…
Browse files Browse the repository at this point in the history
… into w/8.1/improvement/ARSN-430/KMS-client
  • Loading branch information
nicolas2bert committed Sep 27, 2024
2 parents ca26206 + 94b5350 commit 7d6c125
Show file tree
Hide file tree
Showing 9 changed files with 772 additions and 47 deletions.
41 changes: 41 additions & 0 deletions lib/auth/Vault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,4 +423,45 @@ export default class Vault {
return callback(null, obj);
});
}

/**
* Calls Vault to retrieve the default encryption key id of the account, or creates it if it doesn't exist.
*
* @param {string} canonicalID - The canonical id of the account for which
* the encryption key id is being retrieved or created.
* @param {Logger} log - logger
* @param {(err: Error | null, data?: {
* canonicalId: string,
* encryptionKeyId: string,
* action: 'retrieved' | 'created'
* }) => void}
* - canonicalId: The canonical id of the account.
* - encryptionKeyId: The retrieved or newly created encryption key id.
* - action: Describes if the key was 'retrieved' or 'created'.
*
* @returns {void}
*/
getOrCreateEncryptionKeyId(
canonicalID: string,
log: Logger,
callback: (err: Error | null, data?: {
canonicalId: string,
encryptionKeyId: string,
action: 'retrieved' | 'created'
}) => void
) {
log.trace('sending request context params to vault to get or create encryption key id');
this.client.getOrCreateEncryptionKeyId(canonicalID, {
// @ts-ignore
reqUid: log.getSerializedUids(),
}, (err: Error | null, info?: any) => {
if (err) {
log.debug('received error message from auth provider',
{ error: err });
return callback(err);
}
const result = info.message.body;
return callback(null, result);
});
}
}
32 changes: 32 additions & 0 deletions lib/auth/backends/in_memory/Backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,38 @@ class InMemoryBackend extends BaseBackend {
report(log: Logger, callback: any) {
return callback(null, {});
}

/**
* Retrieves or creates an encryption key id for the specified canonical id.
*
* @param {string} canonicalId - The canonical id of the account for which to retrieve or create the encryption key.
* @param {any} _options - An options object, currently unused.
* @param {(err: Error | null, data?: {
* canonicalId: string,
* encryptionKeyId: string,
* action: 'retrieved' | 'created'
* }) => void}
* - canonicalId: The canonical id of the account.
* - encryptionKeyId: The retrieved or newly created encryption key id.
* - action: Describes if the key was 'retrieved' or 'created'.
*
* @returns {void}
*/
getOrCreateEncryptionKeyId(
canonicalId: string,
_options: any,
cb: (err: null, data: { message: { body: { canonicalId: string, encryptionKeyId: string, action: string } } }) => void
): void {
return cb(null, {
message: {
body: {
canonicalId,
encryptionKeyId: 'account-level-master-encryption-key',
action: 'retrieved',
}
}
});
}
}


Expand Down
23 changes: 21 additions & 2 deletions lib/models/BucketInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export type SSE = {
masterKeyId: string;
configuredMasterKeyId: string;
mandatory: boolean;
isAccountEncryptionEnabled: boolean;
};

export type VersioningConfiguration = {
Expand Down Expand Up @@ -210,10 +211,13 @@ export default class BucketInfo {
configuredMasterKeyId, mandatory } = serverSideEncryption;
assert.strictEqual(typeof cryptoScheme, 'number');
assert.strictEqual(typeof algorithm, 'string');
assert.strictEqual(typeof masterKeyId, 'string');
assert.strictEqual(typeof mandatory, 'boolean');
assert.ok(masterKeyId !== undefined || configuredMasterKeyId !== undefined, 'At least one of masterKeyId or configuredMasterKeyId must be defined');
if (masterKeyId !== undefined) {
assert.strictEqual(typeof masterKeyId, 'string', 'masterKeyId must be a string');
}
if (configuredMasterKeyId !== undefined) {
assert.strictEqual(typeof configuredMasterKeyId, 'string');
assert.strictEqual(typeof configuredMasterKeyId, 'string', 'configuredMasterKeyId must be a string');
}
}
if (versioningConfiguration) {
Expand Down Expand Up @@ -635,6 +639,21 @@ export default class BucketInfo {
}
return this._serverSideEncryption.masterKeyId;
}

/**
* Checks if the default encryption is set at the account level instead of the legacy bucket level.
* This method helps to prevent deletion of the account-level master encryption key when deleting buckets.
*
* @returns {boolean} - Returns true if account-level default encryption is enabled,
* false if it uses the legacy bucket level.
*/
isAccountEncryptionEnabled() {
if (!this._serverSideEncryption) {
return false;
}

return this._serverSideEncryption.isAccountEncryptionEnabled;
}
/**
* Get bucket name.
* @return - bucket name
Expand Down
1 change: 1 addition & 0 deletions lib/network/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ export const probe = { ProbeServer, HealthProbeServer, Utils };
export { default as RoundRobin } from './RoundRobin';
export { default as kmip } from './kmip';
export { default as kmipClient } from './kmip/Client';
export { default as KmsAWSClient } from './kmsAWS/Client';
export * as rpc from './rpc/rpc';
export * as level from './rpc/level-net';
65 changes: 20 additions & 45 deletions lib/network/kmip/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
/* eslint new-cap: "off" */

import async from 'async';
import errors from '../../errors';
import TTLVCodec from './codec/ttlv';
import TlsTransport from './transport/tls';
import KMIP from '.';
import * as werelogs from 'werelogs';
import { arsenalErrorKMIP } from '../utils'

const CRYPTOGRAPHIC_OBJECT_TYPE = 'Symmetric Key';
const CRYPTOGRAPHIC_ALGORITHM = 'AES';
Expand Down Expand Up @@ -45,31 +45,6 @@ const searchFilter = {
'Response Message/Batch Item/Response Payload/Data',
};

/**
* Normalize errors according to arsenal definitions
* @param err - an Error instance or a message string
* @returns - arsenal error
*/
function _arsenalError(err: string | Error) {
const messagePrefix = 'KMIP:';
if (typeof err === 'string') {
return errors.InternalError
.customizeDescription(`${messagePrefix} ${err}`);
} else if (
err instanceof Error ||
// INFO: The second part is here only for Jest, to remove when we'll be
// fully migrated to TS
// @ts-expect-error
(err && typeof err.message === 'string')
) {
return errors.InternalError
.customizeDescription(`${messagePrefix} ${err.message}`);
}
return errors.InternalError
.customizeDescription(`${messagePrefix} Unspecified error`);
}


/**
* Negotiate with the server the use of a recent version of the protocol and
* update the low level driver with this new knowledge.
Expand All @@ -93,7 +68,7 @@ function _negotiateProtocolVersion(client: any, logger: werelogs.Logger, cb: any
]),
], (err, response) => {
if (err) {
const error = _arsenalError(err);
const error = arsenalErrorKMIP(err);
logger.error('KMIP::negotiateProtocolVersion',
{ error,
vendorIdentification: client.vendorIdentification });
Expand All @@ -105,7 +80,7 @@ function _negotiateProtocolVersion(client: any, logger: werelogs.Logger, cb: any
response.lookup(searchFilter.protocolVersionMinor);
if (majorVersions.length === 0 ||
majorVersions.length !== minorVersions.length) {
const error = _arsenalError('No suitable protocol version');
const error = arsenalErrorKMIP('No suitable protocol version');
logger.error('KMIP::negotiateProtocolVersion',
{ error,
vendorIdentification: client.vendorIdentification });
Expand All @@ -128,7 +103,7 @@ function _mapExtensions(client: any, logger: werelogs.Logger, cb: any) {
KMIP.Enumeration('Query Function', 'Query Extension Map'),
], (err, response) => {
if (err) {
const error = _arsenalError(err);
const error = arsenalErrorKMIP(err);
logger.error('KMIP::mapExtensions',
{ error,
vendorIdentification: client.vendorIdentification });
Expand All @@ -137,7 +112,7 @@ function _mapExtensions(client: any, logger: werelogs.Logger, cb: any) {
const extensionNames = response.lookup(searchFilter.extensionName);
const extensionTags = response.lookup(searchFilter.extensionTag);
if (extensionNames.length !== extensionTags.length) {
const error = _arsenalError('Inconsistent extension list');
const error = arsenalErrorKMIP('Inconsistent extension list');
logger.error('KMIP::mapExtensions',
{ error,
vendorIdentification: client.vendorIdentification });
Expand All @@ -161,7 +136,7 @@ function _queryServerInformation(client: any, logger: werelogs.Logger, cb: any)
KMIP.Enumeration('Query Function', 'Query Server Information'),
], (err, response) => {
if (err) {
const error = _arsenalError(err);
const error = arsenalErrorKMIP(err);
logger.warn('KMIP::queryServerInformation',
{ error });
/* no error returned, caller can keep going */
Expand Down Expand Up @@ -196,7 +171,7 @@ function _queryOperationsAndObjects(client: any, logger: werelogs.Logger, cb: an
KMIP.Enumeration('Query Function', 'Query Objects'),
], (err, response) => {
if (err) {
const error = _arsenalError(err);
const error = arsenalErrorKMIP(err);
logger.error('KMIP::queryOperationsAndObjects',
{ error,
vendorIdentification: client.vendorIdentification });
Expand Down Expand Up @@ -336,7 +311,7 @@ export default class Client {
KMIP.TextString('Unique Identifier', keyIdentifier),
], (err, response) => {
if (err) {
const error = _arsenalError(err);
const error = arsenalErrorKMIP(err);
logger.error('KMIP::_activateBucketKey',
{ error,
serverInformation: this.serverInformation });
Expand All @@ -345,7 +320,7 @@ export default class Client {
const uniqueIdentifier =
response.lookup(searchFilter.uniqueIdentifier)[0];
if (uniqueIdentifier !== keyIdentifier) {
const error = _arsenalError(
const error = arsenalErrorKMIP(
'Server did not return the expected identifier');
logger.error('KMIP::cipherDataKey',
{ error, uniqueIdentifier });
Expand Down Expand Up @@ -389,7 +364,7 @@ export default class Client {
KMIP.Structure('Template-Attribute', attributes),
], (err, response) => {
if (err) {
const error = _arsenalError(err);
const error = arsenalErrorKMIP(err);
logger.error('KMIP::createBucketKey',
{ error,
serverInformation: this.serverInformation });
Expand All @@ -400,7 +375,7 @@ export default class Client {
const uniqueIdentifier =
response.lookup(searchFilter.uniqueIdentifier)[0];
if (createdObjectType !== CRYPTOGRAPHIC_OBJECT_TYPE) {
const error = _arsenalError(
const error = arsenalErrorKMIP(
'Server created an object of wrong type');
logger.error('KMIP::createBucketKey',
{ error, createdObjectType });
Expand Down Expand Up @@ -433,7 +408,7 @@ export default class Client {
]),
], (err, response) => {
if (err) {
const error = _arsenalError(err);
const error = arsenalErrorKMIP(err);
logger.error('KMIP::_revokeBucketKey',
{ error,
serverInformation: this.serverInformation });
Expand All @@ -442,7 +417,7 @@ export default class Client {
const uniqueIdentifier =
response.lookup(searchFilter.uniqueIdentifier)[0];
if (uniqueIdentifier !== bucketKeyId) {
const error = _arsenalError(
const error = arsenalErrorKMIP(
'Server did not return the expected identifier');
logger.error('KMIP::_revokeBucketKey',
{ error, uniqueIdentifier });
Expand All @@ -461,7 +436,7 @@ export default class Client {
destroyBucketKey(bucketKeyId: string, logger: werelogs.Logger, cb: any) {
return this._revokeBucketKey(bucketKeyId, logger, err => {
if (err) {
const error = _arsenalError(err);
const error = arsenalErrorKMIP(err);
logger.error('KMIP::destroyBucketKey: revocation failed',
{ error,
serverInformation: this.serverInformation });
Expand All @@ -471,7 +446,7 @@ export default class Client {
KMIP.TextString('Unique Identifier', bucketKeyId),
], (err, response) => {
if (err) {
const error = _arsenalError(err);
const error = arsenalErrorKMIP(err);
logger.error('KMIP::destroyBucketKey',
{ error,
serverInformation: this.serverInformation });
Expand All @@ -480,7 +455,7 @@ export default class Client {
const uniqueIdentifier =
response.lookup(searchFilter.uniqueIdentifier)[0];
if (uniqueIdentifier !== bucketKeyId) {
const error = _arsenalError(
const error = arsenalErrorKMIP(
'Server did not return the expected identifier');
logger.error('KMIP::destroyBucketKey',
{ error, uniqueIdentifier });
Expand Down Expand Up @@ -521,7 +496,7 @@ export default class Client {
KMIP.ByteString('IV/Counter/Nonce', CRYPTOGRAPHIC_DEFAULT_IV),
], (err, response) => {
if (err) {
const error = _arsenalError(err);
const error = arsenalErrorKMIP(err);
logger.error('KMIP::cipherDataKey',
{ error,
serverInformation: this.serverInformation });
Expand All @@ -531,7 +506,7 @@ export default class Client {
response.lookup(searchFilter.uniqueIdentifier)[0];
const data = response.lookup(searchFilter.data)[0];
if (uniqueIdentifier !== masterKeyId) {
const error = _arsenalError(
const error = arsenalErrorKMIP(
'Server did not return the expected identifier');
logger.error('KMIP::cipherDataKey',
{ error, uniqueIdentifier });
Expand Down Expand Up @@ -571,7 +546,7 @@ export default class Client {
KMIP.ByteString('IV/Counter/Nonce', CRYPTOGRAPHIC_DEFAULT_IV),
], (err, response) => {
if (err) {
const error = _arsenalError(err);
const error = arsenalErrorKMIP(err);
logger.error('KMIP::decipherDataKey',
{ error,
serverInformation: this.serverInformation });
Expand All @@ -581,7 +556,7 @@ export default class Client {
response.lookup(searchFilter.uniqueIdentifier)[0];
const data = response.lookup(searchFilter.data)[0];
if (uniqueIdentifier !== masterKeyId) {
const error = _arsenalError(
const error = arsenalErrorKMIP(
'Server did not return the right identifier');
logger.error('KMIP::decipherDataKey',
{ error, uniqueIdentifier });
Expand Down
Loading

0 comments on commit 7d6c125

Please sign in to comment.