Back to Checks
aws

DynamoDB table is protected by a backup plan

dynamodb_table_protected_by_backup_plan
Service: dynamodbSeverity: medium
OfficialBuilt-inVerified
Categories:resilience
Resource Type:AwsDynamoDbTable

DynamoDB tables are evaluated for inclusion in an AWS Backup backup plan through resource assignments, including explicit tables, resource-type wildcards, or all-resources coverage.

The result indicates whether a table is governed by scheduled backups and retention defined by the plan.

Risk

Without a backup plan, table data lacks governed copies, harming availability and integrity. Accidental deletes, corrupt writes, or malicious actions can become unrecoverable, and RPO/RTO worsen. You also forfeit cross-Region/account copies and immutability features, increasing downtime and data loss.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks dynamodb_table_protected_by_backup_plan

Recommendation

Place all critical tables under an AWS Backup backup plan following defense in depth and least privilege:

  • Use tag-based assignments for coverage at scale
  • Define schedules, retention, and cross-Region/account copies
  • Enable Vault Lock for immutability
  • Regularly test restores and restrict backup deletion

Remediation

Terraform

# Terraform: Add DynamoDB tables to an AWS Backup plan
resource "aws_backup_plan" "<example_resource_name>" {
  name = "<example_resource_name>"
  rule {
    rule_name         = "r"
    target_vault_name = "Default"
  }
}

data "aws_iam_role" "<example_resource_name>" {
  name = "AWSServiceRoleForBackup"
}

resource "aws_backup_selection" "<example_resource_name>" {
  name         = "<example_resource_name>"
  plan_id      = aws_backup_plan.<example_resource_name>.id
  iam_role_arn = data.aws_iam_role.<example_resource_name>.arn
  resources    = [
    "arn:aws:dynamodb:*:*:table/*" # CRITICAL: adds all DynamoDB tables to the backup plan, making them protected
  ]
}

NativeIaC

# CloudFormation: Add DynamoDB tables to an AWS Backup plan
Resources:
  BackupPlan:
    Type: AWS::Backup::BackupPlan
    Properties:
      BackupPlan:
        BackupPlanName: <example_resource_name>
        BackupPlanRule:
          - RuleName: r
            TargetBackupVault: Default

  BackupSelection:
    Type: AWS::Backup::BackupSelection
    Properties:
      BackupPlanId: !Ref BackupPlan
      BackupSelection:
        SelectionName: <example_resource_name>
        IamRoleArn: <example_role_arn>
        Resources:
          - arn:aws:dynamodb:*:*:table/*  # CRITICAL: adds all DynamoDB tables to the backup plan, making them protected

Other

1In the AWS Backup console, go to Settings > Configure resources and enable DynamoDB, then Confirm
2Go to Backup plans > Create backup plan > Build a new plan
3Enter a plan name, set Rule name to any value, set Backup vault to Default, and Create plan
4On the plan page, choose Assign resources
5Enter a Resource assignment name, set IAM role to Default role, select your DynamoDB table, and choose Assign resources

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.backup.backup_client import backup_client
from prowler.providers.aws.services.dynamodb.dynamodb_client import dynamodb_client


class dynamodb_table_protected_by_backup_plan(Check):
    def execute(self):
        findings = []
        for table in dynamodb_client.tables.values():
            report = Check_Report_AWS(metadata=self.metadata(), resource=table)
            report.status = "FAIL"
            report.status_extended = (
                f"DynamoDB table {table.name} is not protected by a backup plan."
            )

            if (
                table.arn in backup_client.protected_resources
                or f"arn:{dynamodb_client.audited_partition}:dynamodb:*:*:table/*"
                in backup_client.protected_resources
                or "*" in backup_client.protected_resources
            ):
                report.status = "PASS"
                report.status_extended = (
                    f"DynamoDB table {table.name} is protected by a backup plan."
                )

            findings.append(report)

        return findings