Reading through the docs and having a hard time seeing how to associate an aws_iam_role with an aws_iam_policy. Obviously there's aws_iam_role_policy, but that only allows making "inline policies" for a particular role.
Any suggestions?
The aws_iam_policy_attachment resource allows connections to be created between IAM policies and the various other IAM objects.
For example:
resource "aws_iam_role" "foo" {
name = "example-role"
}
resource "aws_iam_policy" "foo" {
name = "example-policy"
description = "An example policy"
policy = "..."
}
resource "aws_iam_policy_attachment" "foo" {
name = "example-attachment"
policy_arn = "${aws_iam_policy.foo.arn}"
roles = ["${aws_iam_role.foo.name}"]
}
Policies can also be attached to users and groups, as illustrated on the Terraform documentation page.
What I've had to do is create a role and a policy and then attach them as shown in an answer by Martin Atkins.
resource "aws_iam_role" "context-builder-role" {
name = "context-builder-role-${terraform.workspace}"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_policy" "arm_cfs_sqs_queue_policy" {
name = "starmine-inline-policy-${terraform.workspace}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Action": [
"sqs:SendMessage",
"sqs:GetQueueUrl",
"sqs:DeleteMessage"
],
"Effect": "Allow",
"Resource": "arn:aws:sqs:*"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "inline-policy-attach" {
role = aws_iam_role.context-builder-role.name
policy_arn = aws_iam_policy.arm_cfs_sqs_queue_policy.arn
}
You can also attach an AWS policy to a role by using the policies ARN:
resource "aws_iam_role_policy_attachment" "s3-read-only-attach" {
role = aws_iam_role.context-builder-role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}
Follow the below steps:
Step 1) Create the policy which you want to associate with the aws role.
Step 2) Create aws role as follow:
i. Set role name.
ii. Set role type according to your preference.
iii. Attach the policy which you have created in step1.
iv. Review and create the role.
Hope it helps.......
Related
I am using terragrunt to call my terraform module.I have one terragrunt.hcl for my dev and another for testing environment.I would like to be able to attach AWS Managed policy(AdministratorAccess) to my Dev account and (AmazonEC2FullAccess) to my testing account using input variable so that I can remove the policy line in my aws_iam_role_policy section
terragrunt.hcl
terraform {
source = "..//module/vpc"
}
include {
path = find_in_parent_folders()
}
inputs = {
}
main.tf
resource "aws_iam_role" "GitHubActions" {
name = var.GithubAction_role
assume_role_policy = <<EOF
{
"Version":"2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRoleWithWebIdentity",
"Principal":{
"Federated": "${aws_iam_openid_connect_provider.github_oidc_github_actions.arn}"
}
}
EOF
}
resource "aws_iam_role_policy" "GitHubActions"{
name = var.policy
role = aws_iam_role.GitHubActions.id
policy = <<EOF
{
"Version": "2012-10-17",
"Statement":[
{
"Sid": "",
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
EOF
}
I'm not sure to fully understand your question. You cannot attach an IAM Policy to an account. However, you can attach it to an IAM Role which seems to be your goal here? If yes, you can use a data source:
data "aws_iam_policy" "AmazonEC2FullAccess" {
arn = "arn:aws:iam::aws:policy/AmazonEC2FullAccess"
}
resource "aws_iam_role_policy_attachment" "attachment" {
role = aws_iam_role.GitHubActions.name
policy_arn = data.aws_iam_policy.AmazonEC2FullAccess.arn
}
See iam_role_policy_attachment and iam policy data source.
I always get the error
Invalid operation: Not authorized to get credentials of role arn:aws:iam::xxxxx:role/default_glue_role
I simply want to load from a json from S3 into a Redshift cluster. It is not clear to me what role I have to attach (to Redshift ?).
I have tried attaching the following IAM policy to Redshift
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::xxxxx:role/default_glue_role"
}
}
and also tried with "Resource": "*" but I always get same error.
Thanks for help!
I had a long chat with AWS support about this same issues. A few things to check:
Your s3 bucket region is the same as your redshift cluster region
You are not signed in as the root aws user, you need to create a user with the correct permissions and sign in as this user to run your queries
You should add the following permissions to your user and redshift policies:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*",
"redshift:*",
"sqlworkbench:*",
"sts:*",
"secretsmanager:*",
"s3-object-lambda:*",
"ec2:*",
"sns:*",
"cloudwatch:*",
"tag:*",
"redshift-data:*",
"sqlworkbench:*",
"redshift-serverless:*"
],
"Resource": "*"
}
]
}
You should have the following trust relationships in your redshift and user role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"s3.amazonaws.com",
"redshift.amazonaws.com",
"iam.amazonaws.com",
"redshift-serverless.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
The actual set of permissions you need might be less but this is what worked for me. Took me a long time to figure this out! I hope it helps.
It looks like you might also need to add permissions for glue.
The redshift-serverless permission might tell you it's causing an error but you should be able to save it anyway (AWS told me to do this)
For everyone using Terraform:
What fixed for me it was the (4) suggestion from #patrick-ward:
data "aws_iam_policy_document" "dms_assume_role" {
statement {
actions = ["sts:AssumeRole"]
principals {
identifiers = [
"s3.amazonaws.com",
"redshift.amazonaws.com",
"iam.amazonaws.com",
"redshift-serverless.amazonaws.com",
"dms.amazonaws.com"
]
type = "Service"
}
}
}
resource "aws_iam_role" "dms-access-for-endpoint" {
assume_role_policy = data.aws_iam_policy_document.dms_assume_role.json
name = "dms-access-for-endpoint"
}
resource "aws_iam_role_policy_attachment" "dms-access-for-endpoint-AmazonDMSRedshiftS3Role" {
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonDMSRedshiftS3Role"
role = aws_iam_role.dms-access-for-endpoint.name
}
resource "aws_iam_role" "dms-cloudwatch-logs-role" {
assume_role_policy = data.aws_iam_policy_document.dms_assume_role.json
name = "dms-cloudwatch-logs-role"
}
resource "aws_iam_role_policy_attachment" "dms-cloudwatch-logs-role-AmazonDMSCloudWatchLogsRole" {
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonDMSCloudWatchLogsRole"
role = aws_iam_role.dms-cloudwatch-logs-role.name
}
resource "aws_iam_role" "dms-vpc-role" {
assume_role_policy = data.aws_iam_policy_document.dms_assume_role.json
name = "dms-vpc-role"
}
resource "aws_iam_role_policy_attachment" "dms-vpc-role-AmazonDMSVPCManagementRole" {
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonDMSVPCManagementRole"
role = aws_iam_role.dms-vpc-role.name
}
Following on the back of this answer, I'm trying to create an aws_iam_role that allows for access to ECR. However, when I define the following:
resource "aws_iam_role" "jenkins_ecr_role" {
name = "JenkinsECRRole"
assume_role_policy = <<END_OF_POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecr.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
END_OF_POLICY
}
I get the error:
Error: Error creating IAM Role JenkinsECRRole:
MalformedPolicyDocument: Invalid principal in policy: "SERVICE":"*"
It looks like ecr.amazonaws.com is a valid principal according to the AWS documentation. What am I doing wrong?
It seems that this question has not been fully answered so I'll try to give an example on how I added ecr for my gitlab-runner ec2 instance. First off the ec2 instance needs a iam_instance_profile which it seems that you already have. Second: You need the assume-role so that the instance can assume the role of the service.
Notice am given access to all the resources not just an specific one(you can adjusted as needed)
The role
resource "aws_iam_role" "role" {
name = "${local.env}-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": ["ec2.amazonaws.com"]
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
The policy to allow access to ECR
resource "aws_iam_policy" "policy" {
name = "${local.env}-ecr-access-policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"ecr:*",
]
Effect = "Allow"
Resource = "*"
},
]
})
}
The attachment of the policy to the role
resource "aws_iam_policy_attachment" "attach" {
name = "${local.env}-attach"
roles = ["${aws_iam_role.role.name}"]
policy_arn = "${aws_iam_policy.policy.arn}"
}
And finally the profile the EC2 will need
resource "aws_iam_instance_profile" "profile" {
name = "${local.env}-gitlab-runner-instance-profile"
role = aws_iam_role.role.name
}
The EC2 instance
resource "aws_instance" "ec2" {
ami = "ami-06c94f9acb4ba21b2"
instance_type = "t2.small"
associate_public_ip_address = true
key_name = "<key_name>"
subnet_id = <subnet>
iam_instance_profile = aws_iam_instance_profile.profile.name
vpc_security_group_ids = ["<security_group>"]
tags = {
Environment = "dev"
}
}
I think you are trying to give EC2 permission to access the ECR. For this, you need to create IAM policy for ECR and create IAM role for EC2 and attach the role with the policy.
Please refer to this code:
resource "aws_iam_role" "role" {
name = "test-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_policy" "policy" {
name = "test-policy"
description = "A test policy"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ecr:*",
"cloudtrail:LookupEvents"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "test-attach" {
role = "${aws_iam_role.role.name}"
policy_arn = "${aws_iam_policy.policy.arn}"
}
Hope, it helps.
You need to attach a below mentioned manual policy to your IAM role.
resource "aws_iam_role_policy" "role_policy" {
name = "${aws_iam_role.role.name}"
role = "${aws_iam_role.role.id}"
policy = <<EOF
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "new statement",
"Effect": "Allow",
"Principal": {
"AWS": "<IAM-ROLE-ARN>"
},
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:BatchGetImage",
"ecr:CompleteLayerUpload",
"ecr:GetDownloadUrlForLayer",
"ecr:InitiateLayerUpload",
"ecr:PutImage",
"ecr:UploadLayerPart"
]
}
]
}
EOF
}
Your role is created for a Service that will need the policy to use other resources, I'm not sure if this helps.
You need to create a role that something will be able to assume, ec2, sagemaker, s3, something. ECR does not assume a role as it's just a registry.
For example, I have a Sagemaker instance:
resource "aws_iam_role" "sagemaker_model" {
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "sagemaker.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
Then that instance needs permission to use other Resource (ECR):
resource "aws_iam_policy" "ecr" {
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ecr:*"
],
"Resource": [
"*"
]
}
]
}
EOF
}
Then I attach that policy to the previous role:
resource "aws_iam_role_policy_attachment" "model_attach_ecr" {
role = aws_iam_role.sagemaker_model.name
policy_arn = aws_iam_policy.ecr.arn
}
Although ECR has a specific property that it has its own access policy, you will need to allow that the previously created role can access the specific container registry by creating one aws_ecr_repository_policy:
resource "aws_ecr_repository_policy" "policy" {
repository = <aws_ecr_repository.repo.name>
policy = <<EOF
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "new statement",
"Effect": "Allow",
"Principal": {
"AWS": "${aws_iam_role.sagemaker_model.arn}"
},
"Action": [
"ecr:*"
]
}
]
}
EOF
}
In this one, you will need to replace <aws_ecr_repository.repo.name> by the actual repository name.
I hope this helps.
I am learning Terraform. I am trying to create a new Lambda function. And I realized that I also need to create an IAM role. So I am trying to do both using Terraform. But it does not allow me to create the role.
This is my Terraform file
provider "aws" {
profile = "default"
region = "eu-west-1"
}
data "aws_iam_policy" "AWSLambdaBasicExecutionRole" {
arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
resource "aws_iam_role" "terraform_function_role" {
name = "terraform_function_role"
assume_role_policy = "${data.aws_iam_policy.AWSLambdaBasicExecutionRole.policy}"
}
resource "aws_lambda_function" "terraform_function" {
filename = "terraform_function.zip"
function_name = "terraform_function"
handler = "index.handler"
role = "${aws_iam_role.terraform_function_role.id}"
runtime = "nodejs8.10"
source_code_hash = "${filebase64sha256("terraform_function.zip")}"
}
This is the error that I am getting
Error creating IAM Role terraform_function_role: MalformedPolicyDocument: Has prohibited field Resource
status code: 400
How do I fix this?
IAM Role's trust relationship (or assume role policy) defines which resource / service can assume the role. In this, we don't define the Resource field. Hence we can't attach IAM policies or use that policy as is. The correct format for Trust Relationship is:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}]
}
In this scenario, all Lambda functions in your account can assume this role.
You can refer this AWS link for more examples.
Edit: Based on #ydaetskcoR comment, here's a working example:
provider "aws" {
profile = "default"
region = "eu-west-1"
}
data "aws_iam_policy_document" "AWSLambdaTrustPolicy" {
statement {
actions = ["sts:AssumeRole"]
effect = "Allow"
principals {
type = "Service"
identifiers = ["lambda.amazonaws.com"]
}
}
}
resource "aws_iam_role" "terraform_function_role" {
name = "terraform_function_role"
assume_role_policy = "${data.aws_iam_policy_document.AWSLambdaTrustPolicy.json}"
}
resource "aws_iam_role_policy_attachment" "terraform_lambda_policy" {
role = "${aws_iam_role.terraform_function_role.name}"
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
resource "aws_lambda_function" "terraform_function" {
filename = "terraform_function.zip"
function_name = "terraform_function"
handler = "index.handler"
role = "${aws_iam_role.terraform_function_role.arn}"
runtime = "nodejs8.10"
source_code_hash = "${filebase64sha256("terraform_function.zip")}"
}
The changes from your code include the following:
Updated aws_iam_policy_document resource for assume role permissions
Changed aws_iam_role resource to use the above mentioned policy document
Created aws_iam_role_policy_attachment to attach LambdaBasicExecution policy (which enables logging to CloudWatch)
Updated aws_lambda_function resource to use IAM Role's ARN instead of Id because Lambda function needs the ARN
Since you are still in the learning phase, I suggest you move to terraform 0.12 instead, so you can use things like templatefile. therefore you don't need to create data objects.
One other thing is to always use the Least Privilege Principle when creating policies, meaning your Resource (Lambda, on this case) will only have access to what it needs. For now, it's only CloudWatch, but in a real world scenario this is very likely not the case.
Back to your question, here's how you can create an IAM Role, an IAM Policy and finally an IAM Policy Attachment (this is the bridge between the policy and the role) as well as the AssumeRolePolicy (this is the trust relationship between the service it's going to use it and the role itself). I have extracted it all into templates for you so it's easier to maintain later on. The gist (for an easier read on the eyes) can be found here.
# iam_role
resource "aws_iam_role" "iam_role" {
name = "iam-role"
assume_role_policy = templatefile("${path.module}/templates/lambda-base-policy.tpl", {})
}
#content of lambda-base-policy.tpl
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
#iam_policy
resource "aws_iam_policy" "policy" {
name = "policy"
policy = templatefile("${path.module}/templates/cloudwatch-policy.tpl", {})
}
#content of cloudwatch-policy.tpl
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
#iam_policy_attachment
resource "aws_iam_policy_attachment" "policy_attachment" {
name = "attachment"
roles = ["${aws_iam_role.iam_role.name}"]
policy_arn = "${aws_iam_policy.policy.arn}"
}
As mentioned in the comment, you have to create assume role then attach the assume rule with your newly created policy, here is the complete working example.
#assume role
resource "aws_iam_role" "role" {
name = "test-alb-logs-to-elk"
path = "/"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
# Created Policy for IAM Role (s3 and log access)
resource "aws_iam_policy" "policy" {
name = "my-test-policy"
description = "A test policy"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:*"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
EOF
}
# Attached IAM Role and the new created Policy
resource "aws_iam_role_policy_attachment" "test-attach" {
role = "${aws_iam_role.role.name}"
policy_arn = "${aws_iam_policy.policy.arn}"
}
# Created AWS Lamdba Function: Memory Size, NodeJS version, handler, endpoint, doctype and environment settings
resource "aws_lambda_function" "elb_logs_to_elasticsearch" {
function_name = "mytest-alb-logs-to-elk"
description = "elb-logs-to-elasticsearch"
memory_size = 1024
filename = "terraform_function.zip"
runtime = "nodejs8.10"
role = "${aws_iam_role.role.arn}"
handler = "index.handler"
}
I am trying to create the following IAM Role with a Policy. The Role is attached to a Lambda.
resource "aws_lambda_function" "lambda" {
function_name = "test"
s3_bucket = "${aws_s3_bucket.deployment_bucket.id}"
s3_key = "${var.deployment_key}"
handler = "${var.function_handler}"
runtime = "${var.lambda_runtimes[var.desired_runtime]}"
role = "${aws_iam_role.lambda_role.arn}"
}
resource "aws_iam_role" "lambda_role" {
name = "test-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy" "lambda_policy" {
name = test-policy"
role = "${aws_iam_role.lambda_role.id}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"xray:PutTelemetryRecords",
"xray:PutTraceSegments",
"logs:CreateLogGroup",
"logs:PutLogEvents"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
EOF
}
I run terraform apply from an EC2 instance that has an IAM Role attached to it. The IAM Role has the AdministratorAccess and can deploy VPCs and EC2s with Terraform without any issue. When I try to create the IAM Role and Policy above though it fails with InvalidClientTokenId error.
aws_iam_role.lambda_role: Error creating IAM Role test-role: InvalidClientTokenId: The security token included in the request is invalid
I then generated a set of access key credentials and hard-coded them and it still failed. Is there something special I need to do when creating an IAM Role? Any other terraform apply commands I run from this machine work fine until I need to create an IAM Role.