Skip to content

Commit

Permalink
Merge branch 'w/8.7/improvement/CLDSRV-565/global-sse' into tmp/octop…
Browse files Browse the repository at this point in the history
…us/w/8.8/improvement/CLDSRV-565/global-sse
  • Loading branch information
bert-e committed Oct 16, 2024
2 parents ab5d49a + 82f81c2 commit 8060696
Show file tree
Hide file tree
Showing 5 changed files with 309 additions and 1 deletion.
5 changes: 5 additions & 0 deletions lib/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,11 @@ class Config extends EventEmitter {

this.kmsAWS = this._parseKmsAWS(config);

const globalEncryptionEnabled = config.globalEncryptionEnabled;
this.globalEncryptionEnabled = globalEncryptionEnabled || false;
assert(typeof this.globalEncryptionEnabled === 'boolean',
'config.globalEncryptionEnabled must be a boolean');

const defaultEncryptionKeyPerAccount = config.defaultEncryptionKeyPerAccount;
this.defaultEncryptionKeyPerAccount = defaultEncryptionKeyPerAccount || false;
assert(typeof this.defaultEncryptionKeyPerAccount === 'boolean',
Expand Down
13 changes: 12 additions & 1 deletion lib/api/apiUtils/bucket/bucketCreation.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const metadata = require('../../../metadata/wrapper');
const kms = require('../../../kms/wrapper');
const isLegacyAWSBehavior = require('../../../utilities/legacyAWSBehavior');
const { isServiceAccount } = require('../authorization/permissionChecks');
const { config } = require('../../../Config');

const usersBucket = constants.usersBucket;
const oldUsersBucket = constants.oldUsersBucket;
Expand Down Expand Up @@ -248,7 +249,17 @@ function createBucket(authInfo, bucketName, headers,
}
const newBucketMD = results.prepareNewBucketMD;
if (existingBucketMD === 'NoBucketYet') {
const sseConfig = parseBucketEncryptionHeaders(headers);
const bucketSseConfig = parseBucketEncryptionHeaders(headers);

// Apply global SSE configuration when global encryption is enabled
// and no SSE settings were specified during bucket creation.
// Bucket-specific SSE headers override the default encryption.
const sseConfig = config.globalEncryptionEnabled && !bucketSseConfig.algorithm
? {
algorithm: 'AES256',
mandatory: true,
} : bucketSseConfig;

return bucketLevelServerSideEncryption(
bucket, sseConfig, log,
(err, sseInfo) => {
Expand Down
5 changes: 5 additions & 0 deletions lib/api/bucketPutEncryption.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ function bucketPutEncryption(authInfo, request, log, callback) {
updatedConfig.configuredMasterKeyId = configuredMasterKeyId;
}

const { isAccountEncryptionEnabled } = existingConfig;
if (isAccountEncryptionEnabled) {
updatedConfig.isAccountEncryptionEnabled = isAccountEncryptionEnabled;
}

return next(null, bucket, updatedConfig);
},
(bucket, updatedConfig, next) => {
Expand Down
157 changes: 157 additions & 0 deletions tests/unit/api/bucketPut.js
Original file line number Diff line number Diff line change
Expand Up @@ -740,3 +740,160 @@ describe('bucketPut API with failed vault service', () => {
});
});

describe('bucketPut API with SSE Configurations', () => {
const initialGlobalEncryption = config.globalEncryptionEnabled;

afterEach(() => {
config.globalEncryptionEnabled = initialGlobalEncryption;
cleanup();
});

const createTestRequestWithSSE = sseHeaders => ({
...testRequest,
headers: {
...testRequest.headers,
...sseHeaders,
},
});

it('should apply default AES256 SSE when global encryption is enabled and no SSE headers are provided', done => {
config.globalEncryptionEnabled = true;
const request = createTestRequestWithSSE({});

bucketPut(authInfo, request, log, err => {
assert.ifError(err);
return metadata.getBucket(bucketName, log, (err, md) => {
assert.ifError(err);
const sse = md.getServerSideEncryption();
assert.strictEqual(sse.algorithm, 'AES256');
assert.strictEqual(sse.mandatory, true);
done();
});
});
});

it('should override global SSE with bucket-specific SSE headers when provided', done => {
config.globalEncryptionEnabled = true;
const request = createTestRequestWithSSE({
'x-amz-scal-server-side-encryption': 'aws:kms',
'x-amz-scal-server-side-encryption-aws-kms-key-id': 'test-kms-key-id',
});

bucketPut(authInfo, request, log, err => {
assert.ifError(err);
return metadata.getBucket(bucketName, log, (err, md) => {
assert.ifError(err);
const sse = md.getServerSideEncryption();
assert.strictEqual(sse.algorithm, 'aws:kms');
assert.strictEqual(sse.mandatory, true);
assert.strictEqual(sse.configuredMasterKeyId, 'test-kms-key-id');
done();
});
});
});

it('should not apply global SSE when global encryption is disabled and no SSE headers are provided', done => {
config.globalEncryptionEnabled = false;
const request = createTestRequestWithSSE({});

bucketPut(authInfo, request, log, err => {
assert.ifError(err);
return metadata.getBucket(bucketName, log, (err, md) => {
assert.ifError(err);
const sse = md.getServerSideEncryption();
assert(!sse);
done();
});
});
});

it('should apply bucket-specific SSE headers when global encryption is disabled', done => {
config.globalEncryptionEnabled = false;
const request = createTestRequestWithSSE({
'x-amz-scal-server-side-encryption': 'AES256',
});

bucketPut(authInfo, request, log, err => {
assert.ifError(err);
return metadata.getBucket(bucketName, log, (err, md) => {
assert.ifError(err);
const sse = md.getServerSideEncryption();
assert.strictEqual(sse.algorithm, 'AES256');
assert.strictEqual(sse.mandatory, true);
done();
});
});
});

it('should apply default AES256 SSE when global encryption is enabled and an invalid algorithm is set', done => {
config.globalEncryptionEnabled = true;
const request = createTestRequestWithSSE({
'x-amz-scal-server-side-encryption': 'INVALID_ALGO',
});

bucketPut(authInfo, request, log, err => {
assert.ifError(err);
metadata.getBucket(bucketName, log, (err, md) => {
assert.ifError(err);
const sse = md.getServerSideEncryption();
assert.strictEqual(sse.algorithm, 'AES256');
assert.strictEqual(sse.mandatory, true);
done();
});
});
});

it('should prioritize bucket-specific SSE over global settings even if global is enabled', done => {
config.globalEncryptionEnabled = true;
const request = createTestRequestWithSSE({
'x-amz-scal-server-side-encryption': 'aws:kms',
'x-amz-scal-server-side-encryption-aws-kms-key-id': 'another-kms-key-id',
});

bucketPut(authInfo, request, log, err => {
assert.ifError(err);
return metadata.getBucket(bucketName, log, (err, md) => {
assert.ifError(err);
const sse = md.getServerSideEncryption();
assert.strictEqual(sse.algorithm, 'aws:kms');
assert.strictEqual(sse.mandatory, true);
assert.strictEqual(sse.configuredMasterKeyId, 'another-kms-key-id');
done();
});
});
});

it('should apply default SSE if global encryption is enabled and no bucket-specific SSE is provided', done => {
config.globalEncryptionEnabled = true;
const request = createTestRequestWithSSE({});

bucketPut(authInfo, request, log, err => {
assert.ifError(err);
return metadata.getBucket(bucketName, log, (err, md) => {
assert.ifError(err);
const sse = md.getServerSideEncryption();
assert.strictEqual(sse.algorithm, 'AES256');
assert.strictEqual(sse.mandatory, true);
done();
});
});
});

it('should not override bucket-specific SSE with global settings', done => {
config.globalEncryptionEnabled = true;
const request = createTestRequestWithSSE({
'x-amz-scal-server-side-encryption': 'aws:kms',
});

bucketPut(authInfo, request, log, err => {
assert.ifError(err);
return metadata.getBucket(bucketName, log, (err, md) => {
assert.ifError(err);
const sse = md.getServerSideEncryption();
assert.strictEqual(sse.algorithm, 'aws:kms');
assert.strictEqual(sse.mandatory, true);
done();
});
});
});
});
130 changes: 130 additions & 0 deletions tests/unit/api/bucketPutEncryption.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,136 @@ describe('bucketPutEncryption API with account level encryption', () => {
});
});
});

