Skip to content

Commit 46e468a

Browse files
CLDSRV-670: Test KMS error returned to end user
1 parent 2b7cf80 commit 46e468a

File tree

1 file changed

+162
-0
lines changed

1 file changed

+162
-0
lines changed

tests/functional/sse-kms-migration/arnPrefix.js

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const log = new DummyRequestLogger();
66
const { makeRequest } = require('../raw-node/utils/makeRequest');
77
const helpers = require('./helpers');
88
const scenarios = require('./scenarios');
9+
const kms = require('../../../lib/kms/wrapper');
910

1011
// copy part of aws-node-sdk/test/object/encryptionHeaders.js and add more tests
1112

@@ -505,3 +506,164 @@ describe('ensure MPU use good SSE', () => {
505506
);
506507
});
507508
});
509+
510+
describe('KMS error', () => {
511+
const destroyKmsKey = promisify(kms.destroyBucketKey);
512+
const sseConfig = { algo: 'aws:kms', masterKeyId: true }
513+
const Bucket = 'bkt-kms-err';
514+
const Key = 'obj';
515+
const body = 'content';
516+
517+
let masterKeyId, masterKeyArn;
518+
let anotherKeyInfo;
519+
520+
let expectedErr, expectedMsg;
521+
522+
const expectedKMIP = {
523+
code: /KMS\.NotFoundException/,
524+
msg: (action, keyId) => new RegExp(`^KMS \\(KMIP\\) error for ${action} on ${keyId}\\..*`),
525+
};
526+
// localkms container returns a different error message when the key is pending deletion
527+
// as we decrypt without passing the keyId, so we need to handle it separately
528+
const localKms = 'The ciphertext refers to a customer master key that does not exist, ' +
529+
'does not exist in this region, or you are not allowed to access\\.';
530+
const expectedAWS = {
531+
code: /KMS\.KMSInvalidStateException|KMS\.AccessDeniedException/,
532+
msg: (_, keyId) => new RegExp(`${keyId} is pending deletion\\.|${localKms}`),
533+
};
534+
535+
if (helpers.config.backends.kms === 'kmip') {
536+
({ code: expectedErr, msg: expectedMsg } = expectedKMIP);
537+
} else if (helpers.config.backends.kms === 'aws') {
538+
({ code: expectedErr, msg: expectedMsg } = expectedAWS);
539+
} else {
540+
throw new Error(`Unsupported KMS backend: ${helpers.config.backends.kms}`);
541+
}
542+
543+
function assertKmsError(action, keyId) {
544+
return err => {
545+
assert.match(err.name, expectedErr);
546+
assert.match(err.message, expectedMsg(action, keyId));
547+
return true;
548+
};
549+
}
550+
551+
552+
before(async () => {
553+
void await helpers.s3.createBucket({ Bucket }).promise();
554+
await helpers.s3.putObject({
555+
...helpers.putObjParams(Bucket, 'plaintext', {}, null),
556+
Body: body,
557+
}).promise();
558+
559+
({ masterKeyId, masterKeyArn } = await helpers.createKmsKey(log));
560+
await helpers.putEncryptedObject(Bucket, Key, sseConfig, masterKeyArn, body);
561+
// ensure we can decrypt and read the object
562+
const obj = await helpers.s3.getObject({ Bucket, Key }).promise();
563+
assert.strictEqual(obj.Body.toString(), body);
564+
void await destroyKmsKey(masterKeyArn, log);
565+
});
566+
567+
after(async () => {
568+
void await helpers.cleanup(Bucket);
569+
if (masterKeyArn) {
570+
try {
571+
void await destroyKmsKey(masterKeyArn, log);
572+
} catch (e) { void e; }
573+
[masterKeyArn, masterKeyId] = [null, null];
574+
}
575+
});
576+
577+
afterEach(async () => {
578+
if (anotherKeyInfo) {
579+
try {
580+
void await destroyKmsKey(anotherKeyInfo.masterKeyArn, log);
581+
} catch (e) { void e; }
582+
anotherKeyInfo = null;
583+
}
584+
});
585+
586+
it('putObject should fail with kms error', async () => {
587+
await assert.rejects(helpers.putEncryptedObject(Bucket, 'fail', sseConfig, masterKeyArn, body),
588+
assertKmsError('Encrypt', masterKeyId));
589+
});
590+
591+
it('getObject should fail with kms error', async () => {
592+
await assert.rejects(helpers.s3.getObject({ Bucket, Key }).promise(),
593+
assertKmsError('Decrypt', masterKeyId));
594+
});
595+
596+
it('copyObject should fail with kms error when getting from source', async () => {
597+
await assert.rejects(helpers.s3.copyObject(
598+
{ Bucket, Key: 'copy', CopySource: `${Bucket}/${Key}` }).promise(),
599+
assertKmsError('Decrypt', masterKeyId)
600+
);
601+
});
602+
603+
it('copyObject should fail with kms error when putting to destination', async () => {
604+
await assert.rejects(helpers.s3.copyObject(
605+
{
606+
Bucket,
607+
Key: 'copyencrypted',
608+
CopySource: `${Bucket}/plaintext`,
609+
ServerSideEncryption: 'aws:kms',
610+
SSEKMSKeyId: masterKeyArn,
611+
}
612+
).promise(),
613+
assertKmsError('Encrypt', masterKeyId));
614+
});
615+
616+
it('createMPU should fail with kms error', async () => {
617+
const mpuKey = 'mpuKeyEncryptedFail';
618+
await assert.rejects(helpers.s3.createMultipartUpload(
619+
helpers.putObjParams(Bucket, mpuKey, sseConfig, masterKeyArn)).promise(),
620+
assertKmsError('Encrypt', masterKeyId));
621+
});
622+
623+
it('mpu uploadPartCopy should fail with kms error when getting from source', async () => {
624+
const mpuKey = 'mpuKey';
625+
const mpu = await helpers.s3.createMultipartUpload(
626+
helpers.putObjParams(Bucket, mpuKey, {}, null)).promise();
627+
await assert.rejects(helpers.s3.uploadPartCopy(
628+
{
629+
UploadId: mpu.UploadId,
630+
Bucket,
631+
Key: mpuKey,
632+
PartNumber: 1,
633+
CopySource: `${Bucket}/${Key}`,
634+
}
635+
).promise(),
636+
assertKmsError('Decrypt', masterKeyId));
637+
});
638+
639+
it('mpu uploadPart & copy should fail with kms error when putting to destination', async () => {
640+
const mpuKey = 'mpuKeyEncrypted';
641+
anotherKeyInfo = await helpers.createKmsKey(log);
642+
643+
const mpu = await helpers.s3.createMultipartUpload(
644+
helpers.putObjParams(Bucket, mpuKey, sseConfig, anotherKeyInfo.masterKeyArn)).promise();
645+
646+
void await destroyKmsKey(anotherKeyInfo.masterKeyArn, log);
647+
await assert.rejects(helpers.s3.uploadPart(
648+
{
649+
UploadId: mpu.UploadId,
650+
Bucket,
651+
Key: mpuKey,
652+
PartNumber: 1,
653+
Body: body,
654+
}
655+
).promise(),
656+
assertKmsError('Encrypt', anotherKeyInfo.masterKeyId));
657+
658+
await assert.rejects(helpers.s3.uploadPartCopy(
659+
{
660+
UploadId: mpu.UploadId,
661+
Bucket,
662+
Key: mpuKey,
663+
PartNumber: 1,
664+
CopySource: `${Bucket}/plaintext`,
665+
}
666+
).promise(),
667+
assertKmsError('Encrypt', anotherKeyInfo.masterKeyId));
668+
});
669+
});

0 commit comments

Comments
 (0)