ECSタスクロール定義の構築

【連載】

AWSで実践! 基盤構築・デプロイ自動化

【第38回】ECSタスクロール定義の構築

[2020/07/22 08:00]川畑 光平 ブックマーク ブックマーク

本連載では、以下のイメージの構成にあるAWSリソース基盤自動化環境の構築を実践しています。

本連載で構築していく基盤自動化環境のイメージ

前回は、ECSタスク定義を行うCloudFormationテンプレートを実装しました。今回はタスク定義したコンテナで実行されるアプリケーションが使用するAWSリソースへのアクセスポリシーを定義し、前回作成したECSタスクのIAMロールへアタッチするCloudFormationテンプレートを作成します。

なお、実際のソースコードはGitHub上にコミットしています。以降のソースコードでは本質的でない記述を一部省略しているので、実行コードを作成する場合は、必要に応じて適宜GitHub上のソースコードも参照してください。

ECSタスクロール定義スタック構築テンプレート

第34回でも述べましたが、本連載でこれまで実装してきたアプリケーションでは以下のようにAWSリソースを利用しています。

  • ALBを経由したバックエンドサービスの呼び出し(ALBのDNSをRestTemplateに指定)
  • エンドポイントを指定したRDSアクセス
  • サービスエンドポイントを指定したDynamoDBアクセス
  • エンドポイントを指定したElastiCacheアクセス
  • S3バケットへのアクセス
  • サービスエンドポイントを指定したSQSへのキュー送信、ポーリングによる取得

Backend Serviceアプリケーションと、Frontend Webアプリケーションがそれぞれ参照するAWSリソースは以下の通りです。

ALB RDS DynamoDB ElastiCache S3 SQS
Backend Service ○(キュー受信)
Frontend WebApp ○(キュー送信)

ECSタスクのIAMロール定義は前回作成していますが、Backend Service、Frontend Webアプリケーションそれぞれで使用するAWSリソースのアクセスポリシーを割り当てねばなりません。アクセスするリソースはアプリケーションごとに異なり、変更されることも多いので、ECSタスク定義とは別に各サービスごとにテンプレートを分けて実装しておくことにします。

また、ALBのようにHTTPリクエスト送信でアクセスするため、リソース定義が不要なものもありますが、一方、CloudFormationやSystem Manager Parameter Storeなど、今回テンプレートの実装のなかでアクセスするサービスも加わります。

アクセスポリシーをCloudFormationで構築する場合、リソースタイプに「AWS::IAM::Policy」を定義する必要がありますが、各AWSリソースごとに定義する内容は異なります。プロパティとして設定可能な属性は、上記リンク先の通りですが、加えて、ポリシー定義を商用環境、ステージング環境、開発環境という3つのパターンに分けて作成するようにします。

まず、RDS、DynamoDB、SQSへアクセスするBackend Serviceアプリケーションに対するアクセスポリシーを定義したECSタスクロールテンプレートのサンプルは以下の通りです。

AWSTemplateFormatVersion: '2010-09-09'

// omit

Parameters:
  // omit
  EnvType:
    Description: Which environments to deploy your service.
    Type: String
    AllowedValues: ["Dev", "Staging", "Production"]
    Default: Dev

