DEV Community

Cover image for Implement Encryption By Using AWS Services | πŸ—οΈ Create A KMS Customer Managed Key

Implement Encryption By Using AWS Services | πŸ—οΈ Create A KMS Customer Managed Key

Exam Guide: Developer - Associate
πŸ—οΈ Domain 2: Security
πŸ“˜ Task 2: Implement Encryption By Using AWS Services.

Encryption shows up everywhere, especially on this exam. S3, DynamoDB, SQS, Lambda environment variables, RDS, and more. You need to know the difference between client-side and server-side encryption, how KMS works, and when to use each approach.


πŸ“˜Concepts

Encryption at Rest vs Encryption In Transit

Encryption At Rest

Data stored on disk: S3 Objects, DynamoDB tables, EBS volumes, RDS databases.

Encryption In Transit

Data moving between services or between client and server: HTTPS, TLS, VPN.

Where At Rest In Transit
S3 SSE-S3, SSE-KMS, SSE-C HTTPS (enforced via bucket policy)
DynamoDB Encrypted by default (AWS owned or KMS) HTTPS (always)
RDS KMS encryption SSL/TLS connections
SQS SSE-KMS HTTPS
Lambda env vars KMS (default + optional CMK) HTTPS

KMS Key Types

Type Managed By Cost Use Case
AWS owned keys AWS Free Default encryption (DynamoDB, S3 SSE-S3)
AWS managed keys AWS (in your account) Free (per-use charges) aws/s3, aws/dynamodb (you can't manage them)
Customer managed keys (CMK) You Monthly + per-use Full control: rotation, policies, cross-account

Envelope Encryption

KMS can only directly encrypt up to 4 KB. For larger data, it uses envelope encryption:

1. KMS generates a data key (plaintext + encrypted copy)
2. You encrypt your data with the plaintext data key
3. You store the encrypted data key alongside the encrypted data
4. You discard the plaintext data key from memory
5. To decrypt: KMS decrypts the data key β†’ you decrypt the data

The AWS Encryption SDK handles this automatically.

Server-Side Encryption Options for S3

Option Key Management Use Case
SSE-S3 AWS manages everything Simplest, no KMS costs
SSE-KMS You control the KMS key Audit trail via CloudTrail, key policies
SSE-C You provide the key with every request Full key control, AWS doesn't store the key

Client-Side vs Server-Side Encryption

Aspect Server-Side Client-Side
Who encrypts AWS (after receiving data) You (before sending to AWS)
Data in transit Encrypted by HTTPS Encrypted by you + HTTPS
Key management AWS or KMS You (via KMS or your own keys)
Complexity Simple More complex
Use case Most workloads When you can't trust the storage layer

Key Rotation

  • AWS managed keys: Rotated every year automatically (can't change this)
  • Customer managed keys: Enable automatic rotation (every year)
  • Old key material is kept, existing encrypted data still works
  • The key ID doesn't change with automatic rotation
  • Manual rotation: Create a new key, update alias to point to it

Certificate Management

Service What It Does Cost
ACM Free public SSL/TLS certificates for AWS services Free
AWS Private CA Issue private certificates for internal services Paid

πŸ’‘ACM certificates can't be exported. They're bound to AWS services (CloudFront, ALB, API Gateway). They auto-renew.


πŸ—οΈ Create A KMS Customer Managed Key

Now let's put these concepts into practice:

  • Create a KMS customer managed key
  • Encrypt and decrypt data using KMS
  • Upload objects to S3 with different encryption options (SSE-S3, SSE-KMS)
  • Enable automatic key rotation
  • Encrypt Lambda environment variables with a custom KMS key

Prerequisites


Part I

Create a KMS Customer Managed Key

Step 01: Open the KMS console
Click Create key

Step 02: Configure key

  • Key type: Symmetric
  • Key usage: Encrypt and decrypt

Click Next

Step 03: Add labels

  • Alias: app-encryption-key
  • Description: Customer managed key for application data

Click Next

Step 04: Define key administrative permissions - optional

  • Key administrators: Select your IAM user

Click Next

Step 05: Define key usage permissions - optional

  • Key administrators: Select your IAM user

Click Next

Step 06: Edit key policy - optional
Click Next

Step 07: Review
Click Finish

βœ…Green banner: Success
Your AWS KMS key was created with alias app-encryption-key and key ID 17fx7cex-17ae-419x-x816-de16fx50x928.

πŸ’‘ You now have a customer managed KMS key. Note the Key ID and ARN.

Enable Automatic Key Rotation

Step 08: Click on your key (app-encryption-key)

Step 09: Go to the Key material rotations tab
Click Edit

Step 10: Edit automatic key rotation

  • Key rotation: Enable
  • Rotation period in days: 365

Click Save

βœ…Green banner: Successfully enabled automatic key rotation

πŸ’‘ With automatic rotation, KMS keeps old key material so existing ciphertext can still be decrypted. The key ID and ARN don't change. With manual rotation (creating a new key), you get a new key ID. Use aliases to abstract this.


Part II

Encrypt and Decrypt Data with KMS

Using the Console

πŸ’‘ In the KMS console, you can't directly encrypt/decrypt from the UI

Step 01: Create a Lambda function to demonstrate
Lambda β†’ Create function:

  • Name: KMSEncryptionDemo
  • Runtime: Python 3.12
  • Deploy: Code:
import json
import boto3
import base64

kms = boto3.client('kms')
KEY_ID = 'alias/app-encryption-key'

def lambda_handler(event, context):
    """
    Demonstrates KMS encrypt/decrypt operations.

    Key concepts:
    - KMS can directly encrypt up to 4 KB
    - For larger data, use GenerateDataKey (envelope encryption)
    - The AWS Encryption SDK handles envelope encryption automatically
    """
    action = event.get('action', 'encrypt')
    plaintext = event.get('data', 'Hello, this is sensitive data!')

    if action == 'encrypt':
        # Encrypt data (up to 4 KB)
        response = kms.encrypt(
            KeyId=KEY_ID,
            Plaintext=plaintext.encode('utf-8')
        )
        ciphertext_b64 = base64.b64encode(response['CiphertextBlob']).decode('utf-8')

        return {
            'statusCode': 200,
            'body': json.dumps({
                'message': 'Data encrypted successfully',
                'ciphertext': ciphertext_b64,
                'keyId': response['KeyId']
            })
        }

    elif action == 'decrypt':
        # Decrypt data
        ciphertext = base64.b64decode(event['ciphertext'])
        response = kms.decrypt(CiphertextBlob=ciphertext)

        return {
            'statusCode': 200,
            'body': json.dumps({
                'message': 'Data decrypted successfully',
                'plaintext': response['Plaintext'].decode('utf-8')
            })
        }

    elif action == 'generate_data_key':
        # Generate a data key for envelope encryption
        response = kms.generate_data_key(
            KeyId=KEY_ID,
            KeySpec='AES_256'
        )

        return {
            'statusCode': 200,
            'body': json.dumps({
                'message': 'Data key generated (envelope encryption)',
                'plaintextKey': '*** exists in memory only β€” use it to encrypt, then discard ***',
                'encryptedKey': base64.b64encode(response['CiphertextBlob']).decode('utf-8'),
                'note': 'Store the encrypted key alongside your encrypted data'
            })
        }
Enter fullscreen mode Exit fullscreen mode

Step 02: Add KMS permissions to the Lambda role:
Configuration β†’ Permissions β†’ click role name
Add permissions β†’ Attach policies β†’ AWSKeyManagementServicePowerUser

Step 03: Test events
Encrypt:

{"action": "encrypt", "data": "My secret credit card number"}
Enter fullscreen mode Exit fullscreen mode

Generate data key:

{"action": "generate_data_key"}
Enter fullscreen mode Exit fullscreen mode

Part III

S3 Encryption Options

Create an S3 Bucket

Step 01: Open the S3 console β†’ Create bucket

Step 02: General configuration

  • Bucket type: General purpose
  • Bucket namespace: Account Regional namespace (recommended)
  • Bucket name prefix: dva-encryption-demo
  • Encryption type: Server-side encryption with Amazon S3 managed keys (SSE-S3)

Step 03: Upload with SSE-S3 (Default)

  • Click Upload
  • Click Add files
  • Add a file (any text file)
  • Click Upload

πŸ’‘SSE-S3 is applied automatically

Step 04: Upload with SSE-KMS

  • Click Upload
  • Click Add files
  • Expand β–Ά Properties
  • Server side encryption: Specify an encryption key
  • Encryption settings: Override bucket settings for default encryption
  • Encryption type: Server-side encryption with AWS Key Management Service keys (SSE-KMS)
  • AWS KMS Key: Choose from your AWS KMS keys
  • Available AWS KMS Key: app-encryption-key
  • Click Upload

Step 05: Verify Encryption
Click on each uploaded file

Step 06: Go to the Properties tab β†’ Server-side encryption settings
You'll see which encryption method was used

πŸ’‘SSE-KMS gives you an audit trail in CloudTrail (every encrypt/decrypt call is logged). SSE-S3 does not. If a question mentions "audit" or "compliance," SSE-KMS is usually the answer.


Part IV

Encrypt Lambda Environment Variables

Using a Custom KMS Key

Step 01: Open your KMSEncryptionDemo function

Step 02: Configuration β†’ Environment variables β†’ Edit

Step 03: Edit environment variables
Click Add environment variable

  • Key: DB_PASSWORD
  • Value: super-secret-password

Step 04: Expand β–Ά Encryption configuration

  • Encryption in transit: βœ” Check Enable helpers for encryption in transit
  • AWS KMS key to encrypt at rest: Use a customer managed key
  • Select app-encryption-key
  • Click the Encrypt button next to DB_PASSWORD

Click Save

The value is now encrypted.
In your code, you'd decrypt it:

import boto3
import base64
import os

kms = boto3.client('kms')

# Decrypt at cold start, cache the result
ENCRYPTED = os.environ['DB_PASSWORD']
DECRYPTED = kms.decrypt(
    CiphertextBlob=base64.b64decode(ENCRYPTED)
)['Plaintext'].decode('utf-8')

def lambda_handler(event, context):
    # Use DECRYPTED: already decrypted at cold start
    print(f"Password length: {len(DECRYPTED)}")  # Don't log the actual password!
Enter fullscreen mode Exit fullscreen mode

πŸ—οΈ What You Built | πŸ“˜ Exam Concepts Recap

What You Built Exam Concept
Created a Customer Managed KMS key Key types: AWS owned vs AWS managed vs customer managed
*Assigned key administrators and key users * KMS key policies: separate admin and usage permissions
Enabled automatic key rotation Old key material preserved, key ID unchanged, seamless decryption
Encrypted data directly with kms.encrypt() KMS direct encryption: limited to 4 KB
Called generate_data_key for AES-256 Envelope encryption: encrypt large data locally, protect the key with KMS
Discarded the plaintext data key after use Security best practice: plaintext key lives only in memory
Uploaded S3 objects with SSE-S3 Default encryption: AWS manages everything, no audit trail
Uploaded S3 objects with SSE-KMS Audit trail in CloudTrail, key policy control, cross-account possible
Encrypted Lambda environment variables with a CMK Protecting secrets at rest in Lambda configuration
Decrypted env vars at cold start and cached the result Performance pattern: avoid decrypting on every invocation

⚠️ Clean Up Protocol

  1. S3 β†’ Empty and delete the bucket
  2. Lambda β†’ Delete KMSEncryptionDemo
  3. KMS β†’ Schedule key deletion (7-day minimum waiting period)
  4. IAM β†’ Delete Lambda execution roles
  5. CloudWatch β†’ Delete log groups

Key Takeaways

  1. KMS encrypts up to 4 KB directly: use envelope encryption (GenerateDataKey) for larger data
  2. SSE-S3: simplest. SSE-KMS: audit trail + key control. SSE-C: you provide the key.
  3. Client-side encryption: you encrypt before sending to AWS
  4. Automatic key rotation keeps old key material and existing data ia still decryptable
  5. Use aliases for seamless manual key rotation
  6. Cross-account KMS requires both a key policy AND an IAM policy
  7. ACM = free public certs (can't export). Private CA = private certs (costs money).
  8. Envelope encryption: the AWS Encryption SDK handles this for you

Additional Resources


πŸ—οΈ

Top comments (0)