Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions DynamoDB/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# AWS DynamoDB

This module creates a single DynamoDB table using native `aws_dynamodb_table`. Naming uses the terraform-accelerator Label module via `context`.
See the [example](./example/) for a minimal runnable setup.

## Features

- **Schema:** Full control via `attribute` (list of name/type) and `key_schema` (list of name/key_type HASH|RANGE).
- **Billing:** On-demand by default (`PAY_PER_REQUEST`); optional provisioned capacity.
- **Security/compliance:** Server-side encryption enabled by default; optional KMS key; point-in-time recovery enabled by default.
- **Optional:** DynamoDB Streams, TTL.

## Usage

### Minimal (hash key only, on-demand, encrypted, PITR)

```hcl
module "dynamodb" {
source = "./DynamoDB"

context = module.this.context

attribute = [
{ name = "id", type = "S" }
]
key_schema = [
{ name = "id", key_type = "HASH" }
]
}
```

### With range key and TTL

```hcl
module "dynamodb" {
source = "./DynamoDB"

context = module.this.context

attribute = [
{ name = "pk", type = "S" },
{ name = "sk", type = "S" },
{ name = "ttl", type = "N" }
]
key_schema = [
{ name = "pk", key_type = "HASH" },
{ name = "sk", key_type = "RANGE" }
]
ttl_attribute_name = "ttl"
}
```

### With streams

```hcl
module "dynamodb" {
source = "./DynamoDB"

context = module.this.context

attribute = [
{ name = "id", type = "S" }
]
key_schema = [
{ name = "id", key_type = "HASH" }
]
stream_enabled = true
stream_view_type = "NEW_AND_OLD_IMAGES"
}
```

### Provisioned capacity

Set `billing_mode = "PROVISIONED"` and provide `read_capacity` and `write_capacity`.

## Module Specs

[SPECS.md](./SPECS.md)
60 changes: 60 additions & 0 deletions DynamoDB/SPECS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | 6.32.1 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_this"></a> [this](#module\_this) | git::git@github.com:generalui/terraform-accelerator.git//Label | 1.0.1-Label |

## Resources

