CloudFront ディストリビューションのオリジンとして S3 REST API エンドポイントを使用しています。403 Access Denied エラーが発生するのはなぜですか?

最終更新日: 2020 年 12 月 18 日

Amazon CloudFront ディストリビューションのオリジンとして Amazon Simple Storage Service (Amazon S3) バケットを使用しています。オリジンドメイン名として S3 REST API エンドポイントを使用しています。CloudFront が Amazon S3 から 403 Access Denied (アクセス拒否) エラーを返すのはなぜですか?

簡単な説明

Access Denied エラーをトラブルシューティングするには、ディストリビューションのオリジンドメイン名が S3 ウェブサイトのエンドポイントか S3 REST API エンドポイントかを知っておく必要があります。エンドポイントの種類を確認するには、次の手順に従ってください。

  1. CloudFront コンソールを開きます。
  2. CloudFront ディストリビューションを選択してから、[ディストリビューションの設定] を選択します。
  3. [オリジンとオリジングループ] タブを開きます。
  4. [Origin Domain Name and Path] (オリジンドメイン名およびパス) の下のドメイン名を確認します。次に、ドメイン名の形式に基づいてエンドポイントタイプを決定します。

REST API エンドポイントは次のフォーマットを使用します。

DOC-EXAMPLE-BUCKET.s3.amazonaws.com

静的ウェブサイトのエンドポイントは、以下の形式を使用します。

DOC-EXAMPLE-BUCKET.s3-website-us-east-1.amazonaws.com

ディストリビューションが S3 静的ウェブサイトエンドポイントを使用している場合は、CloudFront ディストリビューションのオリジンとして S3 ウェブサイトエンドポイントを使用していますを参照してください。403 Access Denied (アクセス拒否) エラーが発生するのはなぜですか?

配信が REST API エンドポイントを使用している場合は、Access Denied エラーを回避するために、設定が以下の要件を満たしていることを確認してください。

  • オリジンアクセスアイデンティティ (OAI) を設定しない場合、オブジェクトは公開されているか、AWS 署名バージョン 4 でリクエストされる必要があります。
  • バケット内のオブジェクトは、AWS Key Management Service (AWS KMS) を使用して暗号化することはできません。
  • S3 バケットポリシーは、s3:GetObject へのアクセスを許可する必要があります。
  • バケットポリシーでアクセスを許可する場合は、同じ AWS アカウントで S3 バケットとオブジェクトの両方を所有するようにします。
  • リクエストされるオブジェクトは、対応する S3 バケット内に置く必要があります。
  • クライアントが配信のルートをリクエストする場合は、デフォルトのルートオブジェクトを定義しておく必要があります。
  • OAI を定義している場合、その OAI は S3 バケットポリシーに含まれる必要があります。
  • OAI を設定しなかった場合は、バケットで Amazon S3 ブロックパブリックアクセスを無効にする必要があります。

解決方法

OAI を定義していない場合、オブジェクトは公開されているか、AWS 署名バージョン 4 でリクエストすることが必要

OAI を定義しない場合、REST API エンドポイントを使用する配信では、パブリックオブジェクト、または AWS 署名バージョン 4 認証でリクエストされたオブジェクトのみをサポートします。

S3 バケット内のオブジェクトが公開されているかどうかを判断するには、ウェブブラウザで S3 オブジェクトの URL を開きます。または、URL に対して curl コマンドを実行します。

以下は、S3 オブジェクトの URL の例です。

http://DOC-EXAMPLE-BUCKET.s3-website-us-east-1.amazonaws.com/index.html

ウェブブラウザまたは curl コマンドが Access Denied エラーを返した場合、そのオブジェクトは公開されていません。オブジェクトが公開されていない場合は、以下のいずれかの設定を行ってください。

バケット内のオブジェクトを AWS KMS で暗号化することができない

CloudFront ディストリビューションでは、AWS KMS で暗号化されたオブジェクトをサポートしていません。配信を通じ提供する S3 オブジェクトからは、KMS による暗号化を削除する必要があります。

注: AWS KMS での暗号化を使用する代わりに、AES-256 を使用してオブジェクトを暗号化できます

バケット内のオブジェクトが KMS で暗号化されているかどうかを確認するには、次のいずれかの方法を使用します。

Amazon S3 コンソールを使用してオブジェクトの暗号化設定を変更するには、S3 オブジェクトに暗号化を追加する方法を参照してください。

AWS CLI を使用してオブジェクトの暗号化設定を変更するには、まずオブジェクトのバケットにデフォルトの暗号化が設定されていないことを確認します。バケットにデフォルトの暗号化が設定されていない場合は、次の AWS CLI コマンドを実行してオブジェクトをそれ自体に上書きすることで、そのオブジェクトの暗号化を削除します。

aws s3 cp s3://DOC-EXAMPLE-BUCKET/index.html s3://DOC-EXAMPLE-BUCKET/index.html --storage-class STANDARD

