From 7df48934f9f70e44ddfb9ac966c5adb75ea1f278 Mon Sep 17 00:00:00 2001 From: sksmsWKd <0nocsace@gmail.com> Date: Fri, 11 Oct 2024 00:30:23 +0900 Subject: [PATCH] feat: Enables exclusive IAM policy management of IAM role with managed_policy_arns option --- modules/iam-assumable-role/README.md | 2 + modules/iam-assumable-role/main.tf | 12 +++-- modules/iam-assumable-role/variables.tf | 12 +++++ wrappers/iam-assumable-role/main.tf | 62 +++++++++++++------------ 4 files changed, 53 insertions(+), 35 deletions(-) diff --git a/modules/iam-assumable-role/README.md b/modules/iam-assumable-role/README.md index e2c0828f..288af624 100644 --- a/modules/iam-assumable-role/README.md +++ b/modules/iam-assumable-role/README.md @@ -55,6 +55,7 @@ No modules. | [custom\_role\_trust\_policy](#input\_custom\_role\_trust\_policy) | A custom role trust policy. (Only valid if create\_custom\_role\_trust\_policy = true) | `string` | `""` | no | | [force\_detach\_policies](#input\_force\_detach\_policies) | Whether policies should be detached from this role when destroying | `bool` | `false` | no | | [inline\_policy\_statements](#input\_inline\_policy\_statements) | List of inline policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) to attach to IAM role as an inline policy | `any` | `[]` | no | +| [managed\_policy\_arns](#input\_managed\_policy\_arns) | Set of exclusive IAM managed policy ARNs to attach to the IAM role. Configuring an empty set will cause Terraform to remove all managed policy attachments | `list(string)` | `[]` | no | | [max\_session\_duration](#input\_max\_session\_duration) | Maximum CLI/API session duration in seconds between 3600 and 43200 | `number` | `3600` | no | | [mfa\_age](#input\_mfa\_age) | Max age of valid MFA (in seconds) for roles which require MFA | `number` | `86400` | no | | [number\_of\_custom\_role\_policy\_arns](#input\_number\_of\_custom\_role\_policy\_arns) | Number of IAM policies to attach to IAM role | `number` | `null` | no | @@ -73,6 +74,7 @@ No modules. | [trusted\_role\_actions](#input\_trusted\_role\_actions) | Additional trusted role actions | `list(string)` |
[
"sts:AssumeRole",
"sts:TagSession"
]
| no | | [trusted\_role\_arns](#input\_trusted\_role\_arns) | ARNs of AWS entities who can assume these roles | `list(string)` | `[]` | no | | [trusted\_role\_services](#input\_trusted\_role\_services) | AWS Services that can assume these roles | `list(string)` | `[]` | no | +| [use\_managed\_policy\_arns\_on\_iam\_role](#input\_use\_managed\_policy\_arns\_on\_iam\_role) | Whether to attach exclusive IAM managed policy to the IAM role. | `bool` | `false` | no | ## Outputs diff --git a/modules/iam-assumable-role/main.tf b/modules/iam-assumable-role/main.tf index 719a3873..4028c91d 100644 --- a/modules/iam-assumable-role/main.tf +++ b/modules/iam-assumable-role/main.tf @@ -7,6 +7,7 @@ locals { role_sts_externalid = flatten([var.role_sts_externalid]) role_name_condition = var.role_name != null ? var.role_name : "${var.role_name_prefix}*" custom_role_trust_policy_condition = var.create_custom_role_trust_policy ? var.custom_role_trust_policy : "" + managed_policy_arns = var.use_managed_policy_arns_on_iam_role && length(var.managed_policy_arns) > 0 ? var.managed_policy_arns : null } data "aws_iam_policy_document" "assume_role" { @@ -150,6 +151,7 @@ resource "aws_iam_role" "this" { force_detach_policies = var.force_detach_policies permissions_boundary = var.role_permissions_boundary_arn + managed_policy_arns = local.managed_policy_arns assume_role_policy = coalesce( local.custom_role_trust_policy_condition, @@ -162,28 +164,28 @@ resource "aws_iam_role" "this" { } resource "aws_iam_role_policy_attachment" "custom" { - count = var.create_role ? coalesce(var.number_of_custom_role_policy_arns, length(var.custom_role_policy_arns)) : 0 + count = var.create_role && local.managed_policy_arns == null ? coalesce(var.number_of_custom_role_policy_arns, length(var.custom_role_policy_arns)) : 0 role = aws_iam_role.this[0].name policy_arn = element(var.custom_role_policy_arns, count.index) } resource "aws_iam_role_policy_attachment" "admin" { - count = var.create_role && var.attach_admin_policy ? 1 : 0 + count = var.create_role && var.attach_admin_policy && local.managed_policy_arns == null ? 1 : 0 role = aws_iam_role.this[0].name policy_arn = var.admin_role_policy_arn } resource "aws_iam_role_policy_attachment" "poweruser" { - count = var.create_role && var.attach_poweruser_policy ? 1 : 0 + count = var.create_role && var.attach_poweruser_policy && local.managed_policy_arns == null ? 1 : 0 role = aws_iam_role.this[0].name policy_arn = var.poweruser_role_policy_arn } resource "aws_iam_role_policy_attachment" "readonly" { - count = var.create_role && var.attach_readonly_policy ? 1 : 0 + count = var.create_role && var.attach_readonly_policy && local.managed_policy_arns == null ? 1 : 0 role = aws_iam_role.this[0].name policy_arn = var.readonly_role_policy_arn @@ -252,7 +254,7 @@ data "aws_iam_policy_document" "inline" { } resource "aws_iam_role_policy" "inline" { - count = local.create_iam_role_inline_policy ? 1 : 0 + count = local.create_iam_role_inline_policy && local.managed_policy_arns == null ? 1 : 0 role = aws_iam_role.this[0].name name_prefix = "${var.role_name}_inline_" diff --git a/modules/iam-assumable-role/variables.tf b/modules/iam-assumable-role/variables.tf index fc9bd2c9..f357bfd7 100644 --- a/modules/iam-assumable-role/variables.tf +++ b/modules/iam-assumable-role/variables.tf @@ -178,3 +178,15 @@ variable "role_session_name" { type = list(string) default = ["$${aws:username}"] } + +variable "use_managed_policy_arns_on_iam_role" { + description = "Whether to attach exclusive IAM managed policy to the IAM role." + type = bool + default = false +} + +variable "managed_policy_arns" { + description = "Set of exclusive IAM managed policy ARNs to attach to the IAM role. Configuring an empty set will cause Terraform to remove all managed policy attachments" + type = list(string) + default = [] +} diff --git a/wrappers/iam-assumable-role/main.tf b/wrappers/iam-assumable-role/main.tf index aef04cfe..b6db4a70 100644 --- a/wrappers/iam-assumable-role/main.tf +++ b/wrappers/iam-assumable-role/main.tf @@ -3,34 +3,36 @@ module "wrapper" { for_each = var.items - admin_role_policy_arn = try(each.value.admin_role_policy_arn, var.defaults.admin_role_policy_arn, "arn:aws:iam::aws:policy/AdministratorAccess") - allow_self_assume_role = try(each.value.allow_self_assume_role, var.defaults.allow_self_assume_role, false) - attach_admin_policy = try(each.value.attach_admin_policy, var.defaults.attach_admin_policy, false) - attach_poweruser_policy = try(each.value.attach_poweruser_policy, var.defaults.attach_poweruser_policy, false) - attach_readonly_policy = try(each.value.attach_readonly_policy, var.defaults.attach_readonly_policy, false) - create_custom_role_trust_policy = try(each.value.create_custom_role_trust_policy, var.defaults.create_custom_role_trust_policy, false) - create_instance_profile = try(each.value.create_instance_profile, var.defaults.create_instance_profile, false) - create_role = try(each.value.create_role, var.defaults.create_role, false) - custom_role_policy_arns = try(each.value.custom_role_policy_arns, var.defaults.custom_role_policy_arns, []) - custom_role_trust_policy = try(each.value.custom_role_trust_policy, var.defaults.custom_role_trust_policy, "") - force_detach_policies = try(each.value.force_detach_policies, var.defaults.force_detach_policies, false) - inline_policy_statements = try(each.value.inline_policy_statements, var.defaults.inline_policy_statements, []) - max_session_duration = try(each.value.max_session_duration, var.defaults.max_session_duration, 3600) - mfa_age = try(each.value.mfa_age, var.defaults.mfa_age, 86400) - number_of_custom_role_policy_arns = try(each.value.number_of_custom_role_policy_arns, var.defaults.number_of_custom_role_policy_arns, null) - poweruser_role_policy_arn = try(each.value.poweruser_role_policy_arn, var.defaults.poweruser_role_policy_arn, "arn:aws:iam::aws:policy/PowerUserAccess") - readonly_role_policy_arn = try(each.value.readonly_role_policy_arn, var.defaults.readonly_role_policy_arn, "arn:aws:iam::aws:policy/ReadOnlyAccess") - role_description = try(each.value.role_description, var.defaults.role_description, "") - role_name = try(each.value.role_name, var.defaults.role_name, null) - role_name_prefix = try(each.value.role_name_prefix, var.defaults.role_name_prefix, null) - role_path = try(each.value.role_path, var.defaults.role_path, "/") - role_permissions_boundary_arn = try(each.value.role_permissions_boundary_arn, var.defaults.role_permissions_boundary_arn, "") - role_requires_mfa = try(each.value.role_requires_mfa, var.defaults.role_requires_mfa, true) - role_requires_session_name = try(each.value.role_requires_session_name, var.defaults.role_requires_session_name, false) - role_session_name = try(each.value.role_session_name, var.defaults.role_session_name, ["$${aws:username}"]) - role_sts_externalid = try(each.value.role_sts_externalid, var.defaults.role_sts_externalid, []) - tags = try(each.value.tags, var.defaults.tags, {}) - trusted_role_actions = try(each.value.trusted_role_actions, var.defaults.trusted_role_actions, ["sts:AssumeRole", "sts:TagSession"]) - trusted_role_arns = try(each.value.trusted_role_arns, var.defaults.trusted_role_arns, []) - trusted_role_services = try(each.value.trusted_role_services, var.defaults.trusted_role_services, []) + admin_role_policy_arn = try(each.value.admin_role_policy_arn, var.defaults.admin_role_policy_arn, "arn:aws:iam::aws:policy/AdministratorAccess") + allow_self_assume_role = try(each.value.allow_self_assume_role, var.defaults.allow_self_assume_role, false) + attach_admin_policy = try(each.value.attach_admin_policy, var.defaults.attach_admin_policy, false) + attach_poweruser_policy = try(each.value.attach_poweruser_policy, var.defaults.attach_poweruser_policy, false) + attach_readonly_policy = try(each.value.attach_readonly_policy, var.defaults.attach_readonly_policy, false) + create_custom_role_trust_policy = try(each.value.create_custom_role_trust_policy, var.defaults.create_custom_role_trust_policy, false) + create_instance_profile = try(each.value.create_instance_profile, var.defaults.create_instance_profile, false) + create_role = try(each.value.create_role, var.defaults.create_role, false) + custom_role_policy_arns = try(each.value.custom_role_policy_arns, var.defaults.custom_role_policy_arns, []) + custom_role_trust_policy = try(each.value.custom_role_trust_policy, var.defaults.custom_role_trust_policy, "") + force_detach_policies = try(each.value.force_detach_policies, var.defaults.force_detach_policies, false) + inline_policy_statements = try(each.value.inline_policy_statements, var.defaults.inline_policy_statements, []) + managed_policy_arns = try(each.value.managed_policy_arns, var.defaults.managed_policy_arns, []) + max_session_duration = try(each.value.max_session_duration, var.defaults.max_session_duration, 3600) + mfa_age = try(each.value.mfa_age, var.defaults.mfa_age, 86400) + number_of_custom_role_policy_arns = try(each.value.number_of_custom_role_policy_arns, var.defaults.number_of_custom_role_policy_arns, null) + poweruser_role_policy_arn = try(each.value.poweruser_role_policy_arn, var.defaults.poweruser_role_policy_arn, "arn:aws:iam::aws:policy/PowerUserAccess") + readonly_role_policy_arn = try(each.value.readonly_role_policy_arn, var.defaults.readonly_role_policy_arn, "arn:aws:iam::aws:policy/ReadOnlyAccess") + role_description = try(each.value.role_description, var.defaults.role_description, "") + role_name = try(each.value.role_name, var.defaults.role_name, null) + role_name_prefix = try(each.value.role_name_prefix, var.defaults.role_name_prefix, null) + role_path = try(each.value.role_path, var.defaults.role_path, "/") + role_permissions_boundary_arn = try(each.value.role_permissions_boundary_arn, var.defaults.role_permissions_boundary_arn, "") + role_requires_mfa = try(each.value.role_requires_mfa, var.defaults.role_requires_mfa, true) + role_requires_session_name = try(each.value.role_requires_session_name, var.defaults.role_requires_session_name, false) + role_session_name = try(each.value.role_session_name, var.defaults.role_session_name, ["$${aws:username}"]) + role_sts_externalid = try(each.value.role_sts_externalid, var.defaults.role_sts_externalid, []) + tags = try(each.value.tags, var.defaults.tags, {}) + trusted_role_actions = try(each.value.trusted_role_actions, var.defaults.trusted_role_actions, ["sts:AssumeRole", "sts:TagSession"]) + trusted_role_arns = try(each.value.trusted_role_arns, var.defaults.trusted_role_arns, []) + trusted_role_services = try(each.value.trusted_role_services, var.defaults.trusted_role_services, []) + use_managed_policy_arns_on_iam_role = try(each.value.use_managed_policy_arns_on_iam_role, var.defaults.use_managed_policy_arns_on_iam_role, false) }