Encrypt at rest, client side and in transit with one private S3 bucket

short · 25 min · Task statement 2.2

Task

Show three kinds of protection on one private bucket. You confirm that Amazon S3 encrypts every new object at rest by default (server-side encryption), you encrypt a file yourself before it leaves CloudShell so that S3 only ever stores ciphertext (client-side encryption), and you add a bucket policy that refuses any request not sent over TLS (encryption in transit). At the end you can say who holds the key in each case and why encryption still does not replace IAM permissions.

Steps

  1. Create a private bucket and read its default encryption:
aws s3 mb s3://clf-lab08-111122223333
aws s3api get-bucket-encryption --bucket clf-lab08-111122223333 --query 'ServerSideEncryptionConfiguration.Rules[0].ApplyServerSideEncryptionByDefault.SSEAlgorithm'

It reads "AES256": server-side encryption with Amazon S3 managed keys (SSE-S3) is on before you have done anything. 2. Write a short note of invented text and upload it, then ask S3 how the stored object is encrypted:

echo 'Lab 8 sample note: invented text, nothing real.' > note.txt
aws s3 cp note.txt s3://clf-lab08-111122223333/note.txt
aws s3api head-object --bucket clf-lab08-111122223333 --key note.txt --query ServerSideEncryption

It reads "AES256". That is encryption at rest. S3 decrypts the object for any identity that IAM allows to read it, which is why access control still matters. 3. Now encrypt on the client side. Choose a passphrase you will remember for the next ten minutes; OpenSSL asks for it twice:

openssl enc -aes-256-cbc -pbkdf2 -in note.txt -out note.txt.enc
aws s3 cp note.txt.enc s3://clf-lab08-111122223333/note.txt.enc

S3 adds its own server-side layer as usual, but it never sees your passphrase. 4. Download the encrypted copy and look at it, then decrypt it with your passphrase:

aws s3 cp s3://clf-lab08-111122223333/note.txt.enc downloaded.enc
head -c 8 downloaded.enc; echo
openssl enc -d -aes-256-cbc -pbkdf2 -in downloaded.enc -out decrypted.txt
cat decrypted.txt

The first eight bytes read Salted__, the OpenSSL header, and the rest is unreadable until you decrypt it. With client-side encryption the key and the process are yours to manage. 5. Require encryption in transit. Write a bucket policy that denies every request sent without TLS, then apply it:

echo '{"Version": "2012-10-17", "Statement": [{"Sid": "DenyInsecureTransport", "Effect": "Deny", "Principal": "*", "Action": "s3:*", "Resource": ["arn:aws:s3:::clf-lab08-111122223333", "arn:aws:s3:::clf-lab08-111122223333/*"], "Condition": {"Bool": {"aws:SecureTransport": "false"}}}]}' > deny-http.json
aws s3api put-bucket-policy --bucket clf-lab08-111122223333 --policy file://deny-http.json
aws s3api get-bucket-policy-status --bucket clf-lab08-111122223333 --query PolicyStatus.IsPublic

It reads false. A Deny statement takes access away from every request that skips TLS; it grants nothing to anyone, so the bucket is no more public than before. 6. See that the AWS CLI already talks to S3 over HTTPS, which is why your own commands still work under that policy:

aws s3 ls s3://clf-lab08-111122223333 --debug 2>&1 | grep -o -m 1 'https://[^/]*amazonaws.com'

The address starts with https://. For a website you would use a TLS certificate from AWS Certificate Manager, and between your own network and a VPC, AWS Site-to-Site VPN. Neither is needed here.

Verify

aws s3api list-objects-v2 --bucket clf-lab08-111122223333 --query KeyCount

Expected output: 2 (note.txt and note.txt.enc).

aws s3api head-object --bucket clf-lab08-111122223333 --key note.txt.enc --query ServerSideEncryption --output text

Expected output: AES256.

aws s3api get-bucket-policy-status --bucket clf-lab08-111122223333 --query PolicyStatus.IsPublic

Expected output: false.

Cost and clean-up

Two tiny objects in one bucket are within the AWS Free Tier for most accounts, but S3 storage and requests may be charged. SSE-S3 adds no key for you to manage or delete.

Created by this lab: the bucket clf-lab08-111122223333, with its bucket policy; the objects note.txt and note.txt.enc in it; the CloudShell files note.txt, note.txt.enc, downloaded.enc, decrypted.txt and deny-http.json.

  1. Empty and delete the bucket. This removes note.txt, note.txt.enc and the bucket policy with it; the policy does not block you, because the CLI uses TLS:
aws s3 rb s3://clf-lab08-111122223333 --force
  1. Remove the working files from CloudShell:
rm note.txt note.txt.enc downloaded.enc decrypted.txt deny-http.json

Check it is gone

aws s3api list-buckets --query "length(Buckets[?Name=='clf-lab08-111122223333'])"

Expected output: 0.

Notes

Who holds the key: with SSE-S3, Amazon S3 manages the keys for you; with SSE-KMS the keys live in AWS KMS and key policies decide who may use them; with client-side encryption you hold the key, and losing your passphrase would lose the data. A regulator that requires single-tenant hardware for keys points to AWS CloudHSM instead of KMS. The detection services in the lesson (GuardDuty, Inspector, Security Hub, Detective, Macie) are worth reading about in the console, but each one starts a trial or a charge when it is turned on, so this lab leaves them all off.

This is an independent study companion for the AWS Certified Cloud Practitioner (CLF-C02) exam and is not produced by or endorsed by Amazon Web Services. AWS, Amazon Web Services and AWS Certified Cloud Practitioner are trademarks of Amazon.com, Inc. or its affiliates.

This is an independent study companion for AWS Certified Cloud Practitioner CLF-C02 and is not produced by or endorsed by CompTIA.