😸

【CloudFormation】EventBridgeからECSタスクを起動するテンプレート

2022/09/14に公開1

1. はじめに

 こんにちわ、Mitsuoです。
今回はCloudFormationを用いてEventBridgeからECSタスクを起動する環境を構築してみました。

2. 概要

流れは以下の通りです。

  1. S3バケットにオブジェクトを格納する
  2. オブジェクトの格納を契機にEventBridgeルールが起動する
  3. ターゲットのECSタスクを実行する

image

3. 作成するリソース

  • 作成する主なリソースは以下の通り
    • VPC × 1
    • Private Subnet × 2
    • NetworkACL × 2
    • Route Table × 2
    • IAMロール × 3 (ECS用に2つ、EventBridge用に1つ)
    • IAMポリシー × 3 (ECS用に2つ、EventBridge用に1つ)
    • Security Group × 3 (CloudWatch LogsおよびECRのVPCEndPoint用)
    • EFS × 1
    • マウントターゲット × 2
    • VPCEndpoint × 3 (Interface型のECRおよびCloudWatch Logsへのアクセス用)
    • VPCEndpoint × 1 (Gateway型のS3へのアクセス用)
    • EventBridgeルール × 1
    • ECSクラスター × 1
    • ECSタスク定義 × 1

など

3.1 補足

  • ブログの範囲では利用しないが、ECSのボリュームはEFSを指定する
  • プライベートサブネット配下でECSタスクを実行する
  • VPCエンドポイント経由でECRおよびCloudWatch Logsエンドポイントにアクセスする

4. 環境構築

  CloudFormationを用いて、次の順で環境構築を行う。

  1. ネットワーク環境を作成
  2. S3バケットを作成
  3. ECRリポジトリを作成
  4. VPCエンドポイントとセキュリティグループ、ECS用のIAMロールを作成
  5. ECS、EFS、CloudWatch Logsを作成
  6. EventBridgeルール、ルール用のIAMロールを作成

4.1 ネットワーク環境を作成

以下の情報を基にスタックを作成する。

パラメータ値:

項目 備考
SystemName プロジェクト名や利用目的等を入力する
EnvType デプロイする環境を選択する
検証、ステージング、本番の3点
Tagprefix 任意で入力するPrefix値を指定する
Owner 作業者、所有者、コスト管理用に入力する
VPCCIDR 作成するVPCのCIDRを指定する
PrivateSubnet1CIDR 作成するVPC配下のサブネットCIDRを指定する
PrivateSubnet2CIDR 作成するVPC配下のサブネットCIDRを指定する

4.1.1 テンプレート情報

AWSTemplateFormatVersion: 2010-09-09
Description: Deploy a VPC and related resources such as Subnet, Route Table.
# ------------------------------------------------------------#
#  Caution:
#  This template is for deploying resources in Tokyo region(ap-northeast-1).
#  If you deploy them in another region, make sure that you understand below content and make modification for parameters such as AvailabilityZone.
# ------------------------------------------------------------#
#  Metadata:
#  This can privide details about the template.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html.
#  As Metadata Keys, AWS::CloudFormation::Interface can Defines the grouping and ordering of input parameters
#  when they are displayed in the AWS CloudFormation console.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-interface.html.
# ------------------------------------------------------------# 

Metadata: 
  "AWS::CloudFormation::Interface": 
    ParameterGroups:
      -  
        Parameters:
          - SystemName
          - EnvType 
          - Tagprefix
          - Owner
          - VPCCIDR          
          - PrivateSubnet1CIDR
          - PrivateSubnet2CIDR     
    ParameterLabels: 
      SystemName:
        default: "SystemName:Type the Systemname"
      EnvType:
        default: "EnvType: Select the environment to which you want to deploy resources"
      Tagprefix:
        default: "Tagprefix: Type the Tagprefix which is logical unit name about this stack(e.g. Webserver,Monitoring,Logging)"
      Owner:
        default: "Owner: Type who owns these resources (e.g. project name or worker, whether this purpose is just verification or not)"        
      VPCCIDR: 
        default: "VPCCIDR: Type VPC's CIDR such as NN.NN.NN.NN/NN based on RFC 1918"   
      PrivateSubnet1CIDR: 
        default: "PrivateSubnet1CIDR: Type your subnet's CIDR in AZ-A such as NN.NN.NN.NN/NN based on RFC 1918"
      PrivateSubnet2CIDR: 
        default: "PrivateSubnet2CIDR: Type your subnet's CIDR in AZ-C such as NN.NN.NN.NN/NN based on RFC 1918"    

# ------------------------------------------------------------#
# Parameters
# This Can enable templates to input custom values each time you create or update a stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html.
# ------------------------------------------------------------# 

Parameters:
  SystemName:
    Type: String
  EnvType:
    Type: String
    Default: "dev"
    AllowedValues:
      - dev
      - stg
      - prd 
  Tagprefix:
    Type: String      
  Owner:
    Type: String
  VPCCIDR:
    Type: String
    Default: "10.0.0.0/16"
    ConstraintDescription: "Type VPC's CIDR such as NN.NN.NN.NN/NN based on RFC 1918"  
  PrivateSubnet1CIDR:
    Type: String
    Default: "10.0.50.0/24"
    ConstraintDescription: "Type your subnet's CIDR in AZ-A such as NN.NN.NN.NN/NN based on RFC 1918"      
  PrivateSubnet2CIDR:
    Type: String
    Default: "10.0.100.0/24"
    ConstraintDescription: "Type your subnet's CIDR in AZ-C such as NN.NN.NN.NN/NN based on RFC 1918"       

# ------------------------------------------------------------#
# Resources
# This can declare the AWS resources that you want to include in the stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html.
# ------------------------------------------------------------# 

Resources:
# ------------------------------------------------------------#
# Create VPC
# ------------------------------------------------------------#

  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
      EnableDnsHostnames: "true"
      EnableDnsSupport: "true"
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-VPC
        - Key: Owner
          Value: !Ref Owner
# ------------------------------------------------------------#
# Create PrivateSubnet
# ------------------------------------------------------------#

  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref PrivateSubnet1CIDR
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-PrivateSubnet-1a
        - Key: Owner
          Value: !Ref Owner

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref PrivateSubnet2CIDR
      AvailabilityZone: ap-northeast-1c
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-PrivateSubnet-1c
        - Key: Owner
          Value: !Ref Owner

