Configure DynamoDB point-in-time recovery and deletion protection using AWS CDK
How to enable point-in-time recovery and deletion protection for a DynamoDB table using AWS CDK in Python
On this page
In the previous article, we created a basic DynamoDB table using AWS CDK. In this post, we will make the table safer by enabling point-in-time recovery and deletion protection.
These two settings solve different problems:
- Point-in-time recovery lets you restore a table to a previous point in time.
- Deletion protection prevents accidental table deletion.
For a real table, especially one that stores user or business data, I would normally configure these before the table receives production traffic.
Prerequisites
- Ensure that you have AWS CDK and SAM CLI installed.
- Complete the previous article: Create a DynamoDB table using AWS CDK in Python.
- Configure your AWS CLI profile for the account and region where you want to deploy the table.
What we will configure
We will update the DynamoDB stack to configure:
- Point-in-time recovery.
- Deletion protection.
- A retain removal policy for safer stack deletion behavior.
The project file we will edit is:
cdk_app/dynamodb_stack.py
Update the DynamoDB table
Open cdk_app/dynamodb_stack.py and update the table definition:
# filename: cdk_app/dynamodb_stack.py
from aws_cdk import (
CfnOutput,
RemovalPolicy,
Stack,
aws_dynamodb as dynamodb,
)
from constructs import Construct
class DynamoDbStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
table = dynamodb.Table(
self,
"TodosTable",
partition_key=dynamodb.Attribute(
name="todo_id",
type=dynamodb.AttributeType.STRING,
),
billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST,
point_in_time_recovery_specification=dynamodb.PointInTimeRecoverySpecification(
point_in_time_recovery_enabled=True,
),
deletion_protection=True,
removal_policy=RemovalPolicy.RETAIN,
)
CfnOutput(self, "TableName", value=table.table_name)
CfnOutput(self, "TableArn", value=table.table_arn)
In the above code:
dynamodb.Tablekeeps the same construct we used in the first DynamoDB article.BillingMode.PAY_PER_REQUESTkeeps the table on on-demand billing.point_in_time_recovery_specificationenables point-in-time recovery.deletion_protection=Trueprevents accidental table deletion.RemovalPolicy.RETAINtells CloudFormation to keep the table if the stack is deleted.
AWS CDK also has an older point_in_time_recovery=True option, but that property is now deprecated. Use PointInTimeRecoverySpecification
for new code.
Do not use RemovalPolicy.DESTROY casually for a DynamoDB table that stores real data. If the table is important, use RemovalPolicy.RETAIN and make data deletion a deliberate manual step.
Why not switch to TableV2 here?
AWS CDK also has a newer dynamodb.TableV2 construct. It is useful for global table use cases and newer per-replica configuration options.
However, do not casually replace an existing dynamodb.Table construct with dynamodb.TableV2 in a deployed stack. AWS documents this in
its
Table to TableV2 migration guidance:
CloudFormation can treat that kind of construct migration as a resource replacement.
For this article, we are updating the table created in the previous lesson, so we keep using dynamodb.Table.
The table shape stays the same:
partition_key=dynamodb.Attribute(
name="todo_id",
type=dynamodb.AttributeType.STRING,
)
And the billing mode stays the same:
billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST
Deploy the change
Before deploying, run cdk diff:
cdk diff
You should see that the DynamoDB table configuration will be updated.
If the diff looks correct, deploy the stack:
cdk deploy
After deployment, the table will have point-in-time recovery and deletion protection enabled.
Verify point-in-time recovery
Get the table name from the stack output:
table_name=$(aws cloudformation describe-stacks \
--stack-name DynamoDbStack \
--query "Stacks[0].Outputs[?OutputKey=='TableName'].OutputValue" \
--output text)
Then run:
aws dynamodb describe-continuous-backups \
--table-name "$table_name"
In the response, check the PointInTimeRecoveryDescription section. The PointInTimeRecoveryStatus value should be ENABLED.
Verify deletion protection
You can verify deletion protection with describe-table:
aws dynamodb describe-table \
--table-name "$table_name" \
--query "Table.DeletionProtectionEnabled"
The output should be:
true
What happens when you destroy the stack?
Because the table uses RemovalPolicy.RETAIN, CloudFormation will not delete the table when you destroy the stack. This is intentional.
Run the following command only if you are done testing the stack:
cdk destroy
After the stack is destroyed, the DynamoDB table can remain in your AWS account. That means you may still be charged for storage or requests against the table.
Fully delete the table
If this is only a tutorial table and you want to delete it completely, make deletion explicit.
First, update the table settings:
# filename: cdk_app/dynamodb_stack.py
table = dynamodb.Table(
self,
"TodosTable",
partition_key=dynamodb.Attribute(
name="todo_id",
type=dynamodb.AttributeType.STRING,
),
billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST,
point_in_time_recovery_specification=dynamodb.PointInTimeRecoverySpecification(
point_in_time_recovery_enabled=True,
),
deletion_protection=False,
removal_policy=RemovalPolicy.DESTROY,
)
Deploy the update:
cdk deploy
Then destroy the stack:
cdk destroy
This deletes the DynamoDB table and the data inside it. Only do this for a tutorial table or after you have exported, backed up, or migrated the data.
Next steps
Now that the table has basic safety settings, the next useful DynamoDB topic is to add a Global Secondary Index so we can query the same table by a different access pattern.
Need help?
Start a discussion on GitHub if you’ve got questions or improvements. Open discussions →
Series