From f9191c9c6c009aa6b3b6090e24e22e4ba9007afb Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Thu, 8 Jun 2023 17:25:49 +0300 Subject: [PATCH 1/8] feat: define iam_policy_statements object syntax --- docs/terraform.md | 4 ++-- variables.tf | 24 ++++++++++++++++++++++-- versions.tf | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/docs/terraform.md b/docs/terraform.md index 63204c6..f985685 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -3,7 +3,7 @@ | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | +| [terraform](#requirement\_terraform) | >= 1.3.0 | | [aws](#requirement\_aws) | >= 4.0 | | [http](#requirement\_http) | >= 3.0 | @@ -43,7 +43,7 @@ | [iam\_override\_policy\_documents](#input\_iam\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank sids will override statements with the same sid from earlier documents in the list. Statements with non-blank sids will also override statements with the same sid from documents provided in the `source_json` and `source_policy_documents` arguments. Non-overriding statements will be added to the exported document. | `list(string)` | `null` | no | | [iam\_policy\_enabled](#input\_iam\_policy\_enabled) | If set to true will create IAM policy in AWS | `bool` | `false` | no | | [iam\_policy\_id](#input\_iam\_policy\_id) | ID for the policy document. | `string` | `null` | no | -| [iam\_policy\_statements](#input\_iam\_policy\_statements) | Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`. | `any` | `{}` | no | +| [iam\_policy\_statements](#input\_iam\_policy\_statements) | Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`. |
object({
sid = optional(string, "")
effect = optional(string, "")
actions = optional(list(string), [])
not_actions = optional(list(string), [])
resources = optional(list(string), [])
not_resources = optional(list(string), [])
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
})
| `{}` | no | | [iam\_source\_json\_url](#input\_iam\_source\_json\_url) | IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`. | `string` | `null` | no | | [iam\_source\_policy\_documents](#input\_iam\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. Statements defined in `source_policy_documents` or `source_json` must have unique sids. Statements with the same sid from documents assigned to the `override_json` and `override_policy_documents` arguments will override source statements. | `list(string)` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | diff --git a/variables.tf b/variables.tf index d40acc8..d77e483 100644 --- a/variables.tf +++ b/variables.tf @@ -5,7 +5,27 @@ variable "iam_source_json_url" { } variable "iam_policy_statements" { - type = any + type = object({ + sid = optional(string, "") + effect = optional(string, "") + actions = optional(list(string), []) + not_actions = optional(list(string), []) + resources = optional(list(string), []) + not_resources = optional(list(string), []) + conditions = optional(list(object({ + test = string + variable = string + values = list(string) + })), []) + principals = optional(list(object({ + type = string + identifiers = list(string) + })), []) + not_principals = optional(list(object({ + type = string + identifiers = list(string) + })), []) + }) description = "Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`." default = {} } @@ -38,4 +58,4 @@ variable "iam_override_policy_documents" { type = list(string) description = "List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank sids will override statements with the same sid from earlier documents in the list. Statements with non-blank sids will also override statements with the same sid from documents provided in the `source_json` and `source_policy_documents` arguments. Non-overriding statements will be added to the exported document." default = null -} \ No newline at end of file +} diff --git a/versions.tf b/versions.tf index a5ae90f..2134073 100644 --- a/versions.tf +++ b/versions.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3.0" required_providers { # Update these to reflect the actual requirements of your module From 419fb4be1558435b8b15d6ed5daa0e52e4e3dd60 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Thu, 8 Jun 2023 18:47:33 +0300 Subject: [PATCH 2/8] fix: update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 30c4a65..8d8c695 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,7 @@ Available targets: | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | +| [terraform](#requirement\_terraform) | >= 1.3.0 | | [aws](#requirement\_aws) | >= 4.0 | | [http](#requirement\_http) | >= 3.0 | @@ -217,7 +217,7 @@ Available targets: | [iam\_override\_policy\_documents](#input\_iam\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank sids will override statements with the same sid from earlier documents in the list. Statements with non-blank sids will also override statements with the same sid from documents provided in the `source_json` and `source_policy_documents` arguments. Non-overriding statements will be added to the exported document. | `list(string)` | `null` | no | | [iam\_policy\_enabled](#input\_iam\_policy\_enabled) | If set to true will create IAM policy in AWS | `bool` | `false` | no | | [iam\_policy\_id](#input\_iam\_policy\_id) | ID for the policy document. | `string` | `null` | no | -| [iam\_policy\_statements](#input\_iam\_policy\_statements) | Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`. | `any` | `{}` | no | +| [iam\_policy\_statements](#input\_iam\_policy\_statements) | Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`. |
object({
sid = optional(string, "")
effect = optional(string, "")
actions = optional(list(string), [])
not_actions = optional(list(string), [])
resources = optional(list(string), [])
not_resources = optional(list(string), [])
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
})
| `{}` | no | | [iam\_source\_json\_url](#input\_iam\_source\_json\_url) | IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`. | `string` | `null` | no | | [iam\_source\_policy\_documents](#input\_iam\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. Statements defined in `source_policy_documents` or `source_json` must have unique sids. Statements with the same sid from documents assigned to the `override_json` and `override_policy_documents` arguments will override source statements. | `list(string)` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | From 43364f4004218687cc31b9de95f0a2be33cd25d1 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Fri, 9 Jun 2023 14:19:53 +0300 Subject: [PATCH 3/8] fix: adjust dynamic statements to stricter object syntax --- README.md | 2 +- docs/terraform.md | 2 +- main.tf | 21 ++++++++++----------- variables.tf | 22 +++++++++++----------- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 8d8c695..a3a2140 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ Available targets: | [iam\_override\_policy\_documents](#input\_iam\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank sids will override statements with the same sid from earlier documents in the list. Statements with non-blank sids will also override statements with the same sid from documents provided in the `source_json` and `source_policy_documents` arguments. Non-overriding statements will be added to the exported document. | `list(string)` | `null` | no | | [iam\_policy\_enabled](#input\_iam\_policy\_enabled) | If set to true will create IAM policy in AWS | `bool` | `false` | no | | [iam\_policy\_id](#input\_iam\_policy\_id) | ID for the policy document. | `string` | `null` | no | -| [iam\_policy\_statements](#input\_iam\_policy\_statements) | Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`. |
object({
sid = optional(string, "")
effect = optional(string, "")
actions = optional(list(string), [])
not_actions = optional(list(string), [])
resources = optional(list(string), [])
not_resources = optional(list(string), [])
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
})
| `{}` | no | +| [iam\_policy\_statements](#input\_iam\_policy\_statements) | Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`. |
map(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), null)
principals = optional(list(object({
type = string
identifiers = list(string)
})), null)
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), null)
}))
| `{}` | no | | [iam\_source\_json\_url](#input\_iam\_source\_json\_url) | IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`. | `string` | `null` | no | | [iam\_source\_policy\_documents](#input\_iam\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. Statements defined in `source_policy_documents` or `source_json` must have unique sids. Statements with the same sid from documents assigned to the `override_json` and `override_policy_documents` arguments will override source statements. | `list(string)` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | diff --git a/docs/terraform.md b/docs/terraform.md index f985685..65ca1e2 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -43,7 +43,7 @@ | [iam\_override\_policy\_documents](#input\_iam\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank sids will override statements with the same sid from earlier documents in the list. Statements with non-blank sids will also override statements with the same sid from documents provided in the `source_json` and `source_policy_documents` arguments. Non-overriding statements will be added to the exported document. | `list(string)` | `null` | no | | [iam\_policy\_enabled](#input\_iam\_policy\_enabled) | If set to true will create IAM policy in AWS | `bool` | `false` | no | | [iam\_policy\_id](#input\_iam\_policy\_id) | ID for the policy document. | `string` | `null` | no | -| [iam\_policy\_statements](#input\_iam\_policy\_statements) | Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`. |
object({
sid = optional(string, "")
effect = optional(string, "")
actions = optional(list(string), [])
not_actions = optional(list(string), [])
resources = optional(list(string), [])
not_resources = optional(list(string), [])
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
})
| `{}` | no | +| [iam\_policy\_statements](#input\_iam\_policy\_statements) | Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`. |
map(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), null)
principals = optional(list(object({
type = string
identifiers = list(string)
})), null)
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), null)
}))
| `{}` | no | | [iam\_source\_json\_url](#input\_iam\_source\_json\_url) | IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`. | `string` | `null` | no | | [iam\_source\_policy\_documents](#input\_iam\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. Statements defined in `source_policy_documents` or `source_json` must have unique sids. Statements with the same sid from documents assigned to the `override_json` and `override_policy_documents` arguments will override source statements. | `list(string)` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | diff --git a/main.tf b/main.tf index 49b3a77..a9d5365 100644 --- a/main.tf +++ b/main.tf @@ -27,21 +27,20 @@ data "aws_iam_policy_document" "this" { source_policy_documents = local.source_policy_documents != [] ? local.source_policy_documents : null dynamic "statement" { - # Only flatten if a list(string) is passed in, otherwise use the map var as-is - for_each = try(flatten(var.iam_policy_statements), var.iam_policy_statements) + for_each = var.iam_policy_statements content { - sid = lookup(statement.value, "sid", statement.key) - effect = lookup(statement.value, "effect", null) + sid = coalesce(statement.value.sid, statement.key) + effect = statement.value.effect - actions = lookup(statement.value, "actions", null) - not_actions = lookup(statement.value, "not_actions", null) + actions = statement.value.actions + not_actions = statement.value.not_actions - resources = lookup(statement.value, "resources", null) - not_resources = lookup(statement.value, "not_resources", null) + resources = statement.value.resources + not_resources = statement.value.not_resources dynamic "principals" { - for_each = lookup(statement.value, "principals", []) + for_each = coalesce(statement.value.principals, []) content { type = principals.value.type @@ -50,7 +49,7 @@ data "aws_iam_policy_document" "this" { } dynamic "not_principals" { - for_each = lookup(statement.value, "not_principals", []) + for_each = coalesce(statement.value.not_principals, []) content { type = not_principals.value.type @@ -59,7 +58,7 @@ data "aws_iam_policy_document" "this" { } dynamic "condition" { - for_each = lookup(statement.value, "conditions", []) + for_each = coalesce(statement.value.conditions, []) content { test = condition.value.test diff --git a/variables.tf b/variables.tf index d77e483..2e35984 100644 --- a/variables.tf +++ b/variables.tf @@ -5,27 +5,27 @@ variable "iam_source_json_url" { } variable "iam_policy_statements" { - type = object({ - sid = optional(string, "") - effect = optional(string, "") - actions = optional(list(string), []) - not_actions = optional(list(string), []) - resources = optional(list(string), []) - not_resources = optional(list(string), []) + type = map(object({ + sid = optional(string, null) + effect = optional(string, null) + actions = optional(list(string), null) + not_actions = optional(list(string), null) + resources = optional(list(string), null) + not_resources = optional(list(string), null) conditions = optional(list(object({ test = string variable = string values = list(string) - })), []) + })), null) principals = optional(list(object({ type = string identifiers = list(string) - })), []) + })), null) not_principals = optional(list(object({ type = string identifiers = list(string) - })), []) - }) + })), null) + })) description = "Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`." default = {} } From 8f2f7534bb2c58b7af135fd24719d30263384498 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Fri, 9 Jun 2023 15:56:11 +0300 Subject: [PATCH 4/8] chore: adds variable for IAM policy version --- README.md | 1 + docs/terraform.md | 1 + main.tf | 1 + variables.tf | 10 ++++++++++ 4 files changed, 13 insertions(+) diff --git a/README.md b/README.md index a3a2140..ccf867d 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,7 @@ Available targets: | [iam\_policy\_enabled](#input\_iam\_policy\_enabled) | If set to true will create IAM policy in AWS | `bool` | `false` | no | | [iam\_policy\_id](#input\_iam\_policy\_id) | ID for the policy document. | `string` | `null` | no | | [iam\_policy\_statements](#input\_iam\_policy\_statements) | Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`. |
map(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), null)
principals = optional(list(object({
type = string
identifiers = list(string)
})), null)
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), null)
}))
| `{}` | no | +| [iam\_policy\_version](#input\_iam\_policy\_version) | IAM policy document version. | `string` | `"2012-10-17"` | no | | [iam\_source\_json\_url](#input\_iam\_source\_json\_url) | IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`. | `string` | `null` | no | | [iam\_source\_policy\_documents](#input\_iam\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. Statements defined in `source_policy_documents` or `source_json` must have unique sids. Statements with the same sid from documents assigned to the `override_json` and `override_policy_documents` arguments will override source statements. | `list(string)` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | diff --git a/docs/terraform.md b/docs/terraform.md index 65ca1e2..d2ae027 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -44,6 +44,7 @@ | [iam\_policy\_enabled](#input\_iam\_policy\_enabled) | If set to true will create IAM policy in AWS | `bool` | `false` | no | | [iam\_policy\_id](#input\_iam\_policy\_id) | ID for the policy document. | `string` | `null` | no | | [iam\_policy\_statements](#input\_iam\_policy\_statements) | Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`. |
map(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), null)
principals = optional(list(object({
type = string
identifiers = list(string)
})), null)
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), null)
}))
| `{}` | no | +| [iam\_policy\_version](#input\_iam\_policy\_version) | IAM policy document version. | `string` | `"2012-10-17"` | no | | [iam\_source\_json\_url](#input\_iam\_source\_json\_url) | IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`. | `string` | `null` | no | | [iam\_source\_policy\_documents](#input\_iam\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. Statements defined in `source_policy_documents` or `source_json` must have unique sids. Statements with the same sid from documents assigned to the `override_json` and `override_policy_documents` arguments will override source statements. | `list(string)` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | diff --git a/main.tf b/main.tf index a9d5365..ecc8d54 100644 --- a/main.tf +++ b/main.tf @@ -22,6 +22,7 @@ data "aws_iam_policy_document" "this" { count = local.enabled ? 1 : 0 policy_id = var.iam_policy_id + version = var.iam_policy_version override_policy_documents = local.iam_override_policy_documents != [] ? local.iam_override_policy_documents : null source_policy_documents = local.source_policy_documents != [] ? local.source_policy_documents : null diff --git a/variables.tf b/variables.tf index 2e35984..9905869 100644 --- a/variables.tf +++ b/variables.tf @@ -48,6 +48,16 @@ variable "iam_policy_id" { default = null } +variable "iam_policy_version" { + type = string + description = "IAM policy document version." + default = "2012-10-17" + validation { + condition = contains(["2008-10-17", "2012-10-17"], var.iam_policy_version) + error_message = "The iam_policy_version valid values are '2008-10-17' or '2012-10-17'." + } +} + variable "iam_source_policy_documents" { type = list(string) description = "List of IAM policy documents that are merged together into the exported document. Statements defined in `source_policy_documents` or `source_json` must have unique sids. Statements with the same sid from documents assigned to the `override_json` and `override_policy_documents` arguments will override source statements." From 315c312f580c5a5cc0912ebb6dc56577516aa0bd Mon Sep 17 00:00:00 2001 From: Nuru Date: Fri, 9 Jun 2023 13:55:18 -0700 Subject: [PATCH 5/8] Add `iam_policy`, deprecate `iam_policy_statements`, fix tflint --- README.md | 10 +-- docs/terraform.md | 10 +-- examples/complete/fixtures.us-east-2.tfvars | 31 +++++++++ examples/complete/main.tf | 19 +++++- examples/complete/outputs.tf | 5 ++ examples/complete/variables.tf | 66 +++++++++++++++++- main.tf | 48 +++++++++---- outputs.tf | 6 +- test/src/examples_complete_test.go | 10 ++- variables.tf | 75 ++++++++++++++++----- 10 files changed, 230 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index ccf867d..880731b 100644 --- a/README.md +++ b/README.md @@ -214,13 +214,13 @@ Available targets: | [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | | [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | | [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | -| [iam\_override\_policy\_documents](#input\_iam\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank sids will override statements with the same sid from earlier documents in the list. Statements with non-blank sids will also override statements with the same sid from documents provided in the `source_json` and `source_policy_documents` arguments. Non-overriding statements will be added to the exported document. | `list(string)` | `null` | no | +| [iam\_override\_policy\_documents](#input\_iam\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document with higher precedence.
In merging, statements with non-blank SIDs will override statements with the same SID
from earlier documents in the list and from other "source" documents. | `list(string)` | `null` | no | +| [iam\_policy](#input\_iam\_policy) | IAM policy as Terraform object, compatible with `aws_iam_policy_document` except
that `source_policy_documents` and `override_policy_documents` are not included.
Use `iam_source_policy_documents` and `iam_override_policy_documents` for that.
Conflicts with `iam_policy_statements`.
This can be used with or instead of the `var.iam_source_json_url`. |
object({
policy_id = optional(string, null)
version = optional(string, null)
statements = list(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
}))
})
| `null` | no | | [iam\_policy\_enabled](#input\_iam\_policy\_enabled) | If set to true will create IAM policy in AWS | `bool` | `false` | no | -| [iam\_policy\_id](#input\_iam\_policy\_id) | ID for the policy document. | `string` | `null` | no | -| [iam\_policy\_statements](#input\_iam\_policy\_statements) | Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`. |
map(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), null)
principals = optional(list(object({
type = string
identifiers = list(string)
})), null)
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), null)
}))
| `{}` | no | -| [iam\_policy\_version](#input\_iam\_policy\_version) | IAM policy document version. | `string` | `"2012-10-17"` | no | +| [iam\_policy\_id](#input\_iam\_policy\_id) | ID for the policy document when using `iam_policy_statements`. | `string` | `null` | no | +| [iam\_policy\_statements](#input\_iam\_policy\_statements) | Deprecated: use `iam_policy` instead.
Map of IAM policy statements to use in the policy. Conflicts with `iam_policy`.
This can be used with or instead of the `var.iam_source_json_url`. |
map(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
}))
| `null` | no | | [iam\_source\_json\_url](#input\_iam\_source\_json\_url) | IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`. | `string` | `null` | no | -| [iam\_source\_policy\_documents](#input\_iam\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. Statements defined in `source_policy_documents` or `source_json` must have unique sids. Statements with the same sid from documents assigned to the `override_json` and `override_policy_documents` arguments will override source statements. | `list(string)` | `null` | no | +| [iam\_source\_policy\_documents](#input\_iam\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document.
Statements defined in `iam_source_policy_documents` must have unique SIDs.
Statements with the same SID as in statements in documents assigned to the
`iam_override_policy_documents` arguments will be overridden. | `list(string)` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | | [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | | [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | diff --git a/docs/terraform.md b/docs/terraform.md index d2ae027..76964a6 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -40,13 +40,13 @@ | [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | | [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | | [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | -| [iam\_override\_policy\_documents](#input\_iam\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank sids will override statements with the same sid from earlier documents in the list. Statements with non-blank sids will also override statements with the same sid from documents provided in the `source_json` and `source_policy_documents` arguments. Non-overriding statements will be added to the exported document. | `list(string)` | `null` | no | +| [iam\_override\_policy\_documents](#input\_iam\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document with higher precedence.
In merging, statements with non-blank SIDs will override statements with the same SID
from earlier documents in the list and from other "source" documents. | `list(string)` | `null` | no | +| [iam\_policy](#input\_iam\_policy) | IAM policy as Terraform object, compatible with `aws_iam_policy_document` except
that `source_policy_documents` and `override_policy_documents` are not included.
Use `iam_source_policy_documents` and `iam_override_policy_documents` for that.
Conflicts with `iam_policy_statements`.
This can be used with or instead of the `var.iam_source_json_url`. |
object({
policy_id = optional(string, null)
version = optional(string, null)
statements = list(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
}))
})
| `null` | no | | [iam\_policy\_enabled](#input\_iam\_policy\_enabled) | If set to true will create IAM policy in AWS | `bool` | `false` | no | -| [iam\_policy\_id](#input\_iam\_policy\_id) | ID for the policy document. | `string` | `null` | no | -| [iam\_policy\_statements](#input\_iam\_policy\_statements) | Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`. |
map(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), null)
principals = optional(list(object({
type = string
identifiers = list(string)
})), null)
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), null)
}))
| `{}` | no | -| [iam\_policy\_version](#input\_iam\_policy\_version) | IAM policy document version. | `string` | `"2012-10-17"` | no | +| [iam\_policy\_id](#input\_iam\_policy\_id) | ID for the policy document when using `iam_policy_statements`. | `string` | `null` | no | +| [iam\_policy\_statements](#input\_iam\_policy\_statements) | Deprecated: use `iam_policy` instead.
Map of IAM policy statements to use in the policy. Conflicts with `iam_policy`.
This can be used with or instead of the `var.iam_source_json_url`. |
map(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
}))
| `null` | no | | [iam\_source\_json\_url](#input\_iam\_source\_json\_url) | IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`. | `string` | `null` | no | -| [iam\_source\_policy\_documents](#input\_iam\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. Statements defined in `source_policy_documents` or `source_json` must have unique sids. Statements with the same sid from documents assigned to the `override_json` and `override_policy_documents` arguments will override source statements. | `list(string)` | `null` | no | +| [iam\_source\_policy\_documents](#input\_iam\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document.
Statements defined in `iam_source_policy_documents` must have unique SIDs.
Statements with the same SID as in statements in documents assigned to the
`iam_override_policy_documents` arguments will be overridden. | `list(string)` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | | [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | | [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | diff --git a/examples/complete/fixtures.us-east-2.tfvars b/examples/complete/fixtures.us-east-2.tfvars index 9abab41..9d7ac6b 100644 --- a/examples/complete/fixtures.us-east-2.tfvars +++ b/examples/complete/fixtures.us-east-2.tfvars @@ -55,6 +55,37 @@ iam_source_json_url = "https://raw.githubusercontent.com/awsdocs/amazon-lookoutm # ] # } +iam_policy = { + statements = [ + { + sid = "ListMyBucket" + effect = "Allow" + actions = ["s3:ListBucket"] + resources = ["arn:aws:s3:::test"] + conditions = [ + { + test = "StringLike" + variable = "cloudwatch:namespace" + values = ["x-*"] + }, + ] + }, + { + sid = "WriteMyBucket" + effect = "Allow" + actions = ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"] + resources = ["arn:aws:s3:::test/*"] + conditions = [ + { + test = "StringLike" + variable = "cloudwatch:namespace" + values = ["x-*"] + }, + ] + } + ] +} + iam_policy_statements = { ListMyBucket = { effect = "Allow" diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 8bce2c7..5810b0c 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -7,12 +7,27 @@ module "iam_policy" { iam_source_json_url = var.iam_source_json_url + iam_policy = var.iam_policy + iam_policy_enabled = false + + context = module.this.context +} + +module "iam_policy_statements" { + source = "../../" + + iam_source_json_url = var.iam_source_json_url + iam_policy_statements = var.iam_policy_statements + iam_policy_enabled = false context = module.this.context } + data "aws_iam_policy_document" "assume_role" { + count = module.this.enabled ? 1 : 0 + statement { actions = ["sts:AssumeRole"] @@ -24,8 +39,10 @@ data "aws_iam_policy_document" "assume_role" { } resource "aws_iam_role" "default" { + count = module.this.enabled ? 1 : 0 + name = module.this.id - assume_role_policy = data.aws_iam_policy_document.assume_role.json + assume_role_policy = one(data.aws_iam_policy_document.assume_role[*].json) inline_policy { name = "test_policy" diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf index 253b366..07f2881 100644 --- a/examples/complete/outputs.tf +++ b/examples/complete/outputs.tf @@ -2,3 +2,8 @@ output "json" { description = "JSON body of the IAM policy document" value = module.iam_policy.json } + +output "deprecated_json" { + description = "JSON body of the IAM policy document" + value = module.iam_policy_statements.json +} diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf index 9d5d3bd..e9f6c46 100644 --- a/examples/complete/variables.tf +++ b/examples/complete/variables.tf @@ -8,8 +8,68 @@ variable "iam_source_json_url" { default = null } +variable "iam_policy" { + type = object({ + policy_id = optional(string, null) + version = optional(string, null) + statements = list(object({ + sid = optional(string, null) + effect = optional(string, null) + actions = optional(list(string), null) + not_actions = optional(list(string), null) + resources = optional(list(string), null) + not_resources = optional(list(string), null) + conditions = optional(list(object({ + test = string + variable = string + values = list(string) + })), []) + principals = optional(list(object({ + type = string + identifiers = list(string) + })), []) + not_principals = optional(list(object({ + type = string + identifiers = list(string) + })), []) + })) + }) + description = <<-EOT + IAM policy as Terraform object, compatible with `aws_iam_policy_document` except + that `source_policy_documents` and `override_policy_documents` are not included. + Use `iam_source_policy_documents` and `iam_override_policy_documents` for that. + Conflicts with `iam_policy_statements`. + This can be used with or instead of the `var.iam_source_json_url`. + EOT + default = null +} + variable "iam_policy_statements" { - type = any - description = "Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`." - default = {} + type = map(object({ + sid = optional(string, null) + effect = optional(string, null) + actions = optional(list(string), null) + not_actions = optional(list(string), null) + resources = optional(list(string), null) + not_resources = optional(list(string), null) + conditions = optional(list(object({ + test = string + variable = string + values = list(string) + })), []) + principals = optional(list(object({ + type = string + identifiers = list(string) + })), []) + not_principals = optional(list(object({ + type = string + identifiers = list(string) + })), []) + })) + description = <<-EOT + Deprecated: use `iam_policy` instead. + Map of IAM policy statements to use in the policy. Conflicts with `iam_policy`. + This can be used with or instead of the `var.iam_source_json_url`. + EOT + default = null } diff --git a/main.tf b/main.tf index ecc8d54..dbc6217 100644 --- a/main.tf +++ b/main.tf @@ -1,12 +1,23 @@ locals { enabled = module.this.enabled - iam_source_json_url_body = var.iam_source_json_url != null || var.iam_source_json_url == "" ? data.http.iam_source_json_url[0].response_body : "" + iam_source_json_url_body = try(length(var.iam_source_json_url), 0) > 0 ? one(data.http.iam_source_json_url[*].response_body) : null - iam_override_policy_documents = var.iam_override_policy_documents == null || var.iam_override_policy_documents == [] ? [] : var.iam_override_policy_documents - iam_source_policy_documents = var.iam_source_policy_documents == null || var.iam_source_policy_documents == [] ? [] : var.iam_source_policy_documents + iam_override_policy_documents = try(length(var.iam_override_policy_documents), 0) > 0 ? var.iam_override_policy_documents : [] + iam_source_policy_documents = try(length(var.iam_source_policy_documents), 0) > 0 ? var.iam_source_policy_documents : [] source_policy_documents = compact(concat([local.iam_source_json_url_body], local.iam_source_policy_documents)) + + deprecated_statements_with_sid = var.iam_policy_statements == null ? [] : [ + for k, v in var.iam_policy_statements : merge(v, v.sid == null ? { sid = k } : {}) + ] + deprecated_policy = { + version = null + policy_id = var.iam_policy_id + statements = local.deprecated_statements_with_sid + } + + policy = var.iam_policy == null ? local.deprecated_policy : var.iam_policy } data "http" "iam_source_json_url" { @@ -21,17 +32,17 @@ data "http" "iam_source_json_url" { data "aws_iam_policy_document" "this" { count = local.enabled ? 1 : 0 - policy_id = var.iam_policy_id - version = var.iam_policy_version + policy_id = local.policy.policy_id + version = local.policy.version - override_policy_documents = local.iam_override_policy_documents != [] ? local.iam_override_policy_documents : null - source_policy_documents = local.source_policy_documents != [] ? local.source_policy_documents : null + override_policy_documents = local.iam_override_policy_documents + source_policy_documents = local.source_policy_documents dynamic "statement" { - for_each = var.iam_policy_statements + for_each = local.policy.statements content { - sid = coalesce(statement.value.sid, statement.key) + sid = statement.value.sid effect = statement.value.effect actions = statement.value.actions @@ -41,7 +52,7 @@ data "aws_iam_policy_document" "this" { not_resources = statement.value.not_resources dynamic "principals" { - for_each = coalesce(statement.value.principals, []) + for_each = statement.value.principals content { type = principals.value.type @@ -50,7 +61,7 @@ data "aws_iam_policy_document" "this" { } dynamic "not_principals" { - for_each = coalesce(statement.value.not_principals, []) + for_each = statement.value.not_principals content { type = not_principals.value.type @@ -59,7 +70,7 @@ data "aws_iam_policy_document" "this" { } dynamic "condition" { - for_each = coalesce(statement.value.conditions, []) + for_each = statement.value.conditions content { test = condition.value.test @@ -69,6 +80,17 @@ data "aws_iam_policy_document" "this" { } } } + + lifecycle { + precondition { + condition = var.iam_policy_statements == null || var.iam_policy == null + error_message = "Only 1 of var.iam_policy and var.iam_policy_statments may be used, preferably var.iam_policy." + } + precondition { + condition = var.iam_policy_statements != null || var.iam_policy != null + error_message = "Exactly 1 of var.iam_policy and var.iam_policy_statments may be used, preferably var.iam_policy." + } + } } resource "aws_iam_policy" "default" { @@ -76,6 +98,6 @@ resource "aws_iam_policy" "default" { name = module.this.id description = var.description - policy = join("", data.aws_iam_policy_document.this.*.json) + policy = one(data.aws_iam_policy_document.this[*].json) tags = module.this.tags } diff --git a/outputs.tf b/outputs.tf index 2f034a7..08aa532 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,9 +1,9 @@ output "json" { description = "JSON body of the IAM policy document" - value = join("", data.aws_iam_policy_document.this[*].json) + value = one(data.aws_iam_policy_document.this[*].json) } output "policy_arn" { description = "ARN of created IAM policy" - value = join("", aws_iam_policy.default[*].arn) -} \ No newline at end of file + value = one(aws_iam_policy.default[*].arn) +} diff --git a/test/src/examples_complete_test.go b/test/src/examples_complete_test.go index 32cf9a1..f248089 100644 --- a/test/src/examples_complete_test.go +++ b/test/src/examples_complete_test.go @@ -37,8 +37,14 @@ func TestExamplesComplete(t *testing.T) { terraform.InitAndApply(t, terraformOptions) // Run `terraform output` to get the value of an output variable - jsonMap := terraform.OutputRequired(t, terraformOptions, "json") + jsonPolicy := terraform.OutputRequired(t, terraformOptions, "json") + oldJsonPolicy := terraform.OutputRequired(t, terraformOptions, "json") // Verify we're getting back the outputs we expect - assert.Greater(t, len(jsonMap), 0) + assert.Greater(t, len(jsonPolicy), 0) + assert.Greater(t, len(oldJsonPolicy), 0) + assert.Equal(t, jsonPolicy, oldJsonPolicy, "jsonPolicy and oldJsonPolicy should match") + + expectedPolicy := "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Action\": [\n \"s3:ListBucket\",\n \"s3:GetBucketAcl\"\n ],\n \"Resource\": [\n \"arn:aws:s3:::${BucketName}\"\n ]\n },\n {\n \"Effect\": \"Allow\",\n \"Action\": [\n \"s3:GetObject\",\n \"s3:GetBucketAcl\"\n ],\n \"Resource\": [\n \"arn:aws:s3:::${BucketName}/*\"\n ]\n },\n {\n \"Effect\": \"Allow\",\n \"Action\": [\n \"kms:Decrypt\",\n \"kms:GenerateDataKey\"\n ],\n \"Resource\": [\n \"arn:aws:kms:::key/*\"\n ],\n \"Condition\": {\n \"ForAllValues:StringLike\": {\n \"kms:EncryptionContext:aws:s3:arn\": [\n \"arn:aws:s3:::${BucketName}\"\n ],\n \"kms:ViaService\": [\n \"s3.${Region}.amazonaws.com\"\n ]\n }\n }\n },\n {\n \"Sid\": \"ListMyBucket\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::test\",\n \"Condition\": {\n \"StringLike\": {\n \"cloudwatch:namespace\": \"x-*\"\n }\n }\n },\n {\n \"Sid\": \"WriteMyBucket\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"s3:PutObject\",\n \"s3:GetObject\",\n \"s3:DeleteObject\"\n ],\n \"Resource\": \"arn:aws:s3:::test/*\",\n \"Condition\": {\n \"StringLike\": {\n \"cloudwatch:namespace\": \"x-*\"\n }\n }\n }\n ]\n}" + assert.Equal(t, expectedPolicy, jsonPolicy, "jsonPolicy should match expected policy") } diff --git a/variables.tf b/variables.tf index 9905869..90f74e3 100644 --- a/variables.tf +++ b/variables.tf @@ -1,6 +1,36 @@ -variable "iam_source_json_url" { - type = string - description = "IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`." +variable "iam_policy" { + type = object({ + policy_id = optional(string, null) + version = optional(string, null) + statements = list(object({ + sid = optional(string, null) + effect = optional(string, null) + actions = optional(list(string), null) + not_actions = optional(list(string), null) + resources = optional(list(string), null) + not_resources = optional(list(string), null) + conditions = optional(list(object({ + test = string + variable = string + values = list(string) + })), []) + principals = optional(list(object({ + type = string + identifiers = list(string) + })), []) + not_principals = optional(list(object({ + type = string + identifiers = list(string) + })), []) + })) + }) + description = <<-EOT + IAM policy as Terraform object, compatible with `aws_iam_policy_document` except + that `source_policy_documents` and `override_policy_documents` are not included. + Use `iam_source_policy_documents` and `iam_override_policy_documents` for that. + Conflicts with `iam_policy_statements`. + This can be used with or instead of the `var.iam_source_json_url`. + EOT default = null } @@ -16,18 +46,22 @@ variable "iam_policy_statements" { test = string variable = string values = list(string) - })), null) + })), []) principals = optional(list(object({ type = string identifiers = list(string) - })), null) + })), []) not_principals = optional(list(object({ type = string identifiers = list(string) - })), null) + })), []) })) - description = "Map of IAM policy statements to use in the policy. This can be used with or instead of the `var.iam_source_json_url`." - default = {} + description = <<-EOT + Deprecated: use `iam_policy` instead. + Map of IAM policy statements to use in the policy. Conflicts with `iam_policy`. + This can be used with or instead of the `var.iam_source_json_url`. + EOT + default = null } variable "description" { @@ -44,28 +78,33 @@ variable "iam_policy_enabled" { variable "iam_policy_id" { type = string - description = "ID for the policy document." + description = "ID for the policy document when using `iam_policy_statements`." default = null } -variable "iam_policy_version" { +variable "iam_source_json_url" { type = string - description = "IAM policy document version." - default = "2012-10-17" - validation { - condition = contains(["2008-10-17", "2012-10-17"], var.iam_policy_version) - error_message = "The iam_policy_version valid values are '2008-10-17' or '2012-10-17'." - } + description = "IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`." + default = null } variable "iam_source_policy_documents" { type = list(string) - description = "List of IAM policy documents that are merged together into the exported document. Statements defined in `source_policy_documents` or `source_json` must have unique sids. Statements with the same sid from documents assigned to the `override_json` and `override_policy_documents` arguments will override source statements." + description = <<-EOT + List of IAM policy documents that are merged together into the exported document. + Statements defined in `iam_source_policy_documents` must have unique SIDs. + Statements with the same SID as in statements in documents assigned to the + `iam_override_policy_documents` arguments will be overridden. + EOT default = null } variable "iam_override_policy_documents" { type = list(string) - description = "List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank sids will override statements with the same sid from earlier documents in the list. Statements with non-blank sids will also override statements with the same sid from documents provided in the `source_json` and `source_policy_documents` arguments. Non-overriding statements will be added to the exported document." + description = <<-EOT + List of IAM policy documents that are merged together into the exported document with higher precedence. + In merging, statements with non-blank SIDs will override statements with the same SID + from earlier documents in the list and from other "source" documents. + EOT default = null } From 97ea586234eb70eeaf694e9d474d0b4981aa18dc Mon Sep 17 00:00:00 2001 From: Nuru Date: Fri, 9 Jun 2023 22:37:31 -0700 Subject: [PATCH 6/8] Address reviewer feedback --- README.md | 4 ++-- docs/terraform.md | 4 ++-- examples/complete/variables.tf | 2 +- test/src/examples_complete_test.go | 2 +- variables.tf | 8 ++++++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 880731b..e179219 100644 --- a/README.md +++ b/README.md @@ -215,11 +215,11 @@ Available targets: | [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | | [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | | [iam\_override\_policy\_documents](#input\_iam\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document with higher precedence.
In merging, statements with non-blank SIDs will override statements with the same SID
from earlier documents in the list and from other "source" documents. | `list(string)` | `null` | no | -| [iam\_policy](#input\_iam\_policy) | IAM policy as Terraform object, compatible with `aws_iam_policy_document` except
that `source_policy_documents` and `override_policy_documents` are not included.
Use `iam_source_policy_documents` and `iam_override_policy_documents` for that.
Conflicts with `iam_policy_statements`.
This can be used with or instead of the `var.iam_source_json_url`. |
object({
policy_id = optional(string, null)
version = optional(string, null)
statements = list(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
}))
})
| `null` | no | +| [iam\_policy](#input\_iam\_policy) | IAM policy as Terraform object, compatible with `aws_iam_policy_document` except
that `source_policy_documents` and `override_policy_documents` are not included.
Use inputs `iam_source_policy_documents` and `iam_override_policy_documents` for that.
Conflicts with `iam_policy_statements`.
This can be used with or instead of the `var.iam_source_json_url`. |
object({
policy_id = optional(string, null)
version = optional(string, null)
statements = list(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
}))
})
| `null` | no | | [iam\_policy\_enabled](#input\_iam\_policy\_enabled) | If set to true will create IAM policy in AWS | `bool` | `false` | no | | [iam\_policy\_id](#input\_iam\_policy\_id) | ID for the policy document when using `iam_policy_statements`. | `string` | `null` | no | | [iam\_policy\_statements](#input\_iam\_policy\_statements) | Deprecated: use `iam_policy` instead.
Map of IAM policy statements to use in the policy. Conflicts with `iam_policy`.
This can be used with or instead of the `var.iam_source_json_url`. |
map(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
}))
| `null` | no | -| [iam\_source\_json\_url](#input\_iam\_source\_json\_url) | IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`. | `string` | `null` | no | +| [iam\_source\_json\_url](#input\_iam\_source\_json\_url) | URL of the IAM policy (in JSON format) to download and use as `source_json` argument.
This is useful when using a 3rd party service that provides their own policy.
This can be used with or instead of `var.iam_policy`. | `string` | `null` | no | | [iam\_source\_policy\_documents](#input\_iam\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document.
Statements defined in `iam_source_policy_documents` must have unique SIDs.
Statements with the same SID as in statements in documents assigned to the
`iam_override_policy_documents` arguments will be overridden. | `list(string)` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | | [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | diff --git a/docs/terraform.md b/docs/terraform.md index 76964a6..cedebb1 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -41,11 +41,11 @@ | [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | | [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | | [iam\_override\_policy\_documents](#input\_iam\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document with higher precedence.
In merging, statements with non-blank SIDs will override statements with the same SID
from earlier documents in the list and from other "source" documents. | `list(string)` | `null` | no | -| [iam\_policy](#input\_iam\_policy) | IAM policy as Terraform object, compatible with `aws_iam_policy_document` except
that `source_policy_documents` and `override_policy_documents` are not included.
Use `iam_source_policy_documents` and `iam_override_policy_documents` for that.
Conflicts with `iam_policy_statements`.
This can be used with or instead of the `var.iam_source_json_url`. |
object({
policy_id = optional(string, null)
version = optional(string, null)
statements = list(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
}))
})
| `null` | no | +| [iam\_policy](#input\_iam\_policy) | IAM policy as Terraform object, compatible with `aws_iam_policy_document` except
that `source_policy_documents` and `override_policy_documents` are not included.
Use inputs `iam_source_policy_documents` and `iam_override_policy_documents` for that.
Conflicts with `iam_policy_statements`.
This can be used with or instead of the `var.iam_source_json_url`. |
object({
policy_id = optional(string, null)
version = optional(string, null)
statements = list(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
}))
})
| `null` | no | | [iam\_policy\_enabled](#input\_iam\_policy\_enabled) | If set to true will create IAM policy in AWS | `bool` | `false` | no | | [iam\_policy\_id](#input\_iam\_policy\_id) | ID for the policy document when using `iam_policy_statements`. | `string` | `null` | no | | [iam\_policy\_statements](#input\_iam\_policy\_statements) | Deprecated: use `iam_policy` instead.
Map of IAM policy statements to use in the policy. Conflicts with `iam_policy`.
This can be used with or instead of the `var.iam_source_json_url`. |
map(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
}))
| `null` | no | -| [iam\_source\_json\_url](#input\_iam\_source\_json\_url) | IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`. | `string` | `null` | no | +| [iam\_source\_json\_url](#input\_iam\_source\_json\_url) | URL of the IAM policy (in JSON format) to download and use as `source_json` argument.
This is useful when using a 3rd party service that provides their own policy.
This can be used with or instead of `var.iam_policy`. | `string` | `null` | no | | [iam\_source\_policy\_documents](#input\_iam\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document.
Statements defined in `iam_source_policy_documents` must have unique SIDs.
Statements with the same SID as in statements in documents assigned to the
`iam_override_policy_documents` arguments will be overridden. | `list(string)` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | | [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf index e9f6c46..1ef3e77 100644 --- a/examples/complete/variables.tf +++ b/examples/complete/variables.tf @@ -37,7 +37,7 @@ variable "iam_policy" { description = <<-EOT IAM policy as Terraform object, compatible with `aws_iam_policy_document` except that `source_policy_documents` and `override_policy_documents` are not included. - Use `iam_source_policy_documents` and `iam_override_policy_documents` for that. + Use inputs `iam_source_policy_documents` and `iam_override_policy_documents` for that. Conflicts with `iam_policy_statements`. This can be used with or instead of the `var.iam_source_json_url`. EOT diff --git a/test/src/examples_complete_test.go b/test/src/examples_complete_test.go index f248089..c6f606e 100644 --- a/test/src/examples_complete_test.go +++ b/test/src/examples_complete_test.go @@ -38,7 +38,7 @@ func TestExamplesComplete(t *testing.T) { // Run `terraform output` to get the value of an output variable jsonPolicy := terraform.OutputRequired(t, terraformOptions, "json") - oldJsonPolicy := terraform.OutputRequired(t, terraformOptions, "json") + oldJsonPolicy := terraform.OutputRequired(t, terraformOptions, "deprecated_json") // Verify we're getting back the outputs we expect assert.Greater(t, len(jsonPolicy), 0) diff --git a/variables.tf b/variables.tf index 90f74e3..a4d370b 100644 --- a/variables.tf +++ b/variables.tf @@ -27,7 +27,7 @@ variable "iam_policy" { description = <<-EOT IAM policy as Terraform object, compatible with `aws_iam_policy_document` except that `source_policy_documents` and `override_policy_documents` are not included. - Use `iam_source_policy_documents` and `iam_override_policy_documents` for that. + Use inputs `iam_source_policy_documents` and `iam_override_policy_documents` for that. Conflicts with `iam_policy_statements`. This can be used with or instead of the `var.iam_source_json_url`. EOT @@ -84,7 +84,11 @@ variable "iam_policy_id" { variable "iam_source_json_url" { type = string - description = "IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`." + description = <<-EOT + URL of the IAM policy (in JSON format) to download and use as `source_json` argument. + This is useful when using a 3rd party service that provides their own policy. + This can be used with or instead of `var.iam_policy`. + EOT default = null } From 6783c8582b96378871ba401e19af2e4fb8a9e7ce Mon Sep 17 00:00:00 2001 From: Nuru Date: Fri, 9 Jun 2023 22:43:04 -0700 Subject: [PATCH 7/8] Update example in README --- README.md | 51 +++++++++++++++++++++++++++++++-------------------- README.yaml | 51 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 62 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index e179219..c83588b 100644 --- a/README.md +++ b/README.md @@ -105,27 +105,38 @@ module "iam_policy" { # Cloud Posse recommends pinning every module to a specific version # version = "x.x.x" - iam_policy_statements = { - ListMyBucket = { - effect = "Allow" - actions = ["s3:ListBucket"] - resources = ["arn:aws:s3:::test"] - conditions = [] - } - WriteMyBucket = { - effect = "Allow" - actions = ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"] - resources = ["arn:aws:s3:::test/*"] - conditions = [ - { - test = "StringLike" - variable = "cloudwatch:namespace" - values = ["x-*"] - }, - ] - } + iam_policy = { + version = "2012-10-17" + policy_id = "example" + statements = [ + { + sid = "ListMyBucket" + effect = "Allow" + actions = ["s3:ListBucket"] + resources = ["arn:aws:s3:::test"] + conditions = [ + { + test = "StringLike" + variable = "cloudwatch:namespace" + values = ["x-*"] + }, + ] + }, + { + sid = "WriteMyBucket" + effect = "Allow" + actions = ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"] + resources = ["arn:aws:s3:::test/*"] + conditions = [ + { + test = "StringLike" + variable = "cloudwatch:namespace" + values = ["x-*"] + }, + ] + } + ] } -} data "aws_iam_policy_document" "assume_role" { statement { diff --git a/README.yaml b/README.yaml index 3df827e..75ceaf4 100644 --- a/README.yaml +++ b/README.yaml @@ -77,27 +77,38 @@ usage: |- # Cloud Posse recommends pinning every module to a specific version # version = "x.x.x" - iam_policy_statements = { - ListMyBucket = { - effect = "Allow" - actions = ["s3:ListBucket"] - resources = ["arn:aws:s3:::test"] - conditions = [] - } - WriteMyBucket = { - effect = "Allow" - actions = ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"] - resources = ["arn:aws:s3:::test/*"] - conditions = [ - { - test = "StringLike" - variable = "cloudwatch:namespace" - values = ["x-*"] - }, - ] - } + iam_policy = { + version = "2012-10-17" + policy_id = "example" + statements = [ + { + sid = "ListMyBucket" + effect = "Allow" + actions = ["s3:ListBucket"] + resources = ["arn:aws:s3:::test"] + conditions = [ + { + test = "StringLike" + variable = "cloudwatch:namespace" + values = ["x-*"] + }, + ] + }, + { + sid = "WriteMyBucket" + effect = "Allow" + actions = ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"] + resources = ["arn:aws:s3:::test/*"] + conditions = [ + { + test = "StringLike" + variable = "cloudwatch:namespace" + values = ["x-*"] + }, + ] + } + ] } - } data "aws_iam_policy_document" "assume_role" { statement { From ba46cc88608db4c91c4d05b0d215ebe234792d6d Mon Sep 17 00:00:00 2001 From: Nuru Date: Sat, 10 Jun 2023 13:40:12 -0700 Subject: [PATCH 8/8] Add description to example inputs --- examples/complete/variables.tf | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf index 1ef3e77..289160e 100644 --- a/examples/complete/variables.tf +++ b/examples/complete/variables.tf @@ -2,12 +2,6 @@ variable "region" { description = "AWS region" } -variable "iam_source_json_url" { - type = string - description = "IAM source JSON policy to download and use as `source_json` argument. This is useful when using a 3rd party service that provides their own policy. This can be used with or instead of the `var.iam_policy_statements`." - default = null -} - variable "iam_policy" { type = object({ policy_id = optional(string, null) @@ -73,3 +67,13 @@ variable "iam_policy_statements" { EOT default = null } + +variable "iam_source_json_url" { + type = string + description = <<-EOT + URL of the IAM policy (in JSON format) to download and use as `source_json` argument. + This is useful when using a 3rd party service that provides their own policy. + This can be used with or instead of `var.iam_policy`. + EOT + default = null +}