Resources:
  CloudFormationAccessPolicy:                                                             #(A)
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub Mynavi-Sample-CloudFormationAccessPolicy-backend-${EnvType}
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
              - "cloudformation:*"
            Resource: "*"
      Roles:
        - Fn::ImportValue: !Sub ${VPCName}-BackendEcsTaskRole-${EnvType}                  #(B)

  SQSAccessPolicy:                                                                        #(C)
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub Mynavi-Sample-SQSAccessPolicy-backend-${EnvType}
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
              - "sqs:*"
            Resource: "*"
      Roles:
        - Fn::ImportValue: !Sub ${VPCName}-BackendEcsTaskRole-${EnvType}

  DynamoDBAccessPolicy:                                                                   #(D)
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub Mynavi-Sample-DynamoDBAccessPolicy-backend-${EnvType}
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
              - "dynamodb:*"
              - "dax:*"
              - "application-autoscaling:DeleteScalingPolicy"
              - "application-autoscaling:DeregisterScalableTarget"
              - "application-autoscaling:DescribeScalableTargets"
              - "application-autoscaling:DescribeScalingActivities"
              - "application-autoscaling:DescribeScalingPolicies"
              - "application-autoscaling:PutScalingPolicy"
              - "application-autoscaling:RegisterScalableTarget"
              - "cloudwatch:DeleteAlarms"
              - "cloudwatch:DescribeAlarmHistory"
              - "cloudwatch:DescribeAlarms"
              - "cloudwatch:DescribeAlarmsForMetric"
              - "cloudwatch:GetMetricStatistics"
              - "cloudwatch:ListMetrics"
              - "cloudwatch:PutMetricAlarm"
              - "datapipeline:ActivatePipeline"
              - "datapipeline:CreatePipeline"
              - "datapipeline:DeletePipeline"
              - "datapipeline:DescribeObjects"
              - "datapipeline:DescribePipelines"
              - "datapipeline:GetPipelineDefinition"
              - "datapipeline:ListPipelines"
              - "datapipeline:PutPipelineDefinition"
              - "datapipeline:QueryObjects"
              - "ec2:DescribeVpcs"
              - "ec2:DescribeSubnets"
              - "ec2:DescribeSecurityGroups"
              - "iam:GetRole"
              - "iam:ListRoles"
              - "kms:DescribeKey"
              - "kms:ListAliases"
              - "sns:CreateTopic"
              - "sns:DeleteTopic"
              - "sns:ListSubscriptions"
              - "sns:ListSubscriptionsByTopic"
              - "sns:ListTopics"
              - "sns:Subscribe"
              - "sns:Unsubscribe"
              - "sns:SetTopicAttributes"
              - "lambda:CreateFunction"
              - "lambda:ListFunctions"
              - "lambda:ListEventSourceMappings"
              - "lambda:CreateEventSourceMapping"
              - "lambda:DeleteEventSourceMapping"
              - "lambda:GetFunctionConfiguration"
              - "lambda:DeleteFunction"
              - "resource-groups:ListGroups"
              - "resource-groups:ListGroupResources"
              - "resource-groups:GetGroup"
              - "resource-groups:GetGroupQuery"
              - "resource-groups:DeleteGroup"
              - "resource-groups:CreateGroup"
              - "tag:GetResources"
            Resource: "*"
      Roles:
        - Fn::ImportValue: !Sub ${VPCName}-BackendEcsTaskRole-${EnvType}

  RDSAccessPolicy:                                                                         #(E)
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub Mynavi-Sample-RDSAccessPolicy-backend-${EnvType}
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
              - "rds:*"
              - "application-autoscaling:DeleteScalingPolicy"
              - "application-autoscaling:DeregisterScalableTarget"
              - "application-autoscaling:DescribeScalableTargets"
              - "application-autoscaling:DescribeScalingActivities"
              - "application-autoscaling:DescribeScalingPolicies"
              - "application-autoscaling:PutScalingPolicy"
              - "application-autoscaling:RegisterScalableTarget"
              - "cloudwatch:DescribeAlarms"
              - "cloudwatch:GetMetricStatistics"
              - "cloudwatch:PutMetricAlarm"
              - "cloudwatch:DeleteAlarms"
              - "ec2:DescribeAccountAttributes"
              - "ec2:DescribeAvailabilityZones"
              - "ec2:DescribeInternetGateways"
              - "ec2:DescribeSecurityGroups"
              - "ec2:DescribeSubnets"
              - "ec2:DescribeVpcAttribute"
              - "ec2:DescribeVpcs"
              - "sns:ListSubscriptions"
              - "sns:ListTopics"
              - "sns:Publish"
              - "logs:DescribeLogStreams"
              - "logs:GetLogEvents"
            Resource: "*"
      Roles:
        - Fn::ImportValue: !Sub ${VPCName}-BackendEcsTaskRole-${EnvType}

  SSMAccessPolicy:                                                                         #(F)
        Statement:
          - Effect: Allow
            Action:
              - "cloudwatch:PutMetricData"
              - "ds:CreateComputer"
              - "ds:DescribeDirectories"
              - "ec2:DescribeInstanceStatus"
              - "logs:*"
              - "ssm:*"
              - "ec2messages:*"
            Resource: "*"
          - Effect: Allow
            Action:
              - "iam:CreateServiceLinkedRole"
            Resource: "arn:aws:iam::*:role/aws-service-role/ssm.amazonaws.com/AWSServiceRoleForAmazonSSM*"
            Condition:
              StringLike:
                iam:AWSServiceName : "ssm.amazonaws.com"
          - Effect: Allow
            Action:
              - "iam:DeleteServiceLinkedRole"
              - "iam:GetServiceLinkedRoleDeletionStatus"
            Resource: "arn:aws:iam::*:role/aws-service-role/ssm.amazonaws.com/AWSServiceRoleForAmazonSSM*"
          - Effect: Allow
            Action:
              - "ssmmessages:CreateControlChannel"
              - "ssmmessages:CreateDataChannel"
              - "ssmmessages:OpenControlChannel"
              - "ssmmessages:OpenDataChannel"
            Resource: "*"
      Roles:
        - Fn::ImportValue: !Sub ${VPCName}-BackendEcsTaskRole-${EnvType}

