Skip to content

Commit d1f8e5c

Browse files
MrArnoldPalmermergify[bot]
authored andcommitted
fix(elbv2): allow multiple certificates on ALB listener (#4116)
* fix(elasticloadbalancingv2): Allow Multiple Certificates on ALB Listener Fixes a cloudformation error when attaching multiple certificates to an alb listener. Cloudformation allows only a single certificate attached to the `LoadBalancer` resource. If multiple certificates are passed to the construct on initialization or through the `.addCertificateArns` method, separate `ListenerCertificate` resources are created for all after the first. Closes [issue #3757](#3757) * PR Revisions
1 parent 899656c commit d1f8e5c

File tree

2 files changed

+103
-3
lines changed

2 files changed

+103
-3
lines changed

packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,11 @@ export class ApplicationListener extends BaseListener implements IApplicationLis
124124
this.loadBalancer = props.loadBalancer;
125125
this.protocol = protocol;
126126
this.certificateArns = [];
127-
this.certificateArns.push(...(props.certificateArns || []));
127+
128+
// Attach certificates
129+
if (props.certificateArns && props.certificateArns.length > 0) {
130+
this.addCertificateArns("ListenerCertificate", props.certificateArns);
131+
}
128132

129133
// This listener edits the securitygroup of the load balancer,
130134
// but adds its own default port.
@@ -142,9 +146,25 @@ export class ApplicationListener extends BaseListener implements IApplicationLis
142146

143147
/**
144148
* Add one or more certificates to this listener.
149+
*
150+
* After the first certificate, this creates ApplicationListenerCertificates
151+
* resources since cloudformation requires the certificates array on the
152+
* listener resource to have a length of 1.
145153
*/
146-
public addCertificateArns(_id: string, arns: string[]): void {
147-
this.certificateArns.push(...arns);
154+
public addCertificateArns(id: string, arns: string[]): void {
155+
const additionalCertArns = [...arns];
156+
157+
if (this.certificateArns.length === 0 && additionalCertArns.length > 0) {
158+
const first = additionalCertArns.splice(0, 1)[0];
159+
this.certificateArns.push(first);
160+
}
161+
162+
if (additionalCertArns.length > 0) {
163+
new ApplicationListenerCertificate(this, id, {
164+
listener: this,
165+
certificateArns: additionalCertArns
166+
});
167+
}
148168
}
149169

150170
/**

packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,30 @@ export = {
9595
test.done();
9696
},
9797

98+
'HTTPS listener can add certificate after construction'(test: Test) {
99+
// GIVEN
100+
const stack = new cdk.Stack();
101+
const vpc = new ec2.Vpc(stack, 'Stack');
102+
const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc });
103+
104+
// WHEN
105+
const listener = lb.addListener('Listener', {
106+
port: 443,
107+
defaultTargetGroups: [new elbv2.ApplicationTargetGroup(stack, 'Group', { vpc, port: 80 })]
108+
});
109+
110+
listener.addCertificateArns("Arns", ['cert']);
111+
112+
// THEN
113+
expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::Listener', {
114+
Certificates: [
115+
{ CertificateArn: "cert" }
116+
],
117+
}));
118+
119+
test.done();
120+
},
121+
98122
'Can configure targetType on TargetGroups'(test: Test) {
99123
// GIVEN
100124
const stack = new cdk.Stack();
@@ -647,6 +671,62 @@ export = {
647671

648672
test.done();
649673
},
674+
675+
'Can pass multiple certificate arns to application listener constructor'(test: Test) {
676+
// GIVEN
677+
const stack = new cdk.Stack();
678+
const vpc = new ec2.Vpc(stack, 'Stack');
679+
const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc });
680+
681+
// WHEN
682+
lb.addListener('Listener', {
683+
port: 443,
684+
certificateArns: ['cert1', 'cert2'],
685+
defaultTargetGroups: [new elbv2.ApplicationTargetGroup(stack, 'Group', { vpc, port: 80 })]
686+
});
687+
688+
// THEN
689+
expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::Listener', {
690+
Protocol: 'HTTPS'
691+
}));
692+
693+
expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::ListenerCertificate', {
694+
Certificates: [{ CertificateArn: 'cert2' }],
695+
}));
696+
697+
test.done();
698+
},
699+
700+
'Can add additional certificates via addCertficateArns to application listener'(test: Test) {
701+
// GIVEN
702+
const stack = new cdk.Stack();
703+
const vpc = new ec2.Vpc(stack, 'Stack');
704+
const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc });
705+
706+
// WHEN
707+
const listener = lb.addListener('Listener', {
708+
port: 443,
709+
certificateArns: ['cert1', 'cert2'],
710+
defaultTargetGroups: [new elbv2.ApplicationTargetGroup(stack, 'Group', { vpc, port: 80 })]
711+
});
712+
713+
listener.addCertificateArns("ListenerCertificateX", ['cert3']);
714+
715+
// THEN
716+
expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::Listener', {
717+
Protocol: 'HTTPS'
718+
}));
719+
720+
expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::ListenerCertificate', {
721+
Certificates: [{ CertificateArn: 'cert2' }],
722+
}));
723+
724+
expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::ListenerCertificate', {
725+
Certificates: [{ CertificateArn: 'cert3' }],
726+
}));
727+
728+
test.done();
729+
},
650730
};
651731

652732
class ResourceWithLBDependency extends cdk.CfnResource {

0 commit comments

Comments
 (0)