amazon-web-servicesamazon-s3amazon-ec2

EC2-hosted website cannot access public S3 URL


I've been working on a web application that wants to retrieve a CSS file (self-hosted FontAwesome assets), currently living on Amazon S3. The import tag looks like the following:

<link rel="stylesheet" href="https://docsbymario-env.s3.eu-north-1.amazonaws.com/fontawesome/css/all.min.css?v=1.0">

However, looking at the console, I get a 403 Forbidden status code on the GET request.

My bucket policies explicitly allow requests coming from the EC2 machines that host the website (created by my Beanstalk environment), and also to some IAM role (for CodePipeline). The policy statements look like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowListBucketToRole",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::390527449299:role/DocsByMarioRole"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::docsbymario-env"
        },
        {
            "Sid": "AllowReadAccessToRole",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::390527449299:role/DocsByMarioRole"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::docsbymario-env/*"
        },
        {
            "Sid": "AllowListBucketToIPs",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::docsbymario-env",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "13.51.220.94/32",
                        "16.16.36.18/32"
                    ]
                }
            }
        },
        {
            "Sid": "AllowReadAccessToIP",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::docsbymario-env/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "13.51.220.94/32",
                        "16.16.36.18/32"
                    ]
                }
            }
        }
    ]
}

The two IP addresses above are the public IP addresses of the EC2 instances I want to load the CSS script to.

I have also enabled public access to my S3 bucket. CodePipeline can properly access the bucket through the role, but EC2 cannot, using the last two IP-based bucket policies.

I thought it might also be CORS-related, so i tried adding CORS policies into the bucket:

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET"
        ],
        "AllowedOrigins": [
            "http://docsbymario.com",
            "http://api.docsbymario.com"
        ],
        "ExposeHeaders": [
            "ETag"
        ],
        "MaxAgeSeconds": 3000
    }
]

... where the two domain names actually point to those two public IP addresses. No change, however.

What could be the problem?


Solution

  • Your Security Group is restricting S3 access to the IP addresses given, which belong to the Amazon EC2 instances.

    However, the HTML web page with the <link> is processed by end-users on their own web browser. Therefore, the IP address requesting the CSS stylesheet will actually be associated with the end-users's computer rather than the EC2 instance running the web server.

    For resources like stylesheets and fonts, you'll typically make the public so that any IP address can access them.