Access Images Stored in AWS S3

I built a very simple image storage solution for a client. The solution stored imagery in an S3 bucket. The images were retrieved by various components referencing the image’s S3 URL. One of the developers asked for guidance on how to access imagery from the bucket.

Step-1: Create the Bucket

AWS provides a fantastic article for folks new to S3: Getting Started with
Amazon Simple Storage Service
. The piece includes guidance on creating an S3 bucket through the AWS console. I’ll create the bucket using the AWS CLI:

aws s3 mb s3://nameofmybucket

Step-2: Grant Read Access to the Bucket

For this example, I’m going to make objects in the bucket publicly accessible. To make that change, you’ll need to shoot over to the bucket’s Permissions tab in the console:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<your-bucket-name>/*"
        },
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::<your-bucket-name>"
        }
    ]
}
  1. Select the CORS configuration block:
  2. Add the following policy to the CORS confiration editor and click Save.
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>5000</MaxAgeSeconds>
        <ExposeHeader>x-amz-request-id</ExposeHeader>
        <ExposeHeader>x-requested-with</ExposeHeader>
        <ExposeHeader>Content-Type</ExposeHeader>
        <ExposeHeader>Content-Length</ExposeHeader>
        <ExposeHeader>x-amz-server-side-encryption</ExposeHeader>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

What did you just do? You’ve removed the default safety measures AWS employs to prevent public access to your bucket, and you’ve created a bucket policy (affects the whole bucket) that permits folks to list the buckets contents and read files from the bucket. Lastly, you’ve enable cross-origin access to the bucket.

CORS is a security feature built into modern browsers, which prohibits a site from access content from a site on a different domain. You can read about CORS from here.

Step-3: Create Your Web Page

The following is my 3rd grade quality simplistic web page:

<html>

<head>
    <title>Web Page with Images Hosted on S3</title>
    <script>
        function downloadArtwork() {
            const imageUrl = "https://nameofmybucket.s3.us-east-2.amazonaws.com/funny_cats.jpg";
            const requestType = 'GET';
            const isAsyncOperation = true;

            // Get the image from S3
            const request = new XMLHttpRequest();

            // Initiate image retrieval
            request.open(requestType, imageUrl, isAsyncOperation);

            // Handle the data you get back from the retrieve call
            request.onload = function () {
                let binary = "";

                // New image object
                const image = new Image();
                const response = request.responseText;

                // Convert the gobbly-gook you get into something your
                // browser can render
                for (i = 0; i < response.length; i++) {
                    binary += 
                        String.fromCharCode(response.charCodeAt(i) & 0xff);
                }

                image.src = 'data:image/jpeg;base64,' + btoa(binary);

                // Link the image data to the image tag/node in your page
                const imageFromS3 = 
                    document.getElementById('exampleImageFromS3');
                imageFromS3.src = image.src;
            }

            request.overrideMimeType('text/plain; charset=x-user-defined');
            request.send();
        }
    </script>
</head>

<body onload="downloadArtwork()">
    <h1>Option-1: Reference the file host in S3</h1> <img
        src="https://nameofmybucket.s3.us-east-2.amazonaws.com/funny_cats.jpg" alt="Using 'img'">
    <h1>Option-2: Download the file from S3</h1> <img src="#" id="exampleImageFromS3" alt="using JavaScript" />
</body>

</html>

The page access the funny_cats.jpg image from my S3 bucket in one of two ways:

  • Option-1: Link directly to the image in the bucket
  • Option-2: Use JavaScript to retrieve the image and add it to the page

And, there are the Gotchas…

When I first created this sketch, I didn’t have CORS enabled on my bucket. I wanted to see the headers coming back from S3, and I didn’t want the browser and page in the way. So, I mimicked the pull with cURL:

curl -H "Origin: https://whatever.net" \
-H "Access-Control-Request-Method: GET" \
-H "Access-Control-Request-Headers: X-Requested-With" \
-X OPTIONS \
--verbose \
https://nameofmybucket.s3.us-east-2.amazonaws.com/funny_cats.jpg

You’re looking for the Access-Control-Allow-origin header on the response, and an HTTP response code of 200.

You can also see the headers associated with HTTP calls from a page in the Chrome.

  1. Select Developer Tools: (Elipse) > More Tools > Developer Tools.
  2. Select the Network tab.
  3. Select the name of the image file from the pane on the left in the console to see the headers associated with its request/response.
|