AWS EmulatorでIAMの権限がAWSどおりに判定されない例

​​AWS Emulator​AWS CLI,IAM,テスト

AWS Emulator では、IAM の権限がない操作でも通ることがあります。ローカルのテストや CI で「権限が足りないと AccessDenied になる」ことを確かめようとしても、エミュレーターの結果は当てになりません。権限のないユーザーとすべてを拒否するポリシーを作って操作を呼び、どの操作が通り、どの操作が拒否されたかを出力のまま載せます。

補足

検証環境は Ubuntu 24.04.5(x86_64)、AWS Emulator 1.0.353(2026年11月14日リリース、Debian パッケージ)、AWS CLI 2.40.3 です。AWS のアカウントは使わず、リクエストはすべて手元の AWS Emulator に送りました。本物の AWS での結果は試しておらず、IAM の公式ドキュメントをもとに書いています。試したのは AWS CLI から呼べる一部の操作だけで、IAM ロールと STS の AssumeRole、権限の境界(permissions boundary)、KMS のキーポリシーは試していません。

公式ドキュメントに書かれている制限

AWS Emulator の紹介ページには、制限の1つ目として「IAM のポリシーとリソースベースのポリシーを、AWS と同じようには評価しない」と書かれています。セキュリティのテストには使わないように、とも書かれています。

セキュリティのページはもう少し詳しく、次のように説明しています。

  • エミュレーターの中で作った IAM ユーザーやロールについて、ポリシーを評価するサービスもあるが、AWS と同じ評価ではない
  • エミュレーター自身のキーで署名したリクエストは、拒否しない
  • AWS なら拒否するリクエストが通ることも、AWS なら通るリクエストが失敗することもある

ここからは、この説明を実際の操作で確かめます。

準備:エミュレーターを起動して、AWS CLI の接続先にする

入れ方は公式ガイドの Linux 向けの手順のとおりで、Debian パッケージの署名を gpg で確かめてから入れました。テレメトリーを切って起動します。

bash
aws-emulator -t off

別の端末で、公式ガイドにある環境変数を設定します。最後の AWS_PAGER は、出力をページャーで開かないために私が足したものです。

bash
export AWS_ENDPOINT_URL=https://127.0.0.1:9297
export AWS_SHARED_CREDENTIALS_FILE=~/.aws/emulator/9297/emulator_credentials
export AWS_CONFIG_FILE=~/.aws/emulator/9297/config
export AWS_CA_BUNDLE=~/.aws/emulator/9297/ca.pem
export AWS_EC2_METADATA_DISABLED=true
export AWS_DISABLE_HOST_PREFIX_INJECTION=true
export AWS_REGION=us-east-1
export AWS_DEFAULT_REGION=us-east-1
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN AWS_PROFILE
export AWS_PAGER=""

以下の出力では、エミュレーターのアカウントID(12桁の0)を <12桁の0> に置き換えています。

エミュレーターのキーには、ポリシーが1つも付いていない

起動したときに書き出されるキーは、emulator という IAM ユーザーのものです。このユーザーには、付けたポリシーもインラインポリシーも、所属するグループもありません。

console
$ aws sts get-caller-identity --query Arn --output text
arn:aws:iam::<12桁の0>:user/emulator
$ aws iam list-attached-user-policies --user-name emulator
{
    "AttachedPolicies": []
}
$ aws iam list-user-policies --user-name emulator
{
    "PolicyNames": []
}
$ aws iam list-groups-for-user --user-name emulator
{
    "Groups": []
}

それでも、S3 のバケット、DynamoDB のテーブル、IAM ユーザーを作れました。セキュリティのページにある「エミュレーター自身のキーで署名したリクエストは拒否しない」という説明のとおりです。

console
$ aws s3api create-bucket --bucket demo-emulator-bucket
{
    "Location": "/demo-emulator-bucket",
    "BucketArn": "arn:aws:s3:::demo-emulator-bucket"
}
$ aws dynamodb create-table --table-name DemoTable \
    --attribute-definitions AttributeName=id,AttributeType=S \
    --key-schema AttributeName=id,KeyType=HASH \
    --billing-mode PAY_PER_REQUEST --query TableDescription.TableStatus
"CREATING"
$ aws iam create-user --user-name no-policy-user --query User.Arn
"arn:aws:iam::<12桁の0>:user/no-policy-user"

本物の AWS では、IAM ユーザーのページにあるとおり、新しい IAM ユーザーは初めは何の権限も持っていません。明示的な拒否と暗黙的な拒否の説明によると、当てはまる Allow も Deny もないリクエストは暗黙的に拒否されます。

