#source: https://github.com/awslabs/aws-cloudformation-templates/tree/master/aws/services/ECS AWSTemplateFormatVersion: '2010-09-09' Description: This stack deploys a Fargate cluster that is in a VPC with both public and private subnets. Containers can be deployed into either the public subnets or the private subnets, and there are two load balancers. One is inside the public subnet, which can be used to send traffic to the containers in the private subnet, and one in the private subnet, which can be used for private internal traffic between internal services. (fdp-1qj64b304) Mappings: # Hard values for the subnet masks. These masks define # the range of internal IP addresses that can be assigned. # The VPC can have all IP's from 10.0.0.0 to 10.0.255.255 # There are four subnets which cover the ranges: # # 10.0.0.0 - 10.0.0.255 # 10.0.1.0 - 10.0.1.255 # 10.0.2.0 - 10.0.2.255 # 10.0.3.0 - 10.0.3.255 # # If you need more IP addresses (perhaps you have so many # instances that you run out) then you can customize these # ranges to add more SubnetConfig: VPC: CIDR: '10.0.0.0/16' PublicOne: CIDR: '10.0.0.0/24' PublicTwo: CIDR: '10.0.1.0/24' PrivateOne: CIDR: '10.0.2.0/24' PrivateTwo: CIDR: '10.0.3.0/24' Resources: # VPC in which containers will be networked. # It has two public subnets, and two private subnets. # We distribute the subnets across the first two available subnets # for the region, for high availability. VPC: Type: AWS::EC2::VPC Properties: EnableDnsSupport: true EnableDnsHostnames: true CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR'] Tags: - Key: "Name" Value: "FargateClusterVPC" # VPC flow logs that that enables you to capture information about # the IP traffic going to and from network interfaces in your VPC VPCFlowLogs: Type: AWS::EC2::FlowLog Properties: DeliverLogsPermissionArn: !GetAtt FlowLogsRole.Arn LogGroupName: !Ref FlowLogGroup ResourceId: !Ref VPC ResourceType: VPC TrafficType: ALL # VPC flow logs can publish data to CloudWatch logs FlowLogGroup: Type: AWS::Logs::LogGroup Properties: RetentionInDays: '30' # Two public subnets, where containers can have public IP addresses PublicSubnetOne: Type: AWS::EC2::Subnet Properties: AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: {Ref: 'AWS::Region'} VpcId: !Ref 'VPC' CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR'] MapPublicIpOnLaunch: true Tags: - Key: "Name" Value: "PublicSubnetOne" PublicSubnetTwo: Type: AWS::EC2::Subnet Properties: AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: {Ref: 'AWS::Region'} VpcId: !Ref 'VPC' CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR'] MapPublicIpOnLaunch: true Tags: - Key: "Name" Value: "PublicSubnetTwo" # Two private subnets where containers will only have private # IP addresses, and will only be reachable by other members of the # VPC PrivateSubnetOne: Type: AWS::EC2::Subnet Properties: AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: {Ref: 'AWS::Region'} VpcId: !Ref 'VPC' CidrBlock: !FindInMap ['SubnetConfig', 'PrivateOne', 'CIDR'] Tags: - Key: "Name" Value: "PrivateSubnetOne" PrivateSubnetTwo: Type: AWS::EC2::Subnet Properties: AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: {Ref: 'AWS::Region'} VpcId: !Ref 'VPC' CidrBlock: !FindInMap ['SubnetConfig', 'PrivateTwo', 'CIDR'] Tags: - Key: "Name" Value: "PrivateSubnetTwo" # Setup networking resources for the public subnets. Containers # in the public subnets have public IP addresses and the routing table # sends network traffic via the internet gateway. InternetGateway: Type: AWS::EC2::InternetGateway GatewayAttachement: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref 'VPC' InternetGatewayId: !Ref 'InternetGateway' PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref 'VPC' PublicRoute: Type: AWS::EC2::Route DependsOn: GatewayAttachement Properties: RouteTableId: !Ref 'PublicRouteTable' DestinationCidrBlock: '0.0.0.0/0' GatewayId: !Ref 'InternetGateway' PublicSubnetOneRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetOne RouteTableId: !Ref PublicRouteTable PublicSubnetTwoRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetTwo RouteTableId: !Ref PublicRouteTable # Setup networking resources for the private subnets. Containers # in these subnets have only private IP addresses, and must use a NAT # gateway to talk to the internet. We launch two NAT gateways, one for # each private subnet. NatGatewayOneAttachment: Type: AWS::EC2::EIP DependsOn: GatewayAttachement Properties: Domain: vpc NatGatewayTwoAttachment: Type: AWS::EC2::EIP DependsOn: GatewayAttachement Properties: Domain: vpc NatGatewayOne: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGatewayOneAttachment.AllocationId SubnetId: !Ref PublicSubnetOne NatGatewayTwo: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGatewayTwoAttachment.AllocationId SubnetId: !Ref PublicSubnetTwo PrivateRouteTableOne: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref 'VPC' PrivateRouteOne: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTableOne DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGatewayOne PrivateRouteTableOneAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTableOne SubnetId: !Ref PrivateSubnetOne PrivateRouteTableTwo: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref 'VPC' PrivateRouteTwo: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTableTwo DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGatewayTwo PrivateRouteTableTwoAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTableTwo SubnetId: !Ref PrivateSubnetTwo # OPTIONAL: VPC Endpoint for DynamoDB # If a container needs to access DynamoDB this allows a container in the private subnet # to talk to DynamoDB directly without needing to go via the NAT gateway. This reduces # the amount of bandwidth through the gateway, meaning that the gateway is free to serve # your other traffic. DynamoDBEndpoint: Type: AWS::EC2::VPCEndpoint Properties: PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: "*" Principal: "*" Resource: "*" RouteTableIds: - !Ref 'PrivateRouteTableOne' - !Ref 'PrivateRouteTableTwo' ServiceName: !Join [ "", [ "com.amazonaws.", { "Ref": "AWS::Region" }, ".dynamodb" ] ] VpcId: !Ref 'VPC' # ECS Resources ECSCluster: Type: AWS::ECS::Cluster # A security group for the containers we will run in Fargate. # Three rules, allowing network traffic from a public facing load # balancer, a private internal load balancer, and from other members # of the security group. # # Remove any of the following ingress rules that are not needed. FargateContainerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Fargate container security group. Use this for all tasks and services. VpcId: !Ref 'VPC' Tags: - Key: "Name" Value: "FargateContainerSecurityGroup" EcsSecurityGroupIngressFromPublicALB: Type: AWS::EC2::SecurityGroupIngress Properties: Description: Ingress from the public ALB GroupId: !Ref 'FargateContainerSecurityGroup' IpProtocol: -1 SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG' EcsSecurityGroupIngressFromPrivateALB: Type: AWS::EC2::SecurityGroupIngress Properties: Description: Ingress from the private ALB GroupId: !Ref 'FargateContainerSecurityGroup' IpProtocol: -1 SourceSecurityGroupId: !Ref 'PrivateLoadBalancerSG' EcsSecurityGroupIngressFromSelf: Type: AWS::EC2::SecurityGroupIngress Properties: Description: Ingress from other containers in the same security group GroupId: !Ref 'FargateContainerSecurityGroup' IpProtocol: -1 SourceSecurityGroupId: !Ref 'FargateContainerSecurityGroup' # Load balancers for getting traffic to containers. # This sample template creates two load balancers: # # - One public load balancer, hosted in public subnets that is accessible # to the public, and is intended to route traffic to one or more public # facing services. # - One private load balancer, hosted in private subnets, that only # accepts traffic from other containers in the Fargate cluster, and is # intended for private services that should not be accessed directly # by the public. # A public facing load balancer, this is used for accepting traffic from the public # internet and directing it to public facing microservices PublicLoadBalancerSG: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Public facing load balancer Security Group VpcId: !Ref 'VPC' SecurityGroupIngress: # Allow access to ALB from anywhere on the internet - CidrIp: 0.0.0.0/0 IpProtocol: -1 PublicLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer DependsOn: GatewayAttachement Properties: Scheme: internet-facing LoadBalancerAttributes: - Key: idle_timeout.timeout_seconds Value: '30' Subnets: # The load balancer is placed into the public subnets, so that traffic # from the internet can reach the load balancer directly via the internet gateway - !Ref PublicSubnetOne - !Ref PublicSubnetTwo SecurityGroups: [!Ref 'PublicLoadBalancerSG'] # An internal load balancer, this would be used for a service that is not # directly accessible to the public, but instead should only receive traffic # from your other services. PrivateLoadBalancerSG: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Internal load balancer security group VpcId: !Ref 'VPC' PrivateLoadBalancerIngressFromECS: Type: AWS::EC2::SecurityGroupIngress Properties: Description: Only accept traffic from a container in the fargate container security group GroupId: !Ref 'PrivateLoadBalancerSG' IpProtocol: -1 SourceSecurityGroupId: !Ref 'FargateContainerSecurityGroup' PrivateLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internal LoadBalancerAttributes: - Key: idle_timeout.timeout_seconds Value: '30' Subnets: # This load balancer is put into the private subnet, so that there is no # route for the public to even be able to access the private load balancer. - !Ref PrivateSubnetOne - !Ref PrivateSubnetTwo SecurityGroups: [!Ref 'PrivateLoadBalancerSG'] # This is an IAM role which authorizes ECS to manage resources on your # account on your behalf, such as updating your load balancer with the # details of where your containers are, so that traffic can reach your # containers. ECSRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ecs.amazonaws.com] Action: ['sts:AssumeRole'] Path: / Policies: - PolicyName: ecs-service PolicyDocument: Statement: - Effect: Allow Action: # Rules which allow ECS to attach network interfaces to instances # on your behalf in order for awsvpc networking mode to work right - 'ec2:AttachNetworkInterface' - 'ec2:CreateNetworkInterface' - 'ec2:CreateNetworkInterfacePermission' - 'ec2:DeleteNetworkInterface' - 'ec2:DeleteNetworkInterfacePermission' - 'ec2:Describe*' - 'ec2:DetachNetworkInterface' # Rules which allow ECS to update load balancers on your behalf # with the information sabout how to send traffic to your containers - 'elasticloadbalancing:DeregisterInstancesFromLoadBalancer' - 'elasticloadbalancing:DeregisterTargets' - 'elasticloadbalancing:Describe*' - 'elasticloadbalancing:RegisterInstancesWithLoadBalancer' - 'elasticloadbalancing:RegisterTargets' Resource: '*' # This is a role which is used by the ECS tasks themselves. ECSTaskExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ecs-tasks.amazonaws.com] Action: ['sts:AssumeRole'] Path: / Policies: - PolicyName: AmazonECSTaskExecutionRolePolicy PolicyDocument: Statement: - Effect: Allow Action: # Allow the ECS Tasks to download images from ECR - 'ecr:GetAuthorizationToken' - 'ecr:BatchCheckLayerAvailability' - 'ecr:GetDownloadUrlForLayer' - 'ecr:BatchGetImage' # Allow the ECS tasks to upload logs to CloudWatch - 'logs:CreateLogStream' - 'logs:PutLogEvents' - 'logs:CreateLogGroup' - 'logs:DescribeLogStreams' Resource: '*' # This is a role which is used to publish flow logs to the specified log group in CloudWatch Logs FlowLogsRole: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: 'vpc-flow-logs.amazonaws.com' Action: 'sts:AssumeRole' Policies: - PolicyName: 'flowlogs-policy' PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 'logs:CreateLogStream' - 'logs:PutLogEvents' - 'logs:DescribeLogGroups' - 'logs:DescribeLogStreams' Resource: !GetAtt FlowLogGroup.Arn # These are the values output by the CloudFormation template. Be careful # about changing any of them, because of them are exported with specific # names so that the other task related CF templates can use them. Outputs: ClusterName: Description: The name of the ECS cluster Value: !Ref 'ECSCluster' Export: Name: 'FargateClusterName' InternalUrl: Description: The url of the internal load balancer Value: !Join ['', ['http://', !GetAtt 'PrivateLoadBalancer.DNSName']] Export: Name: !Join [ ':', [ !Ref 'AWS::StackName', 'InternalUrl' ] ] ExternalUrl: Description: The url of the external load balancer Value: !Join ['', ['http://', !GetAtt 'PublicLoadBalancer.DNSName']] Export: Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ExternalUrl' ] ] ECSPublicLoadBalancer: Description: The ARN of the Public LoadBalancer Value: !Ref 'PublicLoadBalancer' Export: Name: 'ECSPublicLoadBalancer' ECSTaskExecutionRole: Description: The ARN of the ECS role Value: !GetAtt 'ECSTaskExecutionRole.Arn' Export: Name: 'ECSTaskExecutionRole' VPCId: Description: The ID of the VPC that this stack is deployed in Value: !Ref 'VPC' Export: Name: 'FargateClusterVPCId' PublicSubnetOne: Description: Public subnet one Value: !Ref 'PublicSubnetOne' Export: Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnetOne' ] ] PublicSubnetTwo: Description: Public subnet two Value: !Ref 'PublicSubnetTwo' Export: Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnetTwo' ] ] PrivateSubnetOne: Description: Private subnet one Value: !Ref 'PrivateSubnetOne' Export: Name: 'ECSPrivateSubnetOne' PrivateSubnetTwo: Description: Private subnet two Value: !Ref 'PrivateSubnetTwo' Export: Name: 'ECSPrivateSubnetTwo' FargateContainerSecurityGroup: Description: A security group for Fargate containers, tasks, and services Value: !Ref 'FargateContainerSecurityGroup' Export: Name: 'ECSFargateContainerSecurityGroup'