上記テンプレートの記述の基本となるポイントは、下表の通りです。

記述 説明
A アプリケーションからCloudFormationClientを使ってスタック情報を取得するため、CloudFormationのアクセスポリシーを定義します。今回はAWSCloudFormationFullAccessポリシーを参考に全てのアクションを定義していますが、実際のアプリケーションでは、AWS公式サイトの「AWS CloudFormationのアクション、リソース、および条件キー」を参考に必要最小限のアクションを定義するようにしてください
B 定義したポリシーを前回作成したECSタスクのIAMロールにアタッチします。ポリシーから逆にアタッチするロールをクロススタックリファレンス参照することで拡張性を向上させます
C SQSへのアクセスポリシーを定義します。今回はAmazonSQSFullAccessポリシーを参考に全てのアクションを定義していますが、実際のアプリケーションでは、AWS公式サイトの「Amazon SQSのアクション、リソース、および条件キー」を参考に必要最小限のアクションを定義するようにしてください
D DynamoDBへのアクセスポリシーを定義します。今回はAmazonDynamoDBFullAccessポリシーを参考に定義していますが、実際のアプリケーションでは、AWS公式サイトの「Amazon DynamoDB のアクション、リソース、および条件キー」と「Amazon DynamoDB Accelerator(DAX)のアクション、リソース、および条件キー」を参考に必要最小限のアクションを定義するようにしてください
E RDSへのアクセスポリシーを定義します。今回はAmazonRDSFullAccessポリシーを参考に定義していますが、実際のアプリケーションでは、AWS公式サイトの「Amazon RDSのアクション、リソース、および条件キー」を参考に必要最小限のアクションを定義するようにしてください
F Systems Manager Parameters Storeへのアクセスポリシーを定義します。今回はAmazonSSMFullAccessポリシーを参考に定義していますが、実際のアプリケーションでは、AWS公式サイトの「「AWS Systems Manager のアクション、リソース、および条件キー」を参考に必要最小限のアクションを定義するようにしてください

作成したテンプレートに対して、以下のようにスタック名とテンプレートパスを変更してヘルパースクリプトを実行します。

#!/usr/bin/env bash

stack_name="mynavi-sample-ecs-taskrole-backend"
template_path="sample-ecs-taskrole-backend-cfn.yml"

parameters="EnvType=Dev"

aws cloudformation deploy --stack-name ${stack_name} --template-file ${template_path} --parameter-overrides ${parameters} --capabilities CAPABILITY_IAM

実行が正常に終了すると、アクセスポリシーが作成され、ECSタスクのIAMロールにアタッチされます。

続いて、ElastiCache、S3、SQSへアクセスするFrontend Webアプリケーションに対するアクセスポリシーを定義したCloudFormationテンプレートは以下の通りです。

AWSTemplateFormatVersion: '2010-09-09'

// omit

