AWSTemplateFormatVersion: '2010-09-09' Description: AWS Fargate cluster running containers in public and private subnets. Supports public facing microservices behind load balancer, private microservices, and private service discovery namespaces. Deployed resources are all tagged with defined environment name tag. Mappings: # The VPC and subnet configuration is passed in via the environment spec. EnvironmentNameConfig: Environment: Name: '{{ environment.name}}' SubnetConfig: VPC: CIDR: '{{ environment.inputs.vpc_cidr}}' PublicOne: CIDR: '{{ environment.inputs.public_subnet_one_cidr}}' PublicTwo: CIDR: '{{ environment.inputs.public_subnet_two_cidr}}' PrivateOne: CIDR: '{{ environment.inputs.private_subnet_one_cidr}}' PrivateTwo: CIDR: '{{ environment.inputs.private_subnet_two_cidr}}' Resources: # Create the VPC with subnets across 2 Availability Zones, 2 Public subnets, 2 Private subnets, # an Internet Gateway, 2 Nat Gateways and the required routetables and routes VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR'] EnableDnsHostnames: true EnableDnsSupport: true Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC PublicSubnetOne: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: {Ref: 'AWS::Region'} CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR'] MapPublicIpOnLaunch: true Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] PublicSubnetTwo: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: {Ref: 'AWS::Region'} CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR'] MapPublicIpOnLaunch: true Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] PrivateSubnetOne: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: {Ref: 'AWS::Region'} CidrBlock: !FindInMap ['SubnetConfig', 'PrivateOne', 'CIDR'] MapPublicIpOnLaunch: false Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] PrivateSubnetTwo: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: {Ref: 'AWS::Region'} CidrBlock: !FindInMap ['SubnetConfig', 'PrivateTwo', 'CIDR'] MapPublicIpOnLaunch: false Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] NatGatewayOneEIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] NatGatewayTwoEIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] NatGatewayOne: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGatewayOneEIP.AllocationId SubnetId: !Ref PublicSubnetOne Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] NatGatewayTwo: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGatewayTwoEIP.AllocationId SubnetId: !Ref PublicSubnetTwo Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] DefaultPublicRoute: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnetOneRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnetOne PublicSubnetTwoRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnetTwo PrivateRouteTableOne: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] DefaultPrivateRouteOne: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTableOne DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGatewayOne PrivateSubnetOneRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTableOne SubnetId: !Ref PrivateSubnetOne PrivateRouteTableTwo: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] DefaultPrivateRouteTwo: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTableTwo DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGatewayTwo PrivateSubnetTwoRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTableTwo SubnetId: !Ref PrivateSubnetTwo # Create the ECS Cluster to schedule and orchestrate the Fargate containers ECSCluster: Type: AWS::ECS::Cluster Properties: Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] # A security group for the containers we will run in Fargate. # Rules are added to this security group based on what ingress you # add for the cluster. ContainerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Access to the Fargate containers VpcId: !Ref 'VPC' Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] # 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: / ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy' Tags: - Key: Name Value: !FindInMap ['EnvironmentNameConfig', 'Environment', 'Name'] PublicLoadBalancerSG: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Access to the public facing load balancer VpcId: !Ref 'VPC' SecurityGroupIngress: # Allow access to ALB from anywhere on the internet - CidrIp: 0.0.0.0/0 IpProtocol: -1 ECSLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internet-facing LoadBalancerAttributes: - Key: idle_timeout.timeout_seconds Value: '30' Subnets: - !Ref 'PublicSubnetOne' - !Ref 'PublicSubnetTwo' SecurityGroups: [!Ref 'PublicLoadBalancerSG'] # 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. This is used for accepting traffic from the public # internet and directing it to public facing microservices PublicLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - FixedResponseConfig: ContentType: text/plain MessageBody: "nothing here" StatusCode: 200 Type: 'fixed-response' LoadBalancerArn: !Ref 'ECSLoadBalancer' Port: 80 Protocol: HTTP # These output values will be available to service templates to use. Outputs: ClusterName: Description: The name of the ECS cluster Value: !Ref 'ECSCluster' ECSTaskExecutionRole: Description: The ARN of the ECS role Value: !GetAtt 'ECSTaskExecutionRole.Arn' VpcId: Description: The ID of the VPC that this stack is deployed in Value: !Ref 'VPC' PublicSubnetOne: Description: A reference to the public subnet in the 1st Availability Zone Value: !Ref 'PublicSubnetOne' PublicSubnetTwo: Description: A reference to the public subnet in the 2nd Availability Zone Value: !Ref 'PublicSubnetTwo' PrivateSubnetOne: Description: A reference to the private subnet in the 1st Availability Zone Value: !Ref 'PrivateSubnetOne' PrivateSubnetTwo: Description: A reference to the private subnet in the 2nd Availability Zone Value: !Ref 'PrivateSubnetTwo' ContainerSecurityGroup: Description: A security group used to allow Fargate containers to receive traffic Value: !Ref 'ContainerSecurityGroup' LoadBalancerARN: Description: Load balancer ARN used by the environment Value: !Ref 'ECSLoadBalancer' LoadBalancerSG: Description: Load balancer security group Value: !Ref 'PublicLoadBalancerSG' LoadBalancerDNS: Description: Load balancer DNS Name Value: !GetAtt 'ECSLoadBalancer.DNSName' LoadBalancerListner: Description: Listener for the load balancer Value: !Ref PublicLoadBalancerListener