In today’s cloud-driven world, safeguarding your data while delivering content fast is essential. This guide will walk you through the process of creating a secure S3 bucket for storing and serving images. You'll learn how to configure bucket policies, CORS settings, and additional security features—all designed to keep your assets protected and accessible only to trusted sources.
1. Create the S3 Bucket
Log in to the AWS Management Console:
Navigate to the S3 service.
Create a New Bucket:
- Click Create bucket.
- Enter a unique bucket name (e.g.,
best-practices-s3
) and choose your AWS Region. - In the Block Public Access settings, enable Block all public access to prevent accidental exposure.
Important Note:
If you plan to add a bucket policy that grants limited public access using conditions like the aws:Referer
, you must disable the setting that blocks public bucket policies. Otherwise, you will encounter an error such as:
"User is not authorized to perform: s3:PutBucketPolicy ... because public policies are blocked by the BlockPublicPolicy block public access setting."
To use your custom bucket policy, disable Block public bucket policies while keeping the other block settings enabled. (Be sure to manage your policy carefully to avoid unintentional exposure.)
Finalize Creation:
Complete the steps and click Create bucket.
2. Configure Object Ownership
- Go to your bucket’s Permissions tab.
- Under Object Ownership, choose Bucket owner enforced. This setting disables Access Control Lists (ACLs) so that only your bucket policy manages access.
3. Set Up a Bucket Policy
Bucket policies control who can access your bucket’s objects. In this guide, image access is restricted to trusted domains.
Open the Bucket Policy Editor:
In the Permissions tab, click Bucket Policy.Paste the Following Policy:
Replacebest-practices-s3
with your bucket name if needed.
{
"Version": "2012-10-17",
"Id": "PolicyForTrustedAccess",
"Statement": [
{
"Sid": "AllowTrustedAccess",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::best-practices-s3/*",
"Condition": {
"StringLike": {
"aws:Referer": [
"https://*.example.com/*"
]
},
"Bool": {
"aws:SecureTransport": "true"
}
}
},
{
"Sid": "DenyNonTrustedAccess",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::best-practices-s3/*",
"Condition": {
"StringNotLike": {
"aws:Referer": [
"https://*.example.com/*"
]
}
}
}
]
}
- Save the Policy.
4. Configure CORS (Cross-Origin Resource Sharing)
CORS settings allow your images to be requested by web pages from specific domains. They also enable uploads via signed URLs if needed.
Open the CORS Configuration Editor:
In the Permissions tab, click CORS configuration.Enter the Following Configuration for GET requests:
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET"],
"AllowedOrigins": [
"https://*.example.com"
],
"ExposeHeaders": []
}
]
🟢 Important Note:
If you plan to upload images using signed URLs, you must also allow the PUT method. The configuration would then look like this:
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "PUT"],
"AllowedOrigins": [
"https://*.example.com"
],
"ExposeHeaders": []
}
]
3) Save the CORS Configuration.
Below is an example screenshot showing how image access is blocked from non-trusted sources and allowed on approved domains:
5. Enable Additional Security Features
Encryption
- Enable Server-Side Encryption: Activate SSE-S3 or SSE-KMS in your bucket properties to secure data at rest.
Logging and Monitoring
- Enable Access Logging: Turn on S3 server access logging to monitor incoming requests.
- Use AWS CloudTrail: Set up CloudTrail to log API calls for auditing and security monitoring.
6. Test Your Configuration
Upload an Image:
Use the AWS Console, CLI, or SDK to upload an image to your bucket.Access from Allowed Domains:
Add an<img>
tag on a page hosted on one of your trusted domains, for example:
<img src="https://best-practices-s3.s3.ap-south-1.amazonaws.com/uploads/images/your-image.png" alt="Test Image" width="500" height="600">
-
Verify Access:
- The image should load on trusted domains.
- Requests from unapproved sources should return a 403 Forbidden error.
7. Best Practices Recap
- Block Public Access: Always enable block public access settings to prevent accidental exposure. If you add a bucket policy that grants limited public access, disable only the Block public bucket policies setting.
- Least Privilege: Grant only the necessary permissions.
-
Enforce HTTPS:
Include
"aws:SecureTransport": "true"
in your bucket policy. - Monitor Activity: Regularly review logs from S3 and CloudTrail.
Frequently Asked Questions (FAQ)
1. Why do I need to disable 'Block public bucket policies'?
Bucket policies using conditions like aws:Referer
are considered public. If Block public bucket policies is enabled, AWS will block saving such policies. Disable this specific setting while keeping others enabled to use your custom policy.
2. Can I restrict access without using aws:Referer
?
Yes, by leveraging AWS CloudFront with signed URLs or Origin Access Control (OAC), you can enforce access without relying solely on Referer
headers.
3. What should I do if I receive a 403 Forbidden error?
Check that the aws:Referer
in your policy exactly matches the request domain, ensure your CORS configuration allows the required methods (GET/PUT), and confirm that HTTPS is used.
4. How do I avoid CORS errors when uploading with signed URLs?
Ensure that your CORS configuration includes the PUT method if you’re using signed URLs for uploads.
5. Is it safe to allow all headers (AllowedHeaders: ["*"]
)?
This setting is generally safe if you trust the domains specified in AllowedOrigins. However, consider narrowing it in high-security environments.
6. Should I enable server-side encryption?
Yes, enabling SSE-S3 or SSE-KMS is highly recommended to secure data at rest.
7. How can I monitor S3 access?
Enable S3 Server Access Logging and configure AWS CloudTrail to track API calls to your bucket.
8. What’s the difference between 'Bucket Owner Enforced' and 'Bucket Owner Preferred'?
Bucket Owner Enforced disables ACLs completely, managing access solely via bucket policies, while Bucket Owner Preferred allows ACLs but gives preference to the bucket owner.
9. Can I allow access to specific applications only?
Yes, use the aws:Referer
condition or signed URLs/signed cookies with CloudFront for tighter control.
10. What are the core best practices for securing an S3 bucket?
- Block Public Access: Prevent unintended exposure.
- Least Privilege: Grant minimal permissions.
- Enforce HTTPS: Ensure secure communication.
- Enable Encryption: Protect data at rest.
- Monitor Activity: Regularly audit access logs.
🚀 Level Up Your Image Upload Game!
If you found this guide helpful, take a moment to explore the Next.js Multi-Image Upload component on GitHub. This open-source project is designed to streamline your image upload process with powerful features like:
- 📂 Multi-Image Upload: Upload multiple files with ease.
- 💫 Progress Tracking: Visual feedback with upload progress indicators.
- 🎨 Responsive Design: Automatically adapts to any screen size.
- 🚮 Deletion Animations: Smooth, intuitive feedback when removing images.
- ✅ Seamless Form Integration: Built for use with react-hook-form.
- 🔒 Type-Safe Implementation: Written in TypeScript for robust applications.
If you like the project, consider giving it a ⭐️ star on GitHub! Your support helps open-source developers like us keep building and sharing.
Happy securing and happy coding! 🤗
For more detailed insights, visit the AWS S3 Documentation.