エラーの概要

AWS S3 の AccessDenied エラーは、IAM ポリシーの不足、バケットポリシーの明示的な拒否設定、またはオブジェクトの ACL 設定によって、リソースへのアクセスが拒否されたときに発生します。認証情報は正常に認識されているものの、権限がない状態です。

実際のエラーメッセージ例

{
  "Error": {
    "Code": "AccessDenied",
    "Message": "Access Denied"
  }
}
An error occurred (AccessDenied) when calling the GetObject operation: Access Denied

エラーメッセージの読み方:

よくある原因と解決手順

原因1:IAM ポリシーで必要なアクションが許可されていない

S3 バケットにアクセスするユーザー・ロール・サービスに対して、s3:GetObjects3:PutObject などの必要な権限が付与されていない場合に発生します。特に新規に作成した IAM ユーザーや、特定のバケットに限定したアクセスに構成した際に起きやすいです。

Before(エラーが起きるコード):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket"
      ],
      "Resource": "arn:aws:s3:::my-bucket"
    }
  ]
}

After(修正後):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket"
      ],
      "Resource": "arn:aws:s3:::my-bucket"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

✅ 修正後の確認:

aws s3 cp s3://my-bucket/test.txt . --profile <your-profile>

修正が反映されると、指定したファイルダウンロードされ、エラーが出なくなります。

原因2:バケットポリシーで Deny が明示的に設定されている

バケットポリシーで "Effect": "Deny" が設定されている場合、IAM ポリシーで Allow されていても、より制限的なポリシーが優先されて AccessDenied が発生します。IP アドレス制限やプリンシパル制限などの条件で無意識に Deny が適用されていることもあります。

Before(エラーが起きるコード):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::my-bucket",
        "arn:aws:s3:::my-bucket/*"
      ]
    }
  ]
}

After(修正後):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<your-account-id>:root"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

✅ 修正後の確認:

aws s3api get-bucket-policy --bucket my-bucket --profile <your-profile>

バケットポリシーが新しい設定に更新されていれば、制限が解除されます。

原因3:Block Public Access 設定が有効で、公開アクセスがブロックされている

オブジェクトの ACL を Public に設定しても、S3 の Block Public Access 機能が有効な場合は公開アクセスが拒否されます。特に外部ユーザーや別アカウントからのアクセスを想定している場合に発生します。

Before(エラーが起きるコード):

# Block Public Access が全て有効な状態
aws s3api get-public-access-block --bucket my-bucket --profile <your-profile>
# Output: {
#   "PublicAccessBlockConfiguration": {
#     "BlockPublicAcls": true,
#     "IgnorePublicAcls": true,
#     "BlockPublicPolicy": true,
#     "RestrictPublicBuckets": true
#   }
# }

After(修正後):

aws s3api put-public-access-block \
  --bucket my-bucket \
  --public-access-block-configuration \
  "BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false" \
  --profile <your-profile>

✅ 修正後の確認:

aws s3api get-public-access-block --bucket my-bucket --profile <your-profile>

BlockPublicAclsBlockPublicPolicy などの値が false に変更されていれば、Block Public Access 設定が解除されています。

原因4:別のAWSアカウント・クロスアカウントアクセスが正しく設定されていない

別の AWS アカウントのユーザーまたはロールバケットにアクセスする場合、バケットポリシーでそのプリンシパル(外部アカウントの ARN)を明示的に許可し、同時に外部アカウント側の IAM ポリシーも s3 アクションを許可する必要があります。どちらか一方が不足すると AccessDenied が発生します。

Before(エラーが起きるコード):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

外部アカウント(123456789012)の IAM ユーザーの権限が不足している状態。

After(修正後):

バケット側のポリシーはそのままにして、外部アカウント側で以下の IAM ポリシーを適用:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-bucket",
        "arn:aws:s3:::my-bucket/*"
      ]
    }
  ]
}

✅ 修正後の確認:

aws s3 ls s3://my-bucket --profile <cross-account-profile>

外部アカウントのプロファイルからバケット内のオブジェクトが一覧表示されれば、クロスアカウントアクセスが正常です。

解決策の早見表

解決策実装難易度再起動要否対応OS
IAMポリシー権限を追加不要OS
バケットポリシーの Deny 条件を修正不要OS
Block Public Access を無効化不要OS
クロスアカウント権限を設定不要OS

ツール固有の注意点

AWS マネジメントコンソールでの確認方法:

S3 コンソールバケット名をクリック → 「権限」タブで「バケットポリシー」「ACL」「Block Public Access」を確認します。ポリシーJSON は視覚的には わかりにくいため、AWS IAM Policy Simulator(https://policysim.aws.amazon.com/)を使用してアクション実行をシミュレーションすることで、どのポリシーが拒否しているか特定できます。

IAM ロール経由でのアクセス:

EC2 インスタンスや Lambda 関数から S3 にアクセスする場合、インスタンスプロファイルまたは実行ロールに s3 権限が付与されていることを確認してください。aws sts get-caller-identity を実行し、実際に使用されているロール ARN を確認したうえで、そのロールポリシーを検証します。

バージョン管理が有効な場合:

バージョン管理が有効なバケットでは、s3:GetObjectVersion という追加アクションが必要になる場合があります。オブジェクトの過去バージョンにアクセスする際は、IAM ポリシーに明示的に含めてください。

それでも解決しない場合

AWS CloudTrail でリクエストを確認:

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=ResourceType,AttributeValue=AWS::S3::Object \
  --max-results 10 \
  --profile <your-profile>

CloudTrail ログから失敗したリクエストの詳細(どの IAM ユーザー、どのプリンシパルが拒否されたか)が確認できます。拒否の理由が「implicitDeny」(明示的な Allow がない)なのか「explicitDeny」(Deny ポリシーが存在)なのか判定できます。

AWS Access Analyzer の活用:

AWS IAM Access Analyzer を使用すると、バケットポリシーやロールポリシーの問題を自動検出できます。AWS コンソールIAM → Access Analyzer → リソースの外部アクセス可否を調査 で、アクセス拒否の原因を指摘してもらえます。

公式ドキュメント:

AWS S3 での AccessDenied トラブルシューティング

代替ツールの検討

AWS S3 の IAMポリシー管理が複雑で、AccessDenied エラーの原因特定に時間がかかる場合は、以下のツールへの移行を検討できます。

  • Google Cloud Storage(GCS)IAM ロール管理がシンプルで、事前定義ロール(Storage Object Admin など)を割り当てるだけで権限制御が可能です。ポリシー言語が単純化されているため、AccessDenied の原因特定も素早くできます。

  • Azure Blob Storage:ロールベースアクセス制御(RBAC)が統一されており、Azure AD との連携も強固です。きめ細かいアクセス制御が必要な企業環境に適しています。

  • Cloudflare R2:S3 互換 API を提供しながら、シンプルなアクセストークンベースの認証を採用しており、複雑なポリシー管理が不要です。軽量な運用を重視する場合に有効です。

Editor’s Note

AWS 公式ドキュメントでは IAM ポリシーと バケットポリシーの関係を別々に説明していることが多いため、新規ユーザーは「IAM ポリシーで Allow しているのに拒否される」という混乱に陥りやすいです。実際のサポートフォーラムでは、AWS re:Post での AccessDenied 事例でもこの原因が頻出しており、バケットポリシーの Deny 条件や Block Public Access が見落とされるケースが圧倒的です。現場では、まず AWS IAM Policy Simulator でポリシー評価を実行し、複数のポリシーがどの順序で評価されているか可視化してから、個別のポリシーを修正するのが有効です。


免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。