it('should keep isAccountEncryptionEnabled after AES256 encryption update', done => {
const post = templateSSEConfig({ algorithm: 'AES256' });
const expectedSseInfo = {
cryptoScheme: 1,
algorithm: 'AES256',
mandatory: true,
masterKeyId: accountLevelMasterKeyId,
isAccountEncryptionEnabled: true,
};

bucketPutEncryption(authInfo, templateRequest(bucketName, { post }), log, err => {
assert.ifError(err);
return getSSEConfig(bucketName, log, (err, sseInfo) => {
assert.ifError(err);
assert.deepStrictEqual(sseInfo, expectedSseInfo);
const newConf = templateSSEConfig({ algorithm: 'AES256' });
return bucketPutEncryption(authInfo, templateRequest(bucketName, { post: newConf }), log,
err => {
assert.ifError(err);
return getSSEConfig(bucketName, log, (err, updatedSSEInfo) => {
assert.deepStrictEqual(updatedSSEInfo, expectedSseInfo);
done();
});
}
);
});
});
});

it('should keep isAccountEncryptionEnabled after switching from AES256 to aws:kms with keyId', done => {
const post = templateSSEConfig({ algorithm: 'AES256' });
bucketPutEncryption(authInfo, templateRequest(bucketName, { post }), log, err => {
assert.ifError(err);
return getSSEConfig(bucketName, log, (err, sseInfo) => {
assert.ifError(err);
assert.deepStrictEqual(sseInfo, {
cryptoScheme: 1,
algorithm: 'AES256',
mandatory: true,
masterKeyId: accountLevelMasterKeyId,
isAccountEncryptionEnabled: true,
});
const keyId = '12345';
const newConf = templateSSEConfig({ algorithm: 'aws:kms', keyId });
return bucketPutEncryption(authInfo, templateRequest(bucketName, { post: newConf }), log,
err => {
assert.ifError(err);
return getSSEConfig(bucketName, log, (err, updatedSSEInfo) => {
assert.deepStrictEqual(updatedSSEInfo, {
cryptoScheme: 1,
algorithm: 'aws:kms',
mandatory: true,
masterKeyId: accountLevelMasterKeyId,
configuredMasterKeyId: keyId,
isAccountEncryptionEnabled: true,
});
done();
});
}
);
});
});
});

