I am trying to attach an existing IAM policy to multiple IAM roles that have the same naming convention, I am trying it with below terraform files but it's not working.
vars.tf
variable "aws_iam_role_names" {
type = list(string)
default = ["name1", "name2", "name3"]
}
main.tf
resource "aws_iam_role_policy_attachment" "iam-role" {
role = "${var.aws_iam_role_names[count.index]}-iam-role"
policy_arn = var.some_policy_arn
}
My goal here is to use a single resource block and attach some_policy_arn to the roles name1-iam-role, name2-iam-role, name3-iam-role and whichever role names I add to the variables in the future.
Thanks in advance!
You can use count:
resource "aws_iam_role_policy_attachment" "iam-role" {
count = length(var.aws_iam_role_names)
role = "${var.aws_iam_role_names[count.index]}-iam-role"
policy_arn = var.some_policy_arn
}
for for_each:
resource "aws_iam_role_policy_attachment" "iam-role" {
for_each = toset(var.aws_iam_role_names)
role = "${each.key}-iam-role"
policy_arn = var.some_policy_arn
}
Instead of using the aws console to simply attach a couple of pre-existing policies to a pre-existing role, I need to do it via Terraform within a module for a specific system that requires the perms.
I am not having much luck doing it though?
variables.tf
variable "masterrole" {
description = "role already present within the cn-tio-tooling-acc"
default = "arn:aws-cn:iam::12345678910:role/Master"
}
variable "policies" {
description = "policies already present within the cn-tio-tooling-acc"
default = "arn:aws-cn:iam::12345678910:policy/Source-1,arn:aws-cn:iam::351767606935:policy/Source-2"
}
data.tf <-- Referencing the role and policy data that's already present within the account
data "aws_iam_role" "masterrole" {
name = "Master"
}
data "aws_iam_policy" "policies" {
arn = var.policies
}
IAM.tf
resource "aws_iam_role_policy_attachment" "Sources" {
role = aws_iam_role.masterrole.name
policy_arn = aws_iam_policy.policies.arn
}
Probably something really simple here, but why do I get the following from a 'plan' result?
Error: Reference to undeclared resource
on cn_cpm_iam.tf line 3, in resource "aws_iam_role_policy_attachment" "Sources":
3: role = aws_iam_role.masterrole.name
A managed resource "aws_iam_role" "masterrole" has not been declared in the
root module.
Error: Reference to undeclared resource
on cn_cpm_iam.tf line 4, in resource "aws_iam_role_policy_attachment" "Sources":
4: policy_arn = aws_iam_policy.cpmpolicies.arn
A managed resource "aws_iam_policy" "policies" has not been declared in the
root module.
When referencing data sources in terraform you need to prefix them with data.. So try using
resource "aws_iam_role_policy_attachment" "Sources" {
role = data.aws_iam_role.masterrole.name
policy_arn = data.aws_iam_policy.policies.arn
}
But as you already know the name and the ARN you can just use them without querying the data sources:
resource "aws_iam_role_policy_attachment" "Sources" {
role = "Master"
policy_arn = var.policies
}
Let me know if i am missing something here ;)
as i'm new with terraform, i'd like to ask your help once i got stuck for almost a day.
When trying to apply a IAC to deploy a Nginx service into a ECS(EC2 launch type) on aws i'm facing the following problem:
Error: Error creating IAM Role nginx-iam_role: MalformedPolicyDocument: Has prohibited field Resource status code: 400, request id: 0f1696f4-d86b-4ad1-ba3b-9453f3beff2b
I have already checked the documentation and the syntax is fine. What else could be wrong?
Following the snippet code creating the IAM infra:
provider "aws" {
region = "us-east-2"
}
data "aws_iam_policy_document" "nginx-doc-policy" {
statement {
sid = "1"
actions = [
"ec2:*"
]
resources = ["*"]
}
}
resource "aws_iam_role" "nginx-iam_role" {
name = "nginx-iam_role"
path = "/"
assume_role_policy = "${data.aws_iam_policy_document.nginx-doc-policy.json}"
}
resource "aws_iam_group_policy" "nginx-group-policy" {
name = "my_developer_policy"
group = "${aws_iam_group.nginx-iam-group.name}"
policy = "${data.aws_iam_policy_document.nginx-doc-policy.json}"
}
resource "aws_iam_group" "nginx-iam-group" {
name = "nginx-iam-group"
path = "/"
}
resource "aws_iam_user" "nginx-user" {
name = "nginx-user"
path = "/"
}
resource "aws_iam_user_group_membership" "nginx-membership" {
user = "${aws_iam_user.nginx-user.name}"
groups = ["${aws_iam_group.nginx-iam-group.name}"]
}
If you guys need the remaining code: https://github.com/atilasantos/iac-terraform-nginx.git
You are trying to use the aws_iam_policy_document.nginx-doc-policy policy as an assume_role_policy which does not work as an assume role policy needs to define a principal that you trust and want to grant access to assume the role you are creating.
An assume role policy could look like this is you want to grant access to the role to EC2 instances via instance profiles. At the end you can attach your initial role via a new resource as an inline policy to the role:
data "aws_iam_policy_document" "instance-assume-role-policy" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
resource "aws_iam_role" "nginx-iam_role" {
name = "nginx-iam_role"
path = "/"
assume_role_policy = data.aws_iam_policy_document.instance-assume-role-policy.json
}
resource "aws_iam_role_policy" "role_policy" {
name = "role policy"
role = aws_iam_role.nginx-iam_role.id
policy = data.aws_iam_policy_document.nginx-doc-policy.json
}
Instead of attaching the policy as an inline policies you can also create an IAM Policy and attach it to the various iam resources. (e.g.: aws_iam_policy and aws_iam_role_policy_attachment for roles.)
We created a bunch of open-source IAM modules (and others) to make IAM handling easier: Find them here on github. But there are more modules out there that you can try.
I am new to terraform. I was working with terraform v0.12 previously and since I wanted to bring in a dependency between modules, I started using terraform v0.13 recently. I am trying to create an IAM role and attach a few policies to the created role. But the issue arises in policy attachment to the role. Few policies are getting attached to the role but some policies throw an error saying no such role exists while the other policies are attached to the role properly. Is there anything wrong in my implementation?
module.tf
provider "aws" {
region = "ap-southeast-1"
}
#Control Plane role and policies
module "ControlPlane_Role" {
source = "../../templates/IAM/roles"
role_name = var.EKS-master-role
}
module "ControlPlane_Policy1" {
source = "../../templates/IAM/aws_policy"
role_name = var.EKS-master-role
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
depends_on = [module.ControlPlane_Role.role_create]
}
module "ControlPlane_Policy2" {
source = "../../templates/IAM/aws_policy"
role_name = var.EKS-master-role
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSServicePolicy"
depends_on = [module.ControlPlane_Role.role_create]
}
templates/IAM/roles/role.tf
resource "aws_iam_role" "role_create" {
assume_role_policy = data.aws_iam_policy_document.trusted_entity.json
name = var.role_name
}
aws_policy.tf
resource "aws_iam_role_policy_attachment" "aws_policy" {
role = var.role_name
policy_arn = var.policy_arn
}
I'll be passing the variable files separately and there are no issues with that.
Error:
Error: Error attaching policy arn:aws:iam::aws:policy/AmazonEKSClusterPolicy to IAM Role EKS-master: NoSuchEntity: The role with name EKS-master cannot be found.
Error attaching policy arn:aws:iam::aws:policy/AmazonEKSServicePolicy to IAM Role EKS-master: NoSuchEntity: The role with name EKS-master cannot be found.
If I re-run the command terraform apply again on the same resources without any change, the policies are getting attached.
You shouldn't use depends_on except for some exceptional cases. From the templates/IAM/roles, define an output that is the name of the role and in the other modules pass this output (role_name = module.ControlPlane_Role.output_role_name). With this setup, the dependency graph is clear (create the role, create the things that depend on the role) instead of having to manually define dependencies with depends_on.
I want to attach multiple IAM Policy ARNs to a single IAM Role.
One method is to create a new policy with privileges of all the policies (multiple policies).
But in AWS, we have some predefined IAM policies like AmazonEC2FullAccess, AmazomS3FullAccess, etc. I want to use a combination of these for my role.
I could not find a way to do so in the Terraform documentation.
As per documentation we can use aws_iam_role_policy_attachment to attach a policy to a role, but not multiple policies to a role as this is available via AWS console.
Please let me know if there is a method to do the same or is it still a feature to be added.
The Terraform version I use is v0.9.5
For Terraform versions >= 0.12 the cleanest way to add multiple policies is probably something like this:
resource "aws_iam_role_policy_attachment" "role-policy-attachment" {
for_each = toset([
"arn:aws:iam::aws:policy/AmazonEC2FullAccess",
"arn:aws:iam::aws:policy/AmazonS3FullAccess"
])
role = var.iam_role_name
policy_arn = each.value
}
As described in Pranshu Verma's answer, the list of policies can also be put into a variable.
Using for_each in favor of count has the advantage, that insertions to the list are properly recognized by terraform so that it would really only add one policy, while with count all policies after the insertion would be changed (this is described in detail in this blog post)
Thanks Krishna Kumar R for the hint.
A little more polished answer I reached from your answer.
# Define policy ARNs as list
variable "iam_policy_arn" {
description = "IAM Policy to be attached to role"
type = "list"
}
# Then parse through the list using count
resource "aws_iam_role_policy_attachment" "role-policy-attachment" {
role = "${var.iam_role_name}"
count = "${length(var.iam_policy_arn)}"
policy_arn = "${var.iam_policy_arn[count.index]}"
}
And finally the list of policies should be specified in *.tfvars file or in command line using -var, for example:
iam_policy_arn = [
"arn:aws:iam::aws:policy/AmazonEC2FullAccess", "arn:aws:iam::aws:policy/AmazonS3FullAccess"]
Did you try something like this:
resource "aws_iam_role" "iam_role_name" {
name = "iam_role_name"
}
resource "aws_iam_role_policy_attachment" "mgd_pol_1" {
name = "mgd_pol_attach_name"
role = "${aws_iam_role.iam_role_name.name}"
policy_arn = "${aws_iam_policy.mgd_pol_1.arn}"
}
resource "aws_iam_role_policy_attachment" "mgd_pol_2" {
name = "mgd_pol_attach_name"
role = "${aws_iam_role.iam_role_name.name}"
policy_arn = "${aws_iam_policy.mgd_pol_2.arn}"
}
Adding another option, which is similar to the excepted answer but instead of:
policy_arn = "${var.iam_policy_arn[count.index]}"
You can use the element function:
policy_arn = "${element(var.iam_policy_arn,count.index)}"
I think that in some cases (like a project with a large amount of code) this could be more readable.
In my case I added multiple statements in one policy document:
data "aws_iam_policy_document" "sns-and-sqs-policy" {
statement {
sid = "AllowToPublishToSns"
effect = "Allow"
actions = [
"sns:Publish",
]
resources = [
data.resource.arn,
]
}
statement {
sid = "AllowToSubscribeFromSqs"
effect = "Allow"
actions = [
"sqs:changeMessageVisibility*",
"sqs:SendMessage",
"sqs:ReceiveMessage",
"sqs:GetQueue*",
"sqs:DeleteMessage",
]
resources = [
data.resource.arn,
]
}
}
resource "aws_iam_policy" "sns-and-sqs" {
name = "sns-and-sqs-policy"
policy = data.aws_iam_policy_document.sns-and-sqs-policy.json
}
resource "aws_iam_role_policy_attachment" "sns-and-sqs-role" {
role = "role_name"
policy_arn = aws_iam_policy.sns-and-sqs.arn
}
simply combine your policies in one policy
1.Use a datasource with for loop to get all the policies
data "aws_iam_policy" "management_group_policy" {
for_each = toset(["Billing", "AmazonS3ReadOnlyAccess"])
name = each.value
}
2.Attach to role as so;
resource "aws_iam_role_policy_attachment" "dev_role_policy_attachment" {
for_each = data.aws_iam_policy.management_group_policy
role = aws_iam_role.role.name
policy_arn = each.value.arn
}
This is an example how i did it:
resource "aws_iam_group_policy_attachment" "policy_attach_example" {
for_each = aws_iam_policy.example
group = aws_iam_group.example.name
policy_arn = each.value["arn"]
}
So basically "aws_iam_policy.example" is a list of policies that i have made in the same way, with for_each
Hope that this help you, i know i come late but i had this simillar issue