Skip to content

Commit

Permalink
fix(core): ACM Import remove race condition (#77)
Browse files Browse the repository at this point in the history
Removes a race condition where certificates would attempt to be deleted while
ACM thinks the certificates are still in use.
  • Loading branch information
grbartel authored Aug 24, 2020
1 parent 39c3b07 commit ac6b419
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import {
implementsIAcmImportCertProps,
} from './types';

const defaultSleep = function(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
};

const ACM_VERSION = '2015-12-08';
const DYNAMODB_VERSION = '2012-08-10';
const SECRETS_MANAGER_VERSION = '2017-10-17';
Expand Down Expand Up @@ -76,9 +80,34 @@ export class AcmCertificateImporter extends DynamoBackedCustomResource {
this.databasePermissionsCheck(resourceTable),
]);
const resources = await resourceTable.query(physicalId);

const maxAttempts = 10;
for (const [key, resource] of Object.entries(resources)) {
console.log(`Deleting resource for '${key}'`);
const arn: string = resource.ARN;

let inUseByResources = [];
for (let attempt = 0; attempt < maxAttempts; attempt++) {
const { Certificate: cert } = await this.acmClient.describeCertificate({
CertificateArn: arn,
}).promise();

inUseByResources = cert!.InUseBy || [];

if (inUseByResources.length) {
// Exponential backoff with jitter based on 200ms base
// component of backoff fixed to ensure minimum total wait time on
// slow targets.
const base = Math.pow(2, attempt);
await defaultSleep(Math.random() * base * 50 + base * 150);
} else {
break;
}
}

if (inUseByResources.length) {
throw new Error(`Response from describeCertificate did not contain an empty InUseBy list after ${maxAttempts} attempts.`);
}
console.log(`Deleting resource for '${key}'`);
try {
await this.acmClient.deleteCertificate({ CertificateArn: arn }).promise();
} catch (e) {
Expand Down
1 change: 1 addition & 0 deletions packages/aws-rfdk/lib/core/lib/imported-acm-certificate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ export class ImportedAcmCertificate extends Construct implements ICertificate {
lambda.addToRolePolicy(new PolicyStatement({
actions: [
'acm:DeleteCertificate',
'acm:DescribeCertificate',
'acm:GetCertificate',
],
resources: ['*'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ test('Import cert', () => {
{
Action: [
'acm:DeleteCertificate',
'acm:DescribeCertificate',
'acm:GetCertificate',
],
Resource: '*',
Expand Down

0 comments on commit ac6b419

Please sign in to comment.