注: サンプルコマンドの --storage-class 値を、お客様のユースケースに適用できるストレージクラスに変更してください。オブジェクトをそれ自身にコピーすると、storage-class および website-redirect-location の設定が削除されます。新しいオブジェクトでこれらの設定を維持するには、コピーリクエストで storage-classwebsite-redirect-location の値を明示的に指定します。

S3 バケットポリシーは、s3:GetObject へのアクセスを許可することが必要

S3 REST API エンドポイントでディストリビューションを使用するには、バケットポリシーで s3:GetObject をパブリックユーザーまたは CloudFront の OAI のいずれかに許可する必要があります。

バケットポリシーに s3:GetObject に対する明示的な許可ステートメントがある場合でも、競合する明示的な拒否ステートメントがないことを確認してください。明示的な拒否ステートメントは常に明示的な許可ステートメントを上書きします。

s3:GetObject のバケットポリシーを確認するには、次の手順に従います。

1.    Amazon S3 コンソールから S3 バケットを開きます。

2.    [アクセス許可] タブを選択します。

3.    [バケットポリシー] を選択します。

4.    "Action": "s3:GetObject" または "Action": "s3:*" のステートメントのバケットポリシーを確認します。

次のポリシー例では、CloudFront OAI に s3:GetObject へのアクセスを許可する許可ステートメントがあります。s3:GetObject へのパブリックアクセスを許可する許可ステートメントもあります。ただし、リクエストが特定の Amazon Virtual Private Cloud (Amazon VPC) からのものでない限り、アクセスをブロックする s3:GetObject に対する明示的な拒否ステートメントがあります。

{
  "Version": "2008-10-17",
  "Id": "PolicyForCloudFrontPrivateContent",
  "Statement": [{
      "Sid": "Allow-OAI-Access-To-Bucket",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EAF5XXXXXXXXX"
      },
      "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
      ]
    },
    {
      "Sid": "Allow-Public-Access-To-Bucket",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
      ]
    },
    {
      "Sid": "Access-to-specific-VPCE-only",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
      ],
      "Condition": {
        "StringNotEquals": {
          "aws:sourceVpce": "vpce-1a2b3c4d"
        }
      }
    }
  ]
}

5.    バケットポリシーを変更して、s3:GetObject への CloudFront OAI アクセスまたはパブリックアクセスをブロックしているステートメントを、削除または編集します。

注意: CloudFront は、Access Denied エラーの結果を最大 5 分間キャッシュします。バケットポリシーから拒否ステートメントを削除した後、配信に対して無効化を実行することで、オブジェクトをキャッシュから削除できるようになります。

バケットポリシーがアクセスを許可する場合、S3 バケットを所有する AWS アカウントもオブジェクトを所有する必要がある

バケットポリシーを外部のアカウントまたはサービス (パブリック読み取りアクセス、OAI など) に適用するには、バケットを所有する AWS アカウントもオブジェクトを所有している必要があります。バケットまたはオブジェクトは、そのバケットまたはオブジェクトを作成した AWS Identity and Access Management (IAM) ID のアカウントによって所有されます。

注: オブジェクト所有権の要件は、バケットポリシーによって許可されたアクセスに適用されます。オブジェクトのアクセスコントロールリスト (ACL) によって許可されたアクセスには適用されません。

バケットとオブジェクトの所有者が同じかどうかを確認するには、次の手順に従います。

1.    次の AWS CLI コマンドを実行して、バケット所有者の S3 正規 ID を取得します。

aws s3api list-buckets --query Owner.ID

2.    このコマンドを実行して、オブジェクト所有者の S3 正規 ID を取得します。

注意: この例は単一のオブジェクトを示していますが、list コマンドを使用して複数のオブジェクトを確認することができます。

aws s3api list-objects --bucket DOC-EXAMPLE-BUCKET --prefix index.html

3.    正規 ID が一致しない場合、バケットとオブジェクトの所有者が異なります。

注: Amazon S3 コンソールを使用してバケットとオブジェクトの所有者を確認することもできます。所有者はそれぞれのバケットまたはオブジェクトの [アクセス許可] タブにあります。

オブジェクトの所有者をバケットの所有者に変更するには、次の手順に従います。

1.    オブジェクトの所有者の AWS アカウントで、このコマンドを実行して、オブジェクトに割り当てられているアクセスコントロールリスト (ACL) のアクセス許可を取得します。

aws s3api get-object-acl --bucket DOC-EXAMPLE-BUCKET --key object-name

2.    オブジェクトに bucket-owner-full-control の ACL アクセス許可がある場合は、手順 3 に進みます。オブジェクトに bucket-owner-full-control の ACL アクセス許可がない場合は、オブジェクトの所有者のアカウントから次のコマンドを実行します。

aws s3api put-object-acl --bucket DOC-EXAMPLE-BUCKET --key object-name --acl bucket-owner-full-control

