AWS SAM (Serverless Application Model) を使用すると、AWS Lambda などを使用したサーバーレスアプリケーションのテストやデプロイで、様々な便利な機能を使用できます。
今回は、この AWS SAM を使用するために必要な IAM ポリシーについて考えてみます。
どのような IAM ポリシーが必要でしょうか?
もちろん、構築するアプリケーション内容に依存するのですが、AWS のドキュメントにヒントが記載されています。
このドキュメントでは、非常にシンプルな Hello World レベルのアプリケーションだと、以下のポリシーがあれば十分だと記載されています。
- AWSCloudFormationFullAccess
- IAMFullAccess
- AWSLambda_FullAccess
- AmazonAPIGatewayAdministrator
- AmazonS3FullAccess
- AmazonEC2ContainerRegistryFullAccess
ここでいう、Hello World のアプリケーションというのは、hello world という簡単なメッセージを返す Lambda 関数を、Amazon API Gateway のREST API から呼び出せるようにしているアプリケーションの事です。
さらに、このドキュメントには、Hello World アプリケーションに対して、きめ細かくポリシーを指定した場合の例も掲載されています。
ドキュメントの例
{ "Version": "2012-10-17", "Statement": [ { "Sid": "CloudFormationTemplate", "Effect": "Allow", "Action": [ "cloudformation:CreateChangeSet" ], "Resource": [ "arn:aws:cloudformation:*:aws:transform/Serverless-2016-10-31" ] }, { "Sid": "CloudFormationStack", "Effect": "Allow", "Action": [ "cloudformation:CreateChangeSet", "cloudformation:CreateStack", "cloudformation:DeleteStack", "cloudformation:DescribeChangeSet", "cloudformation:DescribeStackEvents", "cloudformation:DescribeStacks", "cloudformation:ExecuteChangeSet", "cloudformation:GetTemplateSummary", "cloudformation:ListStackResources", "cloudformation:UpdateStack" ], "Resource": [ "arn:aws:cloudformation:*:111122223333:stack/*" ] }, { "Sid": "S3", "Effect": "Allow", "Action": [ "s3:CreateBucket", "s3:GetObject", "s3:PutObject" ], "Resource": [ "arn:aws:s3:::*/*" ] }, { "Sid": "ECRRepository", "Effect": "Allow", "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:BatchGetImage", "ecr:CompleteLayerUpload", "ecr:CreateRepository", "ecr:DeleteRepository", "ecr:DescribeImages", "ecr:DescribeRepositories", "ecr:GetDownloadUrlForLayer", "ecr:GetRepositoryPolicy", "ecr:InitiateLayerUpload", "ecr:ListImages", "ecr:PutImage", "ecr:SetRepositoryPolicy", "ecr:UploadLayerPart" ], "Resource": [ "arn:aws:ecr:*:111122223333:repository/*" ] }, { "Sid": "ECRAuthToken", "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken" ], "Resource": [ "*" ] }, { "Sid": "Lambda", "Effect": "Allow", "Action": [ "lambda:AddPermission", "lambda:CreateFunction", "lambda:DeleteFunction", "lambda:GetFunction", "lambda:GetFunctionConfiguration", "lambda:ListTags", "lambda:RemovePermission", "lambda:TagResource", "lambda:UntagResource", "lambda:UpdateFunctionCode", "lambda:UpdateFunctionConfiguration" ], "Resource": [ "arn:aws:lambda:*:111122223333:function:*" ] }, { "Sid": "IAM", "Effect": "Allow", "Action": [ "iam:CreateRole", "iam:AttachRolePolicy", "iam:DeleteRole", "iam:DetachRolePolicy", "iam:GetRole", "iam:TagRole" ], "Resource": [ "arn:aws:iam::111122223333:role/*" ] }, { "Sid": "IAMPassRole", "Effect": "Allow", "Action": "iam:PassRole", "Resource": "*", "Condition": { "StringEquals": { "iam:PassedToService": "lambda.amazonaws.com" } } }, { "Sid": "APIGateway", "Effect": "Allow", "Action": [ "apigateway:DELETE", "apigateway:GET", "apigateway:PATCH", "apigateway:POST", "apigateway:PUT" ], "Resource": [ "arn:aws:apigateway:*::*" ] } ] }
ただし、結論からすると、このドキュメントの例のポリシーは、AWS SAM で Hello World レベルのアプリケーションを作成、更新、削除するには不十分です
例えば、AWS SAM で作成したアプリケーションは、 sam delete
というコマンドで削除できますが、ドキュメントの例のポリシーでは、SAM のリソースを格納している S3 バケットからのオブジェクトの削除権限と、CloudFormation の操作である cloudformation:GetTemplate
を実行する権限が足りません。
また、この AWS SAM アプリケーションを sam deploy --guided
でデプロイする場合にも追加の考慮が必要です。
もし、sam deploy --guided
の実行が、そのリージョンにおいて初めての場合、自動的に CloudFormation で aws-sam-cli-managed-default という名前のスタックが構築され、 SAM 用の S3 バケットが作成されますが、ドキュメントの例だと、その作成権限も足りません。
よって、(ドキュメントの冒頭にも記載はありましたが) S3の権限においては AmazonS3FullAccessポリシー またはそれに相当する権限を付与しておかないと、SAM アプリケーションのデプロイや削除が不意に失敗する可能性があります。
次に示すポリシーは、ドキュメントの例を変更したものです。
S3 の権限の範囲を広げており、cloudformation:GetTemplate
の操作も許可するよう追加しています。
(あくまで一つの例ですが、少なくとも Hello World レベルのアプリケーションの作成、削除は可能です。sam deploy --guided をリージョンで初めて実行する場合でも、権限不足でエラーにはなりません。)
{ "Version": "2012-10-17", "Statement": [ { "Sid": "CloudFormationTemplate", "Effect": "Allow", "Action": [ "cloudformation:CreateChangeSet" ], "Resource": [ "arn:aws:cloudformation:*:aws:transform/Serverless-2016-10-31" ] }, { "Sid": "CloudFormationStack", "Effect": "Allow", "Action": [ "cloudformation:CreateChangeSet", "cloudformation:CreateStack", "cloudformation:DeleteStack", "cloudformation:DescribeChangeSet", "cloudformation:DescribeStackEvents", "cloudformation:DescribeStacks", "cloudformation:ExecuteChangeSet", "cloudformation:GetTemplateSummary", "cloudformation:GetTemplate", "cloudformation:ListStackResources", "cloudformation:UpdateStack" ], "Resource": [ "arn:aws:cloudformation:*:111122223333:stack/*" ] }, { "Sid": "S3", "Effect": "Allow", "Action": [ "s3:*" ], "Resource": [ "*" ] }, { "Sid": "ECRRepository", "Effect": "Allow", "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:BatchGetImage", "ecr:CompleteLayerUpload", "ecr:CreateRepository", "ecr:DeleteRepository", "ecr:DescribeImages", "ecr:DescribeRepositories", "ecr:GetDownloadUrlForLayer", "ecr:GetRepositoryPolicy", "ecr:InitiateLayerUpload", "ecr:ListImages", "ecr:PutImage", "ecr:SetRepositoryPolicy", "ecr:UploadLayerPart" ], "Resource": [ "arn:aws:ecr:*:111122223333:repository/*" ] }, { "Sid": "ECRAuthToken", "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken" ], "Resource": [ "*" ] }, { "Sid": "Lambda", "Effect": "Allow", "Action": [ "lambda:AddPermission", "lambda:CreateFunction", "lambda:DeleteFunction", "lambda:GetFunction", "lambda:GetFunctionConfiguration", "lambda:ListTags", "lambda:RemovePermission", "lambda:TagResource", "lambda:UntagResource", "lambda:UpdateFunctionCode", "lambda:UpdateFunctionConfiguration" ], "Resource": [ "arn:aws:lambda:*:111122223333:function:*" ] }, { "Sid": "IAM", "Effect": "Allow", "Action": [ "iam:CreateRole", "iam:AttachRolePolicy", "iam:DeleteRole", "iam:DetachRolePolicy", "iam:GetRole", "iam:TagRole" ], "Resource": [ "arn:aws:iam::111122223333:role/*" ] }, { "Sid": "IAMPassRole", "Effect": "Allow", "Action": "iam:PassRole", "Resource": "*", "Condition": { "StringEquals": { "iam:PassedToService": "lambda.amazonaws.com" } } }, { "Sid": "APIGateway", "Effect": "Allow", "Action": [ "apigateway:DELETE", "apigateway:GET", "apigateway:PATCH", "apigateway:POST", "apigateway:PUT" ], "Resource": [ "arn:aws:apigateway:*::*" ] } ] }
例えば、すでにそのリージョンに sam deploy --guided
によって SAM 用の S3 バケットが作成されている前提であれば、ポリシーで対象にしているリソースをそのバケットに限定することもできますので、使用する状況により、S3 バケットのポリシーで許可する範囲は絞りこむことをお薦めします。
どなたかの参考になれば幸いです!