# ------------------------------------------------------------#
# Create NetworkACL and associate NetworkACL with each Subnet  
# ------------------------------------------------------------#
  NetworkACL1:
    Type: AWS::EC2::NetworkAcl
    Properties:
      VpcId: !Ref VPC
      Tags: 
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-Networkacl-1a
        - Key: Owner
          Value: !Ref Owner          

  NetworkACLAssoc1:
    Type: AWS::EC2::SubnetNetworkAclAssociation
    Properties: 
      NetworkAclId: !Ref NetworkACL1
      SubnetId: !Ref PrivateSubnet1

  NetworkACL2:
    Type: AWS::EC2::NetworkAcl
    Properties:
      VpcId: !Ref VPC
      Tags: 
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-Networkacl-1c
        - Key: Owner
          Value: !Ref Owner 

  NetworkACLAssoc2:
    Type: AWS::EC2::SubnetNetworkAclAssociation
    Properties: 
      NetworkAclId: !Ref NetworkACL2
      SubnetId: !Ref PrivateSubnet2

# ------------------------------------------------------------#
# Add In/Outbound Rule to NetworkACL   
# ------------------------------------------------------------#

  NaclInboundRule1:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
       NetworkAclId: !Ref NetworkACL1
       RuleNumber: 100
       Protocol: -1
       Egress: false
       RuleAction: allow
       CidrBlock: 0.0.0.0/0

  NaclOutboundRule1:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
       NetworkAclId: !Ref NetworkACL1
       RuleNumber: 100
       Protocol: -1
       Egress: true
       RuleAction: allow
       CidrBlock: 0.0.0.0/0

  NaclInboundRule2:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
       NetworkAclId: !Ref NetworkACL2
       RuleNumber: 100
       Protocol: -1
       Egress: false
       RuleAction: allow
       CidrBlock: 0.0.0.0/0

  NaclOutboundRule2:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
       NetworkAclId: !Ref NetworkACL2
       RuleNumber: 100
       Protocol: -1
       Egress: true
       RuleAction: allow
       CidrBlock: 0.0.0.0/0

# ------------------------------------------------------------#
# Create Route Table and associate with Private Subnet
# ------------------------------------------------------------#

  PrivateRouteTable1:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-RouteTable-PrivateSubnet-1a
      - Key: Owner
        Value: !Ref Owner

  PrivateSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable1

  PrivateRouteTable2:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-RouteTable-PrivateSubnet-1c
      - Key: Owner
        Value: !Ref Owner

  PrivateSubnetRouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable2    

# ------------------------------------------------------------#
# Specify route in a route table
# Exactly one of [LocalGatewayId, InstanceId, NatGatewayId, TransitGatewayId, VpcEndpointId, GatewayId, NetworkInterfaceId, 
# EgressOnlyInternetGatewayId, CarrierGatewayId, VpcPeeringConnectionId] must be specified and not empty.
# ------------------------------------------------------------#

#  Route:
#    Type: AWS::EC2::Route
#    Properties:
#       RouteTableId: !Ref PrivateRouteTable
#       DestinationCidrBlock: 10.0.0.0/16

# ------------------------------------------------------------#
# Outputs
# This can output each value specified as output section.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html.
# ------------------------------------------------------------# 

Outputs:
  VPC:
    Description: VPC
    Value: !Ref VPC

  PrivateSubnet1:
    Description: PrivateSubnet1
    Value: !Ref PrivateSubnet1

  PrivateSubnet2:
    Description: PrivateSubnet2
    Value: !Ref PrivateSubnet2

  NetworkACL1:
    Description: NetworkACL1
    Value: !Ref NetworkACL1

  NetworkACL2:
    Description: NetworkACL2
    Value: !Ref NetworkACL2    
  
  RouteTable1:
    Description: RouteTable1
    Value: !Ref PrivateRouteTable1  

  RouteTable2:
    Description: RouteTable2
    Value: !Ref PrivateRouteTable2  

  AZ1:
    Description: Availability Zone 1
    Value: !GetAtt
      - PrivateSubnet1
      - AvailabilityZone

  AZ2:
    Description: Availability Zone 2
    Value: !GetAtt
      - PrivateSubnet2
      - AvailabilityZone

4.2 S3バケットを作成

  • S3バケットおよびバケットポリシーを作成する
  • イベント発火させるためのオブジェクトを配置するS3バケットである
  • あくまで検証目的なのでバケットポリシーはとりわけ設定していない、必要に応じてポリシーを書き換えること
  • オブジェクトを格納するディレクトリは別途作成する必要あり

以下の情報を基にスタックを作成する。

パラメータ値:

項目 備考
SystemName プロジェクト名や利用目的等を入力する
EnvType デプロイする環境を選択する
検証、ステージング、本番の3点
Tagprefix 任意で入力するPrefix値を指定する
Owner 作業者、所有者、コスト管理用に入力する

4.2.1 テンプレート情報

AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy S3 Bucket with Bucket policie.
# ------------------------------------------------------------#
#  Prerequisite:
#  This template is for deploying four Buckets(S3) with Bucket policies.
# ------------------------------------------------------------#
#  Metadata:
#  This can provide details about the template.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html.
#  As Metadata Keys, AWS::CloudFormation::Interface can define the grouping and ordering of input parameters
#  when they are displayed in the AWS CloudFormation console.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-interface.html.
# ------------------------------------------------------------# 

Metadata: 
  "AWS::CloudFormation::Interface": 
    ParameterGroups:
      -  
        Parameters:
          - SystemName
          - EnvType 
          - Tagprefix
          - Owner

    ParameterLabels: 
      SystemName:
        default: "SystemName: Type your project Name you would like to name"
      EnvType:
        default: "EnvType: Select which environment you would like to deploy buckets in."
      Tagprefix:
        default: "Tagprefix: Type the prefix you would like to add as logical unit name about each resource(e.g. webserver,monitoring,logging)"
      Owner:
        default: "Owner: Type who owns these resources (e.g. project name, worker or for cost management)"            

# ------------------------------------------------------------#
# Parameters
# This can enable templates to input custom values each time you create or update a stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html.
# ------------------------------------------------------------# 

Parameters:
  SystemName:
    Type: String
  EnvType:
    Type: String
    Default: "dev"
    AllowedValues:
      - dev
      - stg
      - prd   
  Tagprefix:
    Type: String      
  Owner:
    Type: String         

# ------------------------------------------------------------#
# Resources
# This can declare the AWS resources that you want to include in the stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html.
# ------------------------------------------------------------# 

Resources:
# ------------------------------------------------------------#
# Create S3 Bucket 1
# ------------------------------------------------------------#

  S3Bucket1:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      BucketName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-s3bucket-place-object-${AWS::AccountId}
      PublicAccessBlockConfiguration: 
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      VersioningConfiguration:
        Status: Suspended          
# アクセスログ設定は無効化
#     LoggingConfiguration: 
#        DestinationBucketName: !Ref S3Bucket3
#        LogFilePrefix: AccessLog/
      BucketEncryption:
        ServerSideEncryptionConfiguration: 
          - ServerSideEncryptionByDefault: 
              SSEAlgorithm: AES256                  
      LifecycleConfiguration:
        Rules:
          - Id: !Sub ${SystemName}-${EnvType}-${Tagprefix}-Lifecycle-s3bucket-place-object
            Status: Enabled
            ExpirationInDays: 30
      OwnershipControls:
        Rules:
          - ObjectOwnership: BucketOwnerEnforced
      NotificationConfiguration:
        EventBridgeConfiguration:
          EventBridgeEnabled: true           
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-s3bucket-place-object-${AWS::AccountId}
        - Key: Owner
          Value: !Sub ${Owner}          

