diff --git a/examples/iam-assumable-role-with-oidc/README.md b/examples/iam-assumable-role-with-oidc/README.md
index bec60f55..dfba9ce0 100644
--- a/examples/iam-assumable-role-with-oidc/README.md
+++ b/examples/iam-assumable-role-with-oidc/README.md
@@ -31,6 +31,7 @@ No providers.
| Name | Source | Version |
|------|--------|---------|
| [iam\_assumable\_role\_admin](#module\_iam\_assumable\_role\_admin) | ../../modules/iam-assumable-role-with-oidc | n/a |
+| [iam\_assumable\_role\_inline\_policy](#module\_iam\_assumable\_role\_inline\_policy) | ../../modules/iam-assumable-role-with-oidc | n/a |
| [iam\_assumable\_role\_self\_assume](#module\_iam\_assumable\_role\_self\_assume) | ../../modules/iam-assumable-role-with-oidc | n/a |
## Resources
diff --git a/examples/iam-assumable-role-with-oidc/main.tf b/examples/iam-assumable-role-with-oidc/main.tf
index 62bc2822..390970bb 100644
--- a/examples/iam-assumable-role-with-oidc/main.tf
+++ b/examples/iam-assumable-role-with-oidc/main.tf
@@ -16,14 +16,13 @@ module "iam_assumable_role_admin" {
Role = "role-with-oidc"
}
- provider_url = "oidc.eks.eu-west-1.amazonaws.com/id/BA9E170D464AF7B92084EF72A69B9DC8"
- provider_urls = ["oidc.eks.eu-west-1.amazonaws.com/id/AA9E170D464AF7B92084EF72A69B9DC8"]
+ provider_url = "oidc.circleci.com/org/"
+
+ oidc_fully_qualified_audiences = [""]
role_policy_arns = [
- "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy",
+ "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser",
]
-
- oidc_fully_qualified_subjects = ["system:serviceaccount:default:sa1", "system:serviceaccount:default:sa2"]
}
#####################################
@@ -41,12 +40,52 @@ module "iam_assumable_role_self_assume" {
Role = "role-with-oidc-self-assume"
}
- provider_url = "oidc.eks.eu-west-1.amazonaws.com/id/BA9E170D464AF7B92084EF72A69B9DC8"
- provider_urls = ["oidc.eks.eu-west-1.amazonaws.com/id/AA9E170D464AF7B92084EF72A69B9DC8"]
+ provider_url = "oidc.circleci.com/org/"
+
+ oidc_fully_qualified_audiences = [""]
role_policy_arns = [
- "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy",
+ "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser",
]
+}
- 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.circleci.com/org/"
+
+ oidc_fully_qualified_audiences = [""]
+
+ 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 = ["*"]
+ }
+ ]
}
diff --git a/examples/iam-assumable-role/README.md b/examples/iam-assumable-role/README.md
index e66df7f8..9c63694c 100644
--- a/examples/iam-assumable-role/README.md
+++ b/examples/iam-assumable-role/README.md
@@ -37,6 +37,7 @@ Run `terraform destroy` when you don't need these resources.
| [iam\_assumable\_role\_admin](#module\_iam\_assumable\_role\_admin) | ../../modules/iam-assumable-role | n/a |
| [iam\_assumable\_role\_custom](#module\_iam\_assumable\_role\_custom) | ../../modules/iam-assumable-role | n/a |
| [iam\_assumable\_role\_custom\_trust\_policy](#module\_iam\_assumable\_role\_custom\_trust\_policy) | ../../modules/iam-assumable-role | n/a |
+| [iam\_assumable\_role\_inline\_policy](#module\_iam\_assumable\_role\_inline\_policy) | ../../modules/iam-assumable-role | n/a |
| [iam\_assumable\_role\_sts](#module\_iam\_assumable\_role\_sts) | ../../modules/iam-assumable-role | n/a |
| [iam\_policy](#module\_iam\_policy) | ../../modules/iam-policy | n/a |
diff --git a/examples/iam-assumable-role/main.tf b/examples/iam-assumable-role/main.tf
index 25b227c9..f4e6c3f0 100644
--- a/examples/iam-assumable-role/main.tf
+++ b/examples/iam-assumable-role/main.tf
@@ -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
####################################################
diff --git a/modules/iam-assumable-role-with-oidc/README.md b/modules/iam-assumable-role-with-oidc/README.md
index 1662a3ed..f38548fb 100644
--- a/modules/iam-assumable-role-with-oidc/README.md
+++ b/modules/iam-assumable-role-with-oidc/README.md
@@ -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
@@ -42,6 +44,7 @@ No modules.
| [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 |
| [create\_role](#input\_create\_role) | Whether to create a role | `bool` | `false` | 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 |
| [max\_session\_duration](#input\_max\_session\_duration) | Maximum CLI/API session duration in seconds between 3600 and 43200 | `number` | `3600` | no |
| [number\_of\_role\_policy\_arns](#input\_number\_of\_role\_policy\_arns) | Number of IAM policies to attach to IAM role | `number` | `null` | no |
| [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 |
diff --git a/modules/iam-assumable-role-with-oidc/main.tf b/modules/iam-assumable-role-with-oidc/main.tf
index e993a5a5..fb14c928 100644
--- a/modules/iam-assumable-role-with-oidc/main.tf
+++ b/modules/iam-assumable-role-with-oidc/main.tf
@@ -107,3 +107,64 @@ resource "aws_iam_role_policy_attachment" "custom" {
role = aws_iam_role.this[0].name
policy_arn = var.role_policy_arns[count.index]
}
+
+###############################
+# IAM Role Inline policy
+###############################
+
+locals {
+ create_iam_role_inline_policy = var.create_role && length(var.inline_policy_statements) > 0
+}
+
+data "aws_iam_policy_document" "inline" {
+ count = local.create_iam_role_inline_policy ? 1 : 0
+
+ dynamic "statement" {
+ for_each = var.inline_policy_statements
+
+ content {
+ sid = try(statement.value.sid, null)
+ actions = try(statement.value.actions, null)
+ not_actions = try(statement.value.not_actions, null)
+ effect = try(statement.value.effect, null)
+ resources = try(statement.value.resources, null)
+ not_resources = try(statement.value.not_resources, null)
+
+ dynamic "principals" {
+ for_each = try(statement.value.principals, [])
+
+ content {
+ type = principals.value.type
+ identifiers = principals.value.identifiers
+ }
+ }
+
+ dynamic "not_principals" {
+ for_each = try(statement.value.not_principals, [])
+
+ content {
+ type = not_principals.value.type
+ identifiers = not_principals.value.identifiers
+ }
+ }
+
+ dynamic "condition" {
+ for_each = try(statement.value.conditions, [])
+
+ content {
+ test = condition.value.test
+ values = condition.value.values
+ variable = condition.value.variable
+ }
+ }
+ }
+ }
+}
+
+resource "aws_iam_role_policy" "inline" {
+ count = local.create_iam_role_inline_policy ? 1 : 0
+
+ role = aws_iam_role.this[0].name
+ name_prefix = "${var.role_name}_inline_"
+ policy = data.aws_iam_policy_document.inline[0].json
+}
diff --git a/modules/iam-assumable-role-with-oidc/variables.tf b/modules/iam-assumable-role-with-oidc/variables.tf
index d9b7cd7b..730f90af 100644
--- a/modules/iam-assumable-role-with-oidc/variables.tf
+++ b/modules/iam-assumable-role-with-oidc/variables.tf
@@ -76,6 +76,12 @@ variable "number_of_role_policy_arns" {
default = null
}
+variable "inline_policy_statements" {
+ description = "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"
+ type = any
+ default = []
+}
+
variable "oidc_fully_qualified_subjects" {
description = "The fully qualified OIDC subjects to be added to the role policy"
type = set(string)
diff --git a/modules/iam-assumable-role/README.md b/modules/iam-assumable-role/README.md
index 6270002c..b35a2250 100644
--- a/modules/iam-assumable-role/README.md
+++ b/modules/iam-assumable-role/README.md
@@ -28,6 +28,7 @@ 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 |
@@ -35,6 +36,7 @@ No modules.
| [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
@@ -52,6 +54,7 @@ No modules.
| [custom\_role\_policy\_arns](#input\_custom\_role\_policy\_arns) | List of ARNs of IAM policies to attach to IAM role | `list(string)` | `[]` | no |
| [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 |
| [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 |
diff --git a/modules/iam-assumable-role/main.tf b/modules/iam-assumable-role/main.tf
index f444f066..719a3873 100644
--- a/modules/iam-assumable-role/main.tf
+++ b/modules/iam-assumable-role/main.tf
@@ -197,3 +197,64 @@ resource "aws_iam_instance_profile" "this" {
tags = var.tags
}
+
+###############################
+# IAM Role Inline policy
+###############################
+
+locals {
+ create_iam_role_inline_policy = var.create_role && length(var.inline_policy_statements) > 0
+}
+
+data "aws_iam_policy_document" "inline" {
+ count = local.create_iam_role_inline_policy ? 1 : 0
+
+ dynamic "statement" {
+ for_each = var.inline_policy_statements
+
+ content {
+ sid = try(statement.value.sid, null)
+ actions = try(statement.value.actions, null)
+ not_actions = try(statement.value.not_actions, null)
+ effect = try(statement.value.effect, null)
+ resources = try(statement.value.resources, null)
+ not_resources = try(statement.value.not_resources, null)
+
+ dynamic "principals" {
+ for_each = try(statement.value.principals, [])
+
+ content {
+ type = principals.value.type
+ identifiers = principals.value.identifiers
+ }
+ }
+
+ dynamic "not_principals" {
+ for_each = try(statement.value.not_principals, [])
+
+ content {
+ type = not_principals.value.type
+ identifiers = not_principals.value.identifiers
+ }
+ }
+
+ dynamic "condition" {
+ for_each = try(statement.value.conditions, [])
+
+ content {
+ test = condition.value.test
+ values = condition.value.values
+ variable = condition.value.variable
+ }
+ }
+ }
+ }
+}
+
+resource "aws_iam_role_policy" "inline" {
+ count = local.create_iam_role_inline_policy ? 1 : 0
+
+ role = aws_iam_role.this[0].name
+ name_prefix = "${var.role_name}_inline_"
+ policy = data.aws_iam_policy_document.inline[0].json
+}
diff --git a/modules/iam-assumable-role/variables.tf b/modules/iam-assumable-role/variables.tf
index 908d55b0..fc9bd2c9 100644
--- a/modules/iam-assumable-role/variables.tf
+++ b/modules/iam-assumable-role/variables.tf
@@ -100,6 +100,12 @@ variable "number_of_custom_role_policy_arns" {
default = null
}
+variable "inline_policy_statements" {
+ description = "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"
+ type = any
+ default = []
+}
+
# Pre-defined policies
variable "admin_role_policy_arn" {
description = "Policy ARN to use for admin role"
diff --git a/wrappers/iam-assumable-role-with-oidc/main.tf b/wrappers/iam-assumable-role-with-oidc/main.tf
index 870acf3a..66b53928 100644
--- a/wrappers/iam-assumable-role-with-oidc/main.tf
+++ b/wrappers/iam-assumable-role-with-oidc/main.tf
@@ -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, [])
diff --git a/wrappers/iam-assumable-role/main.tf b/wrappers/iam-assumable-role/main.tf
index a961ee99..aef04cfe 100644
--- a/wrappers/iam-assumable-role/main.tf
+++ b/wrappers/iam-assumable-role/main.tf
@@ -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)