Securing a statically hosted website on AWS (like one served through Amazon S3 + CloudFront) involves several layers of security controls. Here's a comprehensive breakdown and guide:
{
{
"Version": "2012-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::YOUR-AWS-ACCOUNT-ID:distribution/DISTRIBUTION-ID"
}
}
}
]
}
Or use Origin Access Control (OAC) with CloudFront for secure access.
These can’t be set directly in S3, so use CloudFront Function or Lambda@Edge to inject them:
function handler(event) {
var response = event.response;
var headers = response.headers;
headers['strict-transport-security'] = { value: 'max-age=63072000; includeSubDomains; preload' };
headers['content-security-policy'] = { value: "default-src 'self';" };
headers['x-content-type-options'] = { value: 'nosniff' };
headers['x-frame-options'] = { value: 'DENY' };
headers['x-xss-protection'] = { value: '1; mode=block' };
headers['referrer-policy'] = { value: 'no-referrer' };
return response;
}
Secure cache invalidation with:
aws cloudfront create-invalidation --distribution-id DIST_ID --paths "/*"
Control | Applied? |
---|---|
S3 public access blocked | ✅ |
HTTPS enforced via CloudFront | ✅ |
ACM TLS cert configured | ✅ |
HTTP security headers via Lambda@Edge | ✅ |
CloudFront WAF rules (optional) | ✅/🔲 |
Access logs on S3 and CloudFront | ✅ |
CI/CD secure deployment pipeline | ✅/🔲 |
CloudTrail enabled | ✅ |
Implementation can vary..