Skip to content

DynamoDB tables should have encryption enabled

DynamoDB tables frequently store application state, user profiles, session tokens, and other sensitive records. While AWS enabled default encryption with AWS-owned keys for all new tables created after November 2018, several compliance frameworks require explicit use of AWS managed or customer managed KMS keys to demonstrate control over key lifecycle, rotation, and access policies.

Without explicit encryption configuration, you lose the ability to audit key usage through CloudTrail, enforce key rotation schedules, or revoke access by disabling a key. Customer managed keys give you granular IAM-level control over which principals can decrypt table data, something AWS-owned keys cannot provide.

Retrofit consideration

Switching from AWS-owned to AWS managed or customer managed KMS keys triggers a full table re-encryption. For large tables, this consumes additional read/write capacity and can take significant time.

Implementation

Choose the approach that matches how you manage Terraform.

Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.

module "dynamodb_table" {
  source  = "pcidss.compliance.tf/terraform-aws-modules/dynamodb-table/aws"
  version = ">=5.0.0"

  attributes = [
    {
      name = "id"
      type = "S"
    }
  ]
  hash_key = "id"
  name     = "abc123"
}

module "dynamodb_table" {
  source  = "hipaa.compliance.tf/terraform-aws-modules/dynamodb-table/aws"
  version = ">=5.0.0"

  attributes = [
    {
      name = "id"
      type = "S"
    }
  ]
  hash_key = "id"
  name     = "abc123"
}

module "dynamodb_table" {
  source  = "gdpr.compliance.tf/terraform-aws-modules/dynamodb-table/aws"
  version = ">=5.0.0"

  attributes = [
    {
      name = "id"
      type = "S"
    }
  ]
  hash_key = "id"
  name     = "abc123"
}

module "dynamodb_table" {
  source  = "eugmpannex11.compliance.tf/terraform-aws-modules/dynamodb-table/aws"
  version = ">=5.0.0"

  attributes = [
    {
      name = "id"
      type = "S"
    }
  ]
  hash_key = "id"
  name     = "abc123"
}

module "dynamodb_table" {
  source  = "hipaasecurity2003.compliance.tf/terraform-aws-modules/dynamodb-table/aws"
  version = ">=5.0.0"

  attributes = [
    {
      name = "id"
      type = "S"
    }
  ]
  hash_key = "id"
  name     = "abc123"
}

module "dynamodb_table" {
  source  = "nistcsfv11.compliance.tf/terraform-aws-modules/dynamodb-table/aws"
  version = ">=5.0.0"

  attributes = [
    {
      name = "id"
      type = "S"
    }
  ]
  hash_key = "id"
  name     = "abc123"
}

module "dynamodb_table" {
  source  = "pcidssv321.compliance.tf/terraform-aws-modules/dynamodb-table/aws"
  version = ">=5.0.0"

  attributes = [
    {
      name = "id"
      type = "S"
    }
  ]
  hash_key = "id"
  name     = "abc123"
}

If you use terraform-aws-modules/dynamodb-table/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.

module "dynamodb_table" {
  source  = "terraform-aws-modules/dynamodb-table/aws"
  version = ">=5.0.0"

  attributes = [
    {
      name = "id"
      type = "S"
    }
  ]
  hash_key = "id"
  name     = "abc123"

  server_side_encryption_enabled = true
}

Use AWS provider resources directly. See docs for the resources involved: aws_dynamodb_table.

resource "aws_dynamodb_table" "this" {
  attribute {
    name = "id"
    type = "S"
  }

  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "id"
  name         = "pofix-abc123"

  server_side_encryption {
    enabled = true
  }
}

What this control checks

The control validates that aws_dynamodb_table includes a server_side_encryption block with enabled = true. With enabled = true but no kms_key_arn, DynamoDB uses the AWS managed key (alias/aws/dynamodb). To use a customer managed key, set kms_key_arn to the ARN of an aws_kms_key resource. Omitting the block entirely leaves the table on AWS-owned encryption, which most compliance controls flag as a failure since there is no explicit, auditable encryption configuration.

Common pitfalls

  • AWS-owned encryption may still fail the control

    All DynamoDB tables created after November 2018 use AWS-owned encryption by default, but omitting the server_side_encryption block in aws_dynamodb_table means Terraform sends no explicit encryption configuration. Most compliance controls require enabled = true to register a pass, even though the data is technically encrypted.

  • Global table replicas need per-region KMS keys

    When using replica blocks within aws_dynamodb_table, each replica accepts its own kms_key_arn. Specifying a customer managed key for the primary but omitting it for replicas leaves those replicas on default key settings in their regions, creating an inconsistent compliance posture that is easy to miss until an auditor checks each region independently.

  • Customer managed key deletion makes data permanently inaccessible

    Schedule an aws_kms_key for deletion and let the waiting period expire, and DynamoDB can no longer decrypt the table. There is no recovery path. Use deletion_window_in_days with a long window, and set enable_key_rotation = true to avoid the manual rotation pressure that pushes teams toward risky key replacements.

  • Terraform plan shows replacement when switching encryption types

    Changing kms_key_arn from one customer managed key to another, or toggling between AWS managed and customer managed, triggers an in-place update that re-encrypts the table. On-demand tables handle this transparently, but provisioned tables may experience throttling if throughput is already constrained. Plan the switch during a low-traffic window.

Audit evidence

Auditors expect AWS Config rule evaluation results (such as the managed rule dynamodb-table-encrypted-kms) returning COMPLIANT for each DynamoDB table in scope. The DynamoDB console's "Additional settings" tab displays the encryption type (AWS owned, AWS managed, or customer managed) and the associated KMS key ARN where applicable.

For customer managed keys, CloudTrail logs showing kms:Decrypt and kms:GenerateDataKey calls tied to the DynamoDB table ARN demonstrate active key usage. KMS key policies, key rotation status, and alias configurations provide further evidence of encryption governance. Security Hub consolidates findings across all tables and can produce a single-report view for the auditor.

Framework-specific interpretation

PCI DSS v4.0: Requirements 3.4 and 3.5 call for rendering stored PAN unreadable and protecting the keys used to do it. Enabling DynamoDB encryption with an auditable KMS key supports both requirements for cardholder data stored in the table.

HIPAA Omnibus Rule 2013: HIPAA treats encryption of ePHI at rest as an addressable implementation specification under 45 CFR 164.312(a)(2)(iv). Tables storing ePHI should use documented, risk-based encryption. Customer managed KMS keys improve on the default by making every decrypt operation visible in CloudTrail, which satisfies the auditability expectation that AWS-owned keys cannot meet.

GDPR: Article 32 calls for appropriate technical measures to secure personal data processing. For DynamoDB tables holding personal data of EU data subjects, encryption at rest with a customer managed key provides a concrete, verifiable measure that also reduces the impact of physical media compromise.

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: dynamodb_table_encryption_enabled

  • AWS Config Managed Rule: DYNAMODB_TABLE_ENCRYPTION_ENABLED

  • Checkov Check: CKV_AWS_119

  • Powerpipe Control: aws_compliance.control.dynamodb_table_encryption_enabled

  • Prowler Check: dynamodb_tables_kms_cmk_encryption_enabled

  • KICS Query: ce089fd4-1406-47bd-8aad-c259772bb294

  • Trivy Check: AWS-0025

Last reviewed: 2026-03-09