- Block all public access on buckets by default.
- Use pre-signed URLs to grant temporary access to private objects instead of making buckets public.
- Block all public access at the account or bucket level by default.
- Require encryption at rest (SSE-S3 or SSE-KMS) and transit (HTTPS) for all buckets.
- Use S3 pre-signed URLs (GET/PUT) to grant clients direct, temporary access to objects, bypassing mid-tier API bottlenecks.
- Implement lifecycle rules to automatically transition older objects to Glacier or expire them.