Skip to content

Commit

Permalink
feat(ecs): add support for automatic HTTPS redirect (#9341)
Browse files Browse the repository at this point in the history
closes #8488

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
hoegertn committed Aug 17, 2020
1 parent c3ad47b commit 84a3ef6
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 2 deletions.
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-ecs-patterns/README.md
Expand Up @@ -62,6 +62,8 @@ You can customize the health check for your target group; otherwise it defaults

Fargate services will use the `LATEST` platform version by default, but you can override by providing a value for the `platformVersion` property in the constructor.

By setting `redirectHTTP` to true, CDK will automatically create a listener on port 80 that redirects HTTP traffic to the HTTPS port.

Additionally, if more than one application target group are needed, instantiate one of the following:

* `ApplicationMultipleTargetGroupsEc2Service`
Expand Down
Expand Up @@ -3,7 +3,7 @@ import { IVpc } from '@aws-cdk/aws-ec2';
import { AwsLogDriver, BaseService, CloudMapOptions, Cluster, ContainerImage, ICluster, LogDriver, PropagatedTagSource, Secret } from '@aws-cdk/aws-ecs';
import {
ApplicationListener, ApplicationLoadBalancer, ApplicationProtocol, ApplicationTargetGroup,
IApplicationLoadBalancer, ListenerCertificate,
IApplicationLoadBalancer, ListenerCertificate, ListenerAction,
} from '@aws-cdk/aws-elasticloadbalancingv2';
import { IRole } from '@aws-cdk/aws-iam';
import { ARecord, IHostedZone, RecordTarget } from '@aws-cdk/aws-route53';
Expand Down Expand Up @@ -168,6 +168,14 @@ export interface ApplicationLoadBalancedServiceBaseProps {
* @default - AWS Cloud Map service discovery is not enabled.
*/
readonly cloudMapOptions?: CloudMapOptions;

/**
* Specifies whether the load balancer should redirect traffic on port 80 to port 443 to support HTTP->HTTPS redirects
* This is only valid if the protocol of the ALB is HTTPS
*
* @default false
*/
readonly redirectHTTP?: boolean;
}

export interface ApplicationLoadBalancedTaskImageOptions {
Expand Down Expand Up @@ -276,6 +284,11 @@ export abstract class ApplicationLoadBalancedServiceBase extends cdk.Construct {
*/
public readonly listener: ApplicationListener;

/**
* The redirect listener for the service if redirectHTTP is enabled.
*/
public readonly redirectListener?: ApplicationListener;

/**
* The target group for the service.
*/
Expand Down Expand Up @@ -322,6 +335,9 @@ export abstract class ApplicationLoadBalancedServiceBase extends cdk.Construct {
if (props.certificate !== undefined && props.protocol !== undefined && props.protocol !== ApplicationProtocol.HTTPS) {
throw new Error('The HTTPS protocol must be used when a certificate is given');
}
if (props.protocol !== ApplicationProtocol.HTTPS && props.redirectHTTP === true) {
throw new Error('The HTTPS protocol must be used when redirecting HTTP traffic');
}
const protocol = props.protocol !== undefined ? props.protocol :
(props.certificate ? ApplicationProtocol.HTTPS : ApplicationProtocol.HTTP);

Expand Down Expand Up @@ -353,6 +369,18 @@ export abstract class ApplicationLoadBalancedServiceBase extends cdk.Construct {
if (this.certificate !== undefined) {
this.listener.addCertificates('Arns', [ListenerCertificate.fromCertificateManager(this.certificate)]);
}
if (props.redirectHTTP) {
this.redirectListener = loadBalancer.addListener('PublicRedirectListener', {
protocol: ApplicationProtocol.HTTP,
port: 80,
open: true,
defaultAction: ListenerAction.redirect({
port: props.listenerPort?.toString() || '443',
protocol: ApplicationProtocol.HTTPS,
permanent: true,
}),
});
}

let domainName = loadBalancer.loadBalancerDnsName;
if (typeof props.domainName !== 'undefined') {
Expand Down
Expand Up @@ -396,6 +396,13 @@
"FromPort": 443,
"IpProtocol": "tcp",
"ToPort": 443
},
{
"CidrIp": "0.0.0.0/0",
"Description": "Allow from anyone on port 80",
"FromPort": 80,
"IpProtocol": "tcp",
"ToPort": 80
}
],
"VpcId": {
Expand Down Expand Up @@ -460,6 +467,26 @@
}
}
},
"myServiceLBPublicRedirectListener0EEF9DCA": {
"Type": "AWS::ElasticLoadBalancingV2::Listener",
"Properties": {
"DefaultActions": [
{
"RedirectConfig": {
"Port": "443",
"Protocol": "HTTPS",
"StatusCode": "HTTP_301"
},
"Type": "redirect"
}
],
"LoadBalancerArn": {
"Ref": "myServiceLB168895E1"
},
"Port": 80,
"Protocol": "HTTP"
}
},
"myServiceCertificate152F9DDA": {
"Type": "AWS::CertificateManager::Certificate",
"Properties": {
Expand All @@ -480,7 +507,7 @@
"Type": "A",
"AliasTarget": {
"DNSName": {
"Fn::Join":
"Fn::Join":
[
"",
[
Expand Down
Expand Up @@ -27,6 +27,7 @@ new ApplicationLoadBalancedFargateService(stack, 'myService', {
stack,
node: stack.node,
},
redirectHTTP: true,
});

app.synth();

0 comments on commit 84a3ef6

Please sign in to comment.