# Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 --- AWSTemplateFormatVersion: '2010-09-09' Description: 'AWS CloudFormation Sample Template Managed Single ECS Job Queue: This template demonstrates the usage of simple Job Queue and EC2 style Compute Environment along with multi-node jobs (on a relatively small scale: 4 instances, 16 cores each). N.B.: This is all boilerplate until the EcsInstanceRole! ' Parameters: ProjectName: Type: String Default: "proofs" Description: "S3 bucket will be AccountId-Region-ProjectName" AvailZoneId: Type: String Default: "a" Description: "Availability Zone ID" InstanceType: Type: String Default: "m6i.4xlarge" Description: "Instance type" ContainerMemory: Type: String Description: "Memory Size for containers (61000 for cloud, 253000 for parallel)" AmiImageId: Type: String Description: "Ami for your instances" RegionHasThreeAzs: Type: String Default: "true" Description: | "true" if region has at least three AZs, "false" if not. Determines whether we will have 2 or 3 subnets Conditions: HasThreeAZs: !Equals [ !Ref RegionHasThreeAzs, "true" ] HasSixAZs: !Equals [ !Ref 'AWS::Region', "us-east-1" ] Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 EnableDnsHostnames: true EnableDnsSupport: true # /19 Subnet PrivateSubnet1: Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select [ 0, !GetAZs '' ] CidrBlock: !Select [0, !Cidr [!GetAtt VPC.CidrBlock, 6, 13]] VpcId: !Ref VPC # /19 Subnet PrivateSubnet2: Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select [ 1, !GetAZs '' ] CidrBlock: !Select [1, !Cidr [!GetAtt VPC.CidrBlock, 6, 13]] VpcId: !Ref VPC # /19 Subnet PrivateSubnet3: Condition: HasThreeAZs Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select [ 2, !GetAZs '' ] CidrBlock: !Select [2, !Cidr [!GetAtt VPC.CidrBlock, 6, 13]] VpcId: !Ref VPC # /19 Subnet PrivateSubnet4: Condition: HasSixAZs Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select [ 3, !GetAZs '' ] CidrBlock: !Select [3, !Cidr [!GetAtt VPC.CidrBlock, 6, 13]] VpcId: !Ref VPC # /19 Subnet PrivateSubnet5: Condition: HasSixAZs Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select [ 4, !GetAZs '' ] CidrBlock: !Select [4, !Cidr [!GetAtt VPC.CidrBlock, 6, 13]] VpcId: !Ref VPC # /19 Subnet PrivateSubnet6: Condition: HasSixAZs Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select [ 5, !GetAZs '' ] CidrBlock: !Select [5, !Cidr [!GetAtt VPC.CidrBlock, 6, 13]] VpcId: !Ref VPC RouteTablePrivate1: Type: AWS::EC2::RouteTable Properties: VpcId: Ref: VPC RouteTableAssociation1: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref RouteTablePrivate1 SubnetId: !Ref PrivateSubnet1 RouteTablePrivate2: Type: AWS::EC2::RouteTable Properties: VpcId: Ref: VPC RouteTableAssociation2: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref RouteTablePrivate2 SubnetId: !Ref PrivateSubnet2 RouteTablePrivate3: Condition: HasThreeAZs Type: AWS::EC2::RouteTable Properties: VpcId: Ref: VPC RouteTableAssociation3: Condition: HasThreeAZs Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref RouteTablePrivate3 SubnetId: !Ref PrivateSubnet3 RouteTablePrivate4: Condition: HasSixAZs Type: AWS::EC2::RouteTable Properties: VpcId: Ref: VPC RouteTableAssociation4: Condition: HasSixAZs Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref RouteTablePrivate4 SubnetId: !Ref PrivateSubnet4 RouteTablePrivate5: Condition: HasSixAZs Type: AWS::EC2::RouteTable Properties: VpcId: Ref: VPC RouteTableAssociation5: Condition: HasSixAZs Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref RouteTablePrivate5 SubnetId: !Ref PrivateSubnet5 RouteTablePrivate6: Condition: HasSixAZs Type: AWS::EC2::RouteTable Properties: VpcId: Ref: VPC RouteTableAssociation6: Condition: HasSixAZs Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref RouteTablePrivate6 SubnetId: !Ref PrivateSubnet6 DdbEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .dynamodb RouteTableIds: - !Ref RouteTablePrivate1 - !Ref RouteTablePrivate2 - !If [ HasThreeAZs, !Ref RouteTablePrivate3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref RouteTablePrivate4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref RouteTablePrivate5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref RouteTablePrivate6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Gateway LambdaEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .lambda SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Interface SecurityGroupIds: - !Ref SecurityGroup PrivateDnsEnabled: true SQSEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .sqs SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Interface SecurityGroupIds: - !Ref SecurityGroup PrivateDnsEnabled: true CloudwatchEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .logs SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Interface SecurityGroupIds: - !Ref SecurityGroup PrivateDnsEnabled: true MetricsEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .monitoring SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Interface SecurityGroupIds: - !Ref SecurityGroup PrivateDnsEnabled: true S3Endpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .s3 RouteTableIds: - !Ref RouteTablePrivate1 - !Ref RouteTablePrivate2 - !If [ HasThreeAZs, !Ref RouteTablePrivate3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref RouteTablePrivate4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref RouteTablePrivate5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref RouteTablePrivate6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Gateway EcrDkrEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .ecr.dkr SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Interface SecurityGroupIds: - !Ref SecurityGroup PrivateDnsEnabled: true EcrApiEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .ecr.api SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Interface SecurityGroupIds: - !Ref SecurityGroup PrivateDnsEnabled: true # Endpoints required for Sessions Manager Ec2MessagesEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .ec2messages SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Interface SecurityGroupIds: - !Ref SecurityGroup PrivateDnsEnabled: true SsmEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .ssm SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Interface SecurityGroupIds: - !Ref SecurityGroup PrivateDnsEnabled: true SsmMessagesEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .ssmmessages SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Interface SecurityGroupIds: - !Ref SecurityGroup PrivateDnsEnabled: true # VPC Endpoint needed for EC2 instance to join ECS cluster EcsAgentEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .ecs-agent SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Interface SecurityGroupIds: - !Ref SecurityGroup PrivateDnsEnabled: true EcsTelemetryEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .ecs-telemetry SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Interface SecurityGroupIds: - !Ref SecurityGroup PrivateDnsEnabled: true EcsEndpoint: Type: AWS::EC2::VPCEndpoint Properties: ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .ecs SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] VpcId: !Ref VPC VpcEndpointType: Interface SecurityGroupIds: - !Ref SecurityGroup PrivateDnsEnabled: true SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: EC2 Security Group for instances launched in the VPC by Batch VpcId: Ref: VPC SecurityGroupEgress: - CidrIp: 0.0.0.0/0 Description: Allow all outbound traffic by default IpProtocol: -1 SecurityGroupIngress: - CidrIp: 10.0.0.0/0 Description: SSH port FromPort: 0 IpProtocol: TCP ToPort: 65535 EcsCluster: Type: AWS::ECS::Cluster Properties: ClusterName: SatCompCluster ClusterSettings: - Name: containerInsights Value: enabled Ec2AutoscaleInstanceProfile: Type: "AWS::IAM::InstanceProfile" Properties: Path: "/" Roles: - Ref: "InstanceRole" InstanceRole: Type: AWS::IAM::Role Properties: ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ ec2.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' - 'elasticfilesystem:*' - 'cloudwatch:*' - 'ecs:*' # 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' - 's3:GetObject' - 's3:GetObjectVersion' Resource: '*' EcsInstanceLc: Type: AWS::AutoScaling::LaunchConfiguration Properties: ImageId: !Ref AmiImageId InstanceType: !Select [ 0, [ !Ref InstanceType ] ] AssociatePublicIpAddress: true IamInstanceProfile: !GetAtt Ec2AutoscaleInstanceProfile.Arn SecurityGroups: [ !Ref SecurityGroup ] BlockDeviceMappings: - DeviceName: /dev/xvda Ebs: VolumeSize: 30 VolumeType: gp2 - DeviceName: /dev/xvdcz Ebs: VolumeSize: 22 VolumeType: gp2 UserData: Fn::Base64: !Sub | #!/bin/bash -xe echo ECS_CLUSTER=${EcsCluster} >> /etc/ecs/ecs.config yum install -y aws-cfn-bootstrap python-pip pip install awscli boto3 /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region} EcsInstanceAsg: Type: AWS::AutoScaling::AutoScalingGroup UpdatePolicy: AutoScalingRollingUpdate: MaxBatchSize: 10 MinSuccessfulInstancesPercent: 95 PauseTime: PT30M SuspendProcesses: [ HealthCheck, ReplaceUnhealthy, AZRebalance, AlarmNotification, ScheduledActions ] WaitOnResourceSignals: 'true' Properties: VPCZoneIdentifier: [ !Ref PrivateSubnet1, !Ref PrivateSubnet2, !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ], !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ], !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ], !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] ] LaunchConfigurationName: !Ref EcsInstanceLc MinSize: '0' MaxSize: '0' DesiredCapacity: '0' Tags: - Key: IsAutoscaledCluster PropagateAtLaunch: true Value: "true" - Key: "Patch Group" PropagateAtLaunch: true Value: "ManagedClusterPatchGroup" AutoscaleCapacityProvider: Type: AWS::ECS::CapacityProvider Properties: AutoScalingGroupProvider: AutoScalingGroupArn: !Ref EcsInstanceAsg ManagedTerminationProtection: DISABLED ManagedScaling: Status: DISABLED Name: AutoscaleCapacityProvider # 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' # A role used to allow AWS Autoscaling to inspect stats and adjust scaleable targets # on your AWS account AutoscalingRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ application-autoscaling.amazonaws.com ] Action: [ 'sts:AssumeRole' ] Path: / Policies: - PolicyName: service-autoscaling PolicyDocument: Statement: - Effect: Allow Action: - 'application-autoscaling:*' - 'cloudwatch:DescribeAlarms' - 'cloudwatch:PutMetricAlarm' - 'ecs:DescribeServices' - 'ecs:UpdateService' Resource: '*' # 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' - 'elasticfilesystem:*' # 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: '*' EcsTaskRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonEC2FullAccess - arn:aws:iam::aws:policy/AmazonS3FullAccess Policies: - PolicyName: !Sub "project-metrics-${AWS::Region}-${ProjectName}" PolicyDocument: Version: 2012-10-17 Statement: - Action: - cloudwatch:PutMetricData Effect: Allow Resource: "*" - PolicyName: SatCompQueueExecutionRolePolicy PolicyDocument: Version: 2012-10-17 Statement: - Action: - "sqs:GetQueueAttributes" - "sqs:SendMessage" - "sqs:ReceiveMessage" - "sqs:DeleteMessage" - "sqs:DeleteMessageBatch" - "sqs:GetQueueUrl" Effect: Allow Resource: "*" - PolicyName: SatCompDynamoExecutionRolePolicy PolicyDocument: Version: 2012-10-17 Statement: - Action: - "dynamodb:UpdateItem" - "dynamodb:Scan" Effect: Allow Resource: "*" SolverLeaderTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn TaskRoleArn: !GetAtt EcsTaskRole.Arn NetworkMode: awsvpc RequiresCompatibilities: - EC2 ContainerDefinitions: - Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ProjectName}:leader" Name: !Sub "${ProjectName}-leader" MemoryReservation: 61000 Environment: - Name: SQS_QUEUE_NAME Value: !GetAtt SatCompQueue.QueueName - Name: SQS_OUTPUT_QUEUE_NAME Value: !GetAtt SatCompOutputQueue.QueueName - Name: AWS_DEFAULT_REGION Value: !Ref AWS::Region - Name: SATCOMP_BUCKET_NAME Value: !Ref SatCompBucket LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Sub "/ecs/${ProjectName}-leader" awslogs-region: !Ref AWS::Region awslogs-stream-prefix: ecs PortMappings: - HostPort: 22 ContainerPort: 22 Protocol: TCP SolverLogGroupLeader: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/ecs/${ProjectName}-leader" RetentionInDays: 1827 SolverWorkerTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn TaskRoleArn: !GetAtt EcsTaskRole.Arn NetworkMode: awsvpc RequiresCompatibilities: - EC2 ContainerDefinitions: - Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ProjectName}:worker" Name: !Sub "${ProjectName}-worker" MemoryReservation: 61000 Environment: - Name: SQS_QUEUE_NAME Value: !GetAtt SatCompQueue.QueueName - Name: SQS_OUTPUT_QUEUE_NAME Value: !GetAtt SatCompOutputQueue.QueueName - Name: AWS_DEFAULT_REGION Value: !Ref AWS::Region - Name: SATCOMP_BUCKET_NAME Value: !Ref SatCompBucket LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Sub "/ecs/${ProjectName}-worker" awslogs-region: !Ref AWS::Region awslogs-stream-prefix: ecs PortMappings: - HostPort: 22 ContainerPort: 22 Protocol: TCP SolverLogGroupWorker: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/ecs/${ProjectName}-worker" RetentionInDays: 1827 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: '*' SolverLeaderService: Type: AWS::ECS::Service Properties: Cluster: Ref: EcsCluster DesiredCount: 0 LaunchType: EC2 NetworkConfiguration: AwsvpcConfiguration: SecurityGroups: - !Ref SecurityGroup Subnets: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] TaskDefinition: Ref: SolverLeaderTaskDefinition SolverWorkerService: Type: AWS::ECS::Service Properties: Cluster: Ref: EcsCluster DesiredCount: 0 LaunchType: EC2 NetworkConfiguration: AwsvpcConfiguration: SecurityGroups: - !Ref SecurityGroup Subnets: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [ HasThreeAZs, !Ref PrivateSubnet3, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet4, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet5, !Ref "AWS::NoValue" ] - !If [ HasSixAZs, !Ref PrivateSubnet6, !Ref "AWS::NoValue" ] TaskDefinition: Ref: SolverWorkerTaskDefinition SatCompQueue: Type: AWS::SQS::Queue Properties: QueueName: !Sub "${AWS::AccountId}-${AWS::Region}-SatCompQueue" VisibilityTimeout: 5 ReceiveMessageWaitTimeSeconds: 20 KmsDataKeyReusePeriodSeconds: 3600 KmsMasterKeyId: "alias/aws/sqs" SatCompOutputQueue: Type: AWS::SQS::Queue Properties: QueueName: !Sub "${AWS::AccountId}-${AWS::Region}-SatCompOutputQueue" VisibilityTimeout: 5 ReceiveMessageWaitTimeSeconds: 20 KmsDataKeyReusePeriodSeconds: 3600 KmsMasterKeyId: "alias/aws/sqs" NodeManifest: Type: AWS::DynamoDB::Table Properties: AttributeDefinitions: - AttributeName: nodeId AttributeType: S BillingMode: PAY_PER_REQUEST KeySchema: - AttributeName: nodeId KeyType: HASH TableName: SatCompNodeManifest TaskEndNotification: Type: AWS::DynamoDB::Table Properties: AttributeDefinitions: - AttributeName: leaderIp AttributeType: S BillingMode: PAY_PER_REQUEST KeySchema: - AttributeName: leaderIp KeyType: HASH TableName: TaskEndNotification SolverLeaderEcr: Type: AWS::ECR::Repository Properties: RepositoryName: !Sub "${ProjectName}" LifecyclePolicy: LifecyclePolicyText: ' { "rules": [ { "rulePriority": 10, "description": "remove untagged images except the latest one", "selection": { "tagStatus": "untagged", "countType": "imageCountMoreThan", "countNumber": 1 }, "action": { "type": "expire" } } ] }' # SolverWorkerEcr: # Type: AWS::ECR::Repository # Properties: # RepositoryName: !Sub "${ProjectName}-worker" # LifecyclePolicy: # LifecyclePolicyText: ' # { # "rules": [ { # "rulePriority": 10, # "description": "remove untagged images except the latest one", # "selection": { # "tagStatus": "untagged", # "countType": "imageCountMoreThan", # "countNumber": 1 # }, # "action": { # "type": "expire" # } # } ] # }' SatCompBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub "${AWS::AccountId}-${AWS::Region}-${ProjectName}" BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true Outputs: Subnet: Value: Ref: PrivateSubnet1 Export: Name: SubnetId SecurityGroupId: Value: Ref: SecurityGroup Export: Name: SecurityGroup