Gabriele
Gabriele

Reputation: 731

AWS SAM-defined ECS Fargate scheduled task won't start

I used the following script (anonymised) to create a scheduled Fargate task (and the other needed components):

Transform: AWS::Serverless-2016-10-31
AWSTemplateFormatVersion: "2010-09-09"
Description: Anonymized Description

Parameters:
  StackName:
    Description: Stack Name
    Type: String

  ImageTag:
    Description: Tag name for image
    Type: String
    Default: latest

  Subnet1:
    Description: Subnet 1
    Type: String

  Subnet2:
    Description: Subnet 2
    Type: String

  VersionId:
    Type: String
    Description: "The version identifier for this deployment"

Globals:
  Function:
    Timeout: 3
    MemorySize: 128

Resources:

  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Anonymized Application
      GroupName: anonymized-app
      SecurityGroupEgress:
        - CidrIp: "0.0.0.0/0"
          FromPort: -1
          IpProtocol: -1
          ToPort: -1
      Tags:
        - Key: "stack"
          Value: !Ref StackName
      VpcId: vpc-xxxxxxxxxxxxxxxxx

  Repository:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: !Ref StackName
      Tags:
        - Key: "stack"
          Value: !Ref StackName

  Cluster:
    Type: AWS::ECS::Cluster
    Properties:
      CapacityProviders:
        - FARGATE
      Tags:
        - Key: "stack"
          Value: !Ref StackName

  CronRule:
    Type: AWS::Events::Rule
    Properties:
      Description: Daily run of the task
      EventPattern:
        source:
          - aws.ec2
        detail:
          state:
            - stopping
      ScheduleExpression: "cron(0 7 * * ? *)"
      State: ENABLED
      Targets:
        - Arn: !GetAtt
            - Cluster
            - Arn
          RoleArn: !GetAtt
            - ECSTaskRole
            - Arn
          Id: 'TargetFunctionV1'
          EcsParameters:
            TaskCount: 1
            TaskDefinitionArn: !Ref TaskDefinition
            NetworkConfiguration:
              AwsVpcConfiguration:
                Subnets:
                  - !Ref Subnet1
                  - !Ref Subnet2
                SecurityGroups:
                  - !GetAtt SecurityGroup.GroupId
                AssignPublicIp: DISABLED

  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: anonymized-backend
      Cpu: '1024'
      Memory: '8192'
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn
      TaskRoleArn: !Ref ECSTaskRole
      RuntimePlatform:
        CpuArchitecture: X86_64
      ContainerDefinitions:
        - Name: !Sub ${StackName}-taskdefinition
          Image: !Sub
            - ${RepoUrl}:${ImageTag}
            - RepoUrl: !GetAtt Repository.RepositoryUri
          PortMappings:
            - ContainerPort: 3000
          LogConfiguration:
            LogDriver: awslogs
            Options:
              mode: non-blocking
              max-buffer-size: 25m
              awslogs-group: !Ref LogGroup
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: containerlog
          Environment:
            - Name: VERSION_ID
              Value: !Ref VersionId

  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: /fargatelogs

  ECSTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: [ecs-tasks.amazonaws.com]
          Action: ['sts:AssumeRole']
          Condition:
            ArnLike:
              aws:SourceArn: !Sub arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:*
            StringEquals:
              aws:SourceAccount: !Ref AWS::AccountId
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy

  ECSTaskRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: [ecs-tasks.amazonaws.com]
          Action: ['sts:AssumeRole']
          Condition:
            ArnLike:
              aws:SourceArn: !Sub arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:*
            StringEquals:
              aws:SourceAccount: !Ref AWS::AccountId
      Path: /
      Policies:
        - PolicyName: SSMParameterAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - ssm:GetParameter
                Resource:
                  - '*'
        - PolicyName: S3Access
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                  - s3:ListBucket
                Resource:
                  - '*'

Outputs:
  ClusterName:
    Description: Amazon ECS Cluster Name
    Value: !Ref Cluster
  RepositoryUrl:
    Description: URL of the repo
    Value: !GetAtt Repository.RepositoryUri

The deployment goes well, and I can see the scheduled task from the console. However, the task will not start at the scheduled time.

I was able to create a similar scheduled task, directly from the console, and it starts instead; a difference in the definition that I see is that Launch type: FARGATE and Platform version: LATEST are present in the console-defined one, but I don't see how to provide them in the SAM script.

I expect that they should behave in the same way, why is it not so?

Upvotes: 0

Views: 29

Answers (1)

Mark B
Mark B

Reputation: 200988

In my experience this is almost always because you use the wrong IAM role for the EventBridge scheduler. You can verify that by looking in your AWS account's CloudTrail.

In your code for the CronRule Target, you are giving it the ECSTaskRole. This is incorrect. The ECS Task Definition has the ECSTaskRole assigned to the task already. What you need to give the CronRule is an IAM role it can use that will give it permission to execute tasks in your ECS cluster.

In particular, it needs a role with an Assume Role policy that allows sts:AssumeRole for the service events.amazonaws.com and the role needs the following IAM permissions:

  • iam:PassRole
  • ecs:RunTask

This role configuration is documented here.

Upvotes: 0

Related Questions