ポリシーのないユーザーで呼ぶと、通る操作と拒否される操作に分かれる

次に、上で作った no-policy-user のアクセスキーを作り、そのキーで操作を呼びました。このユーザーにもポリシーは付いていません。

アクセスキーIDとシークレットアクセスキーをシェルの変数に読み込み、環境変数 AWS_ACCESS_KEY_ID と AWS_SECRET_ACCESS_KEY に入れます。エミュレーターのキーのファイルを読まないように、AWS_SHARED_CREDENTIALS_FILE は外します。

bash
read -r AK SK < <(aws iam create-access-key --user-name no-policy-user --query 'AccessKey.[AccessKeyId,SecretAccessKey]' --output text)
unset AWS_SHARED_CREDENTIALS_FILE
export AWS_ACCESS_KEY_ID=$AK AWS_SECRET_ACCESS_KEY=$SK

コマンドのリファレンスによると、エミュレーターの IAM で作ったキーも、署名に使えます。

console
$ aws sts get-caller-identity --query Arn --output text
arn:aws:iam::<12桁の0>:user/no-policy-user

SQS のキューの作成、SNS のトピックの作成、Systems Manager の Parameter Store への書き込みは、どれも通りました。

console
$ aws sqs create-queue --queue-name demo-queue
{
    "QueueUrl": "https://sqs.us-east-1.amazonaws.com/<12桁の0>/demo-queue"
}
$ aws sns create-topic --name demo-topic
{
    "TopicArn": "arn:aws:sns:us-east-1:<12桁の0>:demo-topic"
}
$ aws ssm put-parameter --name /demo/param --value hello --type String
{
    "Version": 1,
    "Tier": "Standard"
}

一方、DynamoDB の項目の書き込みは拒否されました。メッセージの形は、IAM のアクセス拒否のトラブルシューティングに載っている、暗黙的な拒否のときの文言(because no identity-based policy allows ...)と同じです。

console
$ aws dynamodb put-item --table-name DemoTable --item '{"id":{"S":"cat-1"}}'

aws: [ERROR]: An error occurred (AccessDeniedException) when calling the PutItem operation: User: arn:aws:iam::<12桁の0>:user/no-policy-user is not authorized to perform: dynamodb:PutItem on resource: arn:aws:dynamodb:us-east-1:<12桁の0>:table/DemoTable because no identity-based policy allows the dynamodb:PutItem action

同じ S3 でも、バケットの一覧は取れて、バケットの作成は拒否されました。

console
$ aws s3api list-buckets --query 'Buckets[].Name'
[
    "demo-emulator-bucket"
]
$ aws s3api create-bucket --bucket demo-no-policy-bucket

aws: [ERROR]: An error occurred (AccessDenied) when calling the CreateBucket operation: User: arn:aws:iam::<12桁の0>:user/no-policy-user is not authorized to perform: s3:CreateBucket on resource: "arn:aws:s3:::demo-no-policy-bucket" because no identity-based policy allows the s3:CreateBucket action

このユーザーで呼んだ結果をまとめると、次のとおりです。本物の AWS では、上で引いた IAM の公式ドキュメントによれば、どれも暗黙的に拒否されます。

操作 AWS Emulator 1.0.353 での結果
SQS CreateQueue 通った
SNS CreateTopic 通った
Systems Manager PutParameter 通った
S3 ListBuckets 通った
S3 CreateBucket 拒否(AccessDenied)
DynamoDB PutItem、GetItem 拒否(AccessDeniedException)
IAM CreateUser 拒否(AccessDenied)
KMS CreateKey 拒否(AccessDeniedException)
Secrets Manager CreateSecret 拒否(AccessDeniedException)

すべてを拒否するポリシーを付けても、通る操作がある

次に、no-policy-user に AWS 管理ポリシーの AdministratorAccess を付け、さらに、すべての操作を拒否するインラインポリシーを付けました。

console
$ cat deny-all.json
{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Action":"*","Resource":"*"}]}
$ aws iam attach-user-policy --user-name no-policy-user --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
$ aws iam put-user-policy --user-name no-policy-user --policy-name DenyAll --policy-document file://deny-all.json

ポリシーの評価の流れの説明によれば、明示的な拒否は許可より優先されます。本物の AWS では、このユーザーの操作はすべて拒否されることになります。エミュレーターでは、SQS のキューの作成と、Parameter Store の読み出しが通りました。

console
$ aws sqs create-queue --queue-name demo-queue-2
{
    "QueueUrl": "https://sqs.us-east-1.amazonaws.com/<12桁の0>/demo-queue-2"
}
$ aws ssm get-parameter --name /demo/param --query Parameter.Value --output text
hello

同じ SQS でも、キューの削除は拒否されました。メッセージには、明示的な拒否を表す with an explicit deny in an identity-based policy が入っています。同じサービスの中でも、操作によって結果が違いました。

console
$ aws sqs delete-queue --queue-url https://sqs.us-east-1.amazonaws.com/<12桁の0>/demo-queue

aws: [ERROR]: An error occurred (AccessDenied) when calling the DeleteQueue operation: User: arn:aws:iam::<12桁の0>:user/no-policy-user is not authorized to perform: sqs:deletequeue on resource: arn:aws:sqs:us-east-1:<12桁の0>:demo-queue with an explicit deny in an identity-based policy

DynamoDB の DeleteItem、S3 の CreateBucket、IAM の CreateUser も、同じく明示的な拒否のメッセージで拒否されました。

エミュレーターのキーに拒否のポリシーを付けた場合

同じ拒否のポリシーを、エミュレーターのキーの emulator ユーザーに付けて試しました。SQS のキューの作成と IAM ユーザーの作成は通り、S3 のバケットの作成は拒否されました。

console
$ aws iam put-user-policy --user-name emulator --policy-name DenyAll --policy-document file://deny-all.json
$ aws sqs create-queue --queue-name demo-queue-3
{
    "QueueUrl": "https://sqs.us-east-1.amazonaws.com/<12桁の0>/demo-queue-3"
}
$ aws iam create-user --user-name made-by-emulator-after-deny --query User.Arn
"arn:aws:iam::<12桁の0>:user/made-by-emulator-after-deny"
$ aws s3api create-bucket --bucket demo-emulator-deny-bucket

aws: [ERROR]: An error occurred (AccessDenied) when calling the CreateBucket operation: User: arn:aws:iam::<12桁の0>:user/emulator is not authorized to perform: s3:CreateBucket on resource: "arn:aws:s3:::demo-emulator-deny-bucket" with an explicit deny in an identity-based policy

セキュリティのページには「エミュレーター自身のキーで署名したリクエストは拒否しない」とありますが、1.0.353 の S3 では、明示的な拒否のポリシーを付けると拒否されました。

S3 のバケットポリシーも試しました。emulator ユーザーから DenyAll を外し、すべてを拒否するバケットポリシーを付ける前と後で、オブジェクトを書き込みます。セキュリティのページには「S3 のバケットポリシーは確かめない」とありますが、ポリシーを付けた後の PutObject は拒否されました。

console
$ aws iam delete-user-policy --user-name emulator --policy-name DenyAll
$ aws s3api put-object --bucket demo-emulator-bucket --key before.txt --body hello.txt --query ETag
"\"b1946ac92492d2347c6235b4d2611184\""
$ aws s3api put-bucket-policy --bucket demo-emulator-bucket --policy file://bucket-deny.json
$ aws s3api put-object --bucket demo-emulator-bucket --key after.txt --body hello.txt

aws: [ERROR]: An error occurred (AccessDenied) when calling the PutObject operation: User: arn:aws:iam::<12桁の0>:user/emulator is not authorized to perform: s3:PutObject on resource: "arn:aws:s3:::demo-emulator-bucket/after.txt" with an explicit deny in a resource-based policy

bucket-deny.json は、Principal を *、Action を s3:* にした Deny の文1つだけのバケットポリシーです。公式ドキュメントによると、AWS Emulator は1日に何度も更新されます。ここに載せた結果は、1.0.353 で試したときのものです。

AccessDenied が出るかどうかを、テストで当てにしない

ここまでの結果から、エミュレーターで AccessDenied が出ても、出なくても、本物の AWS で同じになるとは言えません。拒否されるべき操作が通る例(SQS、SNS、Parameter Store)も、AWS と同じ形式のメッセージで拒否される例(S3、DynamoDB、IAM、KMS、Secrets Manager)も、同じ1つのエミュレーターの中にあります。

注意

エミュレーターでテストが通っても、IAM の権限が正しいことにはなりません。公式のセキュリティのページも、IAM のポリシー、権限の境界、バケットポリシー、KMS のキーポリシーなどのテストには使わず、本番の前に本物の AWS で確かめるように求めています。

​Posted by 86