Skip to content

Commit

Permalink
Use list(string) for iam policy document (#23)
Browse files Browse the repository at this point in the history
* Use `list(string)` for iam policy document to prevent for_each error

Co-authored-by: cloudpossebot <11232728+cloudpossebot@users.noreply.github.com>
  • Loading branch information
nitrocode and cloudpossebot committed Dec 21, 2021
1 parent 5022028 commit ae44d7f
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 24 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ the registry shows many of our inputs as required when in fact they are optional
The table below correctly indicates which inputs are required.


Here's how to invoke this example module in your projects
Here's how to invoke this module in your projects

```hcl
module "eks_iam_role" {
Expand All @@ -117,10 +117,9 @@ module "eks_iam_role" {
service_account_name = "autoscaler"
service_account_namespace = "kube-system"
# JSON IAM policy document to assign to the service account role
aws_iam_policy_document = data.aws_iam_policy_document.autoscaler.json
aws_iam_policy_document = [data.aws_iam_policy_document.autoscaler.json]
}
data "aws_iam_policy_document" "autoscaler" {
statement {
sid = "AllowToScaleEKSNodeGroupAutoScalingGroup"
Expand Down Expand Up @@ -202,7 +201,7 @@ Available targets:
| <a name="input_additional_tag_map"></a> [additional\_tag\_map](#input\_additional\_tag\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.<br>This is for some rare cases where resources want additional configuration of tags<br>and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no |
| <a name="input_attributes"></a> [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,<br>in the order they appear in the list. New attributes are appended to the<br>end of the list. The elements of the list are joined by the `delimiter`<br>and treated as a single ID element. | `list(string)` | `[]` | no |
| <a name="input_aws_account_number"></a> [aws\_account\_number](#input\_aws\_account\_number) | AWS account number of EKS cluster owner. If an AWS account number is not provided, the current aws provider account number will be used. | `string` | `null` | no |
| <a name="input_aws_iam_policy_document"></a> [aws\_iam\_policy\_document](#input\_aws\_iam\_policy\_document) | JSON string representation of the IAM policy for this service account | `string` | `null` | no |
| <a name="input_aws_iam_policy_document"></a> [aws\_iam\_policy\_document](#input\_aws\_iam\_policy\_document) | JSON string representation of the IAM policy for this service account as list of string (0 or 1 items).<br>If empty, no custom IAM policy document will be used. If the list contains a single document, a custom<br>IAM policy will be created and attached to the IAM role.<br>Can also be a plain string, but that use is DEPRECATED because of Terraform issues. | `any` | `[]` | no |
| <a name="input_aws_partition"></a> [aws\_partition](#input\_aws\_partition) | AWS partition: 'aws', 'aws-cn', or 'aws-us-gov' | `string` | `"aws"` | no |
| <a name="input_context"></a> [context](#input\_context) | Single object for setting entire context at once.<br>See description of individual variables for details.<br>Leave string and numeric variables as `null` to use default value.<br>Individual variable settings (non-null) override settings in context object,<br>except for attributes, tags, and additional\_tag\_map, which are merged. | `any` | <pre>{<br> "additional_tag_map": {},<br> "attributes": [],<br> "delimiter": null,<br> "descriptor_formats": {},<br> "enabled": true,<br> "environment": null,<br> "id_length_limit": null,<br> "label_key_case": null,<br> "label_order": [],<br> "label_value_case": null,<br> "labels_as_tags": [<br> "unset"<br> ],<br> "name": null,<br> "namespace": null,<br> "regex_replace_chars": null,<br> "stage": null,<br> "tags": {},<br> "tenant": null<br>}</pre> | no |
| <a name="input_delimiter"></a> [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.<br>Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no |
Expand Down Expand Up @@ -397,14 +396,16 @@ Check out [our other projects][github], [follow us on twitter][twitter], [apply
### Contributors

<!-- markdownlint-disable -->
| [![Erik Osterman][osterman_avatar]][osterman_homepage]<br/>[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]<br/>[Andriy Knysh][aknysh_homepage] |
|---|---|
| [![Erik Osterman][osterman_avatar]][osterman_homepage]<br/>[Erik Osterman][osterman_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]<br/>[Andriy Knysh][aknysh_homepage] | [![RB][nitrocode_avatar]][nitrocode_homepage]<br/>[RB][nitrocode_homepage] |
|---|---|---|
<!-- markdownlint-restore -->

[osterman_homepage]: https://github.com/osterman
[osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png
[aknysh_homepage]: https://github.com/aknysh
[aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png
[nitrocode_homepage]: https://github.com/nitrocode
[nitrocode_avatar]: https://img.cloudposse.com/150x150/https://github.com/nitrocode.png

[![README Footer][readme_footer_img]][readme_footer_link]
[![Beacon][beacon]][website]
Expand Down
7 changes: 4 additions & 3 deletions README.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ description: |-

# How to use this module. Should be an easy example to copy and paste.
usage: |-
Here's how to invoke this example module in your projects
Here's how to invoke this module in your projects
```hcl
module "eks_iam_role" {
Expand All @@ -89,10 +89,9 @@ usage: |-
service_account_name = "autoscaler"
service_account_namespace = "kube-system"
# JSON IAM policy document to assign to the service account role
aws_iam_policy_document = data.aws_iam_policy_document.autoscaler.json
aws_iam_policy_document = [data.aws_iam_policy_document.autoscaler.json]
}
data "aws_iam_policy_document" "autoscaler" {
statement {
sid = "AllowToScaleEKSNodeGroupAutoScalingGroup"
Expand Down Expand Up @@ -133,3 +132,5 @@ contributors:
github: "osterman"
- name: "Andriy Knysh"
github: "aknysh"
- name: "RB"
github: "nitrocode"
2 changes: 1 addition & 1 deletion docs/terraform.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
| <a name="input_additional_tag_map"></a> [additional\_tag\_map](#input\_additional\_tag\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.<br>This is for some rare cases where resources want additional configuration of tags<br>and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no |
| <a name="input_attributes"></a> [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,<br>in the order they appear in the list. New attributes are appended to the<br>end of the list. The elements of the list are joined by the `delimiter`<br>and treated as a single ID element. | `list(string)` | `[]` | no |
| <a name="input_aws_account_number"></a> [aws\_account\_number](#input\_aws\_account\_number) | AWS account number of EKS cluster owner. If an AWS account number is not provided, the current aws provider account number will be used. | `string` | `null` | no |
| <a name="input_aws_iam_policy_document"></a> [aws\_iam\_policy\_document](#input\_aws\_iam\_policy\_document) | JSON string representation of the IAM policy for this service account | `string` | `null` | no |
| <a name="input_aws_iam_policy_document"></a> [aws\_iam\_policy\_document](#input\_aws\_iam\_policy\_document) | JSON string representation of the IAM policy for this service account as list of string (0 or 1 items).<br>If empty, no custom IAM policy document will be used. If the list contains a single document, a custom<br>IAM policy will be created and attached to the IAM role.<br>Can also be a plain string, but that use is DEPRECATED because of Terraform issues. | `any` | `[]` | no |
| <a name="input_aws_partition"></a> [aws\_partition](#input\_aws\_partition) | AWS partition: 'aws', 'aws-cn', or 'aws-us-gov' | `string` | `"aws"` | no |
| <a name="input_context"></a> [context](#input\_context) | Single object for setting entire context at once.<br>See description of individual variables for details.<br>Leave string and numeric variables as `null` to use default value.<br>Individual variable settings (non-null) override settings in context object,<br>except for attributes, tags, and additional\_tag\_map, which are merged. | `any` | <pre>{<br> "additional_tag_map": {},<br> "attributes": [],<br> "delimiter": null,<br> "descriptor_formats": {},<br> "enabled": true,<br> "environment": null,<br> "id_length_limit": null,<br> "label_key_case": null,<br> "label_order": [],<br> "label_value_case": null,<br> "labels_as_tags": [<br> "unset"<br> ],<br> "name": null,<br> "namespace": null,<br> "regex_replace_chars": null,<br> "stage": null,<br> "tags": {},<br> "tenant": null<br>}</pre> | no |
| <a name="input_delimiter"></a> [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.<br>Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no |
Expand Down
7 changes: 2 additions & 5 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ module "autoscaler_role" {
# Rather than create a whole cluster, just fake the OIDC URL
# eks_cluster_oidc_issuer_url = module.eks_cluster.eks_cluster_identity_oidc_issuer
eks_cluster_oidc_issuer_url = "https://oidc.eks.us-west-2.amazonaws.com/id/FEDCBA9876543210FEDCBA9876543210"
aws_iam_policy_document = data.aws_iam_policy_document.autoscaler.json
aws_iam_policy_document = [data.aws_iam_policy_document.autoscaler.json]

context = module.this.context
}


data "aws_iam_policy_document" "autoscaler" {
statement {
sid = "AllowToScaleEKSNodeGroupAutoScalingGroup"
Expand Down Expand Up @@ -55,12 +54,11 @@ module "cert-manager_role" {
# Rather than create a whole cluster, just fake the OIDC URL
# eks_cluster_oidc_issuer_url = module.eks_cluster.eks_cluster_identity_oidc_issuer
eks_cluster_oidc_issuer_url = "https://oidc.eks.us-west-2.amazonaws.com/id/FEDCBA9876543210FEDCBA9876543210"
aws_iam_policy_document = data.aws_iam_policy_document.cert-manager.json
aws_iam_policy_document = [data.aws_iam_policy_document.cert-manager.json]

context = module.this.context
}


data "aws_iam_policy_document" "cert-manager" {
statement {
sid = "GrantListHostedZonesListResourceRecordSets"
Expand All @@ -74,7 +72,6 @@ data "aws_iam_policy_document" "cert-manager" {
}
}


data "aws_iam_policy" "cert-manager" {
arn = module.cert-manager_role.service_account_policy_arn
}
9 changes: 6 additions & 3 deletions main.tf
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ locals {

service_account_long_id = format("%v@%v", coalesce(var.service_account_name, "all"), coalesce(var.service_account_namespace, "all"))
service_account_id = trimsuffix(local.service_account_long_id, format("@%v", var.service_account_name))

# Try to return the first element, if that doesn't work, try the tostring approach
aws_iam_policy_document = try(var.aws_iam_policy_document[0], tostring(var.aws_iam_policy_document), "{}")
}

data "aws_caller_identity" "current" {}
Expand Down Expand Up @@ -76,15 +79,15 @@ data "aws_iam_policy_document" "service_account_assume_role" {
}

resource "aws_iam_policy" "service_account" {
for_each = var.aws_iam_policy_document != null ? toset(compact([module.service_account_label.id])) : []
for_each = length(var.aws_iam_policy_document) > 0 ? toset(compact([module.service_account_label.id])) : []
name = each.value
description = format("Grant permissions to EKS ServiceAccount %s", local.service_account_id)
policy = coalesce(var.aws_iam_policy_document, "{}")
policy = local.aws_iam_policy_document
tags = module.service_account_label.tags
}

resource "aws_iam_role_policy_attachment" "service_account" {
for_each = var.aws_iam_policy_document != null ? toset(compact([module.service_account_label.id])) : []
for_each = length(var.aws_iam_policy_document) > 0 ? toset(compact([module.service_account_label.id])) : []
role = aws_iam_role.service_account[each.value].name
policy_arn = aws_iam_policy.service_account[each.value].arn
}
6 changes: 3 additions & 3 deletions outputs.tf
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ output "service_account_role_arn" {
}

output "service_account_policy_name" {
value = local.enabled && var.aws_iam_policy_document != null ? values(aws_iam_policy.service_account)[0].name : null
value = local.enabled && length(var.aws_iam_policy_document) > 0 ? values(aws_iam_policy.service_account)[0].name : null
description = "IAM policy name"
}

output "service_account_policy_id" {
value = local.enabled && var.aws_iam_policy_document != null ? values(aws_iam_policy.service_account)[0].id : null
value = local.enabled && length(var.aws_iam_policy_document) > 0 ? values(aws_iam_policy.service_account)[0].id : null
description = "IAM policy ID"
}

output "service_account_policy_arn" {
value = local.enabled && var.aws_iam_policy_document != null ? values(aws_iam_policy.service_account)[0].arn : null
value = local.enabled && length(var.aws_iam_policy_document) > 0 ? values(aws_iam_policy.service_account)[0].arn : null
description = "IAM policy ARN"
}
11 changes: 8 additions & 3 deletions variables.tf
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,14 @@ variable "aws_partition" {
}

variable "aws_iam_policy_document" {
type = string
default = null
description = "JSON string representation of the IAM policy for this service account"
type = any
default = []
description = <<-EOT
JSON string representation of the IAM policy for this service account as list of string (0 or 1 items).
If empty, no custom IAM policy document will be used. If the list contains a single document, a custom
IAM policy will be created and attached to the IAM role.
Can also be a plain string, but that use is DEPRECATED because of Terraform issues.
EOT
}

variable "eks_cluster_oidc_issuer_url" {
Expand Down

0 comments on commit ae44d7f

Please sign in to comment.