# ------------------------------------------------------------#
# Create S3 Bucket Policy
# ------------------------------------------------------------#

  BucketPolicy1:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
      Bucket: !Ref S3Bucket1
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Action:
              - 's3:*'
            Sid: BucketPolicy1              
            Effect: Allow
            Resource: 
              - !Sub 'arn:aws:s3:::${S3Bucket1}'
              - !Sub 'arn:aws:s3:::${S3Bucket1}/*'
            Principal: 
              AWS: 
                - !Sub 'arn:aws:iam::${AWS::AccountId}:root'
    DependsOn: S3Bucket1 

# ------------------------------------------------------------#
# Outputs
# This can output each value specified as output section.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html.
# ------------------------------------------------------------# 

Outputs:
  S3Bucket1:
    Description: S3Bucket1
    Value: !Ref S3Bucket1   
           

4.3 ECRリポジトリを作成

  • ECSからPullするECRリポジトリを作成する
  • この手順ではECRにイメージをPushする手順を書いていない

以下の情報を基にスタックを作成する。

パラメータ値:

項目 備考
SystemName プロジェクト名や利用目的等を入力する
EnvType デプロイする環境を選択する
検証、ステージング、本番の3点
Tagprefix 任意で入力するPrefix値を指定する
Owner 作業者、所有者、コスト管理用に入力する

4.3.1 テンプレート情報

AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy a ECR repository.
# ------------------------------------------------------------#
#  Caution:
#  This template is for deploying ECR repository.
#  Make sure you confirm which the region you set up in advance.
#  The building phase is not designated to set up resource based policy.
#  So note that we deleted related resources.
# ------------------------------------------------------------#
#  Metadata:
#  This can privide details about the template.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html.
#  As Metadata Keys, AWS::CloudFormation::Interface can Defines the grouping and ordering of input parameters
#  when they are displayed in the AWS CloudFormation console.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-interface.html.
# ------------------------------------------------------------# 

Metadata: 
  "AWS::CloudFormation::Interface": 
    ParameterGroups:
      -  
        Parameters:
          - SystemName
          - EnvType 
          - Tagprefix
          - Owner

    ParameterLabels: 
      SystemName:
        default: "SystemName: Type the Systemname"
      EnvType:
        default: "EnvType: Select the environment in which you deploy resources"
      Tagprefix:
        default: "Tagprefix: Type the Tagprefix which is logical unit name about this stack(e.g. Webserver,Monitoring,Logging)"
      Owner:
        default: "Owner: Type who owns these resources (e.g. project name or worker, whether this purpose is just verification or not)"    

# ------------------------------------------------------------#
# Parameters
# This Can enable templates to input custom values each time you create or update a stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html.
# The building phase is not designated to set up resource based policy.
# So note that we deleted related resources.
# ------------------------------------------------------------# 

Parameters:
  SystemName:
    Type: String
  EnvType:
    Type: String
    Default: "dev"
    AllowedValues:
      - dev
      - stg
      - prd
  Tagprefix:
    Type: String
  Owner:
    Type: String

# ------------------------------------------------------------#
# Resources
# This can declare the AWS resources that you want to include in the stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html.
# ------------------------------------------------------------# 

Resources:

# ------------------------------------------------------------#
# Create ECR Repository
# The building phase is not designated to set up resource based policy.
# So note that we deleted related configuration .
# ------------------------------------------------------------#

  ECRRepository1: 
    Type: AWS::ECR::Repository
    Properties: 
      RepositoryName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ecr-repository
      ImageScanningConfiguration: 
        ScanOnPush: false          
      EncryptionConfiguration:
        EncryptionType: AES256
      ImageTagMutability: IMMUTABLE 
      LifecyclePolicy:
          LifecyclePolicyText: >
            {
              "rules": [
                {
                  "action": {
                    "type": "expire"
                  },
                  "selection": {
                    "countType": "imageCountMoreThan",
                    "countNumber": 5,
                    "tagStatus": "any"
                  },
                  "description": "delete old images more than 5 images",
                  "rulePriority": 1
                }
              ]
            }
          RegistryId: !Ref AWS::AccountId
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ecr-repository
        - Key: Owner
          Value: !Ref Owner

# ------------------------------------------------------------#
# Outputs
# This can output each value specified as output section.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html.
# ------------------------------------------------------------# 

Outputs:
  ECRRepository1:
    Description: ECRRepository1
    Value: !Ref ECRRepository1

4.4 VPCエンドポイントとセキュリティグループ、IAMロール(ECS用)を作成

以下の情報を基にスタックを作成する。

パラメータ値:

