Protecting data in AWS is a multifaceted challenge. A significant aspect involves ensuring data security, which encompasses restricting access and ensuring that data is encrypted at rest—a topic I’ve explored extensively in my previous posts. However, equally important, if not more so, is safeguarding against data loss. This article focuses on this critical area, addressing standard concerns such as backups and delving into AWS-specific challenges that arise from managing data through CloudFormation and the consolidated tooling available in the AWS Console
Data Protection and Risks with CDK/CloudFormationAWS CDK and CloudFormation significantly streamline the management of DynamoDB table schemas by enabling the definition and deployment of infrastructure through code. However, this automation introduces risks of data loss, primarily due to automated schema updates. Several actions can inadvertently lead to such risks: Accidental or Unintentional Updates: Mistakes in the CDK code or template.yml, such as inadvertently commenting out a table definition while testing other changes, can result in the deletion of the table during the next deployment, leading to data loss Table Renaming: AWS DynamoDB does not support renaming tables. Attempting to change a table's name requires deleting the existing table and recreating it with the new name, which can cause data loss. Schema Changes: Modifying critical attributes like partition or sort keys can cause deployment errors. These errors may necessitate manual corrective actions, potentially resulting in data loss. Stack Integrity: Managing multiple resources within a single stack increases complexity. Errors during updates can corrupt the stack's state, often requiring complete deletion and recreation of the stack, posing significant risks to the data contained within.
AWS Console Access and Data RisksManaging DynamoDB tables through the AWS Management Console introduces significant risks. Unlike traditional relational database management systems (RDBMS) that rely on specialized tools for Database Administrators (DBAs), DynamoDB tables are accessible to anyone with the appropriate console permissions. This broad accessibility increases the likelihood of accidental modifications or deletions, potentially leading to data corruption or loss. Accidental Modifications: Users might unintentionally alter table configurations, such as changing indexes or adjusting throughput settings, which can degrade performance or disrupt application functionality. Data Deletions: The ease of access means that users can accidentally delete entire tables or specific items within a table, resulting in irreversible data loss if adequate backups are not in place. Security Vulnerabilities: Without stringent access controls, unauthorized users could gain the ability to manipulate sensitive data, leading to potential breaches and compliance issues
Mitigation StrategiesTo safeguard your DynamoDB tables and ensure data integrity, implement the following mitigation strategies: Separate Stacks: Isolate your table definitions from other application components by placing them in dedicated CloudFormation or CDK stacks. This separation minimizes the risk of errors in unrelated parts of your infrastructure affecting your DynamoDB tables. For enhanced protection, consider creating a separate stack for each table, ensuring that issues in one do not cascade to others. Set Removal Policy to RETAIN: By default, CloudFormation and CDK set the removal policy of resources to REMOVE, which deletes the resource when it's removed from the stack. For production data, it is appropriate to set removal policy to RETAIN for DynamoDB tables and S3 buckets. This configuration ensures that these resources are preserved even if they are inadvertently removed from the stack. CDK examples for setting the removal policy are provided in the Appendix. Enable deletion protection: AWS allows you to enable deletion protection on DynamoDB tables, preventing any deletion attempts while the protection is active. Whether configured via the AWS Console or through CloudFormation/CDK, enabling this feature ensures that tables cannot be deleted unless deletion protection is explicitly disabled. This safeguard is essential for all DynamoDB tables containing production data. For S3 buckets, a similar protection can be achieved by setting auto_delete_objects to False, preventing automatic deletion of objects within the bucket. End-of-Day (EOD) Backups: Regular backups are a cornerstone of data protection. End-of-Day (EOD) backups provide consistent snapshots of your data, ensuring that you can recover to the latest state at the end of each day. AWS Backup offers a streamlined way to manage these encrypted backups, eliminating the need for custom serialization or deserialization routines. In the Appendix, you will find a sample implementation of EOD backups. Point-In-Time Recovery (PITR): AWS’s Point-In-Time Recovery (PITR) feature allows you to restore your DynamoDB tables to any second within the last 35 days. Enabling PITR provides continuous backups, offering granular recovery options that are particularly useful for tables containing user-authored data. Unlike automated market data feeds or recalculated datasets, user data benefits greatly from PITR's ability to recover from accidental deletions or modifications without significant additional costs.
Data Protection Costs
Implementing data protection measures in AWS DynamoDB incurs various costs, primarily influenced by the volume of data you manage. Understanding these costs helps with budgeting and optimizing your data management strategies. Here's a breakdown of the key cost components and tools available to help reduce them: DynamoDB Storage: AWS charges based on the amount of data stored in your DynamoDB tables. As your dataset grows, storage costs increase proportionally. Backup Storage: The cost of backups depends on the size of the data being backed up and the retention policies you apply. On-Demand Backups are billed per gigabyte, and maintaining longer retention periods will naturally lead to higher storage costs. Read Capacity Units (RCUs): Larger datasets require more RCUs to handle read operations efficiently. Optimizing your data models, such as by using appropriate indexing and query patterns, can reduce the number of RCUs needed, thereby lowering costs. DynamoDB Backup Costs: AWS charges per gigabyte for On-Demand Backups, and costs accumulate each time a backup is performed. Scheduling backups frequently will increase these costs, so it's important to balance backup frequency with your budget.
Tools for Reducing Data CostsData Aggregation: Consolidate transactions and roll up closed positions to reduce the volume of stored data. By summarizing or archiving less frequently accessed data, you can minimize storage requirements and associated costs. Limit EOD Position Snapshots: Maintain only a limited number of End-of-Day (EOD) position snapshots online. Perform regular automated compression and purges of your data according to well defined rules. Backup Retention Policies: Implement policies to purge backups after a certain period, such as retaining only a couple of weeks of daily backups and only month end backups beyond that. Integrate automated purging into your backup procedure. Time-to-Live (TTL) on Records: Utilize DynamoDB's TTL feature to automatically delete items after a specified timestamp. While TTL offers a hands-off approach to data purging, active purge policies are easier to understand and maintain.
ConclusionThis article shares my perspectives on protecting data in AWS DynamoDB using CDK and CloudFormation. It's not an exhaustive guide, and I recognize that different scenarios may require alternative approaches. I highly value your feedback and would love to hear about your experiences and strategies—please share your thoughts and insights in the comments!
Appendix CDK table templatedef define_table(stack, cdk_name, table_name, partition_key, sort_key=None, stream=None, read_capacity=1, write_capacity=1, indicies=None, point_in_time_recovery = False): table = dynamodb.Table( stack, cdk_name, table_name=table_name, partition_key=dynamodb.Attribute( name=partition_key, type=dynamodb.AttributeType.STRING ), sort_key=dynamodb.Attribute( name=sort_key, type=dynamodb.AttributeType.STRING ) if sort_key else None, billing_mode=dynamodb.BillingMode.PROVISIONED, stream=stream if stream else None, read_capacity=read_capacity, write_capacity=write_capacity, removal_policy=RemovalPolicy.RETAIN, deletion_protection=True, point_in_time_recovery=point_in_time_recovery )
Appendix DB Backup Lambadef create_backup(table_name): backup_name = f"{table_name}-{datetime.now().strftime('%Y-%m-%d')}" try: response = dynamodb.create_backup( TableName=table_name, BackupName=backup_name ) logger.info(f"Created backup for '{table_name}': {backup_name} at {response['BackupDetails']['BackupCreationDateTime']}") except ClientError as e: logger.error(f"Error creating backup for table '{table_name}': {e.response['Error']['Message']}") raise
def list_backups(table_name): backups = [] try: paginator = dynamodb.get_paginator('list_backups') for page in paginator.paginate(TableName=table_name): for backup in page.get('BackupSummaries', []): backups.append({ 'BackupArn': backup['BackupArn'], 'BackupName': backup['BackupName'] }) except ClientError as e: logger.error(f"Error listing backups for table '{table_name}': {e.response['Error']['Message']}") raise return backups
def delete_backup(backup_arn, backup_name, table_name): try: dynamodb.delete_backup( BackupArn=backup_arn ) logger.info(f"Deleted backup '{backup_name}' for table '{table_name}'") except ClientError as e: logger.error(f"Error deleting backup '{backup_name}' for table '{table_name}': {e.response['Error']['Message']}") raise
def purge_old_backups( table_name): backups = list_backups(table_name) logger.info(f"Total backups found for '{table_name}': {len(backups)}") to_delete = filter_files_to_purge([b['BackupName'] for b in backups], datetime.today().date()) for backup in backups: if backup['BackupName'] in to_delete: delete_backup( backup['BackupArn'], backup['BackupName'], table_name)
def execute_backup_policy(): logger.info("Starting DynamoDB Backup and Purge Process") for table in ALL_TABLES: table_name = table.name create_backup(table_name) time.sleep(1) # Small delay to ensure backup is registered purge_old_backups(table_name) logger.info("Backup and Purge Process Completed")
|
1 comment:
Agree, that backing-up data is must feature. I am glad that DynamoDB has built-in feature.
Before it was introduced (7..8 years) ago, our team had even developed custom package, which subscribes to DDB output stream events and applied changes (probably, with Lambda) to -backup table. Now I would also look in Kinesis event bus.
BTW, some AWS Managed service has "deletion protection" flag, to avoid an accidental one.
I am more in favour of native mechanisms although.
Thanks for the article.
Post a Comment