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",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::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..