diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts index 2fc26dcdb586e..369d28e09de66 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts @@ -1,7 +1,7 @@ import { IVpc } from '@aws-cdk/aws-ec2'; import { AwsLogDriver, BaseService, CloudMapOptions, Cluster, ContainerDefinition, ContainerImage, ICluster, LogDriver, - PropagatedTagSource, Protocol, Secret } from '@aws-cdk/aws-ecs'; -import { NetworkListener, NetworkLoadBalancer, NetworkTargetGroup } from '@aws-cdk/aws-elasticloadbalancingv2'; + PropagatedTagSource, Protocol as ecsProtocol, Secret } from '@aws-cdk/aws-ecs'; +import { IListenerCertificate, NetworkListener, NetworkLoadBalancer, NetworkTargetGroup, Protocol as elbv2Protocol } from '@aws-cdk/aws-elasticloadbalancingv2'; import { IRole } from '@aws-cdk/aws-iam'; import { ARecord, IHostedZone, RecordTarget } from '@aws-cdk/aws-route53'; import { LoadBalancerTarget } from '@aws-cdk/aws-route53-targets'; @@ -232,6 +232,20 @@ export interface NetworkListenerProps { * @default 80 */ readonly port?: number; + + /** + * Protocol for listener, expects TCP or TLS + * + * @default - TLS if certificates are provided. TCP otherwise. + */ + readonly protocol?: elbv2Protocol; + + /** + * Certificate list of ACM cert ARNs + * + * @default - No certificates. + */ + readonly certificates?: IListenerCertificate[]; } /** @@ -300,7 +314,11 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { const lb = this.createLoadBalancer(lbProps.name, lbProps.publicLoadBalancer); this.loadBalancers.push(lb); for (const listenerProps of lbProps.listeners) { - const listener = this.createListener(listenerProps.name, lb, listenerProps.port || 80); + const listener = lb.addListener(listenerProps.name, { + port: listenerProps.port || 80, + certificates: listenerProps.certificates, + protocol: listenerProps.protocol + }); this.listeners.push(listener); } this.createDomainName(lb, lbProps.domainName, lbProps.domainZone); @@ -310,8 +328,8 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { this.loadBalancer = this.loadBalancers[0]; this.listener = this.listeners[0]; } else { - this.loadBalancer = this.createLoadBalancer('LB'); - this.listener = this.createListener('PublicListener', this.loadBalancer, 80); + this.loadBalancer = this.createLoadBalancer('LB', true); + this.listener = this.loadBalancer.addListener("PublicListener", {port: 80}); this.createDomainName(this.loadBalancer); new CfnOutput(this, 'LoadBalancerDNS', { value: this.loadBalancer.loadBalancerDnsName }); @@ -365,7 +383,7 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { protected addPortMappingForTargets(container: ContainerDefinition, targets: NetworkTargetProps[]) { for (const target of targets) { - if (!container.findPortMapping(target.containerPort, Protocol.TCP)) { + if (!container.findPortMapping(target.containerPort, ecsProtocol.TCP)) { container.addPortMappings({ containerPort: target.containerPort }); @@ -415,12 +433,6 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { return new NetworkLoadBalancer(this, name, lbProps); } - private createListener(name: string, lb: NetworkLoadBalancer, port: number): NetworkListener { - return lb.addListener(name, { - port - }); - } - private createDomainName(loadBalancer: NetworkLoadBalancer, name?: string, zone?: IHostedZone) { if (typeof name !== 'undefined') { if (typeof zone === 'undefined') { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts index b371eb760bfbe..cfa2dd89fe2d4 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts @@ -2,7 +2,7 @@ import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/ass import { Certificate } from '@aws-cdk/aws-certificatemanager'; import { InstanceType, Vpc } from '@aws-cdk/aws-ec2'; import { AwsLogDriver, Cluster, ContainerImage, Ec2TaskDefinition, PropagatedTagSource, Protocol } from '@aws-cdk/aws-ecs'; -import { ApplicationProtocol } from '@aws-cdk/aws-elasticloadbalancingv2'; +import { ApplicationProtocol, ListenerCertificate, Protocol as elbv2Protocol } from '@aws-cdk/aws-elasticloadbalancingv2'; import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import { PublicHostedZone } from '@aws-cdk/aws-route53'; import { NamespaceType } from '@aws-cdk/aws-servicediscovery'; @@ -989,7 +989,7 @@ export = { listeners: [ { name: "listener2", - port: 81 + port: 81, } ] } @@ -1103,6 +1103,65 @@ export = { test.done(); }, + 'set a TLS listener'(test: Test) { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // WHEN + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 256, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: "lb", + listeners: [ + { + name: "listener", + certificates: [ListenerCertificate.fromArn("arn:aws:acm:region:account:certificate/123456789012-1234-1234-1234-12345678")], + protocol: elbv2Protocol.TLS + } + ] + } + ], + targetGroups: [ + { + containerPort: 80, + listener: "listener" + }, + ] + }); + + // THEN + expect(stack).to(haveResource("AWS::ElasticLoadBalancingV2::Listener", { + DefaultActions: [ + { + TargetGroupArn: { + Ref: "ServicelblistenerECSTargetGroupweb80Group1E0F6DCA" + }, + Type: "forward" + } + ], + LoadBalancerArn: { + Ref: "ServicelbF1E7AAC9" + }, + Port: 80, + Protocol: "TLS", + Certificates: [ + { + CertificateArn: "arn:aws:acm:region:account:certificate/123456789012-1234-1234-1234-12345678" + } + ] + })); + + test.done(); + }, + 'set vpc instead of cluster'(test: Test) { // GIVEN const stack = new Stack();