Skip to content

Commit f77a5c2

Browse files
authored
Merge pull request #7 from scribd/SEC-696
[SEC-696] Support policies for secrets for cross-account access
2 parents e5aed27 + 43a5966 commit f77a5c2

File tree

5 files changed

+95
-22
lines changed

5 files changed

+95
-22
lines changed

README.md

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ A module to create application secrets stored in [AWS Secrets Manager](https://a
88
* [Prerequisites](#prerequisites)
99
* [Example usage](#example-usage)
1010
* [Inputs](#inputs)
11+
* [Secrets](#secrets)
1112
* [Outputs](#outputs)
1213
* [Release](#release)
1314
* [Maintainers](#maintainers)
@@ -24,15 +25,43 @@ module "secrets" {
2425
source = "git::ssh://git@github.com/scribd/terraform-aws-app-secrets.git?ref=main"
2526
2627
app_name = "go-chassis"
27-
secrets = {
28-
"app-env" = "development"
29-
"app-settings-name" = "go-chassis"
30-
"app-database-host" = "[value required]"
31-
"app-database-port" = "3306"
32-
"app-database-name" = "[value required]"
33-
"app-database-username" = "[value required]"
34-
"app-database-password" = "[value required]"
35-
}
28+
secrets = [
29+
{
30+
name = "app-env"
31+
value = "development"
32+
allowed_arns = []
33+
},
34+
{
35+
name = "app-settings-name"
36+
value = "go-chassis"
37+
allowed_arns = []
38+
},
39+
{
40+
name = "app-database-host"
41+
value = "[value required]"
42+
allowed_arn = ["arn:aws:iam::1234567890:role/theirRole"]
43+
},
44+
{
45+
name = "app-database-port"
46+
value = "3306"
47+
allowed_arns = []
48+
},
49+
{
50+
name = "app-database-username"
51+
value = "[value required]"
52+
allowed_arns = []
53+
},
54+
{
55+
name = "app-database-password"
56+
value = "[value required]"
57+
allowed_arns = []
58+
},
59+
{
60+
name = "app-database-name"
61+
value = "[value required]"
62+
allowed_arns = []
63+
}
64+
]
3665
3766
tags = {
3867
department = "engineering"
@@ -49,11 +78,20 @@ module "secrets" {
4978
5079
## Inputs
5180

52-
| Name | Description | Type | Default | Required |
53-
| ----------- | ------------------------ | ----------- | ------- | :-------: |
54-
| app_name | Application name | string | `null` | yes |
55-
| secrets | Key-value map of secrets | map(string) | `null` | yes |
56-
| tags | Key-value map of tags | map(string) | `{}` | no |
81+
| Name | Description | Type | Default | Required |
82+
| ------------ | -------------------------------------- | ------------ | ----------- | --------- |
83+
| `app_name` | Application name | string | `null` | yes |
84+
| `aws_region` | AWS region | string | `us-east-2` | no |
85+
| `secrets` | List of objects of [secrets](#secrets) | list(object) | `null` | yes |
86+
| `tags` | Key-value map of tags | map(string) | `{}` | no |
87+
88+
### Secrets
89+
90+
| Name | Description | Type | Default |
91+
| -------------- | ----------------------------------------------------- | ------ | ------- |
92+
| `name` | Secret name | string | `null` |
93+
| `value` | Secret value | string | `null` |
94+
| `allowed_arns` | List of principal ARNs that have access to the secret | list | `null` |
5795

5896
## Outputs
5997

locals.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
locals {
2+
secrets = { for secret in var.secrets : secret.name => secret.value }
3+
arns = { for secret in var.secrets : secret.name => secret.allowed_arns if length(secret.allowed_arns) > 0 }
4+
}

main.tf

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,35 @@
1+
data "aws_caller_identity" "current" {}
2+
3+
data "aws_iam_policy_document" "access" {
4+
for_each = local.arns
5+
6+
statement {
7+
principals {
8+
type = "AWS"
9+
identifiers = each.value
10+
}
11+
12+
actions = ["secretsmanager:GetSecretValue"]
13+
resources = ["arn:aws:secretsmanager:${var.aws_region}:${data.aws_caller_identity.current.account_id}:secret:${var.app_name}-${each.key}*"]
14+
}
15+
}
16+
117
resource "aws_secretsmanager_secret" "app" {
2-
for_each = var.secrets
18+
for_each = local.secrets
319

420
name_prefix = "${var.app_name}-${each.key}"
521
description = "The ${title(replace(each.key, "-", " "))} secret for ${var.app_name} application"
622

23+
policy = lookup(local.arns, each.key, null) == null ? null : data.aws_iam_policy_document.access[each.key].json
24+
725
tags = merge(var.tags, { "service" = var.app_name })
826
}
927

1028
resource "aws_secretsmanager_secret_version" "app" {
11-
for_each = var.secrets
29+
for_each = local.secrets
1230

1331
secret_id = aws_secretsmanager_secret.app[each.key].id
14-
secret_string = each.value
32+
secret_string = each.value != "" ? each.value : "[value required]"
1533

1634
lifecycle {
1735
ignore_changes = [secret_string]

outputs.tf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
output "all" {
22
description = "Map of names and arns of created secrets"
33
value = [
4-
for k in keys(var.secrets) : {
5-
name = upper(replace(k, "-", "_"))
6-
arn = aws_secretsmanager_secret.app[k].id
4+
for name in keys(local.secrets) : {
5+
name = upper(replace(name, "-", "_"))
6+
arn = aws_secretsmanager_secret.app[name].id
77
}
88
]
99
}

variables.tf

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,22 @@ variable "app_name" {
33
type = string
44
}
55

6+
variable "aws_region" {
7+
description = "AWS region"
8+
type = string
9+
10+
default = "us-east-2"
11+
}
12+
613
variable "secrets" {
7-
description = "Key-value map of secrets"
8-
type = map(string)
14+
description = "List of objects of secrets"
15+
type = list(
16+
object({
17+
name = string
18+
value = string
19+
allowed_arns = list(string)
20+
})
21+
)
922
}
1023

1124
variable "tags" {

0 commit comments

Comments
 (0)