Skip to content

Commit cfc1c9c

Browse files
committed
Merge branch 'SubjectAlternativeNames'
2 parents 724ba90 + 3f19466 commit cfc1c9c

File tree

5 files changed

+94
-32
lines changed

5 files changed

+94
-32
lines changed

Readme.md

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,29 @@ open serverless.yml and add the following:
5858

5959
custom:
6060
customCertificate:
61-
certificateName: 'abc.somedomain.io' //required
62-
idempotencyToken: 'abcsomedomainio' //optional
63-
hostedZoneName: 'somedomain.io.' //required if hostedZoneId is not set
64-
hostedZoneId: 'XXXXXXXXX' //required if hostedZoneName is not set
65-
writeCertInfoToFile: false // optional default is false. if you set it to true you will get a new file (after executing serverless create-cert), that contains certificate info that you can use in your deploy pipeline
66-
certInfoFileName: 'cert-info.yml' // optional, only used when writeCertInfoToFile is set to true. It sets the name of the file containing the cert info
67-
region: eu-west-1 // optional - default is us-east-1 which is required for custom api gateway domains of Type Edge (default)
61+
//required
62+
certificateName: 'abc.somedomain.io'
63+
//optional
64+
idempotencyToken: 'abcsomedomainio'
65+
//required if hostedZoneId is not set
66+
hostedZoneName: 'somedomain.io.'
67+
//required if hostedZoneName is not set
68+
hostedZoneId: 'XXXXXXXXX'
69+
// optional default is false. if you set it to true you will get a new file (after executing serverless create-cert), that contains certificate info that you can use in your deploy pipeline
70+
writeCertInfoToFile: false
71+
// optional, only used when writeCertInfoToFile is set to true. It sets the name of the file containing the cert info
72+
certInfoFileName: 'cert-info.yml'
73+
// optional - default is us-east-1 which is required for custom api gateway domains of Type Edge (default)
74+
region: eu-west-1
75+
//optional - see SubjectAlternativeNames https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/ACM.html#requestCertificate-property
76+
subjectAlternativeNames :
77+
- 'www.somedomain.io'
78+
- 'def.somedomain.io'
79+
//optional - see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/ACM.html#addTagsToCertificate-property
80+
//if you want to give your certificate a name that is shown in the ACM Console you can add a Tag with the key "Name"
81+
tags:
82+
Name: 'somedomain.com'
83+
Environment: 'prod'
6884

6985

7086
now you can run:

examples/certificate-creator-example/serverless.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,10 @@ custom:
4242
idempotencyToken: 'certcreatorsamplegreenelephantio'
4343
writeCertInfoToFile: true
4444
certInfoFileName: "certs/${self:provider.stage}/cert-info.yml"
45-
hostedZoneName: 'greenelephant.io.'
45+
hostedZoneName: 'greenelephant.io.'
46+
subjectAlternativeNames :
47+
- 'certcreatorsample1.greenelephant.io'
48+
- 'certcreatorsample2.greenelephant.io'
49+
tags:
50+
Name: 'somedomain.com'
51+
Environment: 'prod'

index.js

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const path = require('path');
66
const YAML = require('yamljs');
77
const mkdirp = require('mkdirp');
88

9-
const unsupportedRegionPrefixes = [ 'cn-' ];
9+
const unsupportedRegionPrefixes = ['cn-'];
1010

