AWSTemplateFormatVersion: '2010-09-09' Description: A stack for deploying base resources for the Fargate cluster Parameters: GameServerPortStart: Type: Number Default: 1935 Description: The inbound port range startfor the Fargate task game servers GameServerPortEnd: Type: Number Default: 1945 Description: The inbound port range startfor the Fargate task game servers RedisPort: Type: Number Default: 6379 Description: The inbound port to the ElastiCache Redis cluster 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 # # 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. Currently supports 16K game servers SubnetConfig: VPC: CIDR: '10.0.0.0/16' PublicOne: #8K IPs (used by game servers) CIDR: '10.0.0.0/19' PublicTwo: #8K IPs (used by game servers) CIDR: '10.0.32.0/19' PrivateOne: #256 IPs (used by ElastiCache only) CIDR: '10.0.64.0/24' PrivateTwo: #256 IPs (used by ElastiCache only) CIDR: '10.0.65.0/24' Resources: # VPC in which containers will be networked. # It has two public 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'] # 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 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 # Two private subnets for ElastiCache and Scaler Lambda PrivateSubnetOne: Type: AWS::EC2::Subnet Properties: AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: {Ref: 'AWS::Region'} VpcId: !Ref 'VPC' CidrBlock: !FindInMap ['SubnetConfig', 'PrivateOne', 'CIDR'] PrivateSubnetTwo: Type: AWS::EC2::Subnet Properties: AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: {Ref: 'AWS::Region'} VpcId: !Ref 'VPC' CidrBlock: !FindInMap ['SubnetConfig', 'PrivateTwo', 'CIDR'] # 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 #Private route table for ElastiCache and Private Lambda PrivateRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref 'VPC' PrivateSubnetOneRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnetOne RouteTableId: !Ref PrivateRouteTable PrivateSubnetTwoRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnetTwo RouteTableId: !Ref PrivateRouteTable # A security group for the ECS Endpoint EndpointSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Access to the Fargate containers VpcId: !Ref 'VPC' EndpointSecurityGroupIngress: Type: AWS::EC2::SecurityGroupIngress Properties: Description: Ingress from the game clients GroupId: !Ref 'EndpointSecurityGroup' IpProtocol: -1 #FromPort: -1 #ToPort: -1 CidrIp: !FindInMap ['SubnetConfig', 'VPC', 'CIDR'] # Endpoints for our private Lambda functions to access ECS and CloudFormation APIs ECSEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Sub com.amazonaws.${AWS::Region}.ecs VpcId: !Ref VPC VpcEndpointType: Interface PrivateDnsEnabled: True SubnetIds: - !Ref PrivateSubnetOne - !Ref PrivateSubnetTwo SecurityGroupIds: - !Ref EndpointSecurityGroup CloudFormationEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Sub com.amazonaws.${AWS::Region}.cloudformation VpcId: !Ref VPC VpcEndpointType: Interface PrivateDnsEnabled: True SubnetIds: - !Ref PrivateSubnetOne - !Ref PrivateSubnetTwo SecurityGroupIds: - !Ref EndpointSecurityGroup # ECS Resources ECSCluster: Type: AWS::ECS::Cluster Properties: # Enable Container Insights for detailed information on containers ClusterSettings: - Name: containerInsights Value: enabled # A security group for the containers we will run in Fargate. FargateContainerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Access to the Fargate containers VpcId: !Ref 'VPC' EcsSecurityGroupIngressFromGameClients: Type: AWS::EC2::SecurityGroupIngress Properties: Description: Ingress from the game clients GroupId: !Ref 'FargateContainerSecurityGroup' IpProtocol: tcp FromPort: !Ref GameServerPortStart ToPort: !Ref GameServerPortEnd CidrIp: "0.0.0.0/0" # A Security group for internal resources (ElastiCache and private Lambda) InternalSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Access to internal resources VpcId: !Ref 'VPC' # Allow access from this SG and the ECS SG InternalSecurityGroupIngress: Type: AWS::EC2::SecurityGroupIngress Properties: Description: Ingress from this SG GroupId: !Ref 'InternalSecurityGroup' IpProtocol: tcp FromPort: !Ref RedisPort ToPort: !Ref RedisPort SourceSecurityGroupId: !Ref InternalSecurityGroup InternalSecurityGroupIngress2: Type: AWS::EC2::SecurityGroupIngress Properties: Description: Ingress from this SG GroupId: !Ref 'InternalSecurityGroup' IpProtocol: tcp FromPort: !Ref RedisPort ToPort: !Ref RedisPort SourceSecurityGroupId: !Ref FargateContainerSecurityGroup # 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' Resource: '*' # 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: !Join [ ':', [ !Ref 'AWS::StackName', 'ClusterName' ] ] ECSRole: Description: The ARN of the ECS role Value: !GetAtt 'ECSRole.Arn' Export: Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ECSRole' ] ] ECSTaskExecutionRole: Description: The ARN of the ECS role Value: !GetAtt 'ECSTaskExecutionRole.Arn' Export: Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ECSTaskExecutionRole' ] ] VPCId: Description: The ID of the VPC that this stack is deployed in Value: !Ref 'VPC' Export: Name: !Join [ ':', [ !Ref 'AWS::StackName', 'VPCId' ] ] 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: !Join [ ':', [ !Ref 'AWS::StackName', 'PrivateSubnetOne' ] ] PrivateSubnetTwo: Description: Private subnet two Value: !Ref 'PrivateSubnetTwo' Export: Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PrivateSubnetTwo' ] ] FargateContainerSecurityGroup: Description: A security group used to allow Fargate containers to receive traffic Value: !Ref 'FargateContainerSecurityGroup' Export: Name: !Join [ ':', [ !Ref 'AWS::StackName', 'FargateContainerSecurityGroup' ] ] InternalSecurityGroup: Description: A security group used by internal resources Value: !Ref 'InternalSecurityGroup' Export: Name: !Join [ ':', [ !Ref 'AWS::StackName', 'InternalSecurityGroup' ] ]