> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# AWS DynamoDB Tables Should Use KMS CMKs for Encryption

### More Info:

Amazon DynamoDB tables should be using AWS-managed Customer Master Keys (CMKs) instead of AWS-owned CMKs for Server-Side Encryption (SSE), in order to meet strict encryption compliance and regulatory requirements. DynamoDB supports to switch from AWS-owned CMKs to customer-managed CMKs managed using Amazon Key Management Service (KMS), without any code to encrypt the data.

### Risk Level

High

### Address

Security

### Compliance Standards

SOC2, GDPR, HIPAA, NIST, ISO27001

### Remediation

How to reconfigure existing DynamoDB tables to use AWS-managed CMKs for Server-Side Encryption?

#### Using AWS Console

1. Open the AWS Management Console and navigate to the DynamoDB service.
2. Select the desired DynamoDB table that you want to reconfigure.
   (In the Cloudanix Console, navigate to "Misconfig" page and look for Affected Assets for "AWS DynamoDB Tables Should Use KMS CMKs for Encryption" Policy.)
3. Click on the "Manage DynamoDB" button or access the table configuration settings.
4. In the table configuration settings, locate the "Encryption" section.
5. Check if the table is already encrypted. If it is not, proceed to the next step.
6. Click on the "Edit" button or the appropriate option to modify the encryption settings.
7. In the encryption settings, choose the option to enable encryption and select "AWS managed key" as the encryption type.
8. From the drop-down menu, select the AWS-managed CMK that you want to use for server-side encryption.
9. Review any additional encryption-related settings, such as the type of encryption algorithm.
10. Save the changes to apply the new encryption configuration to the DynamoDB table.

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        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

        1. Sign in to the **AWS Management Console**.
        2. Go to **AWS Key Management Service (KMS)**:
           * In the search bar, type **KMS** and open **Key Management Service**.
        3. In the left pane, choose **Customer managed keys**.
        4. Click **Create key**.
        5. Configure the key:
           * **Key type**: Symmetric.
           * **Key usage**: Encrypt and decrypt.
           * Click **Next**.
        6. Set **Alias** (e.g., `alias/dynamodb-table-kms-key`), optional description.
        7. Configure **Key administrators** and **Key users**:
           * Make sure the IAM roles/users that manage/operate DynamoDB have permission to use this key.
        8. 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

        1. Go to the **DynamoDB** console.
        2. In the left pane, click **Tables**.
        3. Click on the table you want to remediate.
        4. In the table’s page, choose the **Additional settings** / **Encryption** tab (exact label may vary slightly).
        5. Under **Encryption at rest**:
           * If it shows **AWS owned CMK**, click **Edit**.
        6. Select **Customer managed key**.
        7. In the dropdown, choose your CMK (e.g., `alias/dynamodb-table-kms-key`).
        8. 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**:
          1. Click **Create table**.
          2. In the **Table settings** / **Additional settings** section, find **Encryption at rest**.
          3. Choose **Customer managed key**.
          4. Select the CMK you created.
          5. Complete table creation.

        * Optionally, enforce via:
          * Standard CloudFormation/Terraform templates that specify `SSESpecification` with a KMS key.
          * IAM policies that restrict use of AWS owned keys for DynamoDB (advanced/optional).

        ***

        These steps will remediate the finding by ensuring DynamoDB tables use a KMS CMK for encryption at rest.
      </Accordion>

      <Accordion title="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`).

        ```bash theme={null}
        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)

        ```bash theme={null}
        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:

        ```bash theme={null}
        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):

        ```bash theme={null}
        aws dynamodb update-table \
          --table-name "$TABLE_NAME" \
          --region "$REGION" \
          --sse-specification Enabled=true,SSEType=KMS,KMSMasterKeyId="alias/dynamodb-cmk"
        ```

        ***

        ### 4. Verify encryption settings

        ```bash theme={null}
        aws dynamodb describe-table \
          --table-name "$TABLE_NAME" \
          --region "$REGION" \
          --query "Table.SSEDescription"
        ```

        You should see something like:

        * `Status`: `ENABLED`
        * `SSEType`: `KMS`
        * `KMSMasterKeyArn`: your CMK ARN

        Repeat steps 3–4 for each non-compliant table.
      </Accordion>

      <Accordion title="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
        * `boto3` installed:
          ```bash theme={null}
          pip install boto3
          ```
        * IAM permissions for:
          * `dynamodb:DescribeTable`, `dynamodb:UpdateTable`
          * `kms: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 = True`
        * `SSEType = "KMS"`
        * `KMSMasterKeyId = "<your-cmk-arn>"`

        This is done with `UpdateTable` and the `SSESpecification` parameter.

        ***

        ## 3. Python: Update a Single Table to Use CMK

        ```python theme={null}
        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

        ```python theme={null}
        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):

        ```json theme={null}
        {
          "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.
      </Accordion>

      <Accordion title="Using Terraform">
        ```hcl theme={null}
        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:...`.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/EncryptionAtRest.html](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/EncryptionAtRest.html)
* [https://aws.amazon.com/about-aws/whats-new/2019/02/amazon-dynamodb-adds-support-for-switching-encryption-keys-to-encrypt-your-data-at-rest/](https://aws.amazon.com/about-aws/whats-new/2019/02/amazon-dynamodb-adds-support-for-switching-encryption-keys-to-encrypt-your-data-at-rest/)