it('should keep isAccountEncryptionEnabled after switching from aws:kms to AES256 encryption', done => {
const post = templateSSEConfig({ algorithm: 'aws:kms' });
bucketPutEncryption(authInfo, templateRequest(bucketName, { post }), log, err => {
assert.ifError(err);
return getSSEConfig(bucketName, log, (err, sseInfo) => {
assert.ifError(err);
assert.deepStrictEqual(sseInfo, {
cryptoScheme: 1,
algorithm: 'aws:kms',
mandatory: true,
masterKeyId: accountLevelMasterKeyId,
isAccountEncryptionEnabled: true,
});
const newConf = templateSSEConfig({ algorithm: 'AES256' });
return bucketPutEncryption(authInfo, templateRequest(bucketName, { post: newConf }), log,
err => {
assert.ifError(err);
return getSSEConfig(bucketName, log, (err, updatedSSEInfo) => {
assert.deepStrictEqual(updatedSSEInfo, {
cryptoScheme: 1,
algorithm: 'AES256',
mandatory: true,
masterKeyId: accountLevelMasterKeyId,
isAccountEncryptionEnabled: true,
});
done();
});
}
);
});
});
});

it('should set isAccountEncryptionEnabled after switching from aws:kms with keyId to AES256', done => {
const keyId = '12345';
const post = templateSSEConfig({ algorithm: 'aws:kms', keyId });
bucketPutEncryption(authInfo, templateRequest(bucketName, { post }), log, err => {
assert.ifError(err);
return getSSEConfig(bucketName, log, (err, sseInfo) => {
assert.ifError(err);
assert.deepStrictEqual(sseInfo, {
cryptoScheme: 1,
algorithm: 'aws:kms',
mandatory: true,
configuredMasterKeyId: keyId,
});
const newConf = templateSSEConfig({ algorithm: 'AES256' });
return bucketPutEncryption(authInfo, templateRequest(bucketName, { post: newConf }), log,
err => {
assert.ifError(err);
return getSSEConfig(bucketName, log, (err, updatedSSEInfo) => {
assert.deepStrictEqual(updatedSSEInfo, {
cryptoScheme: 1,
algorithm: 'AES256',
mandatory: true,
masterKeyId: accountLevelMasterKeyId,
isAccountEncryptionEnabled: true,
});
done();
});
}
);
});
});
});
});

describe('bucketPutEncryption API with failed vault service', () => {
Expand Down

0 comments on commit 8060696

Please sign in to comment.