はじめに
最小権限の実現を考えてみるシリーズの3つ目の記事です。
今回は、生成AIを使ったアプローチで考えてみます。
Amazon Q Developer
普段はClaude Codeを愛用しているのですが、今回はVSCode + AmazonQ Developer(sonnet4.5)で試してみます!
また、AWSの公式ドキュメントを検索してくれる、aws-knowledge-mcp-serverも利用します。
生成手順
以下の手順で生成してみます。
- SAMテンプレート、スタック名を指定し、ポリシー生成
-
/reviewでセキュリティレビュー実施 - レビュー指摘対応
- 動作確認
やってみた!
では、さっそくやってみます。
1. SAMテンプレート、スタック名を指定し、ポリシー生成
以下のような簡単なプロンプトで試してみます。
/dev あなたはAWSセキュリティのエキスパートです。
以下のAWS SAMテンプレートとスタック名から、GitHub ActionsでSAMデプロイを実行するために必要な最小権限のIAMポリシーを生成してください。
また必要に応じて、WEB検索や、aws-knowledge-mcp-serverを活用すること。
##入力情報
###スタック名
* policy-generation-test
##SAMテンプレート
###
* template.yaml
MCP、WEB検索のツールは明示的に使ってもらうようにお願いしました。
お願いすると、SAMテンプレートの中身を確認後、MCPを使って作成してくれました。
生成内容は以下。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CloudFormationPermissions",
"Effect": "Allow",
"Action": [
"cloudformation:CreateChangeSet",
"cloudformation:DescribeChangeSet",
"cloudformation:ExecuteChangeSet",
"cloudformation:DescribeStacks",
"cloudformation:DescribeStackEvents",
"cloudformation:GetTemplateSummary",
"cloudformation:ListStackResources"
],
"Resource": [
"arn:aws:cloudformation:*:*:stack/policy-generation-test/*",
"arn:aws:cloudformation:*:aws:transform/Serverless-2016-10-31"
]
},
{
"Sid": "S3BucketPermissions",
"Effect": "Allow",
"Action": [
"s3:CreateBucket",
"s3:GetBucketLocation",
"s3:ListBucket",
"s3:GetBucketPolicy",
"s3:PutBucketPolicy",
"s3:GetBucketVersioning",
"s3:PutBucketVersioning",
"s3:GetEncryptionConfiguration",
"s3:PutEncryptionConfiguration"
],
"Resource": "arn:aws:s3:::aws-sam-cli-managed-default-samclisourcebucket-*"
},
{
"Sid": "S3ObjectPermissions",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::aws-sam-cli-managed-default-samclisourcebucket-*/*"
},
{
"Sid": "LambdaPermissions",
"Effect": "Allow",
"Action": [
"lambda:CreateFunction",
"lambda:DeleteFunction",
"lambda:GetFunction",
"lambda:GetFunctionConfiguration",
"lambda:UpdateFunctionCode",
"lambda:UpdateFunctionConfiguration",
"lambda:ListTags",
"lambda:TagResource",
"lambda:UntagResource",
"lambda:AddPermission",
"lambda:RemovePermission"
],
"Resource": "arn:aws:lambda:*:*:function:policy-generation-test-*"
},
{
"Sid": "IAMRolePermissions",
"Effect": "Allow",
"Action": [
"iam:CreateRole",
"iam:DeleteRole",
"iam:GetRole",
"iam:PassRole",
"iam:AttachRolePolicy",
"iam:DetachRolePolicy",
"iam:PutRolePolicy",
"iam:DeleteRolePolicy",
"iam:GetRolePolicy",
"iam:TagRole",
"iam:UntagRole"
],
"Resource": "arn:aws:iam::*:role/policy-generation-test-*"
},
{
"Sid": "APIGatewayPermissions",
"Effect": "Allow",
"Action": [
"apigateway:GET",
"apigateway:POST",
"apigateway:PUT",
"apigateway:PATCH",
"apigateway:DELETE"
],
"Resource": [
"arn:aws:apigateway:*::/restapis",
"arn:aws:apigateway:*::/restapis/*"
]
}
]
}
概ね網羅できてそう?
2. /reviewでセキュリティレビュー実施
Amazon Q Developerはコードレビュー機能があるので、活用してみます。
次に以下のプロンプトでレビューをさせてみます。
/review このIAMポリシーをレビューしてください。
特に以下の観点でチェック:
- 過剰な権限(最小権限の原則を守っているか)
- セキュリティリスク
- AWSベストプラクティス違反
また必要に応じて、WEB検索や、aws-knowledge-mcp-serverを活用すること。
結果、CODE ISSUESに以下のような結果が出力されました。
CODE ISSUESの作成有無、修正版のポリシーの作成有無など、毎回レビューの挙動はかなり変動します。
必要な挙動は明示的にプロンプトしないといけないみたいです。
3.レビュー指摘対応
レビュー指摘対応をしていきます。
まず、アカウントとリージョンは明示し、アスタリスクを直しておきます。
レビュー対応していきます。
リージョンは東京、アカウントは111122223333で固定して良い。
結果、高リスクの指摘分は一度に全て直してくれました。
修正完了しました。主な変更点:
リージョン固定: すべてのリソースを ap-northeast-1 に限定
アカウントID固定: 111122223333 に限定
IAM PassRole分離: 専用のステートメントに分離し、Condition句で lambda.amazonaws.com と apigateway.amazonaws.com のみに制限
s3:PutBucketPolicy削除: バケットポリシー変更権限を削除してデータ流出リスクを軽減
これにより、Critical/High の主要なセキュリティリスクが解消されました。
この後も何度か/reviewでレビューを行い、最終的にできたものは以下です。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CloudFormationPermissions",
"Effect": "Allow",
"Action": [
"cloudformation:CreateChangeSet",
"cloudformation:DescribeChangeSet",
"cloudformation:ExecuteChangeSet",
"cloudformation:DescribeStacks",
"cloudformation:DescribeStackEvents",
"cloudformation:GetTemplateSummary",
"cloudformation:ListStackResources"
],
"Resource": [
"arn:aws:cloudformation:ap-northeast-1:111122223333:stack/aws-sam-cli-managed-default/*",
"arn:aws:cloudformation:ap-northeast-1:111122223333:stack/policy-generation-test/*",
"arn:aws:cloudformation:ap-northeast-1:aws:transform/Serverless-2016-10-31"
]
},
{
"Sid": "S3BucketPermissions",
"Effect": "Allow",
"Action": [
"s3:CreateBucket",
"s3:GetBucketLocation",
"s3:ListBucket",
"s3:GetBucketPolicy",
"s3:GetBucketVersioning",
"s3:PutBucketVersioning",
"s3:GetEncryptionConfiguration",
"s3:PutEncryptionConfiguration"
],
"Resource": "arn:aws:s3:::aws-sam-cli-managed-default-samclisourcebucket-*"
},
{
"Sid": "S3ObjectPermissions",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::aws-sam-cli-managed-default-samclisourcebucket-*/*"
},
{
"Sid": "LambdaPermissions",
"Effect": "Allow",
"Action": [
"lambda:CreateFunction",
"lambda:DeleteFunction",
"lambda:GetFunction",
"lambda:GetFunctionConfiguration",
"lambda:UpdateFunctionCode",
"lambda:UpdateFunctionConfiguration",
"lambda:ListTags",
"lambda:TagResource",
"lambda:UntagResource",
"lambda:AddPermission",
"lambda:RemovePermission"
],
"Resource": "arn:aws:lambda:ap-northeast-1:111122223333:function:policy-generation-test-*"
},
{
"Sid": "IAMRolePermissions",
"Effect": "Allow",
"Action": [
"iam:CreateRole",
"iam:DeleteRole",
"iam:GetRole",
"iam:DetachRolePolicy",
"iam:PutRolePolicy",
"iam:DeleteRolePolicy",
"iam:GetRolePolicy",
"iam:TagRole",
"iam:UntagRole"
],
"Resource": "arn:aws:iam::111122223333:role/policy-generation-test-*"
},
{
"Sid": "IAMAttachRolePolicyPermissions",
"Effect": "Allow",
"Action": "iam:AttachRolePolicy",
"Resource": "arn:aws:iam::111122223333:role/policy-generation-test-*",
"Condition": {
"ArnLike": {
"iam:PolicyARN": [
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
"arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess",
"arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy",
"arn:aws:iam::111122223333:policy/policy-generation-test-*"
]
}
}
},
{
"Sid": "IAMPassRolePermissions",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::111122223333:role/policy-generation-test-*",
"Condition": {
"StringEquals": {
"iam:PassedToService": [
"lambda.amazonaws.com",
"apigateway.amazonaws.com"
]
}
}
},
{
"Sid": "APIGatewayPermissions",
"Effect": "Allow",
"Action": [
"apigateway:GET",
"apigateway:POST",
"apigateway:PUT",
"apigateway:PATCH",
"apigateway:DELETE"
],
"Resource": [
"arn:aws:apigateway:ap-northeast-1::/restapis",
"arn:aws:apigateway:ap-northeast-1::/restapis/*"
]
}
]
}
iam:AttachRolePolicy、iam:PassRoleに関してはその影響先のリソースをしっかりCondition句で絞ってくれていますね!
動作確認
動作確認していきます。
エラー対応したのは以下の1件だけであっさりと成功しました!
-
stack/aws-sam-cli-managed-default/*に対するcloudformation:CreateChangeSet付与
まとめ
生成AIを使うことで、少し最小権限の原則の考えが変わりました。
ユーザーが本当に必要なアクセス権のみを持つことだけを考えてましたが、それに加え、不要な権限昇格等のセキュリティの考慮も必要なのですね。
IAM Access Analyzer、バウンダリ、生成AIを使った検証をしていきましたが、やはりAIを活用するのが精度・スピード共に一番良いかもですね。

