Skip to content

Commit 051a6e9

Browse files
authored
Merge pull request #23 from schwamster/next
#21 #22 added remove-cert command
2 parents c16e8dd + f45b855 commit 051a6e9

File tree

4 files changed

+140
-2
lines changed

4 files changed

+140
-2
lines changed

Readme.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ now you can run:
8989

9090
serverless create-cert
9191

92+
To remove the certificate and delete the CNAME recordsets from route53, run:
93+
94+
serverless remove-cert
95+
9296
# Combine with serverless-domain-manager
9397

9498
If you combine this plugin with [serverless-domain-manager](https://github.com/amplify-education/serverless-domain-manager) you can automate the complete process of creating a custom domain with a certificate.

index.js

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,19 @@ class CreateCertificatePlugin {
2222
'create'
2323
]
2424
},
25+
'remove-cert': {
26+
usage: 'removes the certificate previously created by create-cert command',
27+
lifecycleEvents: [
28+
'remove'
29+
]
30+
}
2531
};
2632

2733
this.hooks = {
2834
'create-cert:create': this.createCertificate.bind(this),
2935
'after:deploy:deploy': this.certificateSummary.bind(this),
3036
'after:info:info': this.certificateSummary.bind(this),
37+
'remove-cert:remove': this.deleteCertificate.bind(this),
3138
};
3239

3340
this.variableResolvers = {
@@ -224,6 +231,46 @@ class CreateCertificatePlugin {
224231
})
225232
}
226233

234+
/**
235+
* Deletes the certificate for the given options set in serverless.yml under custom->customCertificate
236+
* (if it exists)
237+
*/
238+
deleteCertificate() {
239+
this.initializeVariables();
240+
if (!this.enabled) {
241+
return this.reportDisabled();
242+
}
243+
this.serverless.cli.log(`Trying to delete certificate for ${this.domain} in ${this.region} ...`);
244+
return this.getExistingCertificate().then(existingCert => {
245+
246+
247+
if (!existingCert) {
248+
this.serverless.cli.log(`Certificate for ${this.domain} in ${this.region} does not exist. Skipping ...`);
249+
return;
250+
}
251+
252+
let params = {
253+
CertificateArn: existingCert.CertificateArn
254+
};
255+
256+
return this.acm.describeCertificate(params).promise()
257+
.then(certificate => this.deleteRecordSetForDnsValidation(certificate))
258+
.then(() => this.acm.deleteCertificate(params).promise())
259+
.then(() => this.serverless.cli.log(`deleted cert: ${existingCert.CertificateArn}`))
260+
.catch(error => {
261+
this.serverless.cli.log('could not delete cert', error);
262+
console.log('problem', error);
263+
throw error;
264+
});
265+
266+
267+
}).catch(error => {
268+
this.serverless.cli.log('could not get certs', error);
269+
console.log('problem', error);
270+
throw error;
271+
})
272+
}
273+
227274
waitUntilCertificateIsValidated(certificateArn) {
228275
this.serverless.cli.log('waiting until certificate is validated...');
229276
var params = {
@@ -301,6 +348,93 @@ class CreateCertificatePlugin {
301348
});
302349
}
303350

351+
/**
352+
* deletes the record set required for validation type dns.
353+
*/
354+
deleteRecordSetForDnsValidation(certificate) {
355+
return this.getHostedZoneIds().then((hostedZoneIds) => {
356+
357+
return Promise.all(hostedZoneIds.map(({ hostedZoneId, Name }) => {
358+
359+
// Make sure the recordset exist before batching up a delete (in case they got manually deleted),
360+
// otherwise the whole batch will fail
361+
return this.listResourceRecordSets(hostedZoneId).then(existingRecords => {
362+
363+
let changes = certificate.Certificate.DomainValidationOptions
364+
.filter(({DomainName}) => DomainName.endsWith(Name))
365+
.map(opt => opt.ResourceRecord)
366+
.filter(record => existingRecords.find(x => x.Name === record.Name && x.Type === record.Type))
367+
.map(record => {
368+
return {
369+
Action: "DELETE",
370+
ResourceRecordSet: {
371+
Name: record.Name,
372+
ResourceRecords: [
373+
{
374+
Value: record.Value
375+
}
376+
],
377+
TTL: 60,
378+
Type: record.Type
379+
}
380+
}
381+
});
382+
383+
if (changes.length === 0) {
384+
this.serverless.cli.log('no matching dns validation record(s) found in route53');
385+
return;
386+
}
387+
388+
var params = {
389+
ChangeBatch: {
390+
Changes: changes
391+
},
392+
HostedZoneId: hostedZoneId
393+
};
394+
return this.route53.changeResourceRecordSets(params).promise().then(recordSetResult => {
395+
this.serverless.cli.log(`${changes.length} dns validation record(s) deleted`);
396+
}).catch(error => {
397+
this.serverless.cli.log('could not delete record set(s) for dns validation', error);
398+
console.log('problem', error);
399+
throw error;
400+
});
401+
});
402+
}));
403+
});
404+
}
405+
406+
/**
407+
* Lists up all resource recordsets in the given route53 hosted zone.
408+
*/
409+
listResourceRecordSets(hostedZoneId) {
410+
var initialParams = {
411+
HostedZoneId: hostedZoneId
412+
}
413+
414+
this.serverless.cli.log('listing existing record sets in hosted zone', hostedZoneId);
415+
416+
let listRecords = (params) => this.route53.listResourceRecordSets(params).promise()
417+
.then(({ ResourceRecordSets, IsTruncated, NextRecordName, NextRecordType, NextRecordIdentifier }) => {
418+
419+
if (IsTruncated) {
420+
let listMoreParams = Object.assign(params, {
421+
StartRecordName: NextRecordName,
422+
StartRecordType: NextRecordType
423+
});
424+
// Resource record sets that have a routing policy other than simple, should not be the case for our DNS validation records
425+
if (NextRecordIdentifier) {
426+
listMoreParams = Object.assign(listMoreParams, { StartRecordIdentifier: NextRecordIdentifier });
427+
}
428+
429+
return listRecords(listMoreParams).then(moreRecords => ResourceRecordSets.concat(moreRecords));
430+
} else {
431+
return ResourceRecordSets;
432+
}
433+
});
434+
435+
return listRecords(initialParams);
436+
}
437+
304438
/**
305439
* Prints out a summary of all certificate related info
306440
*/

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "serverless-certificate-creator",
3-
"version": "1.2.0",
3+
"version": "1.3.0",
44
"description": "creates a certificate that can be used for custom domains for your api gateway",
55
"main": "index.js",
66
"scripts": {

0 commit comments

Comments
 (0)