| Name | Type |
|------|------|
| [aws_dynamodb_table.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/dynamodb_table) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_attribute"></a> [attribute](#input\_attribute) | List of attribute definitions. Each element must have `name` and `type` (S, N, or B).<br>Must include an attribute for every key in `key_schema`. | <pre>list(object({<br> name = string<br> type = string<br> }))</pre> | n/a | yes |
| <a name="input_attributes"></a> [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,<br>in the order they appear in the list. New attributes are appended to the<br>end of the list. The elements of the list are joined by the `delimiter`<br>and treated as a single ID element. | `list(string)` | `[]` | no |
| <a name="input_billing_mode"></a> [billing\_mode](#input\_billing\_mode) | Billing mode: PAY\_PER\_REQUEST (on-demand) or PROVISIONED. | `string` | `"PAY_PER_REQUEST"` | no |
| <a name="input_context"></a> [context](#input\_context) | Single object for setting entire context at once.<br>See description of individual variables for details.<br>Leave string and numeric variables as `null` to use default value.<br>Individual variable settings (non-null) override settings in context object,<br>except for attributes, tags, and additional\_tag\_map, which are merged. | `any` | <pre>{<br> "attributes": [],<br> "name": null,<br> "namespace": null,<br> "stage": null,<br> "tags": {}<br>}</pre> | no |
| <a name="input_enabled"></a> [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no |
| <a name="input_key_schema"></a> [key\_schema](#input\_key\_schema) | List of key schema elements. Each element must have `name` (attribute name) and `key_type` (HASH or RANGE).<br>Exactly one HASH key is required; RANGE key is optional. | <pre>list(object({<br> name = string<br> key_type = string<br> }))</pre> | n/a | yes |
| <a name="input_kms_key_arn"></a> [kms\_key\_arn](#input\_kms\_key\_arn) | ARN of a KMS key for server-side encryption. When null, AWS owned key is used (default). | `string` | `null` | no |
| <a name="input_name"></a> [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.<br>This is the only ID element not also included as a `tag`.<br>The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no |
| <a name="input_namespace"></a> [namespace](#input\_namespace) | ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique | `string` | `null` | no |
| <a name="input_point_in_time_recovery_enabled"></a> [point\_in\_time\_recovery\_enabled](#input\_point\_in\_time\_recovery\_enabled) | Enable point-in-time recovery (continuous backups). Recommended for production and compliance. | `bool` | `true` | no |
| <a name="input_read_capacity"></a> [read\_capacity](#input\_read\_capacity) | Number of read capacity units. Required when billing\_mode is PROVISIONED. | `number` | `null` | no |
| <a name="input_server_side_encryption_enabled"></a> [server\_side\_encryption\_enabled](#input\_server\_side\_encryption\_enabled) | Enable server-side encryption at rest (AWS managed key unless kms\_key\_arn is set). | `bool` | `true` | no |
| <a name="input_stage"></a> [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
| <a name="input_stream_enabled"></a> [stream\_enabled](#input\_stream\_enabled) | Enable DynamoDB Streams for change data capture. | `bool` | `false` | no |
| <a name="input_stream_view_type"></a> [stream\_view\_type](#input\_stream\_view\_type) | Stream view type when stream\_enabled is true: KEYS\_ONLY, NEW\_IMAGE, OLD\_IMAGE, NEW\_AND\_OLD\_IMAGES. | `string` | `"NEW_AND_OLD_IMAGES"` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).<br>Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no |
| <a name="input_ttl_attribute_name"></a> [ttl\_attribute\_name](#input\_ttl\_attribute\_name) | Name of the attribute to use for TTL. When set, TTL is enabled on the table. | `string` | `null` | no |
| <a name="input_ttl_enabled"></a> [ttl\_enabled](#input\_ttl\_enabled) | Enable TTL. Defaults to true when ttl\_attribute\_name is non-null, else false. | `bool` | `null` | no |
| <a name="input_write_capacity"></a> [write\_capacity](#input\_write\_capacity) | Number of write capacity units. Required when billing\_mode is PROVISIONED. | `number` | `null` | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_arn"></a> [arn](#output\_arn) | ARN of the DynamoDB table. |
| <a name="output_id"></a> [id](#output\_id) | Name of the DynamoDB table (unique within the region). |
| <a name="output_name"></a> [name](#output\_name) | Name of the DynamoDB table. |
| <a name="output_stream_arn"></a> [stream\_arn](#output\_stream\_arn) | ARN of the DynamoDB stream (when stream\_enabled is true). |
| <a name="output_stream_label"></a> [stream\_label](#output\_stream\_label) | Timestamp of the stream (when stream\_enabled is true). |
<!-- END_TF_DOCS -->
85 changes: 85 additions & 0 deletions DynamoDB/context.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Module should access the whole context as `module.this.context`
# to get the input variables with nulls for defaults,
# for example `context = module.this.context`,
# and access individual variables as `module.this.<var>`,
# with final values filled in.
#

module "this" {
source = "git::git@github.com:generalui/terraform-accelerator.git//Label?ref=1.0.1-Label"

enabled = var.enabled
namespace = var.namespace
stage = var.stage
name = var.name
attributes = var.attributes
tags = var.tags

context = var.context
}

variable "attributes" {
type = list(string)
default = []
description = <<-EOT
ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element.
EOT
}

variable "context" {
type = any
default = {
attributes = []
name = null
namespace = null
stage = null
tags = {}
}
description = <<-EOT
Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional_tag_map, which are merged.
EOT
}

variable "enabled" {
type = bool
default = null
description = "Set to false to prevent the module from creating any resources"
}

variable "name" {
type = string
default = null
description = <<-EOT
ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input.
EOT
}

variable "namespace" {
type = string
default = null
description = "ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique"
}

variable "stage" {
type = string
default = null
description = "ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release'"
}

variable "tags" {
type = map(string)
default = {}
description = <<-EOT
Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module.
EOT
}
35 changes: 35 additions & 0 deletions DynamoDB/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# DynamoDB example

Runnable example: single DynamoDB table with a string hash key, on-demand billing, encryption, and point-in-time recovery enabled.

## Prerequisites

- AWS CLI configured (profile or default)
- Terraform >= 1.3

## Run

```bash
cd DynamoDB/example
terraform init
terraform apply
```

## Clean up

```bash
terraform destroy
```

## What it creates

- **Label** (context / naming: `namespace` + `project` + `environment_name`, e.g. `xmpl-dynamodb-test`)
- **DynamoDB table** with:
- Hash key `id` (string)
- On-demand billing
- Server-side encryption and PITR enabled (defaults)

## Variables

Override as needed, e.g. `-var="aws_region=us-east-1"` or a `.tfvars` file.
Key variables: `aws_profile`, `aws_region`, `project`, `namespace`, `environment_name`.
67 changes: 67 additions & 0 deletions DynamoDB/example/context.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Label context for the example (naming: namespace + project + environment_name).

module "this" {
source = "git::git@github.com:generalui/terraform-accelerator.git//Label?ref=1.0.1-Label"

attributes = var.attributes
enabled = var.enabled
name = var.project
namespace = var.namespace
stage = var.environment_name
tags = var.tags

context = var.context
}

variable "attributes" {
type = list(string)
default = []
description = "ID element. Additional attributes to add to the label id."
}

variable "context" {
type = any
default = {
attributes = []
enabled = true
name = null
namespace = null
stage = null
tags = {}
}
description = "Single object for setting entire context at once."
}

variable "enabled" {
type = bool
default = true
description = "Set to false to prevent the module from creating any resources."
}

variable "environment_name" {
type = string
default = "test"
description = "Environment name, e.g. prod, staging, dev."
validation {
condition = length(var.environment_name) < 8
error_message = "environment_name must be less than 8 characters."
}
}

variable "namespace" {
type = string
default = "xmpl"
description = "ID element. Usually an abbreviation of your organization name."
}

variable "project" {
type = string
default = "dynamodb"
description = "Project name."
}

variable "tags" {
type = map(string)
default = {}
description = "Additional tags."
}
37 changes: 37 additions & 0 deletions DynamoDB/example/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# DynamoDB example: single table with hash key (on-demand, encrypted, PITR).
# Run from this directory: terraform init && terraform apply

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
required_version = ">= 1.3"
}

provider "aws" {
profile = var.aws_profile
region = var.aws_region
default_tags {
tags = {
Environment = var.environment_name
Maintained = "terraform"
Project = var.project
}
}
}

module "dynamodb" {
source = "../"

context = module.this.context

attribute = [
{ name = "id", type = "S" }
]
key_schema = [
{ name = "id", key_type = "HASH" }
]
}
14 changes: 14 additions & 0 deletions DynamoDB/example/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
output "table_name" {
description = "DynamoDB table name."
value = module.dynamodb.name
}

output "table_arn" {
description = "DynamoDB table ARN."
value = module.dynamodb.arn
}

output "table_id" {
description = "DynamoDB table ID (same as name within the region)."
value = module.dynamodb.id
}
11 changes: 11 additions & 0 deletions DynamoDB/example/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
variable "aws_profile" {
type = string
default = "default"
description = "AWS profile name from shared credentials file."
}

variable "aws_region" {
type = string
default = "us-west-2"
description = "AWS region."
}
Loading