Search code examples
amazon-web-servicesamazon-s3amazon-cloudfronthttp-status-code-403

Using AWS S3 & CloudFront to steam videos from my website is a 403 forbidden


I want to store videos in an Amazon S3 bucket. I want to load them onto my website. I want to use Amazon CloudFront for the CDN/caching etc.

Ideally by the end I would like to restrict the videos to only play on the domains I set.

But initially I am having a 403 error even loading the video.

It says in console:

Failed to load resource: the server responded with a status of 403 ()

And clicking it shows this XML

<Error>
    <Code>AccessDenied</Code>
    <Message>Access Denied</Message>
    <RequestId>9PW32M02SZR567DF</RequestId>
    <HostId>ukPRxDlFq9TYiJcHLnnAhryAewPoAd/ijm/GxHvdB774cMwK4PdQ0yr1CQqa1msCV+CkYj+nkL0=</HostId>
</Error>

I have tried many things after much reading.

Initially, I had set up the distribution with a key and I believe using OAI.

I have now disabled the WAF part of it to try and rule out that as a variable.

I am loading the video directly in the browser. At one point a video player loaded but the video itself did not.

I created public keys

I created key groups

I selected my S3 bucket in CloudFront so I could not have made a typo.

I created an "origin access" and I have tried with both signing and not signing the request.

I set up Identities (legacy)

I have disabled encryption and bucket key.

All public access is blocked.

I copied the permissions from CloudFront and added it to the S3 bucket's permissions.

This is my bucket policy.

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::tpwc-co-uk--media/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::240479180938:distribution/E17GLPD7918NNC"
                }
            }
        }
    ]
}

Server side encryption is set as:

Server-side encryption with Amazon S3 managed keys (SSE-S3)

Here is my URL if that helps: https://d2tzr0xka0eqcu.cloudfront.net

By making my S3 bucket publicly available I can see the URL via S3, but the CloudFront URL still doesn't work.

I updated my policy to include getObject. My S3 bucket policy now stands as:

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::tpwc-co-uk--media/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::240479180938:distribution/E17GLPD7918NNC"
                }
            }
        },
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::tpwc-co-uk--media/*"
        }
    ]
}

Screenshots

Here are screenshots of the things I have configured. Any missing screenshots means no configuration has taken place.

Distribution Screenshots

General

General

Settings

Settings

Origin Settings

Origin

Bucket Screenshots

Permissions

Permissions

Management

Management

Encryption

Ecryption

Can anyone help me to understand where I have gone wrong?


Solution

  • The Block Public Access setting may be the problem. Suggesting to try these steps.

    1 - S3 bucket which stores the video should configured as a static website, ensure block public access setting is OFF.

    2 - Create a S3 bucket policy that gives S3:GetObject permission to *

    3 - Test that it works first.

    4 - In Cloudfront set the S3 bucket as a custom origin

    5 - In Cloudfront configure an Origin Access Control - AWS will generate a Origin Access policy. Copy it.

    6 - Go to the S3 Bucket and edit the policy to only allow the OAI to access (paste the policy)

    7 - Back in CloudFront configure a Behaviour so that a request for the bucket is sent.

    Path pattern : /*.mp4 (example) Origin : Pick the origin created in step 4.

    Hope that worked for you.

    Here is an update with sample screenshot: enter image description here