AWS S3アクセス拒否エラーを即座に解決する3つの診断ステップ

AWS S3へのアクセスが「Access Denied」で失敗する原因は、IAM権限の不備、バケットポリシーの競合、またはリージョン設定の誤りの3つに限定されます。本記事では、実際の運用環境で即座に原因を特定し、修正するための診断フローと具体的なコード例を紹介します。

AWS S3アクセス拒否の主要な3つの原因

S3へのアクセス拒否は、以下の優先順位で確認することで高速に解決できます:

1. IAM権限不足(最も一般的)

IAMユーザーやロールに対して、S3操作に必要なアクセス権限が付与されていない場合です。特にs3:GetObjects3:PutObjectといった個別の権限が不足しているケースが大半です。

2. バケットポリシーによる明示的な拒否

バケット側で特定のユーザーやIPアドレスを明示的に拒否するポリシーが設定されている場合、IAM権限があってもアクセスできません。

3. リージョンの不一致またはバケット存在確認の失敗

指定したリージョンにバケットが存在しない、またはバケット名が誤っている場合も、アクセス拒否として報告されることがあります。

診断ステップ1: IAM権限を確認する

AWS CLIで現在のユーザー情報を確認

まず、どのユーザーで操作しているかを確認します。以下のコマンドで現在のユーザーを表示できます:

aws sts get-caller-identity

出力例:

{
    "UserId": "AIDAI23HXD2O5EXAMPLE",
    "Account": "123456789012",
    "Arn": "arn:aws:iam::123456789012:user/myuser"
}

アタッチされているポリシーを確認

ユーザーにアタッチされているポリシーを確認します:

aws iam list-attached-user-policies --user-name myuser

正しいS3権限をアタッチする

S3へのアクセスに必要な最小限の権限を含むポリシーは以下の通りです。AWS管理ポリシーAmazonS3ReadOnlyAccessを使用するのが簡単ですが、本番環境では最小権限の原則に従い、以下のようなカスタムポリシーを推奨します:

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

このポリシーを以下のコマンドでアタッチします:

aws iam put-user-policy --user-name myuser \
  --policy-name S3AccessPolicy \
  --policy-document file://policy.json

診断ステップ2: バケットポリシーと権限の競合を確認

現在のバケットポリシーを取得

バケットポリシーが権限を明示的に拒否していないか確認します:

aws s3api get-bucket-policy --bucket my-bucket

ハマりポイント: Effect = Deny の存在

バケットポリシーで"Effect": "Deny"が設定されている場合、IAM権限があってもアクセスできません。これはAWSのセキュリティモデルの仕様で、Denyは常に優先されます。以下のような拒否ポリシーが設定されていないか確認してください:

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

このポリシーがある場合、指定されたIPアドレスからのすべてのS3操作がブロックされます。

バケットポリシーを修正する

オブジェクトへのアクセスを許可する標準的なバケットポリシーは以下の通りです:

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

このポリシーをアップロードします:

aws s3api put-bucket-policy --bucket my-bucket \
  --policy file://bucket-policy.json

診断ステップ3: 実際にアクセスをテストする

Python SDKで動作確認(boto3を使用)

実際のアクセス可否を検証するには、プログラムで試すのが確実です。以下はPythonでの例です:

import boto3
import sys

# S3クライアントを作成(リージョンを明示的に指定)
s3_client = boto3.client('s3', region_name='ap-northeast-1')

try:
    # バケット内のオブジェクトを一覧表示
    response = s3_client.list_objects_v2(Bucket='my-bucket')
    print(f"✓ バケット 'my-bucket' へのアクセス成功")
    print(f"オブジェクト数: {response.get('KeyCount', 0)}")
    
    # テストオブジェクトをアップロード
    s3_client.put_object(
        Bucket='my-bucket',
        Key='test-file.txt',
        Body=b'Test content'
    )
    print("✓ アップロード成功")
    
    # オブジェクトをダウンロード
    obj = s3_client.get_object(Bucket='my-bucket', Key='test-file.txt')
    content = obj['Body'].read()
    print(f"✓ ダウンロード成功: {content.decode()}")
    
