Skip to content

Commit e833eb7

Browse files
authored
feat: add configuration block to support secret replication (#6)
1 parent a901af3 commit e833eb7

File tree

9 files changed

+263
-7
lines changed

9 files changed

+263
-7
lines changed

.github/workflows/docs.yml

+8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ jobs:
1818
output-file: README.md
1919
config-file: ".terraform-docs.yml"
2020

21+
- name: Render terraform docs inside the examples/basic/README.md
22+
uses: terraform-docs/[email protected]
23+
with:
24+
working-dir: ./examples/replicated/
25+
git-push: "false"
26+
output-file: README.md
27+
config-file: ".terraform-docs.yml"
28+
2129
- name: Render terraform docs inside the README.md
2230
uses: terraform-docs/[email protected]
2331
with:

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ module "secrets" {
8181
| <a name="input_descriptor_formats"></a> [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.<br>Map of maps. Keys are names of descriptors. Values are maps of the form<br>`{<br> format = string<br> labels = list(string)<br>}`<br>(Type is `any` so the map values can later be enhanced to provide additional options.)<br>`format` is a Terraform format string to be passed to the `format()` function.<br>`labels` is a list of labels, in order, to pass to `format()` function.<br>Label values will be normalized before being passed to `format()` so they will be<br>identical to how they appear in `id`.<br>Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no |
8282
| <a name="input_enabled"></a> [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no |
8383
| <a name="input_environment"></a> [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
84+
| <a name="input_force_overwrite_replica_secret"></a> [force\_overwrite\_replica\_secret](#input\_force\_overwrite\_replica\_secret) | Whether to overwrite a secret with the same name in the destination Region. | `bool` | `true` | no |
8485
| <a name="input_id_length_limit"></a> [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).<br>Set to `0` for unlimited length.<br>Set to `null` for keep the existing setting, which defaults to `0`.<br>Does not affect `id_full`. | `number` | `null` | no |
8586
| <a name="input_kms_key"></a> [kms\_key](#input\_kms\_key) | enabled:<br> Whether to create KSM key.<br>description:<br> The description of the key as viewed in AWS console.<br>alias:<br> The display name of the alias. The name must start with the word alias followed by a forward slash. <br> If not specified, the alias name will be auto-generated.<br>deletion\_window\_in\_days:<br> Duration in days after which the key is deleted after destruction of the resource<br>enable\_key\_rotation:<br> Specifies whether key rotation is enabled. | <pre>object({<br> enabled = optional(bool, true)<br> description = optional(string, "Managed by Terraform")<br> alias = optional(string)<br> deletion_window_in_days = optional(number, 30)<br> enable_key_rotation = optional(bool, true)<br> })</pre> | `{}` | no |
8687
| <a name="input_kms_key_id"></a> [kms\_key\_id](#input\_kms\_key\_id) | ARN or Id of the AWS KMS customer master key (CMK) to be used to encrypt the secret values in the versions stored in this secret. <br>If you don't specify this value, then Secrets Manager defaults to using the AWS account's default CMK (the one named `aws/secretsmanager`). | `string` | `null` | no |
@@ -93,6 +94,7 @@ module "secrets" {
9394
| <a name="input_policy"></a> [policy](#input\_policy) | Valid JSON document representing a resource policy. | `string` | `null` | no |
9495
| <a name="input_recovery_window_in_days"></a> [recovery\_window\_in\_days](#input\_recovery\_window\_in\_days) | Valid JSON document representing a resource policy. | `number` | `30` | no |
9596
| <a name="input_regex_replace_chars"></a> [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.<br>Characters matching the regex will be removed from the ID elements.<br>If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no |
97+
| <a name="input_replicas"></a> [replicas](#input\_replicas) | kms\_key\_id:<br> ARN, Key ID, or Alias of the AWS KMS key within the region secret is replicated to.<br>region:<br> Region for replicating the secret. | <pre>list(<br> object(<br> {<br> kms_key_id = string<br> region = string<br> }<br> )<br> )</pre> | `[]` | no |
9698
| <a name="input_rotation"></a> [rotation](#input\_rotation) | enabled:<br> Whether to create secret rotation rule. <br> Default value: `false`<br>lambda\_arn:<br> Specifies the ARN of the Lambda function that can rotate the secret.<br>automatically\_after\_days:<br> Specifies the number of days between automatic scheduled rotations of the secret. | <pre>object({<br> enabled = optional(bool, false)<br> lambda_arn = string<br> automatically_after_days = number<br> })</pre> | <pre>{<br> "automatically_after_days": 0,<br> "lambda_arn": ""<br>}</pre> | no |
9799
| <a name="input_secret_version"></a> [secret\_version](#input\_secret\_version) | enabled:<br> Whether to create secret version. <br> Default value: `false`<br>secret\_string:<br> Specifies text data that you want to encrypt and store in this version of the secret. <br> This is required if `secret_binary` is not set.<br>secret\_binary:<br> Specifies binary data that you want to encrypt and store in this version of the secret. <br> This is required if `secret_string` is not set. <br> Needs to be encoded to base64. | <pre>object({<br> enabled = optional(bool, true)<br> secret_string = optional(string)<br> secret_binary = optional(string)<br> })</pre> | `{}` | no |
98100
| <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 |

examples/basic/main.tf

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@ module "secrets" {
2929
}
3030
)
3131
}
32-
context = module.label.context
32+
recovery_window_in_days = 0
33+
context = module.label.context
3334
}
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
formatter: markdown
2+
3+
output:
4+
file: README.md
5+
mode: replace
6+
template: |-
7+
<!-- BEGIN_TF_DOCS -->
8+
{{ .Content }}
9+
<!-- END_TF_DOCS -->
10+
11+
## License
12+
The Apache-2.0 license
13+
14+
sort:
15+
enabled: true
16+
by: required
17+
18+
settings:
19+
anchor: true
20+
color: true
21+
default: true
22+
description: false
23+
escape: true
24+
hide-empty: false
25+
html: true
26+
indent: 2
27+
lockfile: true
28+
required: true
29+
sensitive: true
30+
type: true

examples/replicated/README.md

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
## terraform-aws-secretsmanager
2+
Terraform module to provision and manage AWS Secrets Manager.
3+
4+
## Usage
5+
6+
```hcl
7+
module "label" {
8+
source = "cloudposse/label/null"
9+
version = "0.25.0"
10+
11+
name = "alpha"
12+
namespace = "so"
13+
stage = "staging"
14+
}
15+
16+
module "ssh_key_pair" {
17+
source = "cloudposse/key-pair/aws"
18+
version = "0.18.1"
19+
20+
ssh_public_key_path = "keys/"
21+
generate_ssh_key = "true"
22+
23+
context = module.label.context
24+
}
25+
26+
module "secrets" {
27+
source = "SweetOps/secretsmanager/aws"
28+
version = "0.1.0"
29+
30+
secret_version = {
31+
secret_string = jsonencode(
32+
{
33+
ssh_public_key = base64encode(module.ssh_key_pair.public_key)
34+
ssh_private_key = base64encode(module.ssh_key_pair.private_key)
35+
}
36+
)
37+
}
38+
39+
context = module.label.context
40+
}
41+
```
42+
43+
<!-- BEGIN_TF_DOCS -->
44+
## Requirements
45+
46+
| Name | Version |
47+
|------|---------|
48+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
49+
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 3.0 |
50+
51+
## Providers
52+
53+
| Name | Version |
54+
|------|---------|
55+
| <a name="provider_aws.ohio"></a> [aws.ohio](#provider\_aws.ohio) | >= 3.0 |
56+
| <a name="provider_aws.virginia"></a> [aws.virginia](#provider\_aws.virginia) | >= 3.0 |
57+
58+
## Modules
59+
60+
| Name | Source | Version |
61+
|------|--------|---------|
62+
| <a name="module_kms_key"></a> [kms\_key](#module\_kms\_key) | cloudposse/kms-key/aws | 0.12.1 |
63+
| <a name="module_label"></a> [label](#module\_label) | cloudposse/label/null | 0.25.0 |
64+
| <a name="module_secrets"></a> [secrets](#module\_secrets) | ../../ | n/a |
65+
| <a name="module_ssh_key_pair"></a> [ssh\_key\_pair](#module\_ssh\_key\_pair) | cloudposse/key-pair/aws | 0.18.1 |
66+
67+
## Resources
68+
69+
| Name | Type |
70+
|------|------|
71+
| [aws_kms_replica_key.ohio](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_replica_key) | resource |
72+
| [aws_kms_replica_key.virginia](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_replica_key) | resource |
73+
74+
## Inputs
75+
76+
No inputs.
77+
78+
## Outputs
79+
80+
No outputs.
81+
<!-- END_TF_DOCS -->
82+
83+
## License
84+
The Apache-2.0 license

examples/replicated/main.tf

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
provider "aws" {
2+
region = "us-east-1"
3+
alias = "virginia"
4+
}
5+
6+
provider "aws" {
7+
region = "us-east-2"
8+
alias = "ohio"
9+
}
10+
11+
module "label" {
12+
source = "cloudposse/label/null"
13+
version = "0.25.0"
14+
15+
name = "replicated"
16+
namespace = "so"
17+
stage = "staging"
18+
}
19+
20+
module "ssh_key_pair" {
21+
source = "cloudposse/key-pair/aws"
22+
version = "0.18.1"
23+
24+
ssh_public_key_path = "keys/"
25+
generate_ssh_key = "true"
26+
27+
context = module.label.context
28+
}
29+
30+
module "kms_key" {
31+
source = "cloudposse/kms-key/aws"
32+
version = "0.12.1"
33+
34+
multi_region = true
35+
36+
context = module.label.context
37+
}
38+
39+
resource "aws_kms_replica_key" "virginia" {
40+
provider = aws.virginia
41+
42+
description = "Multi-Region replica key"
43+
deletion_window_in_days = 7
44+
primary_key_arn = module.kms_key.key_arn
45+
}
46+
47+
resource "aws_kms_replica_key" "ohio" {
48+
provider = aws.ohio
49+
50+
description = "Multi-Region replica key"
51+
deletion_window_in_days = 7
52+
primary_key_arn = module.kms_key.key_arn
53+
}
54+
55+
module "secrets" {
56+
source = "../../"
57+
58+
secret_version = {
59+
enabled = true
60+
secret_string = jsonencode(
61+
{
62+
ssh_public_key = base64encode(module.ssh_key_pair.public_key)
63+
ssh_private_key = base64encode(module.ssh_key_pair.private_key)
64+
}
65+
)
66+
}
67+
68+
recovery_window_in_days = 0
69+
kms_key_id = module.kms_key.key_id
70+
71+
kms_key = {
72+
enabled = false
73+
}
74+
75+
replicas = [
76+
{
77+
region = "us-east-1"
78+
kms_key_id = aws_kms_replica_key.virginia.key_id
79+
},
80+
{
81+
region = "us-east-2"
82+
kms_key_id = aws_kms_replica_key.ohio.key_id
83+
}
84+
]
85+
86+
context = module.label.context
87+
}

examples/replicated/versions.tf

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
terraform {
2+
required_version = ">= 1.3"
3+
4+
required_providers {
5+
aws = {
6+
source = "hashicorp/aws"
7+
version = ">= 3.0"
8+
}
9+
}
10+
}

main.tf

+16-6
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,22 @@ module "kms_key" {
2626
resource "aws_secretsmanager_secret" "default" {
2727
count = local.enabled ? 1 : 0
2828

29-
name = module.this.id
30-
description = var.description
31-
policy = var.policy
32-
tags = module.this.tags
33-
recovery_window_in_days = var.recovery_window_in_days
34-
kms_key_id = local.kms_key_id
29+
name = module.this.id
30+
description = var.description
31+
policy = var.policy
32+
tags = module.this.tags
33+
recovery_window_in_days = var.recovery_window_in_days
34+
kms_key_id = local.kms_key_id
35+
force_overwrite_replica_secret = var.force_overwrite_replica_secret
36+
37+
dynamic "replica" {
38+
for_each = var.replicas
39+
40+
content {
41+
kms_key_id = replica.value.kms_key_id
42+
region = replica.value.region
43+
}
44+
}
3545
}
3646

3747
resource "aws_secretsmanager_secret_version" "default" {

variables.tf

+24
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,30 @@ variable "recovery_window_in_days" {
1616
description = "Valid JSON document representing a resource policy."
1717
}
1818

19+
variable "force_overwrite_replica_secret" {
20+
type = bool
21+
default = true
22+
description = "Whether to overwrite a secret with the same name in the destination Region."
23+
}
24+
25+
variable "replicas" {
26+
type = list(
27+
object(
28+
{
29+
kms_key_id = string
30+
region = string
31+
}
32+
)
33+
)
34+
default = []
35+
description = <<-DOC
36+
kms_key_id:
37+
ARN, Key ID, or Alias of the AWS KMS key within the region secret is replicated to.
38+
region:
39+
Region for replicating the secret.
40+
DOC
41+
}
42+
1943
variable "kms_key_id" {
2044
type = string
2145
default = null

0 commit comments

Comments
 (0)