Storage Security and Encryption
Locking data at rest, in transit and at the API
Storage security is layered: identity (who can call the API), encryption (data at rest and in transit), and access boundaries (public access blocks, policies, presigned URLs). Most storage breaches are accidental public exposure.
What you will learn
- Enable encryption at rest with provider keys or your own KMS
- Configure identity-based and bucket/container policies
- Block public access and use presigned URLs safely
Block public access by default, encrypt at rest (SSE-KMS / SSE-S3 / Azure SSE / GCS CSEK), encrypt in transit with TLS, and authorize every read/write with IAM + policies so nothing is world-readable unless you make it so.
What is this?
Encryption at rest: AWS SSE-S3 (keys managed), SSE-KMS (customer-managed), SSE-C (your keys); Azure Storage Service Encryption + customer-managed keys; GCP default server-side encryption or CSEK/CMEK. Access: bucket policies, ACLs, IAM roles, presigned URLs (time-limited), signed headers; Azure SAS tokens; GCP signed URLs. Public access blockers (S3 Block Public Access, Azure public network access, GCP uniform bucket-level access) lock the footgun.
Why do you need it?
- Public exposure is the most common real breach story in cloud audits.
- Encryption-at-rest satisfies compliance (PCI, HIPAA, GDPR) by default.
- Presigned/SAS URLs give time-limited external sharing without opening a bucket.
- A single policy review line ('no public read') reduces incident risk enormously.
Mental model
A bonded warehouse with a sign-in desk, encrypted lockers, and courier passes
Storage security
The desk (identity) checks who enters; lockers (encryption) keep contents unreadable if a thief gets past; courier passes (presigned URLs) let specific people take one crate for a short time only.
How it works
- Identity: IAM/Entra/Service Account decides 'who' with scoped permissions.
- Policy: bucket/container policies grant and deny at the resource level with conditions.
- Encryption: object write is encrypted with the bucket's key; reads decrypt at the API edge.
- Presigned URLs: sign GET/SAS for N minutes; the URL alone is the credential.
- Audit: storage access logging and CloudTrail/event logs record who did what.
Storage access decision.
Examples
Lock a bucket down
# AWS: block all public access + encrypt by defaultaws s3api put-public-access-block --bucket my-bucket \ --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=trueaws s3api put-bucket-encryption --bucket my-bucket \ --server-side-encryption-configuration '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms"}}]}'# share one object silently via presigned URLaws s3 presign s3://my-bucket/secrets/report.pdf --expires-in 600Block public access, enforce KMS encryption by default, and share time-limited URLs rather than opening the bucket.
In production
- An HR system holds PII in an S3 bucket with public-access block, SSE-KMS, and a deny-policy for anonymous principals.
- Azure storage accounts use managed identity SAS to give an azure function read-only access to a container.
- GCS buckets use Uniform bucket-level access: no per-object ACLs, policy only, CMEK enforced.
Best practices
- Start deny-by-default: block public access on every new bucket/container.
- Use managed keys where you don't need rotation control; CMEK for strong governance.
- Audit access logs and bucket policies; set a 'public read' alarm.
- Prefer presigned/SAS URLs over ACL grants for all external sharing.
Common mistakes
- Granting public-read to 'check quickly' and forgetting to revoke.
- Using the account-wide key when a bucket- or app-scoped key is safer.
- Sharing full-account credentials instead of scoped presigned URLs.
- Encryption disabled by default and never revisited after compliance flag.
Common issues
Bucket policy denies programmatic accessIAM vs bucket policy overlap and conditions
Use AWS IAM policy simulator (or Azure role explorer) to see effective permissions; align the bucket policy.
Object appears 'public' after ACL changeACL still grants Everyone read
Enable S3 Block Public Access / uniform access and remove object ACLs.
Debugging tips
- 403 on a 'public' bucket: the public-access block may override the policy — check both.
- 'Shared with anyone' errors: ACLs + policy conflict — enable uniform/consistent access.
- To find stray public buckets fast: run the provider hygiene report (Trusted Advisor / Azure Security / GCP Security Command Center).
Interview checkpoint
Hands-on lab
- Enable encryption + block public access on a bucket
- Exercise a presigned URL end to end
- Audit the effective policy
Harden an Object Store and Share via Presigned URL
30 min · intermediate
Quick quiz
What's the safest way to let an external user download one object, temporarily?