3.    このコマンドをバケット所有者のアカウントから実行して、オブジェクトをそれ自体に上書きコピーし、そのオブジェクトの所有者を変更します。

aws s3 cp s3://DOC-EXAMPLE-BUCKET/index.html s3://DOC-EXAMPLE-BUCKET/index.html --storage-class STANDARD

注: サンプルコマンドの --storage-class 値を、お客様のユースケースに適用できるストレージクラスに変更してください。

リクエストされたオブジェクトはバケットに存在することが必要

ユーザーに s3:ListBucket のアクセス許可がない場合、ユーザーには 404 Not Found エラーの代わりに、存在しないオブジェクトに対し、アクセス拒否エラーが表示されます。head-object AWS CLI コマンドを実行して、オブジェクトがバケットに存在するかどうかを確認します。

注: CloudFront に送信されたオブジェクトリクエストが S3 オブジェクト名と正確に一致することを確認してください。S3 オブジェクト名では大文字と小文字が区別されます。リクエストが正しいオブジェクト名を持っていない場合、Amazon S3 はオブジェクトが見つからないかのように応答します。CloudFront が Amazon S3 からリクエストしているオブジェクトを特定するには、サーバーアクセスログを使用します。

バケットにオブジェクトが存在する場合は、Access Denied エラーが「404 Not Found」エラーを隠すことはありません。アクセス拒否エラーを解決するには、他の設定要件を確認してください。

オブジェクトがバケット内にない場合は、アクセス拒否エラーは「404 Not Found」エラーを隠します。存在しないオブジェクトに関連する問題を解決します。

注: パブリック s3:ListBucket アクセスを有効にすることは、セキュリティ上のベストプラクティスではありません。パブリック s3:ListBucket アクセスを有効にすると、ユーザーはバケット内のすべてのオブジェクトを表示およびリスト化できます。これにより、ユーザーがオブジェクトをダウンロードするアクセス許可を持っていない場合でも、オブジェクトのメタデータの詳細 (キーやサイズなど) がユーザーに公開されます。

クライアントがディストリビューションのルートをリクエストする場合は、デフォルトのルートオブジェクトを定義する必要がある

ディストリビューションにデフォルトのルートオブジェクトが定義されておらず、リクエスタが s3:ListBucket アクセス許可を持っていない場合、リクエスタはアクセス拒否エラーを受け取ります。ディストリビューションのルートをリクエストするとき、リクエスタは 404 Not Found エラーの代わりにこのエラーを受け取ります。

デフォルトのルートオブジェクトの定義方法については、デフォルトのルートオブジェクトの指定を参照してください。

注意: s3:ListBucket へのパブリックアクセスを有効にすることは、セキュリティ上のベストプラクティスではありません。パブリック s3:ListBucket アクセスを有効にすると、ユーザーはバケット内のすべてのオブジェクトを表示およびリスト化できます。これにより、ユーザーがオブジェクトをダウンロードするアクセス許可を持っていない場合でも、オブジェクトのメタデータの詳細 (キーやサイズなど) がユーザーに公開されます。

OAI を設定した場合は、その OAI を S3 バケットポリシーに含めることが必要

CloudFront ディストリビューションに OAI を追加した場合は、S3 バケットポリシーに OAI の許可ステートメントも含める必要があります。

バケットポリシーで OAI が許可されているかどうかを確認するには、Amazon S3 コンソールで S3 バケットを開きます。次に、[アクセス許可] タブを選択してバケットポリシーを確認します。以下は、OAI の許可ステートメントの例です。

{
  "Sid": "1",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EAF5XXXXXXXXX"
  },
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
}

CloudFront コンソールを使用してバケットポリシーを更新するには、次の手順に従ってください。

  1. CloudFront コンソールを開き、対象の配信を選択します。
  2. [Origins and Origin Groups] (オリジンとオリジングループ) タブを開きます。
  3. S3 オリジンを選択して [Edit] (編集) をクリックします。
  4. [Restrict Bucket Access] で、[Yes] を選択します。
  5. [Origin Access Identity] で、既存のアイデンティティを選択するか、新規に作成します。
  6. [Grant Read Permissions on Bucket] で、[Yes, Update Bucket Policy] を選択します。
  7. [Yes, Edit] (はい、編集します) をクリックします。

OAI を定義していない場合は、Amazon S3 ブロックパブリックアクセス設定を無効にする必要があります。

ディストリビューションが OAI を使用しておらず、オブジェクトが AWS 署名バージョン 4 でリクエストされていない場合、REST API エンドポイントを持ったディストリビューションはパブリックに読み取り可能なオブジェクトのみをサポートします。つまり、バケットに Amazon S3 ブロックパブリックアクセス設定が適用されていないことを確認する必要があります。これらの設定は、パブリック読み取りアクセスを許可するアクセス許可を上書きできます。Amazon S3 ブロックパブリックアクセス設定は、個々のバケットまたは AWS アカウントに適用できます。