1111
class CreateCertificatePlugin {
1212
constructor(serverless, options) {
@@ -45,9 +45,11 @@ class CreateCertificatePlugin {
4545
this.idempotencyToken = this.serverless.service.custom.customCertificate.idempotencyToken;
4646
this.writeCertInfoToFile = this.serverless.service.custom.customCertificate.writeCertInfoToFile || false;
4747
this.certInfoFileName = this.serverless.service.custom.customCertificate.certInfoFileName || 'cert-info.yml';
48+
this.subjectAlternativeNames = this.serverless.service.custom.customCertificate.subjectAlternativeNames || [];
49+
this.tags = this.serverless.service.custom.customCertificate.tags || {};
4850

4951
unsupportedRegionPrefixes.forEach(unsupportedRegionPrefix => {
50-
if(this.region.startsWith(unsupportedRegionPrefix)){
52+
if (this.region.startsWith(unsupportedRegionPrefix)) {
5153
console.log(`The configured region ${this.region} does not support ACM. Plugin disabled`);
5254
this.enabled = false;
5355
}
@@ -92,6 +94,34 @@ class CreateCertificatePlugin {
9294
return this.acm.listCertificates({}).promise();
9395
}
9496

97+
/**
98+
* tags a certificate
99+
*/
100+
tagCertificate(certificateArn) {
101+
let mappedTags = [];
102+
if (Object.keys(this.tags).length) {
103+
mappedTags = Object.keys(this.tags).map((tag) => {
104+
return {
105+
Key: tag,
106+
Value: this.tags[tag]
107+
}
108+
});
109+
const params = {
110+
CertificateArn: certificateArn,
111+
Tags: mappedTags
112+
}
113+
114+
this.serverless.cli.log(`tagging certificate`);
115+
return this.acm.addTagsToCertificate(params).promise().catch(error => {
116+
this.serverless.cli.log('tagging certificate failed', error);
117+
console.log('problem', error);
118+
throw error;
119+
});
120+
}
121+
122+
return Promise.resolve();
123+
}
124+
95125
getExistingCertificate() {
96126
return this.listCertificates().then(data => {
97127

@@ -124,7 +154,7 @@ class CreateCertificatePlugin {
124154
/**
125155
* Creates a certificate for the given options set in serverless.yml under custom->customCertificate
126156
*/
127-
createCertificate() {
157+
createCertificate() {
128158
this.initializeVariables();
129159
if (!this.enabled) {
130160
return this.reportDisabled();
@@ -142,9 +172,13 @@ class CreateCertificatePlugin {
142172
let params = {
143173
DomainName: this.domain,
144174
ValidationMethod: 'DNS',
145-
IdempotencyToken: this.idempotencyToken
175+
IdempotencyToken: this.idempotencyToken,
146176
};
147177

178+
if (this.subjectAlternativeNames && this.subjectAlternativeNames.length) {
179+
params.SubjectAlternativeNames = this.subjectAlternativeNames
180+
}
181+
148182
return this.acm.requestCertificate(params).promise().then(requestCertificateResponse => {
149183
this.serverless.cli.log(`requested cert: ${requestCertificateResponse.CertificateArn}`);
150184

@@ -154,7 +188,10 @@ class CreateCertificatePlugin {
154188

155189
return delay(10000).then(() => this.acm.describeCertificate(params).promise().then(certificate => {
156190
this.serverless.cli.log(`got cert info: ${certificate.Certificate.CertificateArn} - ${certificate.Certificate.Status}`);
157-
return this.createRecordSetForDnsValidation(certificate).then(() => this.waitUntilCertificateIsValidated(certificate.Certificate.CertificateArn));
191+
return this.createRecordSetForDnsValidation(certificate)
192+
.then(() => this.tagCertificate(certificate.Certificate.CertificateArn))
193+
.then(() => this.waitUntilCertificateIsValidated(certificate.Certificate.CertificateArn));
194+
158195
}).catch(error => {
159196
this.serverless.cli.log('could not get cert info', error);
160197
console.log('problem', error);
@@ -219,29 +256,32 @@ class CreateCertificatePlugin {
219256
*/
220257
createRecordSetForDnsValidation(certificate) {
221258
return this.getHostedZoneId().then((hostedZoneId) => {
259+
260+
let changes = certificate.Certificate.DomainValidationOptions.map((x) => {
261+
return {
262+
Action: "CREATE",
263+
ResourceRecordSet: {
264+
Name: x.ResourceRecord.Name,
265+
ResourceRecords: [
266+
{
267+
Value: x.ResourceRecord.Value
268+
}
269+
],
270+
TTL: 60,
271+
Type: x.ResourceRecord.Type
272+
}
273+
}
274+
});
275+
222276
var params = {
223277
ChangeBatch: {
224-
Changes: [
225-
{
226-
Action: "CREATE",
227-
ResourceRecordSet: {
228-
Name: certificate.Certificate.DomainValidationOptions[0].ResourceRecord.Name,
229-
ResourceRecords: [
230-
{
231-
Value: certificate.Certificate.DomainValidationOptions[0].ResourceRecord.Value
232-
}
233-
],
234-
TTL: 60,
235-
Type: certificate.Certificate.DomainValidationOptions[0].ResourceRecord.Type
236-
}
237-
}
238-
],
278+
Changes: changes,
239279
Comment: `DNS Validation for certificate ${certificate.Certificate.DomainValidationOptions[0].DomainName}`
240280
},
241281
HostedZoneId: hostedZoneId
242282
};
243283
return this.route53.changeResourceRecordSets(params).promise().then(recordSetResult => {
244-
this.serverless.cli.log('dns validation record created - certificate is ready for use after validation has gone through');
284+
this.serverless.cli.log('dns validation record(s) created - certificate is ready for use after validation has gone through');
245285
}).catch(error => {
246286
this.serverless.cli.log('could not create record set for dns validation', error);
247287
console.log('problem', error);
@@ -251,7 +291,7 @@ class CreateCertificatePlugin {
251291
}
252292

253293
/**
254-
* Prints out a summary of all domain manager related info
294+
* Prints out a summary of all certificate related info
255295
*/
256296
certificateSummary() {
257297
this.initializeVariables();

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.0.9",
3+
"version": "1.1.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)