# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 AWSTemplateFormatVersion: 2010-09-09 Description: CloudFormation template that represents a worker service on Amazon ECS. Metadata: Version: v1.29.0 Manifest: | # The manifest for the "dog-worker" service. # Read the full specification for the "Worker Service" type at: # https://aws.github.io/copilot-cli/docs/manifest/worker-service/ # Your service name will be used in naming your resources like log groups, ECS services, etc. name: dogworker type: Worker Service # Configuration for your containers and service. cpu: 256 # Number of CPU units for the task. memory: 512 # Amount of memory in MiB used by the task. count: range: min: 1 max: 10 spot_from: 6 queue_delay: # Should result in 900 msgs backlog. acceptable_latency: 15m msg_processing_time: 1s exec: true # Enable running commands in your container. deployment: rollback_alarms: cpu_utilization: 70 memory_utilization: 50 messages_delayed: 5 publish: topics: - name: givesOtherdogs - name: mytopic fifo: true - name: mytopic - name: yourtopic fifo: content_based_deduplication: true - name: nonfifotopic fifo: false subscribe: queue: delay: 1s dead_letter: tries: 5 topics: - name: givesdogs service: dogsvc filter_policy: store: - example_corp event: - anything-but: order_cancelled cutomer_interests: - rugby - football - baseball price_usd: - numeric: - ">=" - 100 - name: giveshuskies service: dogsvc queue: timeout: 1s - name: mytopic service: mytopic queue: fifo: true - name: yourtopic service: yourtopic queue: fifo: content_based_deduplication: true high_throughput: true - name: nonfifotopic service: nonfifotopic queue: fifo: false # Optional fields for more advanced use-cases. # #variables: # Pass environment variables as key value pairs. # LOG_LEVEL: info #secrets: # Pass secrets from AWS Systems Manager (SSM) Parameter Store. # GITHUB_TOKEN: GITHUB_TOKEN # The key is the name of the environment variable, the value is the name of the SSM parameter. # You can override any of the values defined above by environment. environments: test: image: location: amazon/ecs-example network: connect: true Parameters: AppName: Type: String EnvName: Type: String WorkloadName: Type: String ContainerImage: Type: String TaskCPU: Type: String TaskMemory: Type: String TaskCount: Type: Number AddonsTemplateURL: Description: 'URL of the addons nested stack template within the S3 bucket.' Type: String Default: "" EnvFileARN: Description: 'URL of the environment file.' Type: String Default: "" LogRetention: Type: Number Default: 30 Conditions: IsGovCloud: !Equals [!Ref "AWS::Partition", "aws-us-gov"] HasAddons: !Not [!Equals [!Ref AddonsTemplateURL, ""]] HasEnvFile: !Not [!Equals [!Ref EnvFileARN, ""]] Resources: LogGroup: Metadata: 'aws:copilot:description': 'A CloudWatch log group to hold your service logs' Type: AWS::Logs::LogGroup Properties: LogGroupName: !Join ['', [/copilot/, !Ref AppName, '-', !Ref EnvName, '-', !Ref WorkloadName]] RetentionInDays: !Ref LogRetention TaskDefinition: Metadata: 'aws:copilot:description': 'An ECS task definition to group your containers and run them on ECS' Type: AWS::ECS::TaskDefinition DependsOn: LogGroup Properties: Family: !Join ['', [!Ref AppName, '-', !Ref EnvName, '-', !Ref WorkloadName]] NetworkMode: awsvpc RequiresCompatibilities: - FARGATE Cpu: !Ref TaskCPU Memory: !Ref TaskMemory ExecutionRoleArn: !GetAtt ExecutionRole.Arn TaskRoleArn: !GetAtt TaskRole.Arn ContainerDefinitions: - Name: !Ref WorkloadName Image: !Ref ContainerImage # We pipe certain environment variables directly into the task definition. # This lets customers have access to, for example, their LB endpoint - which they'd # have no way of otherwise determining. Environment: - Name: COPILOT_APPLICATION_NAME Value: !Sub '${AppName}' - Name: COPILOT_SERVICE_DISCOVERY_ENDPOINT Value: test.my-app.local - Name: COPILOT_ENVIRONMENT_NAME Value: !Sub '${EnvName}' - Name: COPILOT_SERVICE_NAME Value: !Sub '${WorkloadName}' - Name: COPILOT_SNS_TOPIC_ARNS Value: '{"givesOtherdogs":"arn:aws:sns:us-west-2:123456789123:my-app-test-dogworker-givesOtherdogs","mytopic":"arn:aws:sns:us-west-2:123456789123:my-app-test-dogworker-mytopic","mytopic.fifo":"arn:aws:sns:us-west-2:123456789123:my-app-test-dogworker-mytopic.fifo","nonfifotopic":"arn:aws:sns:us-west-2:123456789123:my-app-test-dogworker-nonfifotopic","yourtopic.fifo":"arn:aws:sns:us-west-2:123456789123:my-app-test-dogworker-yourtopic.fifo"}' - Name: COPILOT_QUEUE_URI Value: !Ref EventsQueue - Name: COPILOT_TOPIC_QUEUE_URIS Value: !Sub - '{"dogsvcGiveshuskiesEventsQueue":"${dogsvcgiveshuskiesURL}","mytopicMytopicfifoEventsQueue":"${mytopicmytopicfifoURL}","nonfifotopicNonfifotopicEventsQueue":"${nonfifotopicnonfifotopicURL}","yourtopicYourtopicfifoEventsQueue":"${yourtopicyourtopicfifoURL}"}' - dogsvcgiveshuskiesURL: !Ref dogsvcgiveshuskiesEventsQueue mytopicmytopicfifoURL: !Ref mytopicmytopicfifoEventsQueue yourtopicyourtopicfifoURL: !Ref yourtopicyourtopicfifoEventsQueue nonfifotopicnonfifotopicURL: !Ref nonfifotopicnonfifotopicEventsQueue EnvironmentFiles: - !If - HasEnvFile - Type: s3 Value: !Ref EnvFileARN - !Ref AWS::NoValue LogConfiguration: LogDriver: awslogs Options: awslogs-region: !Ref AWS::Region awslogs-group: !Ref LogGroup awslogs-stream-prefix: copilot ExecutionRole: Metadata: 'aws:copilot:description': 'An IAM Role for the Fargate agent to make AWS API calls on your behalf' Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: 'sts:AssumeRole' Policies: - PolicyName: !Join ['', [!Ref AppName, '-', !Ref EnvName, '-', !Ref WorkloadName, SecretsPolicy]] PolicyDocument: Version: '2012-10-17' Statement: - Effect: 'Allow' Action: - 'ssm:GetParameters' Resource: - !Sub 'arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/*' Condition: StringEquals: 'ssm:ResourceTag/copilot-application': !Sub '${AppName}' 'ssm:ResourceTag/copilot-environment': !Sub '${EnvName}' - Effect: 'Allow' Action: - 'secretsmanager:GetSecretValue' Resource: - !Sub 'arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:*' Condition: StringEquals: 'secretsmanager:ResourceTag/copilot-application': !Sub '${AppName}' 'secretsmanager:ResourceTag/copilot-environment': !Sub '${EnvName}' - Effect: 'Allow' Action: - 'kms:Decrypt' Resource: - !Sub 'arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/*' - !If - HasEnvFile - PolicyName: !Join ['', [!Ref AppName, '-', !Ref EnvName, '-', !Ref WorkloadName, GetEnvFilePolicy]] PolicyDocument: Version: '2012-10-17' Statement: - Effect: 'Allow' Action: - 's3:GetObject' Resource: - !Ref EnvFileARN - Effect: 'Allow' Action: - 's3:GetBucketLocation' Resource: - !Join - '' - - 'arn:' - !Ref AWS::Partition - ':s3:::' - !Select [0, !Split ['/', !Select [5, !Split [':', !Ref EnvFileARN]]]] - !Ref AWS::NoValue ManagedPolicyArns: - !Sub 'arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy' TaskRole: Metadata: 'aws:copilot:description': 'An IAM role to control permissions for the containers in your tasks' Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: 'sts:AssumeRole' Policies: - PolicyName: 'DenyIAMExceptTaggedRoles' PolicyDocument: Version: '2012-10-17' Statement: - Effect: 'Deny' Action: 'iam:*' Resource: '*' - Effect: 'Allow' Action: 'sts:AssumeRole' Resource: - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/*' Condition: StringEquals: 'iam:ResourceTag/copilot-application': !Sub '${AppName}' 'iam:ResourceTag/copilot-environment': !Sub '${EnvName}' - PolicyName: 'ExecuteCommand' PolicyDocument: Version: '2012-10-17' Statement: - Effect: 'Allow' Action: ["ssmmessages:CreateControlChannel", "ssmmessages:OpenControlChannel", "ssmmessages:CreateDataChannel", "ssmmessages:OpenDataChannel"] Resource: "*" - Effect: 'Allow' Action: ["logs:CreateLogStream", "logs:DescribeLogGroups", "logs:DescribeLogStreams", "logs:PutLogEvents"] Resource: "*" - PolicyName: 'Publish2SNS' PolicyDocument: Version: '2012-10-17' Statement: - Effect: 'Allow' Action: 'sns:Publish' Resource: - !Ref givesOtherdogsSNSTopic - !Ref mytopicfifoSNSTopic - !Ref mytopicSNSTopic - !Ref yourtopicfifoSNSTopic - !Ref nonfifotopicSNSTopic DynamicDesiredCountAction: Metadata: 'aws:copilot:description': "A custom resource returning the ECS service's running task count" Type: Custom::DynamicDesiredCountFunction Properties: ServiceToken: !GetAtt DynamicDesiredCountFunction.Arn Cluster: Fn::ImportValue: !Sub '${AppName}-${EnvName}-ClusterId' App: !Ref AppName Env: !Ref EnvName Svc: !Ref WorkloadName DefaultDesiredCount: !Ref TaskCount # We need to force trigger this lambda function on all deployments, so we give it a random ID as input on all event types. UpdateID: RandomGUID DynamicDesiredCountFunction: Type: AWS::Lambda::Function Properties: Handler: "index.handler" Timeout: 600 MemorySize: 512 Role: !GetAtt 'DynamicDesiredCountFunctionRole.Arn' Runtime: nodejs16.x DynamicDesiredCountFunctionRole: Metadata: 'aws:copilot:description': "An IAM Role for describing number of running tasks in your ECS service" Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: "DelegateDesiredCountAccess" PolicyDocument: Version: '2012-10-17' Statement: - Sid: ECS Effect: Allow Action: - ecs:DescribeServices Resource: "*" Condition: ArnEquals: 'ecs:cluster': Fn::Sub: - arn:${AWS::Partition}:ecs:${AWS::Region}:${AWS::AccountId}:cluster/${ClusterName} - ClusterName: Fn::ImportValue: !Sub '${AppName}-${EnvName}-ClusterId' - Sid: ResourceGroups Effect: Allow Action: - resource-groups:GetResources Resource: "*" - Sid: Tags Effect: Allow Action: - "tag:GetResources" Resource: "*" AutoScalingRole: Metadata: 'aws:copilot:description': 'An IAM role for container auto scaling' Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: 'sts:AssumeRole' ManagedPolicyArns: - !Sub 'arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonEC2ContainerServiceAutoscaleRole' AutoScalingTarget: Metadata: 'aws:copilot:description': "An autoscaling target to scale your service's desired count" Type: AWS::ApplicationAutoScaling::ScalableTarget Properties: MinCapacity: 1 MaxCapacity: 10 ResourceId: Fn::Join: - '/' - - 'service' - Fn::ImportValue: !Sub '${AppName}-${EnvName}-ClusterId' - !GetAtt Service.Name ScalableDimension: ecs:service:DesiredCount ServiceNamespace: ecs RoleARN: !GetAtt AutoScalingRole.Arn BacklogPerTaskCalculatorLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: Fn::Join: - '/' - - '/aws' - 'lambda' - Fn::Sub: "${BacklogPerTaskCalculatorFunction}" RetentionInDays: 3 BacklogPerTaskCalculatorFunction: Metadata: 'aws:copilot:description': "A Lambda function to emit BacklogPerTask metrics to CloudWatch" Type: AWS::Lambda::Function Properties: Handler: "index.handler" Timeout: 600 MemorySize: 512 Role: !GetAtt BacklogPerTaskCalculatorRole.Arn Runtime: nodejs16.x Environment: Variables: CLUSTER_NAME: Fn::ImportValue: !Sub '${AppName}-${EnvName}-ClusterId' SERVICE_NAME: !Ref Service NAMESPACE: !Sub '${AppName}-${EnvName}-${WorkloadName}' QUEUE_NAMES: Fn::Join: - ',' - - !GetAtt EventsQueue.QueueName - !GetAtt dogsvcgiveshuskiesEventsQueue.QueueName - !GetAtt mytopicmytopicfifoEventsQueue.QueueName - !GetAtt yourtopicyourtopicfifoEventsQueue.QueueName - !GetAtt nonfifotopicnonfifotopicEventsQueue.QueueName BacklogPerTaskCalculatorRole: Metadata: 'aws:copilot:description': 'An IAM role for BacklogPerTaskCalculatorFunction' Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: "BacklogPerTaskCalculatorAccess" PolicyDocument: Version: '2012-10-17' Statement: - Sid: ECS Effect: Allow Action: - ecs:DescribeServices Resource: "*" Condition: ArnEquals: 'ecs:cluster': Fn::Sub: - arn:${AWS::Partition}:ecs:${AWS::Region}:${AWS::AccountId}:cluster/${ClusterName} - ClusterName: Fn::ImportValue: !Sub '${AppName}-${EnvName}-ClusterId' - Sid: SQS Effect: Allow Action: - sqs:GetQueueAttributes - sqs:GetQueueUrl Resource: - !GetAtt EventsQueue.Arn - !GetAtt dogsvcgiveshuskiesEventsQueue.Arn - !GetAtt mytopicmytopicfifoEventsQueue.Arn - !GetAtt yourtopicyourtopicfifoEventsQueue.Arn - !GetAtt nonfifotopicnonfifotopicEventsQueue.Arn ManagedPolicyArns: - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole BacklogPerTaskScheduledRule: Metadata: 'aws:copilot:description': "A trigger to invoke the BacklogPerTaskCalculator Lambda function every minute" DependsOn: - BacklogPerTaskCalculatorLogGroup # Ensure log group is created before invoking. Type: AWS::Events::Rule Properties: ScheduleExpression: "rate(1 minute)" State: "ENABLED" Targets: - Arn: !GetAtt BacklogPerTaskCalculatorFunction.Arn Id: "BacklogPerTaskCalculatorFunctionTrigger" PermissionToInvokeBacklogPerTaskCalculatorLambda: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref BacklogPerTaskCalculatorFunction Action: lambda:InvokeFunction Principal: events.amazonaws.com SourceArn: !GetAtt BacklogPerTaskScheduledRule.Arn AutoScalingPolicyEventsQueue: Metadata: 'aws:copilot:description': "An autoscaling policy to maintain 900 messages/task for EventsQueue" Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: !Join ['-', [!Ref WorkloadName, BacklogPerTask, !GetAtt EventsQueue.QueueName]] PolicyType: TargetTrackingScaling ScalingTargetId: !Ref AutoScalingTarget TargetTrackingScalingPolicyConfiguration: ScaleInCooldown: 120 ScaleOutCooldown: 60 CustomizedMetricSpecification: Namespace: !Sub '${AppName}-${EnvName}-${WorkloadName}' MetricName: BacklogPerTask Statistic: Average Dimensions: - Name: QueueName Value: !GetAtt EventsQueue.QueueName Unit: Count TargetValue: 900 AutoScalingPolicydogsvcgiveshuskiesEventsQueue: Metadata: 'aws:copilot:description': "An autoscaling policy to maintain 900 messages/task for dogsvcgiveshuskiesEventsQueue" Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: !Join ['-', [!Ref WorkloadName, BacklogPerTask, !GetAtt dogsvcgiveshuskiesEventsQueue.QueueName]] PolicyType: TargetTrackingScaling ScalingTargetId: !Ref AutoScalingTarget TargetTrackingScalingPolicyConfiguration: ScaleInCooldown: 120 ScaleOutCooldown: 60 CustomizedMetricSpecification: Namespace: !Sub '${AppName}-${EnvName}-${WorkloadName}' MetricName: BacklogPerTask Statistic: Average Dimensions: - Name: QueueName Value: !GetAtt dogsvcgiveshuskiesEventsQueue.QueueName Unit: Count TargetValue: 900 AutoScalingPolicymytopicmytopicfifoEventsQueue: Metadata: 'aws:copilot:description': "An autoscaling policy to maintain 900 messages/task for mytopicmytopicfifoEventsQueue" Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: !Join [ '-', [ !Ref WorkloadName, BacklogPerTask, !GetAtt mytopicmytopicfifoEventsQueue.QueueName ] ] PolicyType: TargetTrackingScaling ScalingTargetId: !Ref AutoScalingTarget TargetTrackingScalingPolicyConfiguration: ScaleInCooldown: 120 ScaleOutCooldown: 60 CustomizedMetricSpecification: Namespace: !Sub '${AppName}-${EnvName}-${WorkloadName}' MetricName: BacklogPerTask Statistic: Average Dimensions: - Name: QueueName Value: !GetAtt mytopicmytopicfifoEventsQueue.QueueName Unit: Count TargetValue: 900 AutoScalingPolicyyourtopicyourtopicfifoEventsQueue: Metadata: 'aws:copilot:description': "An autoscaling policy to maintain 900 messages/task for yourtopicyourtopicfifoEventsQueue" Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: !Join [ '-', [ !Ref WorkloadName, BacklogPerTask, !GetAtt yourtopicyourtopicfifoEventsQueue.QueueName ] ] PolicyType: TargetTrackingScaling ScalingTargetId: !Ref AutoScalingTarget TargetTrackingScalingPolicyConfiguration: ScaleInCooldown: 120 ScaleOutCooldown: 60 CustomizedMetricSpecification: Namespace: !Sub '${AppName}-${EnvName}-${WorkloadName}' MetricName: BacklogPerTask Statistic: Average Dimensions: - Name: QueueName Value: !GetAtt yourtopicyourtopicfifoEventsQueue.QueueName Unit: Count TargetValue: 900 AutoScalingPolicynonfifotopicnonfifotopicEventsQueue: Metadata: 'aws:copilot:description': "An autoscaling policy to maintain 900 messages/task for nonfifotopicnonfifotopicEventsQueue" Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: !Join [ '-', [ !Ref WorkloadName, BacklogPerTask, !GetAtt nonfifotopicnonfifotopicEventsQueue.QueueName ] ] PolicyType: TargetTrackingScaling ScalingTargetId: !Ref AutoScalingTarget TargetTrackingScalingPolicyConfiguration: ScaleInCooldown: 120 ScaleOutCooldown: 60 CustomizedMetricSpecification: Namespace: !Sub '${AppName}-${EnvName}-${WorkloadName}' MetricName: BacklogPerTask Statistic: Average Dimensions: - Name: QueueName Value: !GetAtt nonfifotopicnonfifotopicEventsQueue.QueueName Unit: Count TargetValue: 900 Service: DependsOn: - EnvControllerAction Metadata: 'aws:copilot:description': 'An ECS service to run and maintain your tasks in the environment cluster' Type: AWS::ECS::Service Properties: Cluster: Fn::ImportValue: !Sub '${AppName}-${EnvName}-ClusterId' TaskDefinition: !Ref TaskDefinition DesiredCount: !GetAtt DynamicDesiredCountAction.DesiredCount DeploymentConfiguration: DeploymentCircuitBreaker: Enable: true Rollback: true MinimumHealthyPercent: 100 MaximumPercent: 200 Alarms: AlarmNames: - my-app-test-dogworker-CopilotRollbackCPUAlarm - my-app-test-dogworker-CopilotRollbackMemAlarm - my-app-test-dogworker-CopilotRollbackMsgsDelayedAlarm Enable: true Rollback: true PlatformVersion: LATEST PropagateTags: SERVICE EnableExecuteCommand: true CapacityProviderStrategy: - CapacityProvider: FARGATE_SPOT Weight: 1 - CapacityProvider: FARGATE Weight: 0 Base: 5 ServiceConnectConfiguration: Enabled: True Namespace: test.my-app.local LogConfiguration: LogDriver: awslogs Options: awslogs-region: !Ref AWS::Region awslogs-group: !Ref LogGroup awslogs-stream-prefix: copilot NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED Subnets: Fn::Split: - ',' - Fn::ImportValue: !Sub '${AppName}-${EnvName}-PublicSubnets' SecurityGroups: - Fn::ImportValue: !Sub '${AppName}-${EnvName}-EnvironmentSecurityGroup' ServiceRegistries: !Ref 'AWS::NoValue' EventsKMSKey: Metadata: 'aws:copilot:description': 'A KMS key to encrypt messages in your queues' Type: AWS::KMS::Key Properties: KeyPolicy: Version: '2012-10-17' Statement: - Sid: "Allow key use" Effect: Allow Principal: AWS: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:root' Action: - "kms:Create*" - "kms:Describe*" - "kms:Enable*" - "kms:List*" - "kms:Put*" - "kms:Update*" - "kms:Revoke*" - "kms:Disable*" - "kms:Get*" - "kms:Delete*" - "kms:ScheduleKeyDeletion" - "kms:CancelKeyDeletion" - "kms:Tag*" - "kms:UntagResource" - "kms:Encrypt" - "kms:Decrypt" - "kms:ReEncrypt*" - "kms:GenerateDataKey*" Resource: '*' - Sid: "Allow SNS encryption" Effect: "Allow" Principal: Service: sns.amazonaws.com Action: - "kms:Decrypt" - "kms:GenerateDataKey*" Resource: '*' - Sid: "Allow SQS encryption" Effect: "Allow" Principal: Service: sqs.amazonaws.com Action: - "kms:Encrypt" - "kms:Decrypt" - "kms:ReEncrypt*" - "kms:GenerateDataKey*" Resource: '*' - Sid: "Allow task role encrypt/decrypt" Effect: "Allow" Principal: AWS: - !GetAtt TaskRole.Arn Action: - "kms:Encrypt" - "kms:Decrypt" Resource: '*' EventsQueue: Metadata: 'aws:copilot:description': 'An events SQS queue to buffer messages' Type: AWS::SQS::Queue Properties: KmsMasterKeyId: !Ref EventsKMSKey DelaySeconds: 1 RedrivePolicy: deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn maxReceiveCount: 5 DeadLetterQueue: Metadata: 'aws:copilot:description': 'A dead letter SQS queue to buffer failed messages from the events queue' Type: AWS::SQS::Queue Properties: KmsMasterKeyId: !Ref EventsKMSKey MessageRetentionPeriod: 1209600 # 14 days DeadLetterPolicy: Type: AWS::SQS::QueuePolicy Properties: Queues: [!Ref 'DeadLetterQueue'] PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: - !GetAtt TaskRole.Arn Action: - sqs:ReceiveMessage - sqs:DeleteMessage Resource: !GetAtt DeadLetterQueue.Arn QueuePolicy: Type: AWS::SQS::QueuePolicy Properties: Queues: [!Ref 'EventsQueue'] PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: - !GetAtt TaskRole.Arn Action: - sqs:ReceiveMessage - sqs:DeleteMessage Resource: !GetAtt EventsQueue.Arn - Effect: Allow Principal: Service: sns.amazonaws.com Action: - sqs:SendMessage Resource: !GetAtt EventsQueue.Arn Condition: ArnEquals: aws:SourceArn: !Join ['', [!Sub 'arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:', !Ref AppName, '-', !Ref EnvName, '-dogsvc-givesdogs']] dogsvcgivesdogsSNSTopicSubscription: Metadata: 'aws:copilot:description': 'A SNS subscription to topic givesdogs from service dogsvc' Type: AWS::SNS::Subscription Properties: TopicArn: !Join ['', [!Sub 'arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:', !Ref AppName, '-', !Ref EnvName, '-dogsvc-givesdogs']] Protocol: 'sqs' FilterPolicy: {"cutomer_interests": ["rugby", "football", "baseball"], "event": [{"anything-but": "order_cancelled"}], "price_usd": [{"numeric": [">=", 100]}], "store": ["example_corp"]} Endpoint: !GetAtt EventsQueue.Arn dogsvcgiveshuskiesSNSTopicSubscription: Metadata: 'aws:copilot:description': 'A SNS subscription to topic giveshuskies from service dogsvc' Type: AWS::SNS::Subscription Properties: TopicArn: !Join ['', [!Sub 'arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:', !Ref AppName, '-', !Ref EnvName, '-dogsvc-giveshuskies']] Protocol: 'sqs' Endpoint: !GetAtt dogsvcgiveshuskiesEventsQueue.Arn dogsvcgiveshuskiesEventsQueue: Metadata: 'aws:copilot:description': 'A SQS queue to buffer messages from the topic giveshuskies' Type: AWS::SQS::Queue Properties: KmsMasterKeyId: !Ref EventsKMSKey VisibilityTimeout: 1 dogsvcgiveshuskiesQueuePolicy: Type: AWS::SQS::QueuePolicy Properties: Queues: [!Ref 'dogsvcgiveshuskiesEventsQueue'] PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: - !GetAtt TaskRole.Arn Action: - sqs:ReceiveMessage - sqs:DeleteMessage Resource: !GetAtt dogsvcgiveshuskiesEventsQueue.Arn - Effect: Allow Principal: Service: sns.amazonaws.com Action: - sqs:SendMessage Resource: !GetAtt dogsvcgiveshuskiesEventsQueue.Arn Condition: ArnEquals: aws:SourceArn: !Join ['', [!Sub 'arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:', !Ref AppName, '-', !Ref EnvName, '-dogsvc-giveshuskies']] mytopicmytopicfifoSNSTopicSubscription: Metadata: 'aws:copilot:description': 'A SNS subscription to topic mytopic.fifo from service mytopic' Type: AWS::SNS::Subscription Properties: TopicArn: !Join [ '', [ !Sub 'arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:', !Ref AppName, '-', !Ref EnvName, '-mytopic-mytopic.fifo' ] ] Protocol: 'sqs' Endpoint: !GetAtt mytopicmytopicfifoEventsQueue.Arn mytopicmytopicfifoEventsQueue: Metadata: 'aws:copilot:description': 'A SQS FIFO queue to buffer messages from the topic mytopic.fifo' Type: AWS::SQS::Queue Properties: KmsMasterKeyId: !Ref EventsKMSKey FifoQueue: true mytopicmytopicfifoQueuePolicy: Type: AWS::SQS::QueuePolicy Properties: Queues: [ !Ref 'mytopicmytopicfifoEventsQueue' ] PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: - !GetAtt TaskRole.Arn Action: - sqs:ReceiveMessage - sqs:DeleteMessage Resource: !GetAtt mytopicmytopicfifoEventsQueue.Arn - Effect: Allow Principal: Service: sns.amazonaws.com Action: - sqs:SendMessage Resource: !GetAtt mytopicmytopicfifoEventsQueue.Arn Condition: ArnEquals: aws:SourceArn: !Join [ '', [ !Sub 'arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:', !Ref AppName, '-', !Ref EnvName, '-mytopic-mytopic.fifo' ] ] yourtopicyourtopicfifoSNSTopicSubscription: Metadata: 'aws:copilot:description': 'A SNS subscription to topic yourtopic.fifo from service yourtopic' Type: AWS::SNS::Subscription Properties: TopicArn: !Join [ '', [ !Sub 'arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:', !Ref AppName, '-', !Ref EnvName, '-yourtopic-yourtopic.fifo' ] ] Protocol: 'sqs' Endpoint: !GetAtt yourtopicyourtopicfifoEventsQueue.Arn yourtopicyourtopicfifoEventsQueue: Metadata: 'aws:copilot:description': 'A SQS FIFO queue to buffer messages from the topic yourtopic.fifo' Type: AWS::SQS::Queue Properties: KmsMasterKeyId: !Ref EventsKMSKey FifoQueue: true FifoThroughputLimit: perMessageGroupId DeduplicationScope: messageGroup ContentBasedDeduplication: true yourtopicyourtopicfifoQueuePolicy: Type: AWS::SQS::QueuePolicy Properties: Queues: [ !Ref 'yourtopicyourtopicfifoEventsQueue' ] PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: - !GetAtt TaskRole.Arn Action: - sqs:ReceiveMessage - sqs:DeleteMessage Resource: !GetAtt yourtopicyourtopicfifoEventsQueue.Arn - Effect: Allow Principal: Service: sns.amazonaws.com Action: - sqs:SendMessage Resource: !GetAtt yourtopicyourtopicfifoEventsQueue.Arn Condition: ArnEquals: aws:SourceArn: !Join [ '', [ !Sub 'arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:', !Ref AppName, '-', !Ref EnvName, '-yourtopic-yourtopic.fifo' ] ] nonfifotopicnonfifotopicSNSTopicSubscription: Metadata: 'aws:copilot:description': 'A SNS subscription to topic nonfifotopic from service nonfifotopic' Type: AWS::SNS::Subscription Properties: TopicArn: !Join [ '', [ !Sub 'arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:', !Ref AppName, '-', !Ref EnvName, '-nonfifotopic-nonfifotopic' ] ] Protocol: 'sqs' Endpoint: !GetAtt nonfifotopicnonfifotopicEventsQueue.Arn nonfifotopicnonfifotopicEventsQueue: Metadata: 'aws:copilot:description': 'A SQS queue to buffer messages from the topic nonfifotopic' Type: AWS::SQS::Queue Properties: KmsMasterKeyId: !Ref EventsKMSKey nonfifotopicnonfifotopicQueuePolicy: Type: AWS::SQS::QueuePolicy Properties: Queues: [ !Ref 'nonfifotopicnonfifotopicEventsQueue' ] PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: - !GetAtt TaskRole.Arn Action: - sqs:ReceiveMessage - sqs:DeleteMessage Resource: !GetAtt nonfifotopicnonfifotopicEventsQueue.Arn - Effect: Allow Principal: Service: sns.amazonaws.com Action: - sqs:SendMessage Resource: !GetAtt nonfifotopicnonfifotopicEventsQueue.Arn Condition: ArnEquals: aws:SourceArn: !Join [ '', [ !Sub 'arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:', !Ref AppName, '-', !Ref EnvName, '-nonfifotopic-nonfifotopic' ] ] givesOtherdogsSNSTopic: Metadata: 'aws:copilot:description': 'A SNS topic to broadcast givesOtherdogs events' Type: AWS::SNS::Topic Properties: TopicName: !Sub '${AWS::StackName}-givesOtherdogs' KmsMasterKeyId: 'alias/aws/sns' givesOtherdogsSNSTopicPolicy: Type: AWS::SNS::TopicPolicy DependsOn: givesOtherdogsSNSTopic Properties: Topics: - !Ref givesOtherdogsSNSTopic PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:root' Action: - sns:Subscribe Resource: !Ref givesOtherdogsSNSTopic Condition: StringEquals: "sns:Protocol": "sqs" mytopicfifoSNSTopic: Metadata: 'aws:copilot:description': 'A SNS FIFO topic to broadcast mytopic.fifo events' Type: AWS::SNS::Topic Properties: TopicName: !Sub '${AWS::StackName}-mytopic.fifo' FifoTopic: true KmsMasterKeyId: 'alias/aws/sns' mytopicfifoSNSTopicPolicy: Type: AWS::SNS::TopicPolicy DependsOn: mytopicfifoSNSTopic Properties: Topics: - !Ref mytopicfifoSNSTopic PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:root' Action: - sns:Subscribe Resource: !Ref mytopicfifoSNSTopic Condition: StringEquals: "sns:Protocol": "sqs" mytopicSNSTopic: Metadata: 'aws:copilot:description': 'A SNS topic to broadcast mytopic events' Type: AWS::SNS::Topic Properties: TopicName: !Sub '${AWS::StackName}-mytopic' KmsMasterKeyId: 'alias/aws/sns' mytopicSNSTopicPolicy: Type: AWS::SNS::TopicPolicy DependsOn: mytopicSNSTopic Properties: Topics: - !Ref mytopicSNSTopic PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:root' Action: - sns:Subscribe Resource: !Ref mytopicSNSTopic Condition: StringEquals: "sns:Protocol": "sqs" yourtopicfifoSNSTopic: Metadata: 'aws:copilot:description': 'A SNS FIFO topic to broadcast yourtopic.fifo events' Type: AWS::SNS::Topic Properties: TopicName: !Sub '${AWS::StackName}-yourtopic.fifo' FifoTopic: true ContentBasedDeduplication: true KmsMasterKeyId: 'alias/aws/sns' yourtopicfifoSNSTopicPolicy: Type: AWS::SNS::TopicPolicy DependsOn: yourtopicfifoSNSTopic Properties: Topics: - !Ref yourtopicfifoSNSTopic PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:root' Action: - sns:Subscribe Resource: !Ref yourtopicfifoSNSTopic Condition: StringEquals: "sns:Protocol": "sqs" nonfifotopicSNSTopic: Metadata: 'aws:copilot:description': 'A SNS topic to broadcast nonfifotopic events' Type: AWS::SNS::Topic Properties: TopicName: !Sub '${AWS::StackName}-nonfifotopic' KmsMasterKeyId: 'alias/aws/sns' nonfifotopicSNSTopicPolicy: Type: AWS::SNS::TopicPolicy DependsOn: nonfifotopicSNSTopic Properties: Topics: - !Ref nonfifotopicSNSTopic PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:root' Action: - sns:Subscribe Resource: !Ref nonfifotopicSNSTopic Condition: StringEquals: "sns:Protocol": "sqs" AddonsStack: Metadata: 'aws:copilot:description': 'An Addons CloudFormation Stack for your additional AWS resources' Type: AWS::CloudFormation::Stack Condition: HasAddons Properties: Parameters: App: !Ref AppName Env: !Ref EnvName Name: !Ref WorkloadName TemplateURL: !Ref AddonsTemplateURL CPURollbackAlarm: Metadata: 'aws:copilot:description': "A CloudWatch alarm associated with CPU utilization for deployment rollbacks" Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: "Roll back ECS service if CPU utilization is greater than or equal to 70% twice in 3 minutes." AlarmName: my-app-test-dogworker-CopilotRollbackCPUAlarm Namespace: 'AWS/ECS' Dimensions: - Name: ClusterName Value: Fn::ImportValue: !Sub '${AppName}-${EnvName}-ClusterId' - Name: ServiceName Value: !Select [ 2, !Split [ "/", !Ref Service ] ] MetricName: 'CPUUtilization' ComparisonOperator: 'GreaterThanOrEqualToThreshold' DatapointsToAlarm: 2 EvaluationPeriods: 3 Period: 60 Statistic: 'Average' Threshold: 70 Unit: 'Percent' MemoryRollbackAlarm: Metadata: 'aws:copilot:description': "A CloudWatch alarm associated with memory utilization for deployment rollbacks" Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: "Roll back ECS service if memory utilization is greater than or equal to 50% twice in 3 minutes." AlarmName: my-app-test-dogworker-CopilotRollbackMemAlarm Namespace: 'AWS/ECS' Dimensions: - Name: ClusterName Value: Fn::ImportValue: !Sub '${AppName}-${EnvName}-ClusterId' - Name: ServiceName Value: !Select [ 2, !Split [ "/", !Ref Service ] ] MetricName: 'MemoryUtilization' ComparisonOperator: 'GreaterThanOrEqualToThreshold' DatapointsToAlarm: 2 EvaluationPeriods: 3 Period: 60 Statistic: 'Average' Threshold: 50 Unit: 'Percent' MessagesDelayedRollbackAlarm: Metadata: 'aws:copilot:description': "A CloudWatch alarm associated with number of messages delayed for deployment rollbacks" Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: "Roll back worker service if number of messages delayed is greater than or equal to 5 twice in 3 minutes." AlarmName: my-app-test-dogworker-CopilotRollbackMsgsDelayedAlarm Namespace: 'AWS/SQS' Dimensions: - Name: QueueName Value: !GetAtt EventsQueue.QueueName MetricName: 'ApproximateNumberOfMessagesDelayed' ComparisonOperator: 'GreaterThanOrEqualToThreshold' DatapointsToAlarm: 2 EvaluationPeriods: 3 Period: 60 Statistic: 'Average' Threshold: 5 Unit: 'Count' EnvControllerAction: Metadata: 'aws:copilot:description': "Update your environment's shared resources" Type: Custom::EnvControllerFunction Properties: ServiceToken: !GetAtt EnvControllerFunction.Arn Workload: !Ref WorkloadName EnvStack: !Sub '${AppName}-${EnvName}' Parameters: [] EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: Handler: "index.handler" Timeout: 900 MemorySize: 512 Role: !GetAtt 'EnvControllerRole.Arn' Runtime: nodejs16.x EnvControllerRole: Metadata: 'aws:copilot:description': "An IAM role to update your environment stack" Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: "EnvControllerStackUpdate" PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - cloudformation:DescribeStacks - cloudformation:UpdateStack Resource: !Sub 'arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${AppName}-${EnvName}/*' Condition: StringEquals: 'cloudformation:ResourceTag/copilot-application': !Sub '${AppName}' 'cloudformation:ResourceTag/copilot-environment': !Sub '${EnvName}' - PolicyName: "EnvControllerRolePass" PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - iam:PassRole Resource: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${AppName}-${EnvName}-CFNExecutionRole' Condition: StringEquals: 'iam:ResourceTag/copilot-application': !Sub '${AppName}' 'iam:ResourceTag/copilot-environment': !Sub '${EnvName}' ManagedPolicyArns: - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole