こんにちは、かつコーチです。
AWSを触っていると、一度は必ずぶつかるのが「Access Denied」エラーです。
私自身、S3もLambdaもEC2も、権限まわりで何度も手が止まった経験があります。
この記事では、Access Deniedエラーが起きる典型的な原因を整理し、実際に切り分けていく手順を、私がハマった実例つきで解説します。
Access Deniedエラーとは?
エラーの意味
Access Deniedとは、AWSのリソースに対する操作が権限不足で拒否されたときに返されるエラーです。
社員証の例で言えば、入室権限のないドアの前で警備員に止められている状態に近いです。
問題は「どのドア(リソース)」で「どの権限」が足りないのかが、エラーメッセージだけでは分かりにくいことです。
なぜ切り分けが難しいのか
Access Deniedの原因は一つではありません。
IAMポリシー本体の記述ミス、リソース指定の誤り、S3であればバケットポリシーとの競合など、複数の要因が絡み合います。
さらにIAMの権限反映には数秒〜数十秒のタイムラグがあることもあり、「さっき直したのにまだ怒られる」という状況も起こります。
だからこそ、原因を一つずつ機械的に潰していく手順を持っておくことが重要です。
基本の切り分け手順
手順1: エラーメッセージを最後まで読む
AWSのAccess Deniedエラーには、原因のヒントが含まれていることが多いです。
例えば以下のように、どのアクションが拒否されたかが明示されます。
An error occurred (AccessDenied) when calling the PutObject operation:
User: arn:aws:iam::123456789012:user/sample-user is not authorized to perform:
s3:PutObject on resource: "arn:aws:s3:::my-sample-bucket/uploads/test.png"
because no identity-based policy allows the s3:PutObject action
この場合、「どのユーザーが」「どの操作を」「どのリソースに対して」拒否されたかが明確です。
まずはこの3点をメモに書き出すところから始めましょう。
手順2: IAM Policy Simulatorで机上検証する
原因の見当がついたら、実際にリソースへアクセスする前にIAM Policy Simulator(ポリシーの動作をシミュレーションできるAWSの公式ツール)で検証すると安全です。
対象のユーザーやロール、アクション、リソースARNを指定するだけで、許可されるか拒否されるかを事前に確認できます。
本番環境で試行錯誤してエラーを量産する前に、ここで当たりをつけるのがおすすめです。
つまずきやすい設定・注意点
権限を修正した直後は、キャッシュや伝播の関係で反映まで少し時間がかかることがあります。
修正してすぐ同じエラーが出ても焦らず、数十秒〜1分ほど待ってから再実行してみてください。
それでも直らない場合は、修正した箇所が本当に正しいか、次章の原因パターンと照らし合わせましょう。
よくあるつまずきポイント・エラー対処
原因1: ポリシーの記述ミス(Actionのタイプミス)
一番多いのが、Actionのサービス名や操作名のタイプミスです。
“s3:GetObeject”のようにスペルが1文字違うだけで、ポリシーは静かに無効化されます。
AWSはこの手のタイプミスに対してエラーを出さず、単に該当ポリシーが機能しないだけなので気づきにくいのが厄介です。
- ❌ Before:
"Action": "s3:GetObeject"(タイポでActionが機能していない) - ✅ After:
"Action": "s3:GetObject"(正しいアクション名に修正)
JSONの構文エラーと違い、タイプミスは文法的には正しいので、AWS側もエラーを出してくれません。
ポリシーをJSONバリデーターに通すだけでは防げないため、AWSのドキュメントでアクション名をコピーする習慣をつけるのが確実です。
原因2: リソース指定の誤り(ARNの範囲違い)
前回の記事でも触れましたが、Resourceの範囲指定ミスも頻出です。
特定のフォルダ配下だけに絞ったつもりが、ARNのパス指定を誤って全く別の階層を指してしまうケースがあります。
- ❌ Before:
"Resource": "arn:aws:s3:::my-sample-bucket/uploads"(末尾に/*がなく、フォルダ内オブジェクトを指せていない) - ✅ After:
"Resource": "arn:aws:s3:::my-sample-bucket/uploads/*"(ワイルドカードでフォルダ配下を正しく指定)
ARNの末尾に/*を付け忘れると、フォルダそのものは指せてもその中のオブジェクトには権限が及びません。
原因3: バケットポリシーとIAMポリシーの競合(私が一番ハマった話)
これが実際に私が一番時間を溶かした原因です。
IAMユーザーには正しくs3:GetObjectを許可するポリシーをアタッチしていたのに、なぜかS3コンソールから該当オブジェクトを開くと以下のエラーが出続けました。
An error occurred (AccessDenied) when calling the GetObject operation: Access Denied
IAMポリシー側は何度見直しても正しく、Policy Simulatorでも「Allowed」と判定されるのに、実際のアクセスは拒否される。
半日近く原因が分からず、最終的にバケット側の設定を確認して気づいたのが、バケットポリシーに以下のようなDeny文が入っていたことでした。
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-sample-bucket/*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalOrgID": "o-xxxxxxxxxx"
}
}
}
このバケットポリシーは「特定の組織ID以外からのアクセスを拒否する」という設定で、私の検証用アカウントがその組織IDに含まれていなかったのです。
AWSのIAMでは、明示的なDenyはどんなAllowよりも優先されます。
つまりIAMポリシー側でAllowしていても、バケットポリシー側にDenyがあれば必ず拒否されるということです。
- ❌ Before: IAMポリシーだけを見て「Allowになっているのになぜ拒否されるのか」と悩み続けた
- ✅ After: バケットポリシー側も確認し、明示的なDenyの条件を洗い出して修正した
この経験から、S3まわりのAccess Deniedでは「IAMポリシー」と「バケットポリシー」の両方を必ずセットで確認するようにしています。
応用・一歩先の使い方
CloudTrailでさらに深く調査する
Policy Simulatorでも原因が特定できない場合は、CloudTrail(AWS内で行われたAPI呼び出しの履歴を記録するサービス)のログを確認するのが有効です。
実際に発生したAPIコールの詳細イベントを見ると、どのポリシーが評価され、なぜ拒否されたのかのヒントが得られることがあります。
特にSCP(組織単位のポリシー)やリソースベースポリシーが絡む複雑な環境では、CloudTrailでの実イベント確認が最終的な決め手になることが多いです。
まとめ
この記事のポイント
- Access Deniedはエラーメッセージの「誰が・何を・どこに」を最初に読み解く
- IAM Policy Simulatorで本番アクセス前に机上検証すると安全
- 原因はActionのタイプミス、Resourceのワイルドカード漏れ、バケットポリシーとの競合の3パターンが多い
- 明示的なDenyはAllowより必ず優先される点を覚えておく
- 原因不明のときはCloudTrailの実イベントログを確認する
次に読むべき記事
ポリシーの書き方をまだ読んでいない方は「IAMポリシーの書き方基本(JSON構文とアクション指定)」から復習しておくと、今回の内容がより理解しやすくなります。
また、次はネットワークまわりの基礎として「VPCとは?AWS上に専用ネットワークを作る仕組み」もあわせて読んでみてください。
