AWS Security Lab: Implementing Encryption with KMS and Amazon S3
Implement encryption by using AWS services
AWS Security Lab: Implementing Encryption with KMS and Amazon S3
This hands-on lab guides you through the process of implementing encryption at rest using AWS Key Management Service (KMS) and Amazon S3. You will learn how to create a Customer Managed Key (CMK), configure S3 for server-side encryption with KMS keys (SSE-KMS), and use the AWS CLI to perform programmatic encryption operations.
[!WARNING] Remember to run the teardown commands at the end of the lab to avoid ongoing charges for the KMS key ($1/month prorated) and S3 storage.
Prerequisites
- An active AWS Account.
- IAM Permissions: You must have
AdministratorAccessor a policy that allowskms:*ands3:*operations. - AWS CLI installed and configured on your local machine with access keys (
aws configure). - Basic familiarity with the AWS Management Console.
Learning Objectives
- Create and manage an AWS KMS Customer Managed Key (CMK).
- Configure an Amazon S3 bucket to use SSE-KMS for default encryption.
- Perform programmatic encryption and decryption of small data chunks (up to 4KB) using the AWS KMS API.
- Understand the metadata differences between SSE-S3 and SSE-KMS.
Architecture Overview
The Envelope Encryption Concept
\begin{tikzpicture}[node distance=2cm, auto] \draw[thick, fill=blue!10] (0,0) rectangle (3,2) node[pos=.5] {Plaintext Data}; \draw[->, thick] (3.2,1) -- (4.8,1) node[midway, above] {Encrypt}; \draw[thick, fill=red!10] (5,0) rectangle (8,2) node[pos=.5] {Ciphertext}; \draw[thick] (4, -1) circle (0.4) node {K}; \draw[->, dashed] (4, -0.6) -- (4, 0.8); \node at (4,-1.6) {Data Key}; \end{tikzpicture}
Step-by-Step Instructions
Step 1: Create a KMS Customer Managed Key (CMK)
We will start by creating a symmetric encryption key. This key will be used to protect our S3 objects and perform manual encryption operations.
CLI Interface:
aws kms create-key --description "Lab Key for S3 Encryption" \
--tags TagKey=Purpose,TagValue=BrainyBeeLabNote: Copy the KeyId (UUID) from the JSON output. You will need it for the next steps.
▶Console alternative
- Navigate to KMS in the AWS Console.
- Choose Customer managed keys in the sidebar.
- Click Create key.
- Select Symmetric and Encrypt and decrypt.
- Give it the Alias
lab-encryption-key. - Assign your current IAM user as the Key Administrator and Key User.
- Click Finish.
Step 2: Create an Encrypted S3 Bucket
Now, we will create an S3 bucket and configure it to use our new KMS key for all future object uploads by default.
CLI Interface:
# 1. Create the bucket (Replace <ID> with a random number)
aws s3 mb s3://brainybee-lab-bucket-<ID>
# 2. Apply default SSE-KMS encryption
aws s3api put-bucket-encryption \
--bucket brainybee-lab-bucket-<ID> \
--server-side-encryption-configuration '{
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "<YOUR_KEY_ID_OR_ALIAS>"
}
}
]
}'Step 3: Test Encryption with Object Uploads
Upload a simple file and verify that S3 is using the KMS key for encryption.
CLI Interface:
echo "This is secret data" > secret.txt
# Upload the file
aws s3 cp secret.txt s3://brainybee-lab-bucket-<ID>/
# Verify the encryption metadata
aws s3api head-object --bucket brainybee-lab-bucket-<ID> --key secret.txt[!TIP] In the
head-objectoutput, look for"ServerSideEncryption": "aws:kms"and yourSSEKMSKeyId.
Step 4: Programmatic Encryption (API Practice)
KMS isn't just for S3. You can use it to encrypt small bits of data (strings, passwords) directly in your code using the Encrypt API.
CLI Interface:
# Encrypt the string "MySecretPassword"
aws kms encrypt --key-id <YOUR_KEY_ID> \
--plaintext $(echo -n "MySecretPassword" | base64) \
--query CiphertextBlob --output text > encrypted_blob.txt
# View the encrypted (binary) data encoded in base64
cat encrypted_blob.txtCheckpoints
- KMS Verification: Run
aws kms list-keys. Does your new key appear in the list? - S3 Encryption: In the S3 Console, click on your bucket -> Properties. Under Default encryption, does it show SSE-KMS and your specific key ARN?
- Decryption Check: Try to decrypt the blob from Step 4:
Expected Output:bash
aws kms decrypt --ciphertext-blob fileb://<(base64 -d encrypted_blob.txt) --query Plaintext --output text | base64 -dMySecretPassword
Clean-Up / Teardown
To avoid ongoing costs, you must delete the S3 bucket and schedule the KMS key for deletion.
# 1. Empty and delete the S3 bucket
aws s3 rb s3://brainybee-lab-bucket-<ID> --force
# 2. Schedule KMS key deletion (Waiting period: 7 days)
aws kms schedule-key-deletion --key-id <YOUR_KEY_ID> --pending-window-in-days 7Troubleshooting
| Error | Possible Cause | Fix |
|---|---|---|
AccessDeniedException | IAM user lacks kms:Encrypt or kms:Decrypt | Update IAM Policy or Key Policy to include your user as a 'Key User'. |
InvalidCiphertextException | Binary data corrupted during base64 conversion | Ensure you use the fileb:// prefix when passing binary blobs to the CLI. |
MalformedPolicyDocument | JSON syntax error in bucket policy | Validate the JSON structure for the put-bucket-encryption command. |
Stretch Challenge
Goal: Enforce SSE-KMS encryption via a Bucket Policy.
Try to apply a bucket policy that denies any s3:PutObject request that does not include the header x-amz-server-side-encryption: aws:kms. This ensures that even if a developer tries to upload an unencrypted file, S3 will reject it.
Cost Estimate
| Service | Usage | Estimated Cost |
|---|---|---|
| AWS KMS | 1 Customer Managed Key | $1.00 / month (prorated to ~$0.04 for 1 day) |
| Amazon S3 | < 1GB Storage / 100 Requests | $0.00 (Free Tier eligible) |
| KMS API Calls | < 100 Requests | $0.0003 ($0.03 per 10k requests) |
Concept Review
| Feature | SSE-S3 | SSE-KMS | SSE-C |
|---|---|---|---|
| Key Managed By | AWS (S3 Service) | AWS (KMS) | Customer (External) |
| Rotation | Automatic | Automatic/Manual | Manual |
| Access Control | S3 Permissions | S3 + KMS Key Policy | Customer-side |
| Audit Trail | No (S3 logs only) | Yes (CloudTrail) | No |
Key Takeaway: Use SSE-KMS when you need audit trails and separate administrative control over who can encrypt/decrypt specific objects.