Image Resizing after Upload with Amazon S3, AWS Lambda and CloudFront for SSL

Author profile picture

@manjiltamangManjil Tamang

Full stack developer | Design enthusiast

When developing an application it is important to have assets resized for different capabilities, screen sizes, and resolutions. This is important for many reasons.
  1. Low resolution images on high resolution displays make a bad UX
  2. High resolution images on low resolution displays waste both bandwidth and device and server resources
  3. Creating several thumbnails during image upload, can be a lot of workand limits the agility for future redesigns.
  4. Adopting an image in-app and cropping/resizing it may be heavy for the app especially if you use Frameworks.

Resizing on the fly

Instead of processing and resizing images into all necessary sizes upon upload, the approach of processing images on the fly has several upsides:
  1. Increased agility
  2. Reduced storage costs
  3. Resilience to failure
In this post, we’ll be using a different approach and outline a method of lazily generating images, in which a resized asset is only created if a user requests that specific size.

Creating a new bucket

Open s3 console
  • You can create new bucket or use existing one but make sure the bucket’s read access permission is set to public.
  • Create new bucket, uncheck Block all public access
  • Go to permissions tab then choose bucket policy
  • To grant read-only permission to an anonymous user. Copy and paste this configuration to your bucket policy. Make sure to replace YOUR_BUCKET_NAME_HERE with the name of the bucket. You can read about bucket policy more in here
  • {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "PublicRead",
                "Effect": "Allow",
                "Principal": "*",
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::YOUR_BUCKET_NAME_HERE/*"
            }
        ]
    }
  • 6. Choose save
  • Go to properties tab
  • Choose static web hosting
  • Choose use this bucket to host a website
  • For index document, enter index.html
  • Choose save. We’ll come later and add redirection rule but for now just leave it empty.
  • Note the website’s endpoint*

Creating CloudFront distribution for SSL

Open CloudFront console
  • Choose create distribution
  • Choose web distribution
  • Enter the static website’s endpoint that was noted previously, for origin domain name
  • For viewer protocol policy — choose Redirect HTTP to HTTPS
  • For object chaching choose customizeset minimum and default TTL to 0 and maximum TTL to 31536000
  • Rest of the configuration you can leave as it is.
  • You can now choose create distribution
This can take few mins, wait until the status changes from ‘in progress’ to ‘deployed’. After the status is changed to deployed, note the CloudFront domain name. It should look similar to blabla.cloudfront.net

Setting up permission for Lambda function

Open IAM console
Creating policy:
  • In the IAM console select Policies from the dashboard to the left
  • Choose create policy
  • Navigate to JSON tab
  • Replace YOUR_BUCKET_NAME_HERE with the name of the bucket that you’ve created and copy the following code into the policy document. Note that any leading spaces in your policy may cause a validation error.
  • {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents"
                ],
                "Resource": "arn:aws:logs:*:*:*"
            },
            {
                "Effect": "Allow",
                "Action": "s3:PutObject",
                "Resource": "arn:aws:s3:::__YOUR_BUCKET_NAME_HERE__/*"
            }
        ]
    }
  • Choose review policy
  • Enter your policy name
  • You can use any name but just for simplicity we’ll use the name imageResizePolicy
  • Create policy
Creating role:
  • In the IAM console select Roles from the dashboard to the left
  • Select create role
  • Choose Lamda in for a use case, next
  • In permission section search for the imageResizePolicy that you just created and choose that, nextYou can skip the tags section and choose Next
  • In review section, enter role name, you can use any name but for the sake of simplicity we’ll be using the name imageResizeRole
  • Create role

Creating Lambda function

Open Lambda console
  • In the lambda console choose create function
  • For function name enter your function name, now of course you can choose any name for just to be safe use imageResize as your function name. So that it’ll be easy for you to follow along.
  • Choose Node.js 12.x as a runtime. Again you can choose any other language but we’re going to choose Node. You don’t need to worry about it as this lamba function works completely independent from your application. The only purpose it’ll serve is to provide you with resized images on fly.
  • Expand the permission dropdown and select use existing role.
  • Select imageResizeRole
  • Choose create function
  • Now choose add trigger and select API Gateway from the dropdown
  • For API type choose HTTP API
  • To allow all users to invoke the API method, for Security, choose Open and then Add.
  • Now back to the main function window, you’ll see function code section.
  • For code entry type choose upload a zip file
  • Download function.zip file from this link and upload the zip file, choose save from top right corner
  • To configure your function environment variables add two variables:
  • For key, and enter BUCKET; for value, enter the bucket name that you created above.
  • For key, enter URL; for value enter the domain the you created above from CloudFront, similar to blabla.cloudfront.net
  • On the main function window, choose API gateway and scroll a bit till you see our function’s API endpoint.
    Note the full path of the endpoint, depending upon your personal configuration these might be slightly different.

Setting up S3 redirection rule

Ok we’re almost there, phew that was a lot of configurations.
  • In s3 console, open the bucket that you created above.
  • To to properties and expand static website hosting, edit redirection rules.
  • Replace YOUR_API_HOSTNAME_HERE (similar to blabla.execute-api.us-east-1.amazonaws.com) with the hostname that you noted above and copy the following into redirection rules configuration.
  • Notice the path inside <ReplaceKeyPrefixWith> tag, it’s the same from the one we noted above in picture. If your path is different the update it with your path.
<RoutingRules>
  <RoutingRule>
    <Condition>
      <KeyPrefixEquals/>
      <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
    </Condition>
    <Redirect>
      <Protocol>https</Protocol>
      <HostName>__YOUR_API_HOSTNAME_HERE</HostName>
      <ReplaceKeyPrefixWith>default/imageResize?key=</ReplaceKeyPrefixWith>
      <HttpRedirectCode>307</HttpRedirectCode>
    </Redirect>
  </RoutingRule>
</RoutingRules>

Test image resizing

Upload a test image into your bucket to for testing. Once uploaded, try to retrieve resized versions of the image using your CloudFront domain:
  • https://YOUR_CLOUDFRONT_DOMAIN/300×300/{image_name.jpg}
  • https://YOUR_CLOUDFRONT_DOMAIN/25×25/{image_name.jpg}
  • https://YOUR_CLOUDFRONT_DOMAIN/500×500/{image_name.jpg}
You should see a smaller version of the test photo. If not, choose Monitoring in your Lambda function and check CloudWatch Logs for troubleshooting. You can also refer to the serverless-image-resizing GitHub repo for a working example that you can deploy to your account.

YOU MADE IT!!! 🚀🎉🎊

Comments

Tags

The Noonification banner

Subscribe to get your daily round-up of top tech stories!