Skip to content

Commit

Permalink
feat: Add support for inline policy creation
Browse files Browse the repository at this point in the history
This commit adds support for creating an inline policy for an IAM role
to the `iam-assumable-role-with-oidc` and `iam-assumable-role` modules.

Also updated examples for these modules, and corresponding wrappers.
  • Loading branch information
janschumann authored and fatmcgav committed Apr 19, 2024
1 parent 39e42e1 commit 7df208a
Show file tree
Hide file tree
Showing 12 changed files with 162 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/iam-assumable-role-with-oidc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ No providers.
| Name | Source | Version |
|------|--------|---------|
| <a name="module_iam_assumable_role_admin"></a> [iam\_assumable\_role\_admin](#module\_iam\_assumable\_role\_admin) | ../../modules/iam-assumable-role-with-oidc | n/a |
| <a name="module_iam_assumable_role_inline_policy"></a> [iam\_assumable\_role\_inline\_policy](#module\_iam\_assumable\_role\_inline\_policy) | ../../modules/iam-assumable-role-with-oidc | n/a |
| <a name="module_iam_assumable_role_self_assume"></a> [iam\_assumable\_role\_self\_assume](#module\_iam\_assumable\_role\_self\_assume) | ../../modules/iam-assumable-role-with-oidc | n/a |

## Resources
Expand Down
42 changes: 42 additions & 0 deletions examples/iam-assumable-role-with-oidc/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,45 @@ module "iam_assumable_role_self_assume" {

oidc_fully_qualified_subjects = ["system:serviceaccount:default:sa1", "system:serviceaccount:default:sa2"]
}

#####################################
# IAM assumable role with inline policy
#####################################
module "iam_assumable_role_inline_policy" {
source = "../../modules/iam-assumable-role-with-oidc"

create_role = true

role_name = "role-with-oidc-inline-policy"

tags = {
Role = "role-with-oidc-inline-policy"
}

provider_url = "oidc.eks.eu-west-1.amazonaws.com/id/BA9E170D464AF7B92084EF72A69B9DC8"
provider_urls = ["oidc.eks.eu-west-1.amazonaws.com/id/AA9E170D464AF7B92084EF72A69B9DC8"]

inline_policy_statements = [
{
sid = "AllowECRPushPull"
actions = [
"ecr:GetAuthorizationToken",
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchCheckLayerAvailability",
"ecr:DescribeImages",
"ecr:DescribeRepositories",
"ecr:GetDownloadUrlForLayer",
"ecr:ListImages",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
]
effect = "Allow"
resources = ["*"]
}
]

oidc_fully_qualified_subjects = ["system:serviceaccount:default:sa1", "system:serviceaccount:default:sa2"]
}
1 change: 1 addition & 0 deletions examples/iam-assumable-role/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Run `terraform destroy` when you don't need these resources.
| <a name="module_iam_assumable_role_admin"></a> [iam\_assumable\_role\_admin](#module\_iam\_assumable\_role\_admin) | ../../modules/iam-assumable-role | n/a |
| <a name="module_iam_assumable_role_custom"></a> [iam\_assumable\_role\_custom](#module\_iam\_assumable\_role\_custom) | ../../modules/iam-assumable-role | n/a |
| <a name="module_iam_assumable_role_custom_trust_policy"></a> [iam\_assumable\_role\_custom\_trust\_policy](#module\_iam\_assumable\_role\_custom\_trust\_policy) | ../../modules/iam-assumable-role | n/a |
| <a name="module_iam_assumable_role_inline_policy"></a> [iam\_assumable\_role\_inline\_policy](#module\_iam\_assumable\_role\_inline\_policy) | ../../modules/iam-assumable-role | n/a |
| <a name="module_iam_assumable_role_sts"></a> [iam\_assumable\_role\_sts](#module\_iam\_assumable\_role\_sts) | ../../modules/iam-assumable-role | n/a |
| <a name="module_iam_policy"></a> [iam\_policy](#module\_iam\_policy) | ../../modules/iam-policy | n/a |

Expand Down
44 changes: 44 additions & 0 deletions examples/iam-assumable-role/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,50 @@ module "iam_assumable_role_custom" {
# number_of_custom_role_policy_arns = 3
}

##########################################
# IAM assumable role with inline policy
##########################################
module "iam_assumable_role_inline_policy" {
source = "../../modules/iam-assumable-role"

trusted_role_arns = [
"arn:aws:iam::307990089504:root",
]

trusted_role_services = [
"codedeploy.amazonaws.com"
]

create_role = true

role_name_prefix = "custom-"
role_requires_mfa = false

role_sts_externalid = "some-id-goes-here"

inline_policy_statements = [
{
sid = "AllowECRPushPull"
actions = [
"ecr:GetAuthorizationToken",
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchCheckLayerAvailability",
"ecr:DescribeImages",
"ecr:DescribeRepositories",
"ecr:GetDownloadUrlForLayer",
"ecr:ListImages",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
]
effect = "Allow"
resources = ["*"]
}
]
}

####################################################
# IAM assumable role with multiple sts external ids
####################################################
Expand Down
3 changes: 3 additions & 0 deletions modules/iam-assumable-role-with-oidc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ No modules.
| Name | Type |
|------|------|
| [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy.inline](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
| [aws_iam_role_policy_attachment.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_iam_policy_document.assume_role_with_oidc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.inline](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |

## Inputs
Expand All @@ -42,6 +44,7 @@ No modules.
| <a name="input_aws_account_id"></a> [aws\_account\_id](#input\_aws\_account\_id) | The AWS account ID where the OIDC provider lives, leave empty to use the account for the AWS provider | `string` | `""` | no |
| <a name="input_create_role"></a> [create\_role](#input\_create\_role) | Whether to create a role | `bool` | `false` | 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 to attach to IAM role as an inline policy | <pre>list(object({<br> sid = string<br> actions = list(string)<br> effect = string<br> resources = list(string)<br> }))</pre> | `[]` | 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_number_of_role_policy_arns"></a> [number\_of\_role\_policy\_arns](#input\_number\_of\_role\_policy\_arns) | Number of IAM policies to attach to IAM role | `number` | `null` | no |
| <a name="input_oidc_fully_qualified_audiences"></a> [oidc\_fully\_qualified\_audiences](#input\_oidc\_fully\_qualified\_audiences) | The audience to be added to the role policy. Set to sts.amazonaws.com for cross-account assumable role. Leave empty otherwise. | `set(string)` | `[]` | no |
Expand Down
22 changes: 22 additions & 0 deletions modules/iam-assumable-role-with-oidc/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,25 @@ resource "aws_iam_role_policy_attachment" "custom" {
role = aws_iam_role.this[0].name
policy_arn = var.role_policy_arns[count.index]
}

data "aws_iam_policy_document" "inline" {
count = var.create_role && length(var.inline_policy_statements) > 0 ? 1 : 0

dynamic "statement" {
for_each = var.inline_policy_statements
content {
sid = statement.value.sid
actions = statement.value.actions
effect = statement.value.effect
resources = statement.value.resources
}
}
}

resource "aws_iam_role_policy" "inline" {
count = var.create_role && length(var.inline_policy_statements) > 0 ? 1 : 0

role = aws_iam_role.this[0].name
name_prefix = "${var.role_name}_inline_"
policy = data.aws_iam_policy_document.inline[0].json
}
11 changes: 11 additions & 0 deletions modules/iam-assumable-role-with-oidc/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ variable "number_of_role_policy_arns" {
default = null
}

variable "inline_policy_statements" {
description = "List of inline policy statements to attach to IAM role as an inline policy"
type = list(object({
sid = string
actions = list(string)
effect = string
resources = list(string)
}))
default = []
}

variable "oidc_fully_qualified_subjects" {
description = "The fully qualified OIDC subjects to be added to the role policy"
type = set(string)
Expand Down
3 changes: 3 additions & 0 deletions modules/iam-assumable-role/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ No modules.
|------|------|
| [aws_iam_instance_profile.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource |
| [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy.inline](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
| [aws_iam_role_policy_attachment.admin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.poweruser](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.readonly](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_iam_policy_document.assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.assume_role_with_mfa](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.inline](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |

## Inputs
Expand All @@ -52,6 +54,7 @@ No modules.
| <a name="input_custom_role_policy_arns"></a> [custom\_role\_policy\_arns](#input\_custom\_role\_policy\_arns) | List of ARNs of IAM policies to attach to IAM role | `list(string)` | `[]` | no |
| <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 to attach to IAM role as an inline policy | <pre>list(object({<br> sid = string<br> actions = list(string)<br> effect = string<br> resources = list(string)<br> }))</pre> | `[]` | 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 Down
22 changes: 22 additions & 0 deletions modules/iam-assumable-role/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,28 @@ resource "aws_iam_role_policy_attachment" "readonly" {
policy_arn = var.readonly_role_policy_arn
}

data "aws_iam_policy_document" "inline" {
count = var.create_role && length(var.inline_policy_statements) > 0 ? 1 : 0

dynamic "statement" {
for_each = var.inline_policy_statements
content {
sid = statement.value.sid
actions = statement.value.actions
effect = statement.value.effect
resources = statement.value.resources
}
}
}

resource "aws_iam_role_policy" "inline" {
count = var.create_role && length(var.inline_policy_statements) > 0 ? 1 : 0

role = aws_iam_role.this[0].name
name_prefix = "${var.role_name}_inline_"
policy = data.aws_iam_policy_document.inline[0].json
}

resource "aws_iam_instance_profile" "this" {
count = var.create_role && var.create_instance_profile ? 1 : 0
name = var.role_name
Expand Down
11 changes: 11 additions & 0 deletions modules/iam-assumable-role/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,17 @@ variable "number_of_custom_role_policy_arns" {
default = null
}

variable "inline_policy_statements" {
description = "List of inline policy statements to attach to IAM role as an inline policy"
type = list(object({
sid = string
actions = list(string)
effect = string
resources = list(string)
}))
default = []
}

# Pre-defined policies
variable "admin_role_policy_arn" {
description = "Policy ARN to use for admin role"
Expand Down
1 change: 1 addition & 0 deletions wrappers/iam-assumable-role-with-oidc/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module "wrapper" {
aws_account_id = try(each.value.aws_account_id, var.defaults.aws_account_id, "")
create_role = try(each.value.create_role, var.defaults.create_role, false)
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)
number_of_role_policy_arns = try(each.value.number_of_role_policy_arns, var.defaults.number_of_role_policy_arns, null)
oidc_fully_qualified_audiences = try(each.value.oidc_fully_qualified_audiences, var.defaults.oidc_fully_qualified_audiences, [])
Expand Down
1 change: 1 addition & 0 deletions wrappers/iam-assumable-role/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module "wrapper" {
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)
Expand Down

0 comments on commit 7df208a

Please sign in to comment.