Ddb Customer KMS Keys Remediation
Triage and Remediation
- Remediation
Remediation
Using Console
Below are step‑by‑step console instructions to ensure DynamoDB tables use a customer‑managed KMS key (CMK) instead of the default AWS owned key.
1. Create (or Identify) a KMS CMK
- Sign in to the AWS Management Console.
- Go to AWS Key Management Service (KMS):
- In the search bar, type KMS and open Key Management Service.
- In the left pane, choose Customer managed keys.
- Click Create key.
- Configure the key:
- Key type: Symmetric.
- Key usage: Encrypt and decrypt.
- Click Next.
- Set Alias (e.g.,
alias/dynamodb-table-kms-key), optional description. - Configure Key administrators and Key users:
- Make sure the IAM roles/users that manage/operate DynamoDB have permission to use this key.
- Finish the wizard:
- Review and click Finish (or Create key).
You now have a CMK that can be used by DynamoDB.
2. Update an Existing DynamoDB Table to Use the CMK
- Go to the DynamoDB console.
- In the left pane, click Tables.
- Click on the table you want to remediate.
- In the table’s page, choose the Additional settings / Encryption tab (exact label may vary slightly).
- Under Encryption at rest:
- If it shows AWS owned CMK, click Edit.
- Select Customer managed key.
- In the dropdown, choose your CMK (e.g.,
alias/dynamodb-table-kms-key). - Click Save changes / Update.
The table’s encryption at rest will now use your CMK. Repeat for each non‑compliant table.
3. Ensure New Tables Use CMKs by Default
There’s no single global default per service via console, so enforce this via process or templates:
-
When creating any new table in the DynamoDB console:
- Click Create table.
- In the Table settings / Additional settings section, find Encryption at rest.
- Choose Customer managed key.
- Select the CMK you created.
- Complete table creation.
-
Optionally, enforce via:
- Standard CloudFormation/Terraform templates that specify
SSESpecificationwith a KMS key. - IAM policies that restrict use of AWS owned keys for DynamoDB (advanced/optional).
- Standard CloudFormation/Terraform templates that specify
These steps will remediate the finding by ensuring DynamoDB tables use a KMS CMK for encryption at rest.
Using CLI
Below are the CLI steps to ensure a DynamoDB table uses a customer-managed KMS key (CMK) for encryption.
1. Identify the table and region
Decide which table(s) to fix and the AWS Region (e.g., us-east-1).
TABLE_NAME="my-dynamodb-table"
REGION="us-east-1"
2. Create (or choose) a KMS CMK
2.1 Create a new CMK (if you don’t already have one)
aws kms create-key \
--description "CMK for DynamoDB encryption" \
--key-usage ENCRYPT_DECRYPT \
--origin AWS_KMS \
--region $REGION
Note the KeyId in the output.
Optionally, give it an alias:
CMK_KEY_ID="<KeyId-from-previous-command>"
aws kms create-alias \
--alias-name "alias/dynamodb-cmk" \
--target-key-id "$CMK_KEY_ID" \
--region $REGION
You can also reuse an existing CMK or alias, e.g. alias/dynamodb-cmk.
3. Update the DynamoDB table to use the CMK
Use update-table and specify server-side encryption with KMS and your CMK (either KeyId or alias):
aws dynamodb update-table \
--table-name "$TABLE_NAME" \
--region "$REGION" \
--sse-specification Enabled=true,SSEType=KMS,KMSMasterKeyId="alias/dynamodb-cmk"
4. Verify encryption settings
aws dynamodb describe-table \
--table-name "$TABLE_NAME" \
--region "$REGION" \
--query "Table.SSEDescription"
You should see something like:
Status:ENABLEDSSEType:KMSKMSMasterKeyArn: your CMK ARN
Repeat steps 3–4 for each non-compliant table.
Using Python
Below is a practical, step‑by‑step approach using Python (boto3) to ensure DynamoDB tables are encrypted with a customer-managed KMS key (CMK).
1. Prerequisites
- Python 3.x
boto3installed:pip install boto3- IAM permissions for:
dynamodb:DescribeTable,dynamodb:UpdateTablekms:DescribeKey
- A KMS CMK ARN you want to use (or create one in KMS console and copy its ARN).
2. Understand What You Need to Change
You want each DynamoDB table to have:
SSEEnabled = TrueSSEType = "KMS"KMSMasterKeyId = "<your-cmk-arn>"
This is done with UpdateTable and the SSESpecification parameter.
3. Python: Update a Single Table to Use CMK
import boto3
from botocore.exceptions import ClientError
region = "us-east-1" # change as needed
table_name = "your-table-name" # change as needed
cmk_arn = "arn:aws:kms:us-east-1:123456789012:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
dynamodb = boto3.client("dynamodb", region_name=region)
def enable_kms_cmk_encryption(table_name, cmk_arn):
try:
# Describe current SSE settings
resp = dynamodb.describe_table(TableName=table_name)
sse_desc = resp["Table"].get("SSEDescription", {})
already_ok = (
sse_desc.get("Status") in ("ENABLED", "UPDATING") and
sse_desc.get("SSEType") == "KMS" and
sse_desc.get("KMSMasterKeyArn") == cmk_arn
)
if already_ok:
print(f"Table {table_name} already uses CMK: {cmk_arn}")
return
print(f"Updating table {table_name} to use CMK: {cmk_arn}")
# Update SSE specification
dynamodb.update_table(
TableName=table_name,
SSESpecification={
"Enabled": True,
"SSEType": "KMS",
"KMSMasterKeyId": cmk_arn,
},
)
print(f"Update initiated for {table_name}. Encryption change is asynchronous.")
except ClientError as e:
print(f"Error updating {table_name}: {e}")
if __name__ == "__main__":
enable_kms_cmk_encryption(table_name, cmk_arn)
4. Python: Bulk Remediation for All Tables in a Region
import boto3
from botocore.exceptions import ClientError
region = "us-east-1" # change as needed
cmk_arn = "arn:aws:kms:us-east-1:123456789012:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
dynamodb = boto3.client("dynamodb", region_name=region)
def list_all_tables():
tables = []
paginator = dynamodb.get_paginator("list_tables")
for page in paginator.paginate():
tables.extend(page.get("TableNames", []))
return tables
def remediate_tables_with_cmk(cmk_arn):
for table_name in list_all_tables():
try:
resp = dynamodb.describe_table(TableName=table_name)
sse_desc = resp["Table"].get("SSEDescription", {})
status = sse_desc.get("Status")
sse_type = sse_desc.get("SSEType")
current_key = sse_desc.get("KMSMasterKeyArn")
# Skip if already using this CMK
if status in ("ENABLED", "UPDATING") and sse_type == "KMS" and current_key == cmk_arn:
print(f"[SKIP] {table_name} already uses CMK: {cmk_arn}")
continue
print(f"[UPDATE] {table_name} -> CMK: {cmk_arn}")
dynamodb.update_table(
TableName=table_name,
SSESpecification={
"Enabled": True,
"SSEType": "KMS",
"KMSMasterKeyId": cmk_arn,
},
)
except ClientError as e:
print(f"[ERROR] {table_name}: {e}")
if __name__ == "__main__":
remediate_tables_with_cmk(cmk_arn)
5. KMS Key Policy Considerations
Ensure the CMK key policy allows DynamoDB to use it. A minimal example statement (add to CMK key policy):
{
"Sid": "AllowDynamoDBUseOfTheKey",
"Effect": "Allow",
"Principal": {
"Service": "dynamodb.amazonaws.com"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
}
Also ensure your IAM principal (user/role running the script) has kms:DescribeKey and, if needed, kms:ListAliases.
If you share any specific error you hit while running this, I can adjust the code or permissions for your case.
Using Terraform
resource "aws_kms_key" "dynamodb_cmk" {
description = "CMK for DynamoDB table encryption"
deletion_window_in_days = 30
# Optional: restrict usage via key policy, tags, etc.
# See AWS KMS docs for hardening guidance.
}
resource "aws_dynamodb_table" "this" {
name = "YOUR_TABLE_NAME" # replace with your table name
billing_mode = "PAY_PER_REQUEST"
hash_key = "PARTITION_KEY_NAME" # replace with your partition key
attribute {
name = "PARTITION_KEY_NAME" # replace with your partition key
type = "S" # adjust type as needed
}
server_side_encryption {
enabled = true
kms_key_arn = aws_kms_key.dynamodb_cmk.arn
}
# ...any other existing arguments (tags, range key, GSIs, LSIs, etc.)
}
Changing server_side_encryption to use a CMK is an in-place update for existing DynamoDB tables and does not force replacement.
To verify, terraform plan should show an in-place update (~) on the aws_dynamodb_table resource adding/updating the server_side_encryption block with enabled = true and kms_key_arn = arn:aws:kms:....