Parameters:
  EnvType:
    Description: Which environments to deploy your service.
    Type: String
    AllowedValues: ["Dev", "Staging", "Production"]
    Default: Dev

Resources:
  CloudFormationAccessPolicy:                                                          #(A)
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub Mynavi-Sample-CloudFormationAccessPolicy-frontend-${EnvType}
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
              - "cloudformation:*"
            Resource: "*"
      Roles:
        - Fn::ImportValue: !Sub ${VPCName}-FrontendEcsTaskRole-${EnvType}              #(B)

  S3AccessPolicy:                                                                      #(C)
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub Mynavi-Sample-S3AccessPolicy-frontend-${EnvType}
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
              - "s3:*"
            Resource:
              - Fn::Join:
                  - ""
                  - - Fn::ImportValue: !Sub MynaviSampleS3Bucket-Arn-${EnvType}        #(D)
                    - "/*"
      Roles:
        - Fn::ImportValue: !Sub ${VPCName}-FrontendEcsTaskRole-${EnvType}

  SQSAccessPolicy:                                                                     #(E)
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub Mynavi-Sample-SQSAccessPolicy-frontend-${EnvType}
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
              - "sqs:*"
            Resource: "*"
      Roles:
        - Fn::ImportValue: !Sub ${VPCName}-FrontendEcsTaskRole-${EnvType}

  ElastiCacheAccessPolicy:                                                             #(F)
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub Mynavi-Sample-ElastiCacheAccessPolicy-frontend-${EnvType}
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
              - "elasticache:*"
            Resource: "*"
          - Effect: Allow
            Action:
              - "iam:CreateServiceLinkedRole"
            Resource: "*arn:aws:iam::*:role/aws-service-role/elasticache.amazonaws.com/AWSServiceRoleForElastiCache"
            Condition:
              StringLike:
                iam:AWSServiceName : "elasticache.amazonaws.com"
      Roles:
        - Fn::ImportValue: !Sub ${VPCName}-FrontendEcsTaskRole-${EnvType}

  SSMAccessPolicy:                                                                      #(G)
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub Mynavi-Sample-SSMAccessPolicy-frontend-${EnvType}
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
              - "cloudwatch:PutMetricData"
              - "ds:CreateComputer"
              - "ds:DescribeDirectories"
              - "ec2:DescribeInstanceStatus"
              - "logs:*"
              - "ssm:*"
              - "ec2messages:*"
            Resource: "*"
          - Effect: Allow
            Action:
              - "iam:CreateServiceLinkedRole"
            Resource: "arn:aws:iam::*:role/aws-service-role/ssm.amazonaws.com/AWSServiceRoleForAmazonSSM*"
            Condition:
              StringLike:
                iam:AWSServiceName : "ssm.amazonaws.com"
          - Effect: Allow
            Action:
              - "iam:DeleteServiceLinkedRole"
              - "iam:GetServiceLinkedRoleDeletionStatus"
            Resource: "arn:aws:iam::*:role/aws-service-role/ssm.amazonaws.com/AWSServiceRoleForAmazonSSM*"
          - Effect: Allow
            Action:
              - "ssmmessages:CreateControlChannel"
              - "ssmmessages:CreateDataChannel"
              - "ssmmessages:OpenControlChannel"
              - "ssmmessages:OpenDataChannel"
            Resource: "*"
      Roles:
        - Fn::ImportValue: !Sub ${VPCName}-FrontendEcsTaskRole-${EnvType}

上記テンプレート記述の基本となるポイントは、下表の通りです。

