Securing Serverless Site Migrating From S3 Hosting To Amazon Cloudfront Https
Building a static site is easy, but making it professional and secure requires moving beyond basic S3 hosting. As part of my AWS Serverless Sump Chart project, I recently migrated my site to a CloudFront-driven architecture to support HTTPS and a custom domain. Here is the breakdown of how I structured the setup and the critical “gotchas” I discovered along the way.
Architecture
The setup follows a secure, serverless pattern:
User → HTTPS → CloudFront → OAC → S3 Bucket (Private)
In this configuration, S3 is no longer acting as a web server; it functions purely as private storage. CloudFront handles the heavy lifting of security, SSL termination, and content delivery.
Implementation Steps
- Request SSL Certificate: I used AWS Certificate Manager (ACM) to obtain a free SSL certificate. Note that for CloudFront usage, the certificate must be requested in the us-east-1 (N. Virginia) region.
- Configure S3 Storage: I used my existing S3 bucket containing the website files. I ensured “Block Public Access” was enabled to keep the data private from the open web.
- Create CloudFront Distribution: I set up a new distribution and selected the S3 bucket as the origin.
- Implement Origin Access Control (OAC): This is the modern way to secure the connection between CloudFront and S3. It ensures that users cannot bypass CloudFront to access your files directly.
- Apply Bucket Policy: To allow CloudFront to fetch files from my private bucket, I applied a specific policy that grants s3:GetObject permissions only to my specific CloudFront distribution ARN.
{ "Version": "2008-10-17", "Id": "PolicyForCloudFrontPrivateContent", "Statement": [ { "Sid": "AllowCloudFrontServicePrincipal", "Effect": "Allow", "Principal": { "Service": "cloudfront.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::sump-water-level/*", "Condition": { "StringEquals": { "AWS:SourceArn": "" } } } ] }
Key Lessons
While standard tutorials cover the basics, these specific steps were crucial for a working production environment:
- Disable S3 Static Website Hosting: Once you move to CloudFront with OAC, you should disable the “Static Website Hosting” feature in the S3 properties. Since S3 is now just a storage layer, leaving hosting enabled creates an unnecessary (and unencrypted) public endpoint.
- Set the Default Root Object: This is the most common reason for a “403 Forbidden” or “Access Denied” error. Because CloudFront is fetching from a storage bucket rather than a web server, it doesn’t know to look for index.html automatically. You must manually define index.html as the Default Root Object in your CloudFront settings.
- Redirect HTTP to HTTPS: To ensure a seamless user experience, I configured the CloudFront distribution behavior “Viewer Protocol Policy” to automatically redirect all insecure HTTP requests to HTTPS.
If you are following along and hitting a wall, check your IAM policy ARN and Default Root Object first—those are usually the culprits.