except s3_client.exceptions.NoSuchBucket:
    print("✗ エラー: バケットが存在しません")
    sys.exit(1)
    
except Exception as e:
    print(f"✗ アクセス拒否エラー: {str(e)}")
    print(f"エラーコード: {e.response['Error']['Code']}")
    sys.exit(1)

CloudTrailでアクセス拒否ログを確認

上記のテストコードでもアクセス拒否が続く場合、CloudTrailでエラーの詳細を確認します:

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=ResourceName,AttributeValue=my-bucket \
  --region ap-northeast-1 \
  --query 'Events[?CloudTrailEvent like `*AccessDenied*`]' \
  | head -20

CloudTrailが有効になっていない場合は、AWS管理コンソールで有効化してください。

実際に使えるトラブルシューティングチェックリスト

アクセス拒否が発生した時の確認順序

以下の順序で確認することで、大半のケースが5分以内に解決します:

# 1. 使用しているユーザーを確認
aws sts get-caller-identity

# 2. そのユーザーのS3権限を確認
aws iam list-attached-user-policies --user-name 

# 3. バケット名が正しいか確認(存在確認)
aws s3 ls s3://my-bucket

# 4. バケットポリシーで明示的な拒否がないか確認
aws s3api get-bucket-policy --bucket my-bucket

# 5. 実際にオブジェクトにアクセスしてみる
aws s3api get-object --bucket my-bucket --key path/to/file.txt output.txt

使うべき場面と使うべきでない場面

バケットポリシーを使うべき場面:特定のIPアドレスからのアクセスのみを許可したい、特定のAWSアカウント外のユーザーにアクセスを許可したい場合。

IAMポリシーを使うべき場面:組織内の複数ユーザーに対して、細かく権限を制御する必要がある場合。日常的な権限管理はIAMで行い、バケットポリシーは例外的なケースに限定することが推奨されます。

よくある質問

A: EC2インスタンスに適切なIAMロールがアタッチされていない可能性があります。EC2インスタンスには、IAMユーザー認証ではなく、IAMロール経由でアクセス権限を付与する必要があります。EC2コンソールからインスタンスのセキュリティ設定を確認し、IAMロール(例:EC2-S3-Access-Role)がアタッチされているか確認してください。

A: IAMポリシーやバケットポリシーで、パス(フォルダ)単位で権限が制限されている可能性があります。Resource属性に"arn:aws:s3:::my-bucket/allowed-path/*"のように指定されている場合、該当パス内のみアクセス可能です。全オブジェクトへのアクセスが必要な場合は、"arn:aws:s3:::my-bucket/*"に変更してください。

A: AWSのセキュリティモデルでは、いずれかが「Deny」であれば拒否されます。つまり両方で「Allow」である必要があります。設計としては、IAMポリシーで基本的な権限を制御し、バケットポリシーはクロスアカウントアクセスや例外的なケースに限定するのが一般的です。

まとめ

  • S3アクセス拒否の原因は「IAM権限不足」「バケットポリシーのDeny」「バケット名/リージョン誤り」の3つに限定される
  • aws sts get-caller-identityaws iam list-attached-user-policiesで権限を確認し、必要な権限をアタッチする
  • バケットポリシーの"Effect": "Deny"はIAM権限を上書きするため、必ず確認する
  • Python(boto3)でテストコードを実行することで、設定の正確性を即座に検証できる
  • CloudTrailで詳細なエラーログを確認することで、複雑なケースの原因特定が可能
  • 本番環境では最小権限の原則に従い、必要最小限の権限のみを付与する

本番環境での運用時には、AWS S3セキュリティに関する公式ドキュメントを参照しながら、組織のセキュリティポリシーに準拠した権限設計を心がけてください。

テスト環境:macOS 14 / Python 3.11 / AWS CLI 2.13 / boto3 1.28

K
AWS・Python・生成AIを専門とするソフトウェアエンジニア。AI・クラウド・開発ワークフローの実践ガイドを執筆しています。詳しく見る →