Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Enables exclusive IAM policy management of IAM role with managed_policy_arns option #526

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions modules/iam-assumable-role/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ No modules.
| <a name="input_custom_role_trust_policy"></a> [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 |
| <a name="input_force_detach_policies"></a> [force\_detach\_policies](#input\_force\_detach\_policies) | Whether policies should be detached from this role when destroying | `bool` | `false` | no |
| <a name="input_inline_policy_statements"></a> [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 |
| <a name="input_managed_policy_arns"></a> [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 |
| <a name="input_max_session_duration"></a> [max\_session\_duration](#input\_max\_session\_duration) | Maximum CLI/API session duration in seconds between 3600 and 43200 | `number` | `3600` | no |
| <a name="input_mfa_age"></a> [mfa\_age](#input\_mfa\_age) | Max age of valid MFA (in seconds) for roles which require MFA | `number` | `86400` | no |
| <a name="input_number_of_custom_role_policy_arns"></a> [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 |
Expand All @@ -73,6 +74,7 @@ No modules.
| <a name="input_trusted_role_actions"></a> [trusted\_role\_actions](#input\_trusted\_role\_actions) | Additional trusted role actions | `list(string)` | <pre>[<br/> "sts:AssumeRole",<br/> "sts:TagSession"<br/>]</pre> | no |
| <a name="input_trusted_role_arns"></a> [trusted\_role\_arns](#input\_trusted\_role\_arns) | ARNs of AWS entities who can assume these roles | `list(string)` | `[]` | no |
| <a name="input_trusted_role_services"></a> [trusted\_role\_services](#input\_trusted\_role\_services) | AWS Services that can assume these roles | `list(string)` | `[]` | no |
| <a name="input_use_managed_policy_arns_on_iam_role"></a> [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

Expand Down
12 changes: 7 additions & 5 deletions modules/iam-assumable-role/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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_"
Expand Down
12 changes: 12 additions & 0 deletions modules/iam-assumable-role/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
}
62 changes: 32 additions & 30 deletions wrappers/iam-assumable-role/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}