Terraform module for defining a performant DynamoDB table with point-in-time recovery enabled by default. In accordance with security and performance best practices, all DynamoDB tables with "Provisioned" read/write capacity are provided with AutoScaling resources.
- DynamoDB Server-Side Encryption
- Restoring a DynamoDB Table Using Point-In-Time Recovery
- DynamoDB Security Standards & Controls
- Useful Links
- Usage Examples
- ⚙️ Module Usage
- 📝 License
- 💬 Contact
All DynamoDB tables are encrypted using either an AWS-owned key, AWS-managed key, or CMK (customer-managed key). By default, all tables are encrypted using an AWS-owned key in the DynamoDB service account. The AWS-owned key is free of charge and its use does not count against AWS KMS resource or request quotas. CMKs and AWS-managed keys incur a charge for each API call and AWS KMS quotas apply to these KMS keys.
Use the AWS managed key if you need any of the following features:
- You can view the KMS key and view its key policy. (You cannot change the key policy.)
- You can audit the encryption and decryption of your DynamoDB table by examining the DynamoDB API calls to AWS KMS in AWS CloudTrail logs.
Use a CMK to get the following features:
- You create and manage the KMS key, including setting the key policies, IAM policies, and grants to control access to the KMS key. You can enable and disable the KMS key, enable and disable automatic key rotation, and delete the KMS key when it is no longer in use.
- You can use a customer-managed key with imported key material or a customer-managed key in a custom key store that you own and manage.
- You can audit the encryption and decryption of your DynamoDB table by examining the DynamoDB API calls to AWS KMS in AWS CloudTrail logs.
When you restore a DynamoDB table using point-in-time recovery, the settings listed below can be manually overridden for the restore-table, and if not provided will instead be copied over from current settings of the source table at the time of the restore.
- Global secondary indexes (GSIs)
- Local secondary indexes (LSIs)
- Billing mode
- Provisioned read and write capacity
- Encryption settings
- Region
To better illustrate the source of these settings, here's an example from AWS docs:
For example, suppose that a table's provisioned throughput was recently lowered to 50 read capacity units and 50 write capacity units. You then restore the table's state to three weeks ago, at which time its provisioned throughput was set to 100 read capacity units and 100 write capacity units. In this case, DynamoDB restores your table data to that point in time, but uses the current provisioned throughput (50 read capacity units and 50 write capacity units).
In contrast, the settings listed below must be provided for the restore table, as they do not carry over from the source table:
- Auto scaling policies
- AWS Identity and Access Management (IAM) policies
- Amazon CloudWatch metrics and alarms
- Tags
- Stream settings
- Time to Live (TTL) settings
- Point-in-time recovery settings
Service metrics show that 95 percent of table restores complete in less than one hour. However, restore times are directly related to a table's configurations, such as the size of the table, the number of underlying partitions, and other related variables. A best practice when planning for disaster recovery is to regularly document average restore completion times and establish how these times affect your overall Recovery Time Objective.
| Source | Control | Pass/Fail | Notes |
|---|---|---|---|
| AWS Foundational Security Best Practices | [DynamoDB.1] DynamoDB tables should automatically scale capacity with demand | ✅ | |
| AWS Foundational Security Best Practices | [DynamoDB.2] DynamoDB tables should have point-in-time recovery enabled | ✅ | |
| AWS Foundational Security Best Practices | [DynamoDB.3] DynamoDB Accelerator (DAX) clusters should be encrypted at rest | N/A | DAX resources not yet supported. |
- AWS Documentation:
- Terragrunt: view Terragrunt usage exmaple
- Terraform: view vanilla Terraform usage exmaple
- Terragrunt: view Terragrunt usage exmaple
- Terraform: view vanilla Terraform usage exmaple
| Name | Version |
|---|---|
| terraform | 1.3.2 |
| aws | ~> 4.34.0 |
| Name | Version |
|---|---|
| aws | ~> 4.34.0 |
No modules.
| Name | Type |
|---|---|
| aws_appautoscaling_policy.map | resource |
| aws_appautoscaling_target.map | resource |
| aws_dynamodb_kinesis_streaming_destination.list | resource |
| aws_dynamodb_table.this | resource |
| aws_dynamodb_table_item.list | resource |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| attributes | List of DynamoDB table attribute config objects. Attribute "type" values must be either "S", "N", or "B" (for String, Number, or Binary). All table and index keys must be defined here, along with any attributes included in index "non_key_attributes" lists. |
list(object({ |
n/a | yes |
| billing_mode | (Optional) The DynamoDB table's billing mode. This can either be "PROVISIONED" or "PAY_PER_REQUEST"; if no value is provided, this defaults to "PROVISIONED". A table with "PROVISIONED" billing must define a "capacity" config; see the var.capacity description for more information. |
string |
"PROVISIONED" |
no |
| capacity | (Optional if var.billing_mode is PAY_PER_REQUEST) Autoscaling configs for a DynamoDB table with "PROVISIONED" throughput. "var.capacity" must specify "min", "max", and "target_percentage" values for both "read" and "write". "target_percentage" reflects the desired utilization of provisioned capacity. |
object({ |
null |
no |
| dynamodb_table_items | (Optional) A list of JSON-encoded DynamoDB table items. | list(string) |
null |
no |
| enable_point_in_time_recovery | (Optional) Point in time recovery is enabled by default; set to false to override this behavior. |
bool |
true |
no |
| global_secondary_indexes | (Optional) Map of GSI names to config objects for each respective GSI. Note that the maximum number of GSIs a DynamoDB table can have is 20. Each GSI must have a "hash_key", and can optionally define a "range_key", both of which must be included in var.attributes. "projection_type" defines which table attributes to include (or "project") in the index - it must be either "KEYS_ONLY", "ALL", or "INCLUDE". "KEYS_ONLY" will result in just the table's hash_key and range_key being included in the index, "ALL" will result in every table attribute being included in the index, and "INCLUDE" will result in the table's hash_key, range_key, and attributes defined in the "non_key_attributes" list being included in the index. Note that any attributes listed in "non_key_attributes" must be defined in var.attributes. If the base table uses "PROVISIONED" throughput, all GSI configs must specify autoscaling configs via the "capacity" property with "min", "max", and "target_percentage" values for both "read" and "write". "target_percentage" reflects the desired utilization of provisioned capacity. |
map( |
{} |
no |
| hash_key | The DynamoDB table's hash key (also called a "partition" or "primary" key). | string |
n/a | yes |
| local_secondary_indexes | (Optional) Map of LSI names to config objects for each respective LSI. Note that the maximum number of LSIs a DynamoDB table can have is 5. All LSIs use the table's "hash_key" as their own, and must define a "range_key". |
map( |
{} |
no |
| range_key | (Optional) The DynamoDB table's range key (also called a "sort" key). | string |
null |
no |
| replicas | (Optional) Map for configuring table replicas. For map keys, use AWS region names for regions in which a replica table is desired; map region names to regional replica config objects. A "kms_key_arn" must be provided for each replica; this can be an alias given the proper key/alias/permissions configs. If not provided, "enable_point_in_time_recovery" defaults to true. |
map( |
null |
no |
| restore_table_from | (Optional) Use this variable to create a restore-table from a source table with point-in-time recovery enabled. To create a restore-table, you must provide a "source_table_name", and a time indicator. The time indicator can be specified using either "use_latest_recovery_point" (default: false), of an explicit date-time string can be supplied to "restore_date_time". Please see the README and AWS docs for more info on the necessary inputs. |
object({ |
null |
no |
| server_side_encryption | Config object for the DynamoDB table's server side encryption. "key_type" must be either "AWS-OWNED", "AWS-MANAGED", or "CMK" (customer-managed key). For "CMK", a "kms_key_arn" must be provided (this can also be an alias). For more information, see DynamoDB Server-Side Encryption. |
object({ |
n/a | yes |
| streams | (Optional) Object for enabling a DynamoDB table stream and/or a Kinesis data stream. For a DynamoDB table stream, "dynamodb_stream_view_type" must be one of "KEYS_ONLY", "NEW_IMAGE", "OLD_IMAGE", or "NEW_AND_OLD_IMAGES", which defines what table-modification info is added to each stream window. With "KEYS_ONLY", only the key attributes of the modified item are added; with "NEW_IMAGE", the entire item is added as it appears AFTER it was modified; with "OLD_IMAGE", the entire item is added as it appeared BEFORE it was modified; with "NEW_AND_OLD_IMAGES", both the new and old images are added to each stream window. For a Kinesis data stream, this module will associate a DynamoDB table with an existing Kinesis stream using the value provided to "kinesis_stream_arn", but does not create any Kinesis resources. |
object({ |
null |
no |
| table_name | The name of the DynamoDB table. | string |
n/a | yes |
| table_storage_class | (Optional) The storage class for the DynamoDB table. Can be either "STANDARD" or "STANDARD_INFREQUENT_ACCESS"; default: "STANDARD". |
string |
"STANDARD" |
no |
| tags | (Optional) Map of tags for the DynamoDB table. | map(string) |
null |
no |
| ttl | (Optional) Object for configuring TTL; "enabled" defaults to true if not provided. | object({ |
null |
no |
| Name | Description |
|---|---|
| DynamoDB_AutoScaling_Policies | Map of DynamoDB autoscaling policy resource objects, the keys of which are in the format "(table|gsi)/NAME/(reads|writes)". So a table with PROVISIONED capacity named "Foo_Table" with global indexes "Foo_GSI_1" and "Foo_GSI_2" would have the following six keys: "table/Foo_Table/reads", "table/Foo_Table/writes", "gsi/Foo_GSI_1/reads", "gsi/Foo_GSI_1/writes", "gsi/Foo_GSI_2/reads", and "gsi/Foo_GSI_2/writes". |
| DynamoDB_AutoScaling_Targets | Map of DynamoDB autoscaling policy resource objects, the keys of which are in the format "(table|gsi)/NAME/(reads|writes)". So a table with PROVISIONED capacity named "Foo_Table" with global indexes "Foo_GSI_1" and "Foo_GSI_2" would have the following six keys: "table/Foo_Table/reads", "table/Foo_Table/writes", "gsi/Foo_GSI_1/reads", "gsi/Foo_GSI_1/writes", "gsi/Foo_GSI_2/reads", and "gsi/Foo_GSI_2/writes". |
| DynamoDB_Kinesis_Stream_Destination | The DynamoDB Kinesis data stream destination resource object. |
| DynamoDB_Table | The DynamoDB table resource object. |
| DynamoDB_Table_Items | List of DynamoDB table item resource objects. |
All scripts and source code contained herein are for commercial use only by Nerdware, LLC.
See LICENSE for more information.