Setting the file. One moment.
Chapter 113 · Securing S3 Buckets
Subchapter 113.4
references/remediation.mdMarkdown5 KBView on GitHub
aws s3api put-public-access-block \
--bucket <bucket-name> \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
# WARNING: Do NOT delete the entire bucket policy — it may contain critical controls (HTTPS enforcement, VPC restrictions, etc.).
# Instead, surgically remove only the offending public-grant statement(s):
# 1. Review the current policy:
aws s3api get-bucket-policy --bucket <bucket-name> --output text | jq .
# 2. Back up existing policy before modification:
aws s3api get-bucket-policy --bucket <bucket-name> --output text > backup-policy-$(date +%s).json
# 3. Remove only statements with "Principal": "*" or "AWS": "*" that grant public access.
# 4. Re-apply the scoped-down policy:
aws s3api put-bucket-policy --bucket <bucket-name> --policy file://scoped-down-policy.json
# Verify
aws s3api get-public-access-block --bucket <bucket-name># Set default encryption
aws s3api put-bucket-encryption \
--bucket <bucket-name> \
--server-side-encryption-configuration \
'{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"},"BucketKeyEnabled":true,"BlockedEncryptionTypes":{"EncryptionType":["SSE-C"]}}]}'
# Re-encrypt existing objects
# ⚠️ WARNING: --metadata-directive REPLACE without --metadata drops all user-defined metadata.
# Before running, verify no objects carry custom metadata:
# aws s3api head-object --bucket <bucket-name> --key <sample-key>
# If objects have custom metadata, use a per-object script that reads
# metadata via head-object and re-supplies it with --metadata on copy.
aws s3 cp s3://<bucket-name>/ s3://<bucket-name>/ \
--recursive --sse AES256 --metadata-directive REPLACEaws s3api put-bucket-encryption \
--bucket <bucket-name> \
--server-side-encryption-configuration \
'{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms","KMSMasterKeyID":"<key-arn>"},"BucketKeyEnabled":true,"BlockedEncryptionTypes":{"EncryptionType":["SSE-C"]}}]}'You MUST apply a least-privilege key policy — do NOT create a key without --policy file://key-policy.json. See encryption.md § Least-Privilege KMS Key Policy Template for the full template.
# 1. Save the key-policy.json template from encryption.md (replace placeholders)
# 2. Create customer managed key with least-privilege policy
aws kms create-key --description "S3 encryption key" --policy file://key-policy.json
# 3. Update bucket encryption to use the new key (full ARN, not alias)
aws s3api put-bucket-encryption \
--bucket <bucket-name> \
--server-side-encryption-configuration \
'{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms","KMSMasterKeyID":"arn:aws:kms:<region>:<account>:key/<key-id>"},"BucketKeyEnabled":true,"BlockedEncryptionTypes":{"EncryptionType":["SSE-C"]}}]}'aws s3api put-bucket-encryption \
--bucket <bucket-name> \
--server-side-encryption-configuration \
'{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"},"BucketKeyEnabled":true,"BlockedEncryptionTypes":{"EncryptionType":["SSE-C"]}}]}'Enable either S3 server access logging or CloudTrail data events — one is sufficient.
Option A — S3 Server Access Logging (no per-request charge; you pay only for log file storage in S3):
aws s3api put-bucket-logging \
--bucket <bucket-name> \
--bucket-logging-status \
'{"LoggingEnabled":{"TargetBucket":"<logging-bucket>","TargetPrefix":"<bucket-name>/"}}'Option B — CloudTrail Data Events (per-event charge applies; provides full IAM principal attribution, logs anonymous requests and AccessDenied failures, and supports real-time alerting):
# IMPORTANT: use the trail's home region, not the bucket's region
aws cloudtrail describe-trails --query 'trailList[*].[Name,HomeRegion]'
aws cloudtrail put-event-selectors \
--trail-name <trail-name> \
--region <trail-home-region> \
--event-selectors '[{"ReadWriteType":"All","IncludeManagementEvents":true,"DataResources":[{"Type":"AWS::S3::Object","Values":["arn:aws:s3:::<bucket-name>/*"]}]}]'Action to minimum requiredCondition blocks to restrict by IP, VPC, or MFA# Simulate effective permissions before changing
aws iam simulate-principal-policy \
--policy-source-arn <role-arn> \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::<bucket-name>/keyDiagnosis order:
simulate-principal-policyget-bucket-policyget-public-access-block