Skip to content

Latest commit

 

History

History
218 lines (158 loc) · 19.9 KB

File metadata and controls

218 lines (158 loc) · 19.9 KB

Fixit Cloud ☁️ Module: AWS DynamoDB

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.

Table of Contents

DynamoDB Server-Side Encryption

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.

Restoring a DynamoDB Table Using Point-In-Time Recovery

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

Recovery Time

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.

DynamoDB Security Standards & Controls

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.

Useful Links

Usage Examples


⚙️ Module Usage

Usage Examples

Requirements

Name Version
terraform 1.3.2
aws ~> 4.34.0

Providers

Name Version
aws ~> 4.34.0

Modules

No modules.

Resources

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

Inputs

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({
name = string
type = string # "S", "N", or "B"
}))
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({
read = object({
max = number
target_percentage = number
min = number
})
write = object({
max = number
target_percentage = number
min = number
})
})
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(
# map keys: GSI names
object({
hash_key = string
range_key = optional(string)
projection_type = string
non_key_attributes = optional(list(string))
capacity = optional(object({
read = object({
max = number
target_percentage = number
min = number
})
write = object({
max = number
target_percentage = number
min = number
})
}))
})
)
{} 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(
# map keys: LSI names
object({
range_key = string
projection_type = string
non_key_attributes = optional(list(string))
})
)
{} 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(
# map keys: AWS regions in which to create table replicas
object({
propagate_tags = bool
kms_key_arn = string
enable_point_in_time_recovery = optional(bool) # default: false, make TRUE DEFAULT
})
)
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({
source_table_name = string
use_latest_recovery_point = optional(bool)
restore_date_time = optional(string)
})
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({
key_type = string
kms_key_arn = optional(string)
})
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({
dynamodb_stream_view_type = optional(string)
kinesis_stream_arn = optional(string)
})
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({
enabled = optional(bool)
attribute_name = string
})
null no

Outputs

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.

📝 License

All scripts and source code contained herein are for commercial use only by Nerdware, LLC.

See LICENSE for more information.

💬 Contact

Trevor Anderson - @TeeRevTweets - Trevor@Nerdware.cloud

     

Dare Mighty Things.