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: Add support for inline policy creation #479

Merged
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
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
57 changes: 48 additions & 9 deletions examples/iam-assumable-role-with-oidc/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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/<CIRCLECI_ORG_UUID>"

oidc_fully_qualified_audiences = ["<CIRCLECI_ORG_UUID>"]

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"]
}

#####################################
Expand All @@ -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/<CIRCLECI_ORG_UUID>"

oidc_fully_qualified_audiences = ["<CIRCLECI_ORG_UUID>"]

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/<CIRCLECI_ORG_UUID>"

oidc_fully_qualified_audiences = ["<CIRCLECI_ORG_UUID>"]

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 = ["*"]
}
]
}
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](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_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
61 changes: 61 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,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
}
6 changes: 6 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,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)
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](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_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
61 changes: 61 additions & 0 deletions modules/iam-assumable-role/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
6 changes: 6 additions & 0 deletions modules/iam-assumable-role/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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"
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