項目 備考
SystemName プロジェクト名や利用目的等を入力する
EnvType デプロイする環境を選択する
検証、ステージング、本番の3点
Tagprefix 任意で入力するPrefix値を指定する
Owner 作業者、所有者、コスト管理用に入力する
VPCID 作成済みのVPCのID
VPCCIDR 作成済みのVPCのCIDR`
InterfaceSubnetId1 作成済みVPCのプライベートサブネット(AZは1a)
InterfaceSubnetId2 作成済みVPCのプライベートサブネット(AZは1c)
RouteTableId1 作成済みVPCのプライベートサブネット(1a)におけるルートテーブルID
RouteTableId2 作成済みVPCのプライベートサブネット(1c)におけるルートテーブルID
S3BucketName1 作成済みのS3バケット名
ECRRepositoryName1 作成済みのECRリポジトリ名
  • 作成するロールには、S3に対するアクションなどを書いている
  • あくまで例として記載するので、適宜修正すること

4.4.1 テンプレート情報

AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy some IAM Role and VPCEndPoint using both Interface(PrivateLink) and Gateway types.
# ------------------------------------------------------------#
#  Caution:
#  This template is for deploying resources in Tokyo region(ap-northeast-1).
#  If you deploy them in another region, make sure that you understand below content and make modification for parameters such as AvailabilityZone.
#  This also includes Security Gruops to attach them to endpoints.
#  And This makes Security Gruop for instance in VPC network because source configuration for each security gruop need that in advance.
#  The building phase is not designated to set up resource based policy.
#  So note that we deleted related resources.
# ------------------------------------------------------------#
#  Metadata:
#  This can privide details about the template.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html.
#  As Metadata Keys, AWS::CloudFormation::Interface can Defines the grouping and ordering of input parameters
#  when they are displayed in the AWS CloudFormation console.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-interface.html.
# ------------------------------------------------------------#

Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      -
        Parameters:
          - SystemName
          - EnvType
          - Tagprefix
          - Owner
          - VPCCIDR
          - VPCID
          - InterfaceSubnetId1
          - InterfaceSubnetId2
          - RouteTableId1
          - RouteTableId2  
          - S3BucketName1                
          - ECRRepositoryName1

    ParameterLabels:
      SystemName:
        default: "SystemName: Type the Systemname"
      EnvType:
        default: "EnvType: Select the environment in which you deploy resources"
      Tagprefix:
        default: "Tagprefix: Type the Tagprefix which is logical unit name about this stack(e.g. Webserver,Monitoring,Logging)"
      Owner:
        default: "Owner: Type who owns these resources (e.g. project name or worker, whether this purpose is just verification or not)"
      VPCID:
        default: "VPCID: Select the VPC ID"
      VPCCIDR:
        default: "VPCCIDR: This is for deciding Security Group Ingress CIDR for instance in VPC. Type VPC's CIDR such as NN.NN.NN.NN/NN based on RFC 1918."
      InterfaceSubnetId1:
        default: "InterfaceSubnetId1: Select private subnet-1a associated with VPC Endpoints(Interface Type)"
      InterfaceSubnetId2:
        default: "InterfaceSubnetId2: Select private subnet-1c associated with VPC Endpoints(Interface Type)"
      RouteTableId1:
        default: "RouteTableId1: Type your RouteTableId for private subnet-1a associated with VPC Endpoints(Gateway Type)."
      RouteTableId2:
        default: "RouteTableId2: Type your RouteTableId for private subnet-1c associated with VPC Endpoints(Gateway Type)."   
      S3BucketName1:
        default: "S3BucketName1: Type your bucket for creating object"                
      ECRRepositoryName1:
        default: "ECRRepositoryName1: Type your Repository for shipping docker images"

# ------------------------------------------------------------#
# Parameters
# This Can enable templates to input custom values each time you create or update a stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html.
# ------------------------------------------------------------#

Parameters:
  SystemName:
    Type: String
  EnvType:
    Type: String
    Default: "dev"
    AllowedValues:
      - dev
      - stg
      - prd
  Tagprefix:
    Type: String
  Owner:
    Type: String
  VPCID:
    Type: AWS::EC2::VPC::Id
    ConstraintDescription: "Select VPC's ID"
  VPCCIDR:
    Type: String
    Default: "10.0.0.0/16"
    ConstraintDescription: "This is for deciding Security Group Ingress CIDR for instance in VPC. Type VPC's CIDR such as NN.NN.NN.NN/NN based on RFC 1918."
  InterfaceSubnetId1:
    Type : AWS::EC2::Subnet::Id
    ConstraintDescription: "Select private subnet-1a associated with VPC Endpoints(Interface Type)"
  InterfaceSubnetId2:
    Type : AWS::EC2::Subnet::Id
    ConstraintDescription: "Select private subnet-1c associated with VPC Endpoints(Interface Type)"
  RouteTableId1:
    Type: String
    Default: "rtb-XXXXXXXXXXXXXXXXX"
    ConstraintDescription: "Type your RouteTableId for private subnet-1a associated with VPC Endpoints(Gateway Type)."
  RouteTableId2:
    Type: String
    Default: "rtb-XXXXXXXXXXXXXXXXX"
    ConstraintDescription: "Type your RouteTableId for private subnet-1c associated with VPC Endpoints(Gateway Type)."    
  S3BucketName1:
    Type: String
    ConstraintDescription: "Type your bucket for creating object"
  ECRRepositoryName1:
    Type: String      
    ConstraintDescription: "Type your Repository for shipping docker images"

# ------------------------------------------------------------#
# Resources
# This can declare the AWS resources that you want to include in the stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html.
#  The building phase is not designated to set up resource based policy.
#  So note that we deleted related resources.
# ------------------------------------------------------------#

Resources:

# ------------------------------------------------------------#
# Create IAM Roles for ECS task and ECS task execution.
# ------------------------------------------------------------#

  IAMRoleforECSTask1:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ECS-Task-IAM-Role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action:
              - sts:AssumeRole
      MaxSessionDuration: 3600        
      Path: /
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ECS-Task-IAM-Role
        - Key: Owner
          Value: !Ref Owner

  IAMRoleforECSTaskExecution1:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ECS-TaskExecution-IAM-Role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action:
              - sts:AssumeRole
      MaxSessionDuration: 3600        
      Path: /
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ECS-TaskExecution-IAM-Role
        - Key: Owner
          Value: !Ref Owner

# ------------------------------------------------------------#
# Create Instance Profiles for IAM Roles
# ------------------------------------------------------------#

  InstanceProfileforECSTask1:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      InstanceProfileName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ECS-Task-IAM-Role
      Path: /
      Roles:
        - !Ref IAMRoleforECSTask1
    DependsOn: IAMRoleforECSTask1

  InstanceProfileforECSTaskExecution1:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      InstanceProfileName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ECS-TaskExecution-IAM-Role
      Path: /
      Roles:
        - !Ref IAMRoleforECSTaskExecution1
    DependsOn: IAMRoleforECSTaskExecution1    

# ------------------------------------------------------------#
# Create IAM Policies for IAM Roles
# ------------------------------------------------------------#

  IAMPolicyforECSTaskRole1:
    Type: 'AWS::IAM::ManagedPolicy'
    Properties:
      Description: Policy for ECS Task Role
      Path: /
      ManagedPolicyName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ECS-Task-IAM-Policy
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Sid: WidePolicyforBucket
            Action:
              - s3:ListBucket
              - s3:Get*
              - s3:PutObject
              - s3:PutObjectAcl
            Resource:
              - !Sub 'arn:aws:s3:::${S3BucketName1}'
              - !Sub 'arn:aws:s3:::${S3BucketName1}/*'        
      Roles:
        - !Ref IAMRoleforECSTask1

  IAMPolicyforECSTaskExecutionRole1:
    Type: 'AWS::IAM::ManagedPolicy'
    Properties:
      Description: Policy for ECS Task execution Role
      Path: /
      ManagedPolicyName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ECS-TaskExecution-IAM-Policy
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Sid: ECRPolicy
            Action:
              - ecr:BatchCheckLayerAvailability
              - ecr:GetDownloadUrlForLayer
              - ecr:BatchGetImage
            Resource: !Sub 'arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/${ECRRepositoryName1}'
          - Effect: Allow
            Sid: LoggroupPolicy
            Action:
              - logs:CreateLogStream
            Resource: !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:*'
          - Effect: Allow
            Sid: LogstreamPolicy
            Action:
              - logs:PutLogEvents
            Resource: !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:*:log-stream:*'                          
          - Effect: Allow
            Action: ecr:GetAuthorizationToken
            Resource: '*'
          - Effect: Allow
            Action: s3:GetObject          
            Resource: !Sub 'arn:aws:s3:::prod-${AWS::Region}-starport-layer-bucket/*'
          - Effect: Allow
            Sid: ReadBucketOnly
            Action:
              - s3:ListBucket
              - s3:Get*
            Resource:
              - !Sub 'arn:aws:s3:::${S3BucketName1}'
              - !Sub 'arn:aws:s3:::${S3BucketName1}/*'              
      Roles:
        - !Ref IAMRoleforECSTaskExecution1

# ------------------------------------------------------------#
# Create Security Group for VPC EndPoint(CloudWatch Logs)
# ------------------------------------------------------------#

  SecurityGroupEndpointsLogs:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-SG-ForEndpoint-logs
      GroupDescription: Security Group for Logs VPC Endpoint.
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !Ref VPCCIDR
      VpcId: !Ref VPCID
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-SG-ForEndpoint-logs
        - Key: Owner
          Value: !Ref Owner

# ------------------------------------------------------------#
#  Create Security Group for VPC End Point(ECR)
#  The building phase is not designated to set up resource based policy.
#  So note that we deleted related resources.
# ------------------------------------------------------------#

  SecurityGroupEndpointsEcrdkr:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-SG-ForEndpoint-Ecrdkr
      GroupDescription: Security Group for ECR VPC Endpoint.
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !Ref VPCCIDR
      VpcId: !Ref VPCID
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-SG-ForEndpoint-Ecrdkr
        - Key: Owner
          Value: !Ref Owner

  SecurityGroupEndpointsEcrapi:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-SG-ForEndpoint-Ecrapi
      GroupDescription: Security Group for ECR VPC Endpoint.
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !Ref VPCCIDR
      VpcId: !Ref VPCID
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-SG-ForEndpoint-Ecrapi
        - Key: Owner
          Value: !Ref Owner

# ------------------------------------------------------------#
#  Create CloudWatch Logs End Point
#  VPCEndpoints is unsupported to use property Tags.
#  The building phase is not designated to set up resource based policy.
#  So note that we deleted related resources.
# ------------------------------------------------------------#

  LogsEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub com.amazonaws.${AWS::Region}.logs
      SubnetIds:
        - !Ref InterfaceSubnetId1
        - !Ref InterfaceSubnetId2
      VpcId: !Ref VPCID
      VpcEndpointType: Interface
      SecurityGroupIds:
        - !Ref SecurityGroupEndpointsLogs
      PrivateDnsEnabled: true
    DependsOn: 
      - SecurityGroupEndpointsLogs
      - IAMPolicyforECSTaskExecutionRole1
      - InstanceProfileforECSTaskExecution1

# ------------------------------------------------------------#
#  Create ECR End Point
#  Amazon ECS tasks hosted on Fargate using platform version 1.4.0 or later require both the com.amazonaws.region.ecr.dkr
#  and com.amazonaws.region.ecr.api Amazon ECR VPC endpoints as well as the Amazon S3 gateway endpoint to take advantage of this feature.
#  For more information, see https://docs.aws.amazon.com/AmazonECR/latest/userguide/vpc-endpoints.html
#  VPCEndpoints is unsupported to use property Tags.
#  The building phase is not designated to set up resource based policy.
#  So note that we deleted related resources.
# ------------------------------------------------------------#

  EcrdkrEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ecr.dkr
      SubnetIds:
        - !Ref InterfaceSubnetId1
        - !Ref InterfaceSubnetId2
      VpcId: !Ref VPCID
      VpcEndpointType: Interface
      SecurityGroupIds:
        - !Ref SecurityGroupEndpointsEcrdkr
      PrivateDnsEnabled: true
    DependsOn: 
      - SecurityGroupEndpointsEcrdkr
      - IAMPolicyforECSTaskExecutionRole1

  EcrapiEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ecr.api
      SubnetIds:
        - !Ref InterfaceSubnetId1
        - !Ref InterfaceSubnetId2
      VpcId: !Ref VPCID
      VpcEndpointType: Interface
      SecurityGroupIds:
        - !Ref SecurityGroupEndpointsEcrapi
      PrivateDnsEnabled: true
    DependsOn: 
      - SecurityGroupEndpointsEcrapi
      - IAMPolicyforECSTaskExecutionRole1

# ------------------------------------------------------------#
#  Create S3 End Point(Gateway)
#  VPCEndpoints is unsupported to use property Tags.
#  The building phase is not designated to set up resource based policy.
#  So note that we deleted related resources.
# ------------------------------------------------------------#

  S3GatewayEndpoint:
    Type: 'AWS::EC2::VPCEndpoint'
    Properties:
      RouteTableIds:
        - !Ref RouteTableId1
        - !Ref RouteTableId2
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcId: !Ref VPCID
      VpcEndpointType: Gateway
    DependsOn: IAMPolicyforECSTaskRole1

# ------------------------------------------------------------#
# Outputs
# This can output each value specified as output section.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html.
# ------------------------------------------------------------#

Outputs:

# ------------------------------------------------------------#
# Output Security Groups
# ------------------------------------------------------------#

  SecurityGroupEndpointsLogs:
    Description: SecurityGroupEndpointsLogs
    Value: !Ref SecurityGroupEndpointsLogs

  SecurityGroupEndpointsEcrdkr:
    Description: SecurityGroupEndpointsEcrdkr
    Value: !Ref SecurityGroupEndpointsEcrdkr

  SecurityGroupEndpointsEcrapi:
    Description: SecurityGroupEndpointsEcrapi
    Value: !Ref SecurityGroupEndpointsEcrapi

# ------------------------------------------------------------#
# Output IAM Resources
# ------------------------------------------------------------#

  IAMRoleforECSTask1:
    Description: IAMRoleforECSTask1
    Value: !Ref IAMRoleforECSTask1

  IAMRoleforECSTaskExecution1:
    Description: IAMRoleforECSTaskExecution1
    Value: !Ref IAMRoleforECSTaskExecution1

  InstanceProfileforECSTask1:
    Description: InstanceProfileforECSTask1
    Value: !Ref InstanceProfileforECSTask1   

  InstanceProfileforECSTaskExecution1:
    Description: InstanceProfileforECSTaskExecution1
    Value: !Ref InstanceProfileforECSTaskExecution1

  IAMPolicyforECSTaskRole1:
    Description: IAMPolicyforECSTaskRole1
    Value: !Ref IAMPolicyforECSTaskRole1

  IAMPolicyforECSTaskExecutionRole1:
    Description: IAMPolicyforECSTaskExecutionRole1
    Value: !Ref IAMPolicyforECSTaskExecutionRole1

# ------------------------------------------------------------#
# Output VPC Endpoints using Interface Type
# ------------------------------------------------------------#

  LogsEndpoint:
    Description: LogsEndpoint
    Value: !Ref LogsEndpoint

  EcrdkrEndpoint:
    Description: EcrdkrEndpoint
    Value: !Ref EcrdkrEndpoint

  EcrapiEndpoint:
    Description: EcrapiEndpoint
    Value: !Ref EcrapiEndpoint

# ------------------------------------------------------------#
# Output VPC Endpoints using Gateway Type
# ------------------------------------------------------------#

  S3GatewayEndpoint:
    Description: S3GatewayEndpoint
    Value: !Ref S3GatewayEndpoint

4.5 ECSおよび関連リソースを作成

  • ECSクラスター、タスク定義を作成する
  • また、タスク実行時にログ出力先としてCloudWatch Logsのロググループもここで作成する
  • ECSのコンテナ設定でイメージ取得先を設定しているECRに格納されているイメージと同一になる様に留意すること
  • ECSのストレージとして、EFSを作成している

以下の情報を基にスタックを作成する。

パラメータ値:

項目 備考
SystemName プロジェクト名や利用目的等を入力する
EnvType デプロイする環境を選択する
検証、ステージング、本番の3点
Tagprefix 任意で入力するPrefix値を指定する
Owner 作業者、所有者、コスト管理用に入力する
ECSTaskCPUUnit ECSタスクを起動するためのCPUユニット値を選択する (任意の値)
ECSTaskMemory ECSタスクを起動するためのメモリ値を選択 (任意の値)
VPCID 作成済みのVPCのID
VPCCIDR 作成済みのVPCのCIDR
PrivateSubnet1 作成済みVPCのプライベートサブネット(AZは1a)
PrivateSubnet2 作成済みVPCのプライベートサブネット(AZは1c)
ECRRepositoryName1 作成済みのECRリポジトリ名
TaskRoleArn 作成したタスク用IAMロールのARN
ExecutionRoleArn 作成したタスク実行用IAMロールのARN

4.5.1 テンプレート情報

AWSTemplateFormatVersion: "2010-09-09"
Description: Create ECS and related resources such as EFS, CloudWatch Logs

# ------------------------------------------------------------#
#  Caution:
#  This template is for deploying resources in Tokyo region(ap-northeast-1).
# ------------------------------------------------------------#
#  Metadata:
#  This can privide details about the template.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html.
#  As Metadata Keys, AWS::CloudFormation::Interface can Defines the grouping and ordering of input parameters
#  when they are displayed in the AWS CloudFormation console.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-interface.html.
# ------------------------------------------------------------#

Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      -
        Parameters:
          - SystemName
          - EnvType
          - Tagprefix
          - Owner
          - ECSTaskCPUUnit
          - ECSTaskMemory
          - VPCID
          - VPCCIDR
          - PrivateSubnet1
          - PrivateSubnet2
          - ECRRepositoryName1
          - TaskRoleArn
          - ExecutionRoleArn

    ParameterLabels:
      SystemName:
        default: "SystemName: Type the Systemname"
      EnvType:
        default: "EnvType: Select the environment in which you deploy resources"
      Tagprefix:
        default: "Tagprefix: Type the Tagprefix which is logical unit name about this stack(e.g. Webserver,Monitoring,Logging)"
      Owner:
        default: "Owner: Type who owns these resources (e.g. project name or worker, whether this purpose is just verification or not)"
      ECSTaskCPUUnit:
        default: "ECSTaskCPUUnit: Select CPUUnit you use for ECSTask"
      ECSTaskMemory:
        default: "ECSTaskMemory: Select Memory you use for ECSTask"
      VPCID:
        default: "VPCID: Select the VPC ID"
      VPCCIDR:
        default: "VPCCIDR: This is for deciding Security Group Ingress CIDR for instance in VPC. Type VPC's CIDR such as NN.NN.NN.NN/NN based on RFC 1918."
      PrivateSubnet1:
        default: "PrivateSubnet1: Select your subnet's CIDR in AZ-A such as NN.NN.NN.NN/NN based on RFC 1918"
      PrivateSubnet2:
        default: "PrivateSubnet2: Select your subnet's CIDR in AZ-C such as NN.NN.NN.NN/NN based on RFC 1918"        
      ECRRepositoryName1:
        default: "ECRRepositoryName1: Type your Repository for shipping docker images"
      TaskRoleArn:
        default: "TaskRoleArn: Type ARN of IAM Role for task assumed by the containers running in the task" 
      ExecutionRoleArn:
        default: "ExecutionRoleArn: Type ARN of IAM Role for task executed by Fargate agents to make AWS API calls on your behalf"      

# ------------------------------------------------------------#
# Parameters
# This Can enable templates to input custom values each time you create or update a stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html.
# ------------------------------------------------------------#

Parameters:
  SystemName:
    Type: String
  EnvType:
    Type: String
    Default: "dev"
    AllowedValues:
      - dev
      - stg
      - prd
  Tagprefix:
    Type: String
  Owner:
    Type: String
  ECSTaskCPUUnit:
    AllowedValues: [ 256, 512, 1024, 2048, 4096  ]
    Type: String
    Default: "256"
  ECSTaskMemory:
    AllowedValues: [ 256, 512, 1024, 2048, 4096  ]
    Type: String
    Default: "512"
  VPCID:
    Type: AWS::EC2::VPC::Id
    ConstraintDescription: "Select the VPC ID"
  VPCCIDR:
    Type: String
    Default: "10.0.0.0/16"
    ConstraintDescription: "This is for deciding Security Group Ingress CIDR for instance in VPC. So please type VPC's CIDR such as NN.NN.NN.NN/NN based on RFC 1918."
  PrivateSubnet1:
    Type: AWS::EC2::Subnet::Id
    ConstraintDescription: "Select your subnet's CIDR in AZ-A such as NN.NN.NN.NN/NN based on RFC 1918"
  PrivateSubnet2:
    Type: AWS::EC2::Subnet::Id
    ConstraintDescription: "Select your subnet's CIDR in AZ-C such as NN.NN.NN.NN/NN based on RFC 1918"
  ECRRepositoryName1:
    Type: String      
    ConstraintDescription: "Type your Repository for shipping docker images"
  TaskRoleArn:
    Type: String
    ConstraintDescription: "Type ARN of IAM Role for task assumed by the containers running in the task" 
  ExecutionRoleArn:
    Type: String  
    ConstraintDescription: "Type ARN of IAM Role for task executed by Fargate agents to make AWS API calls on your behalf" 

# ------------------------------------------------------------#
# Resources
# This can declare the AWS resources that you want to include in the stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html.
# ------------------------------------------------------------#

Resources:

#---------------------------------
# Create Security Group for Mount target in EFS. 
#---------------------------------

  EFSSecurityGroup1:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-SG-ForEFS
      GroupDescription: Security Group for Mount target in EFS 
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 2049
          ToPort: 2049
          CidrIp: !Ref VPCCIDR
      VpcId: !Ref VPCID          
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-SG-ForEFS
        - Key: Owner
          Value: !Ref Owner

#---------------------------------
# Create EFS File system 
# BypassPolicyLockoutSafetyCheck is not used because this EFS does not set up File system Policy.
# For more information about BypassPolicyLockoutSafetyCheck, see https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-efs-filesystem.html#cfn-efs-filesystem-bypasspolicylockoutsafetycheck
# LifecyclePolicies is not used because this EFS does not use itself for infrequent access and basically uses EFS Standard class.
#---------------------------------

  EFSFileSystem1:
    Type: AWS::EFS::FileSystem
    Properties:
      BackupPolicy:
        Status: DISABLED
      Encrypted: true
      FileSystemTags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-EFS-FileSystem
        - Key: Owner
          Value: !Ref Owner
      PerformanceMode: generalPurpose
      ThroughputMode: bursting

#---------------------------------
# Create EFS Mount Target 
#---------------------------------

  EFSMountTarget1:
    Type: AWS::EFS::MountTarget
    Properties:
      FileSystemId: !Ref EFSFileSystem1
      SecurityGroups:
        - !Ref EFSSecurityGroup1
      SubnetId: !Ref PrivateSubnet1
    DependsOn: 
      - EFSFileSystem1  

  EFSMountTarget2:
    Type: AWS::EFS::MountTarget
    Properties:
      FileSystemId: !Ref EFSFileSystem1
      SecurityGroups:
        - !Ref EFSSecurityGroup1
      SubnetId: !Ref PrivateSubnet2
    DependsOn: 
      - EFSFileSystem1 

# ------------------------------------------------------------#
# Create ECS LogGroup
# ------------------------------------------------------------#
  ECSLogGroup1:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "/ecs/logs/${SystemName}-${EnvType}-${Tagprefix}-ECS-Cluster"
      RetentionInDays: 30

# ------------------------------------------------------------#
# Create ECS Cluster
# ------------------------------------------------------------#

  ECSCluster1:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ECS-Cluster
      ClusterSettings:
        - Name: containerInsights
          Value: enabled
      CapacityProviders:
        - FARGATE
      DefaultCapacityProviderStrategy:
        - CapacityProvider: FARGATE
          Base: 1
          Weight: 1        
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ECS-Cluster      
        - Key: Owner
          Value: !Ref Owner

# ------------------------------------------------------------#
#  ECS TaskDefinition
# ------------------------------------------------------------#

  ECSTaskDefinition1:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Cpu: !Ref ECSTaskCPUUnit
      ExecutionRoleArn: !Ref ExecutionRoleArn
      TaskRoleArn: !Ref TaskRoleArn
      Family: !Sub ${SystemName}-${EnvType}-${Tagprefix}-TaskFamily
      Memory: !Ref ECSTaskMemory
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      RuntimePlatform:
        CpuArchitecture: X86_64
        OperatingSystemFamily: LINUX
      Volumes:
        - Name: efs-mount-target-vol
          EFSVolumeConfiguration:
            FileSystemId: !Ref EFSFileSystem1
            RootDirectory: /
            TransitEncryption: ENABLED
            AuthorizationConfig:
              IAM: DISABLED
      ContainerDefinitions:
        - Name: !Sub ${SystemName}-${EnvType}-${Tagprefix}-Container
          Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRRepositoryName1}:latest
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref ECSLogGroup1
              awslogs-region: !Ref "AWS::Region"
              awslogs-stream-prefix: !Sub  ${SystemName}-${EnvType}-${Tagprefix}-container  
          PortMappings:
            - Protocol: tcp
              ContainerPort: 443
          MountPoints:
            - ContainerPath: /mounttarget
              ReadOnly: False
              SourceVolume: efs-mount-target-vol
      Tags:
        - Key: Owner
          Value: !Ref Owner
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-ECS-TaskDefinition
    DependsOn: 
      - EFSMountTarget1
      - EFSMountTarget2

# ------------------------------------------------------------#
# Outputs
# This can output each value specified as output section.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html.
# ------------------------------------------------------------#

Outputs:

  ECSCluster1:
    Description: ECSCluster1
    Value: !Ref ECSCluster1

  ECSTaskDefinition1:
    Description: ECSTaskDefinition1
    Value: !Ref ECSTaskDefinition1  

  ECSLogGroup1:
    Description: ECSLogGroup1
    Value: !Ref ECSLogGroup1

  EFSSecurityGroup1:
    Description: EFSSecurityGroup1 
    Value: !Ref EFSSecurityGroup1

  EFSFileSystem1:
    Description: EFSFileSystem1
    Value: !Ref EFSFileSystem1

  EFSMountTarget1:
    Description: EFSMountTarget1
    Value: !Ref EFSMountTarget1

  EFSMountTarget2:
    Description: EFSMountTarget2
    Value: !Ref EFSMountTarget2  

4.6 EventBridgeルール、関連リソース作成

  • ECSタスクにイベントを通知するEventBridgeのルールを作成する
  • またECSタスクにアクセス出来る様にするIAMロールもここで作成する
  • Fargateのバージョンをこのテンプレートで指定している
  • プラットフォームのバージョンは1.4である、必要に応じて適宜変更する

以下の情報を基にスタックを作成する

パラメータ値:

項目 備考
SystemName プロジェクト名や利用目的等を入力する
EnvType デプロイする環境を選択する
検証、ステージング、本番の3点
Tagprefix 任意で入力するPrefix値を指定する
Owner 作業者、所有者、コスト管理用に入力する
VPCID 作成済みのVPCのID
PrivateSubnet1 作成済みVPCのプライベートサブネット(AZは1a)
PrivateSubnet2 作成済みVPCのプライベートサブネット(AZは1c)
S3BucketName1 作成したS3バケット名
PrefixName1 イベント駆動する格納先のパス
例:バケット直下のeventディレクトリにtest.txtを格納する場合はevent/test.txt
ECSClusterName1 作成済みECSのクラスター名
TaskDefinitionName1 作成済みECSのタスク定義名

4.6.1 テンプレート情報

AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy an EventBridge Rule.
# ------------------------------------------------------------#
#  Caution:
#  This template is for deploying resources in Tokyo region(ap-northeast-1).
# ------------------------------------------------------------#
#  Metadata:
#  This can privide details about the template.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html.
#  As Metadata Keys, AWS::CloudFormation::Interface can Defines the grouping and ordering of input parameters
#  when they are displayed in the AWS CloudFormation console.
#  For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-interface.html.
# ------------------------------------------------------------#

Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      -
        Parameters:
          - SystemName
          - EnvType
          - Tagprefix
          - Owner
          - VPCID         
          - PrivateSubnet1
          - PrivateSubnet2           
          - S3BucketName1
          - PrefixName1
          - ECSClusterName1
          - TaskDefinitionName1        

    ParameterLabels:
      SystemName:
        default: "SystemName: Type the Systemname"
      EnvType:
        default: "EnvType: Select the environment in which you deploy resources"
      Tagprefix:
        default: "Tagprefix: Type the Tagprefix which is logical unit name about this stack(e.g. Webserver,Monitoring,Logging)"
      Owner:
        default: "Owner: Type who owns these resources (e.g. project name or worker, whether this purpose is just verification or not)"
      VPCID:
        default: "VPCID: Select the VPC ID"  
      PrivateSubnet1:
        default: "PrivateSubnet1: Select your subnet's CIDR in AZ-A such as NN.NN.NN.NN/NN based on RFC 1918"
      PrivateSubnet2:
        default: "PrivateSubnet2: Select your subnet's CIDR in AZ-C such as NN.NN.NN.NN/NN based on RFC 1918"               
      S3BucketName1:
        default: "S3BucketName1: Type your bucket name triggered to EventBridge(must not contain uppercase characters)"
      PrefixName1:
        default: "PrefixName1: Type prefix name for above bucket(Do not contain uppercase characters) such as XXX/XXX/XXX.csv"
      ECSClusterName1:
        default: "ECSClusterName1: Type name of ECSCluster for target"
      TaskDefinitionName1:
        default: "TaskDefinitionName1: Type name of task definition for target"        

# ------------------------------------------------------------#
# Parameters
# This Can enable templates to input custom values each time you create or update a stack.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html.
# ------------------------------------------------------------#

Parameters:
  SystemName:
    Type: String
  EnvType:
    Type: String
    Default: "dev"
    AllowedValues:
      - dev
      - stg
      - prd
  Tagprefix:
    Type: String
  Owner:
    Type: String
  VPCID:
    Type: AWS::EC2::VPC::Id
    ConstraintDescription: "Select the VPC ID"
  PrivateSubnet1:
    Type: AWS::EC2::Subnet::Id
    ConstraintDescription: "Select your subnet's CIDR in AZ-A such as NN.NN.NN.NN/NN based on RFC 1918"
  PrivateSubnet2:
    Type: AWS::EC2::Subnet::Id
    ConstraintDescription: "Select your subnet's CIDR in AZ-C such as NN.NN.NN.NN/NN based on RFC 1918"    
  S3BucketName1:
    Type: String
    ConstraintDescription: "Type your bucket name triggered to EventBridge(must not contain uppercase characters)"
  PrefixName1:
    Type: String
    ConstraintDescription: "Type prefix name for above bucket(Do not contain uppercase characters) such as XXX/XXX/XXX.csv"
  ECSClusterName1:
    Type: String
    Default: "XX-XXX-XX-ECS-Cluster"
    ConstraintDescription: "Type name of ECSClusterName for Target"    
  TaskDefinitionName1:
    Type: String
    Default: "XX-XXX-XX-TaskFamily"
    ConstraintDescription: "Type name of task definition for Target "        

Resources:

# ------------------------------------------------------------#
# Create Security Gruop Task execution 
# ------------------------------------------------------------#

  SecurityGroupForTaskexecution1:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-SG-Taskexecution1
      GroupDescription: Security Group for Task execution.
      VpcId: !Ref VPCID
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-SG-Taskexecution1
        - Key: Owner
          Value: !Ref Owner

# ------------------------------------------------------------#
# Create IAM Role for EventBridge Rule
# ------------------------------------------------------------#

  EventBridgeRuleRole1:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-EventBridge-Role
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          -
            Effect: "Allow"
            Principal:
              Service:
                - "events.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvType}-${Tagprefix}-EventBridge-Role
        - Key: Owner
          Value: !Ref Owner

# ------------------------------------------------------------#
# Create IAM Policy for EventBridge Rule
# ------------------------------------------------------------#

  EventBridgeRulePolicy1:
    Type: "AWS::IAM::ManagedPolicy"
    Properties:
      Description: Policy for EventBridge Rule   
      Path: /    
      ManagedPolicyName: !Sub ${SystemName}-${EnvType}-${Tagprefix}-EventBridge-Policy
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Action:
              - "ecs:RunTask"
            Resource:
              - !Sub arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:task-definition/${TaskDefinitionName1}:*
              - !Sub arn:aws:ecs:*:${AWS::AccountId}:task-definition/${TaskDefinitionName1}
            Condition:
              ArnLike:
                ecs:cluster: !Sub arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:cluster/${ECSClusterName1}
          - Effect: "Allow"
            Action:
              - "iam:PassRole"
            Resource:
              - "*"
            Condition:
              StringLike:
                iam:PassedToService: "ecs-tasks.amazonaws.com"
      Roles:
        - Ref: EventBridgeRuleRole1

# ------------------------------------------------------------#
# Create EventBridge Rule triggered by S3 bucket
# ------------------------------------------------------------#

  EventBridgeRule1:
    Type: 'AWS::Events::Rule'
    Properties:
      Name: !Sub ${SystemName}-${EnvType}-${Tagprefix}-EventBridge-Rule-S3-Object
      Description: "Events Rule triggered by S3 Object event to ECS task execution"
      EventBusName: "default"
      EventPattern:
        source:
          - aws.s3
        detail-type:
          - Object Created
        detail:
          bucket:
            name:
              - Ref: S3BucketName1
          object:
            key:
              - prefix: !Ref PrefixName1
      Targets:
        - Arn: !Sub arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:cluster/${ECSClusterName1}
          Id: RuletoTask1
          RoleArn: !GetAtt EventBridgeRuleRole1.Arn
          EcsParameters:
            EnableECSManagedTags: true
            EnableExecuteCommand: false
            LaunchType: FARGATE
            PlatformVersion: 1.4.0  
            NetworkConfiguration:
              AwsVpcConfiguration:
                AssignPublicIp: DISABLED
                SecurityGroups: 
                  - !Ref SecurityGroupForTaskexecution1
                Subnets: 
                  - !Ref PrivateSubnet1
                  - !Ref PrivateSubnet2    
            PropagateTags: TASK_DEFINITION
            TaskCount: 1
            TaskDefinitionArn: !Sub arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:task-definition/${TaskDefinitionName1}

# ------------------------------------------------------------#
# Outputs
# This can output each value specified as output section.
# For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html.
# ------------------------------------------------------------#

Outputs:

  SecurityGroupForTaskexecution1:
    Description: SecurityGroupForTaskexecution1
    Value: !Ref SecurityGroupForTaskexecution1  

  EventBridgeRuleRole1:
    Description: EventBridgeRuleRole1
    Value: !Ref EventBridgeRuleRole1   

  EventBridgeRulePolicy1:
    Description: EventBridgeRulePolicy1
    Value: !Ref EventBridgeRulePolicy1   

  EventBridgeRule1:
    Description: EventBridgeRule1
    Value: !Ref EventBridgeRule1

5. まとめ

  一式の環境を構築する為のテンプレートをご紹介しました。
環境構築には比較的時間を要しますし、役に立ちそうであれば、是非ともご利用ください。

また、これらのリソースを用いてECSタスクを起動する記事は別途書こうと思います。

この記事が誰かの役に立てば嬉しいです!Mitsuoでした!

Discussion

YutaKawanagaYutaKawanaga

同じようなことがやりたくて凄く参考になりました。
何より見やすかったです!