Reputation: 2975
I want to attach a managed IAM Policy ARN (like AmazomS3FullAccess
) and an inline/custom IAM policy (written in JSON in terraform file) to a single IAM Role.
by using aws_iam_role_policy_attachment
I am able to attach only one policy, what's the way to attach both?
variables.tf
------------
variable "iam_policy_arn" {
description = "IAM Policy to be attached to role"
type = list(string)
default = ["arn:aws:iam::aws:policy/AWSLambdaFullAccess", "arn:aws:iam::aws:policy/AmazonSSMFullAccess", "arn:aws:iam::aws:policy/AmazonSageMakerFullAccess"]
}
main.tf
-------
resource "aws_iam_role" "test_role" {
name = "test_role"
assume_role_policy = <<-EOF
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Principal":{
"Service":"ec2.amazonaws.com"
},
"Action":"sts:AssumeRole"
},
{
"Effect":"Allow",
"Principal":{
"Service":"sagemaker.amazonaws.com",
"AWS":"*"
},
"Action":"sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "role_policy_attachment" {
role = "${aws_iam_role.test_role.name}"
count = "${length(var.iam_policy_arn)}"
policy_arn = "${element(var.iam_policy_arn,count.index)}"
}
resource "aws_iam_instance_profile" "test_profile" {
name = "test_profile"
role = "${aws_iam_role.test_role.name}"
}
now I want to attach a custom policy like below to the role
resource "aws_iam_role_policy" "test_policy" {
name = "test_policy"
role = aws_iam_role.test_role.id
policy = <<-EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ec2:Describe*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
EOF
}
How do I attach a managed IAM policy and a custom IAM policy to IAM roles?
Upvotes: 5
Views: 16992
Reputation: 375
You might need to modify the policy to your needs but that's what it would look like. You can do the following:
data "template_file" "test_role_template" {
template = "${file("pathToRoleJson")}"
}
data "template_file" "test_policy_template" {
template = "${file("pathToPolicyJson")}"
vars = {
customParam = "${var.ValueOfParam}"
}
}
resource "aws_iam_role" "test_role" {
name = "roleName"
assume_role_policy = "${data.template_file.test_role.rendered}"
}
#-----------------------------------------
resource "aws_iam_policy" "test_role_policy" {
name = "policyName"
policy = "${data.template_file.test_policy_template.rendered}"
}
# Attach policy to role nat_ec2_role
#-----------------------------------------
resource "aws_iam_role_policy_attachment" "nat_ec2_role_policy-attachment" {
role = "${aws_iam_role.test_role.name}"
policy_arn = "${aws_iam_policy.test_role_policy.arn}"
}
# Policy Template File
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Principal":{
"Service":"ec2.amazonaws.com"
},
"Action":"sts:AssumeRole"
},
{
"Effect":"Allow",
"Principal":{
"Service":"sagemaker.amazonaws.com",
"AWS":"*"
},
{
"Action": [
"ec2:Describe*"
],
"Effect": "Allow",
"Resource": "*"
}
"Action":"sts:AssumeRole"
}
]
}
resource "aws_iam_instance_profile" "test_profile" {
name = "test_profile"
role = "${aws_iam_role.test_role.name}"
}
Upvotes: 1
Reputation: 17009
AWS offers different identity-based policies, see Identity-based policies:
Managed policies – Standalone identity-based policies that you can attach to multiple users, groups, and roles in your AWS account. There are two types of managed policies:
AWS managed policies – Managed policies that are created and managed by AWS.
Customer managed policies – Managed policies that you create and manage in your AWS account. Customer managed policies provide more precise control over your policies than AWS managed policies.
Inline policies – Policies that you add directly to a single user, group, or role. Inline policies maintain a strict one-to-one relationship between a policy and an identity. They are deleted when you delete the identity.
You can mix these policies, see Choosing between managed policies and inline policies:
You can use both managed and inline policies together to define common and unique permissions for a principal entity.
Terraform can add a policy to a role with:
aws_iam_role_policy
(for inline policy)
inline_policy
(for inline policy)
aws_iam_role_policy_attachment
(for AWS/custom managed policy)
aws_iam_policy_attachment
(for AWS/custom managed policy)
managed_policy_arns
(for AWS/custom managed policy)
But you can't mix them arbitrarily, see aws_iam_role_policy
:
For a given role, this resource is incompatible with using the
aws_iam_role
resourceinline_policy
argument. When using that argument and this resource, both will attempt to manage the role's inline policies and Terraform will show a permanent difference.
and aws_iam_role_policy_attachment
:
The usage of this resource conflicts with the
aws_iam_policy_attachment
resource and will permanently show a difference if both are defined.
and aws_iam_role
:
If you use this resource's
managed_policy_arns
argument orinline_policy
configuration blocks, this resource will take over exclusive management of the role's respective policy types (e.g., both policy types if both arguments are used). These arguments are incompatible with other ways of managing a role's policies, such asaws_iam_policy_attachment
,aws_iam_role_policy_attachment
, andaws_iam_role_policy
. If you attempt to manage a role's policies by multiple means, you will get resource cycling and/or errors.
You can use aws_iam_role_policy_attachment
and aws_iam_role_policy
together.
Example
resource "aws_iam_role" "my_role" {
name = "my-role"
assume_role_policy = data.aws_iam_policy_document.instance-assume-role-policy.json
}
resource "aws_iam_role_policy_attachment" "rekognition" {
role = aws_iam_role.my_role.name
policy_arn = data.aws_iam_policy.rekognition.arn
}
resource "aws_iam_role_policy" "s3" {
name = "my-inline-policy"
role = aws_iam_role.my_role.name
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"s3:GetObject",
"s3:ListBucket",
]
Effect = "Allow"
Resource = [
"my-bucket",
"my-bucket/*",
]
}
]
})
}
If you want to validate your custom managed / inline policy by Terraform, you could use aws_iam_policy_document
, see Refactor your policy:
The
aws_iam_policy_document
data source uses HCL to generate a JSON representation of an IAM policy document. Writing the policy as a Terraform configuration has several advantages over defining your policy inline in theaws_iam_policy
resource.
- Terraform data sources makes applying policies to your AWS resources more flexible. You can overwrite, append, or update policies with this resource by using the
source_policy_documents
andoverride_policy_documents
arguments.- Terraform data sources make it easier to reuse policies throughout your environment.
- Terraform error checking automatically formats your policy document into correct JSON when you run your apply.
Upvotes: 1
Reputation: 21716
You can add the inline policy with embedded JSON as follows:
resource "aws_iam_role_policy" "test_policy" {
name = "test_policy"
role = aws_iam_role.test_role.id
policy = <<-EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ec2:Describe*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
EOF
}
Or you can use a aws_iam_policy_document
to get better error-checking in IDEs like IntelliJ IDEA:
resource "aws_iam_role_policy" "policy" {
name = "test-policy"
description = "A test policy"
policy = data.aws_iam_policy_document.allow_ec2_describe
}
data "aws_iam_policy_document" "allow_ec2_describe" {
version = "2012-10-17"
statement {
actions = [
"ec2:Describe*",
]
effect = "Allow"
resources = [
"*",
]
}
}
Side note: you can more cleanly attach the Amazon Managed Policies using an aws_iam_role_policy_attachment
resource with for_each
like this:
resource "aws_iam_role_policy_attachment" "managed_policy_attachments" {
for_each = {for arn in var.iam_policy_arns : arn => arn}
role = aws_iam_role.test_role.name
policy_arn = data.aws_iam_policy.managed_policies[each.key]
}
Side note: you can also use aws_iam_role_policy_attachment
for cleaner assume_role_policy
setup:
resource "aws_iam_role" "test_role" {
name = "test_role"
assume_role_policy = data.aws_iam_policy_document.allow_ec2_and_sagemaker
}
data "aws_iam_policy_document" "allow_ec2_and_sagemaker" {
version = "2012-10-17"
statement {
sid = "AllowEC2AndSageMaker"
effect = "Allow"
actions = [
"sts:AssumeRole",
]
principals {
type = "Service"
identifiers = [
"ec2.amazonaws.com",
"sagemaker.amazonaws.com",
]
}
}
}
Upvotes: 2
Reputation: 2975
I was able to attach a managed IAM policy and an inline/custom IAM policy to IAM role using the below code.
# variables.tf
variable "cloudwatch_lambda_iam_policy_arn" {
type = list(string)
description = "IAM Policy to be attached to AWS CloudWatch Lambda role"
default = ["arn:aws:iam::aws:policy/AmazonEC2FullAccess", "arn:aws:iam::aws:policy/AWSLambdaExecute", "arn:aws:iam::aws:policy/AmazonCloudDirectoryFullAccess", "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]
}
#------------------------------------------------------------
# lambda.tf
resource "aws_iam_role" "awsmetrics_exec_role" {
name = "awsmetrics-exec-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
# custom/inline policy
resource "aws_iam_role_policy" "sts_assumerole_lambda" {
name = "sts-assumerole-lambda"
role = aws_iam_role.awsmetrics_exec_role.id
policy = <<-EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"sts:AssumeRole",
"sts:DecodeAuthorizationMessage",
"sts:AssumeRoleWithSAML",
"sts:AssumeRoleWithWebIdentity"
],
"Resource": "*"
}
]
}
EOF
}
# AWS managed policies
resource "aws_iam_role_policy_attachment" "awsmetrics_role_policy_attachment" {
role = aws_iam_role.awsmetrics_exec_role.name
count = length(var.cloudwatch_lambda_iam_policy_arn)
policy_arn = element(var.cloudwatch_lambda_iam_policy_arn, count.index)
}
Upvotes: 4
Reputation:
Just pass them as variable or declare them as a local value, and then iterate over such variable.
For example:
resource "aws_iam_role_policy_attachment" "attach" {
count = length(var.policies)
role = aws_iam_role.my_role.name
policy_arn = ${var.policies[count.index]}
}
where var.policies
is a list of policies ["arn:aws:iam::aws:policy/AmazonS3FullAccess", "arn:aws:iam::<your_account>:policy/your_policy"]
Upvotes: 0