記述 説明
A アプリケーションからCloudFormationClientを使ってスタック情報を取得するため、CloudFormationのアクセスポリシーを定義します。今回はAWSCloudFormationFullAccessポリシーを参考に全てのアクションを定義していますが、実際のアプリケーションでは、AWS公式サイトの「AWS CloudFormation のアクション、リソース、および条件キー」を参考に必要最小限のアクションを定義するようにしてください
B 定義したポリシーを前回作成したECSタスクのIAMロールにアタッチします。ポリシーから逆にアタッチするロールをクロススタックリファンレンス参照することで拡張性を向上させます
C S3へのアクセスポリシーを定義します。今回はAmazonS3FullAccessポリシーを参考に全てのアクションを定義していますが、実際のアプリケーションでは、AWS公式サイトの「Amazon S3 のアクション、リソース、および条件キー」を参考に必要最小限のアクションを定義するようにしてください
D S3へのアクセスを「ref:section-cloudformation-s3-sample-label」で構築したバケットのARN(AmazonResourceName) に対し、クロススタックリファレンスで取得した値とワイルドカードを文字列結合しています
E SQSへのアクセスポリシーを定義します。今回はAmazonSQSFullAccessポリシーを参考に全てのアクションを定義していますが、実際のアプリケーションでは、AWS公式サイトの「Amazon SQS のアクション、リソース、および条件キー」を参考に必要最小限のアクションを定義するようにしてください
F ElastiCacheへのアクセスポリシーを定義します。今回はAmazonElastiCacheFullAccessポリシーを参考に定義していますが、実際のアプリケーションでは、AWS公式サイトの「Amazon ElastiCacheのアクション、リソース、および条件キー」を参考に必要最小限のアクションを定義するようにしてください
G Systems Manager Parameters Storeへのアクセスポリシーを定義します。今回はAmazonSSMFullAccessポリシーを参考に定義していますが、 実際のアプリケーションでは、AWS公式サイトの「AWS Systems Manager のアクション、リソース、および条件キー」を参考に必要最小限のアクションを定義するようにしてください

作成したテンプレートに対して、以下のように、スタック名とテンプレートパスを変更してヘルパースクリプトを実行します。

#!/usr/bin/env bash

stack_name="mynavi-sample-ecs-taskrole-frontend"
template_path="sample-ecs-taskrole-frontend-cfn.yml"

parameters="EnvType=Dev"

aws cloudformation deploy --stack-name ${stack_name} --template-file ${template_path} --parameter-overrides ${parameters} --capabilities CAPABILITY_IAM

実行が正常に終了すると、アクセスポリシーが作成され、ECSタスクのIAMロールにアタッチされます。

ガートナー ジャパン リサーチ部門 ITインフラストラクチャ&セキュリティのリサーチ ディレクター、池田武史氏

以上、今回はECSタスクのIAMロールにアタッチするポリシーを構築するCloudFormationテンプレートを実装しました。次回は、ECSサービスを構築するCloudFormationテンプレートを作成する手順を紹介します。

著者紹介


川畑 光平(KAWABATA Kohei) - NTTデータ

金融機関システム業務アプリケーション開発・システム基盤担当、ソフトウェア開発自動化関連の研究開発を経て、デジタル技術関連の研究開発・推進に従事。

Red Hat Certified Engineer、Pivotal Certified Spring Professional、AWS Certified Solutions Architect Professional等の資格を持ち、アプリケーション基盤・クラウドなど様々な開発プロジェクト支援にも携わる。AWS Top Engineers & Ambassadors選出。

本連載の内容に対するご意見・ご質問は Facebook まで。

※ 本記事は掲載時点の情報であり、最新のものとは異なる場合がございます。予めご了承ください。

一覧はこちら

連載目次

関連リンク

この記事に興味を持ったら"いいね!"を Click
Facebook で IT Search+ の人気記事をお届けします
注目の特集/連載
[解説動画] Googleアナリティクス分析&活用講座 - Webサイト改善の正しい考え方
[解説動画] 個人の業務効率化術 - 短時間集中はこうして作る
ミッションステートメント
教えてカナコさん! これならわかるAI入門
AWSではじめる機械学習 ~サービスを知り、実装を学ぶ~
対話システムをつくろう! Python超入門
Kubernetes入門
SAFeでつくる「DXに強い組織」~企業の課題を解決する13のアプローチ~
PowerShell Core入門
AWSで作るマイクロサービス
マイナビニュース スペシャルセミナー 講演レポート/当日講演資料 まとめ
セキュリティアワード特設ページ

一覧はこちら

今注目のIT用語の意味を事典でチェック!

一覧はこちら

会員登録(無料)

ページの先頭に戻る