This example creates a policy via terraforms aws_iam_policy_document
and then adds it to a role's policy_arns
list.
By using aws_iam_policy_document
you have the advantage to use terraform's variables inside the policy definition and be able to first gather already existing resources and add them to that policy. This makes the process of creating policies as dynamic and flexible as it can get.
The following defines two roles, both without any policy attached.
terraform.tfvars
roles = [
{
name = "ROLE-ADMIN"
path = null
desc = null
trust_policy_file = "data/trust-policy-file.json"
permissions_boundary = null
policies = []
inline_policies = []
policy_arns = []
},
{
name = "ROLE-DEV"
path = null
desc = null
trust_policy_file = "data/trust-policy-file.json"
permissions_boundary = null
policies = []
inline_policies = []
policy_arns = []
},
]
Now we're going to dynamically fetch the current AWS account id (just for the sake of this example to have something dynamic).
main.tf
data "aws_caller_identity" "current" {}
We can then use this account id and include it in our policy document.
main.tf
data "aws_iam_policy_document" "s3" {
statement {
sid = "1"
actions = [
"s3:ListAllMyBuckets",
]
resources = [
"arn:aws:s3::${data.aws_caller_identity.current.account_id}:*",
]
}
}
Based on the created policy document, we can define our policy.
main.tf
resource "aws_iam_policy" "s3" {
name = "s3-policy"
path = "/custom/"
description = "Custom S3 policy"
policy = data.aws_iam_policy_document.s3.json
lifecycle {
create_before_destroy = true
}
}
We can now enrich the roles list and add this policy to ROLE-ADMIN
.
We do this by creating a local with the exact same structure and use a condition to attach it to the specific role.
main.tf
locals {
# Roles in this list will have the custom policy added to its policy_arns list
roles_enriched = [
for role in var.roles : {
name = role.name
path = role.path
desc = role.desc
trust_policy_file = role.trust_policy_file
permissions_boundary = role.permissions_boundary
policies = role.policies
inline_policies = role.inline_policies
policy_arns = concat(role.policy_arns, [aws_iam_policy.s3.arn])
} if role["name"] == "ROLE-ADMIN"
]
# Roles in this list will be left as they were (condition reversed)
roles_default = [
for role in var.roles : {
name = role.name
path = role.path
desc = role.desc
trust_policy_file = role.trust_policy_file
permissions_boundary = role.permissions_boundary
policies = role.policies
inline_policies = role.inline_policies
policy_arns = role.policy_arns
} if role["name"] != "ROLE-ADMIN"
]
# Let's merge both created lists
roles = concat(local.roles_enriched, local.roles_default)
}
Now we add everything together and use the iam module
main.tf
module "aws_iam" {
source = "github.com/cytopia/terraform-aws-iam?ref=v5.0.4"
# Note: we're using the local here as input instead
roles = local.roles
}
To run this example you need to execute:
$ terraform init
$ terraform plan
$ terraform apply
Note that this example may create resources which cost money. Run terraform destroy when you don't need these resources.
No requirements.
Name | Version |
---|---|
aws | n/a |
Name | Description | Type | Default | Required |
---|---|---|---|---|
account_alias | Assign the account alias for the AWS Account. Unmanaged by default. Resource will be created if the string is non-empty. | string |
"" |
no |
account_pass_policy | Manages Password Policy for the AWS Account. Unmanaged by default. Resource will be created if 'manage' is set to true. | object({ |
{ |
no |
providers_saml | A list of dictionaries defining saml providers. | list(object({ |
[] |
no |
providers_oidc | A list of dictionaries defining openid connect providers. | list(object({ |
[] |
no |
policies | A list of dictionaries defining all policies. | list(object({ |
[] |
no |
groups | A list of dictionaries defining all groups. | list(object({ |
[] |
no |
users | A list of dictionaries defining all users. | list(object({ |
[] |
no |
roles | A list of dictionaries defining all roles. | list(object({ |
[] |
no |
policy_path | The default path under which to create the policy if not specified in the policies list. You can use a single path, or nest multiple paths as if they were a folder structure. For example, you could use the nested path /division_abc/subdivision_xyz/product_1234/engineering/ to match your company's organizational structure. | string |
"/" |
no |
policy_desc | The default description of the policy. | string |
"Managed by Terraform" |
no |
group_path | The path under which to create the group. You can use a single path, or nest multiple paths as if they were a folder structure. For example, you could use the nested path /division_abc/subdivision_xyz/product_1234/engineering/ to match your company's organizational structure. | string |
"/" |
no |
user_path | The path under which to create the user. You can use a single path, or nest multiple paths as if they were a folder structure. For example, you could use the nested path /division_abc/subdivision_xyz/product_1234/engineering/ to match your company's organizational structure. | string |
"/" |
no |
role_path | The path under which to create the role. You can use a single path, or nest multiple paths as if they were a folder structure. For example, you could use the nested path /division_abc/subdivision_xyz/product_1234/engineering/ to match your company's organizational structure. | string |
"/" |
no |
role_desc | The description of the role. | string |
"Managed by Terraform" |
no |
role_max_session_duration | The maximum session duration (in seconds) that you want to set for the specified role. This setting can have a value from 1 hour to 12 hours specified in seconds. | string |
"3600" |
no |
role_force_detach_policies | Specifies to force detaching any policies the role has before destroying it. | bool |
true |
no |
tags | Key-value mapping of tags for the IAM role or user. | map(any) |
{} |
no |
Name | Description |
---|---|
roles | Created roles |