本連載では、以下のイメージの構成にあるAWSリソース基盤自動化環境の構築を実践しています。
前回は、ECSタスク定義を行うCloudFormationテンプレートを実装しました。今回はタスク定義したコンテナで実行されるアプリケーションが使用するAWSリソースへのアクセスポリシーを定義し、前回作成したECSタスクのIAMロールへアタッチするCloudFormationテンプレートを作成します。 実際のソースコードは GitHub 上にコミットしています。 ソースコード中で本質的でない記述を一部省略しているので、実行コードを作成する場合は、必要に応じて適宜GitHub上のソースコードも参照してください。
Spring Cloud AWSのCloudFormationサポート でも述べた通り、実装してきたアプリケーションでは以下のようにAWSリソースを利用しています。
Backend ServiceアプリケーションおよびFrontend Webアプリケーションがそれぞれ参照するAWSリソースは以下の通りです。
AWSリソース | Frontend WebApp | Backend Service |
ALB | ○ | |
RDS | ○ | |
DynamoDB | ○ | |
ElastiCache | ○ | |
S3 | ○ | |
SQS | ○(キュー送信) | ○(キュー受信) |
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}
Backend ServiceアプリケーションにおけるECSタスクロール定義のテンプレートの記述の基本となるポイントは(A)〜(F)の通りです。
記述 | 説明 |
アプリケーションからCloudFormationClientを使ってスタック情報を取得するため、CloudFormationのアクセスポリシーを定義します。今回はAWSCloudFormationFullAccessポリシーを参考に全てのアクションを定義していますが、実際のアプリケーションでは、AWS CloudFormation のアクション、リソース、および条件キー を参考に必要最小限のアクションを定義するようにしてください。 | |
定義したポリシーを前回作成したECSタスクのIAMロールにアタッチします。ポリシーから逆にアタッチするロールをクロススタックリファレンス参照することで拡張性を向上させます。 | |
SQSへのアクセスポリシーを定義します。今回はAmazonSQSFullAccessポリシーを参考に全てのアクションを定義していますが、実際のアプリケーションでは、Amazon SQS のアクション、リソース、および条件キー を参考に必要最小限のアクションを定義するようにしてください。 | |
DynamoDBへのアクセスポリシーを定義します。今回はAmazonDynamoDBFullAccessポリシーを参考に定義していますが、実際のアプリケーションでは、Amazon DynamoDB のアクション、リソース、および条件キー および Amazon DynamoDB Accelerator (DAX) のアクション、リソース、および条件キー を参考に必要最小限のアクションを定義するようにしてください。 | |
RDSへのアクセスポリシーを定義します。今回はAmazonRDSFullAccessポリシーを参考に定義していますが、実際のアプリケーションでは、 Amazon RDS のアクション、リソース、および条件キー を参考に必要最小限のアクションを定義するようにしてください。 | |
Systems Manager Parameters Storeへのアクセスポリシーを定義します。今回はAmazonSSMFullAccessポリシーを参考に定義していますが、実際のアプリケーションでは、 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}
Frontend WebアプリケーションにおけるECSタスクロール定義のテンプレートの記述の基本となるポイントは(A)〜(G)の通りです。
記述 | 説明 |
アプリケーションからCloudFormationClientを使ってスタック情報を取得するため、CloudFormationのアクセスポリシーを定義します。今回はAWSCloudFormationFullAccessポリシーを参考に全てのアクションを定義していますが、実際のアプリケーションでは、AWS CloudFormation のアクション、リソース、および条件キー を参考に必要最小限のアクションを定義するようにしてください。 | |
定義したポリシーを前回作成したECSタスクのIAMロールにアタッチします。ポリシーから逆にアタッチするロールをクロススタックリファンレンス参照することで拡張性を向上させます。 | |
S3へのアクセスポリシーを定義します。今回はAmazonS3FullAccessポリシーを参考に全てのアクションを定義していますが、実際のアプリケーションでは、Amazon S3 のアクション、リソース、および条件キー を参考に必要最小限のアクションを定義するようにしてください。 | |
S3へのアクセスを ref:section-cloudformation-s3-sample-label で構築したバケットのARNに対し、クロススタックリファレンスで取得した値とワイルドカードを文字列結合しています。 | |
SQSへのアクセスポリシーを定義します。今回はAmazonSQSFullAccessポリシーを参考に全てのアクションを定義していますが、実際のアプリケーションでは、Amazon SQS のアクション、リソース、および条件キー を参考に必要最小限のアクションを定義するようにしてください。 | |
ElastiCacheへのアクセスポリシーを定義します。今回はAmazonElastiCacheFullAccessポリシーを参考に定義していますが、実際のアプリケーションでは、Amazon ElastiCache のアクション、リソース、および条件キー を参考に必要最小限のアクションを定義するようにしてください。 | |
Systems Manager Parameters Storeへのアクセスポリシーを定義します。今回はAmazonSSMFullAccessポリシーを参考に定義していますが、 実際のアプリケーションでは、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ロールにアタッチされます。
今回はECSタスクのIAMロールにアタッチするポリシーを構築するCloudFormationテンプレートを実装しました。次回は、ECSサービスを構築するCloudFormationテンプレートを作成する手順を紹介します。
川畑 光平(KAWABATA Kohei) - NTTデータ 課長代理
金融機関システム業務アプリケーション開発・システム基盤担当を経て、現在はソフトウェア開発自動化関連の研究開発・推進に従事。
Red Hat Certified Engineer、Pivotal Certified Spring Professional、AWS Certified Solutions Architect Professional等の資格を持ち、アプリケーション基盤・クラウドなど様々な開発プロジェクト支援にも携わる。