Following cloudformation template gives error on line 9 :
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Policy to allow send receive message from SQS Queue",
"Resources" : {
"MyPolicy" : {
"Type" : "AWS::IAM::Policy",
"Properties" : {
"PolicyName" : "CFUsers",
"Roles": [ { "arn:aws:iam::710161973367:role/Cognito_CFIAuth_Role" } ],
"PolicyDocument" : {
"Version" : "2012-10-17",
"Statement": [
{
"Sid": "Sid1482400105445",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::710161973367:role/Cognito_CFIAuth_Role"
},
"Action": [
"SQS:SendMessage",
"SQS:ReceiveMessage",
"SQS:DeleteMessage",
"SQS:GetQueueUrl"
],
"Resource": "arn:aws:sqs:ap-south-1:710161973367:CFI-Trace"
}
]
}
}
}
}
I want role Cognito_CFIAuth_Role to have message send/read/delete previleges on SQS queue CFI-Trace. How do I attach SQS operation privileges to IAM Role ?
First, Line 9 contains a JSON syntax error, the brackets {} around your Role string should be removed:
"Roles": [ "arn:aws:iam::710161973367:role/Cognito_CFIAuth_Role" ],
Second, AWS::IAM::Policy's Roles property accepts "The names of AWS::IAM::Roles to attach to this policy", not full ARNs, so your line should be:
"Roles": [ "Cognito_CFIAuth_Role" ],
You also need a missing closing bracket } at the end of your example.
With the AWS::IAM::Policy resource, you're creating an inline policy. http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-policy.html explains that this takes a list of "The names of AWS::IAM::Roles, which I take to be the logical name of role resources defined within the same stack.
If you want to attach the policy to a preexisting role, you should use the ManagedPolicy type instead. http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-managedpolicy.html#cfn-iam-managedpolicy-roles takes the name of the preexisting role(s).
Cloudformation type IAM::Policy is for Users and Groups. Roles and instance profiles are for ec2. You have conflated both ideas. If you have the role predefined in a different CFN then you use just an Instance Profile for your EC2 instance, if not you can create it too and then ref it
"RootInstanceProfile": {
"Type": "AWS::IAM::InstanceProfile",
"Properties": {
"Path": "/",
"Roles": [ {
"arn:aws:iam::710161973367:role/Cognito_CFIAuth_Role"
} ]
}
}
or
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"SQSRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "root",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"SQS:SendMessage",
"SQS:ReceiveMessage",
"SQS:DeleteMessage",
"SQS:GetQueueUrl"
],
"Resource": "arn:aws:sqs:ap-south-1:710161973367:CFI-Trace"
}
]
}
}
]
}
},
"RootInstanceProfile": {
"Type": "AWS::IAM::InstanceProfile",
"Properties": {
"Path": "/",
"Roles": [
{
"Ref": "SQSRole"
}
]
}
}
}
}
IAM Policy
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iam-policy.html
IAM role
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html
Now there is also SQS Policy
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-policy.html
You can also attach ManagedPolicyArns to CloudFormation resource type AWS::IAM::Role https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-managepolicyarns
Related
Hello I recently made a CFT for my lambda and sqs (both on the same account/region) but I noticed that when I go to the aws console, it shows the SQS resource both on the "input side" and the "output side" of my lambda. Is this intentional? or did I just do my CFTs incorrectly. Below is the relevant JSON code.
"MyLambdaFunctionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "root",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:GetQueueAttributes"
],
"Resource": {
"Fn::Sub": "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:test-${Environment}-my-queue"
}
}
]
}
}
]
}
},
"OutputRouterEventSource": {
"Type": "AWS::Lambda::EventSourceMapping",
"Properties": {
"BatchSize": 10,
"Enabled" : true,
"EventSourceArn": {
"Fn::Sub": "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:test-${Environment}-my-queue"
},
"FunctionName": {
"Fn::GetAtt": [
"MyLambdaFunction",
"Arn"
]
}
}
},
"OutputRouterLambdaInvokePermission": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:InvokeFunction",
"Principal": "sns.amazonaws.com",
"SourceArn": {
"Fn::Sub": "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:test-${Environment}-my-queue"
},
"FunctionName": {
"Fn::Sub": "test-${Environment}-my-lambda"
}
}
}
It is normal to have SQS on both side in this case: SQS triggers your Lambda function (left side) and your Lambda function's role must have the permission to receive and delete messages from the queue (right side).
(I think your are mixing services in your OutputRouterLambdaInvokePermission resource where the principal is SNS and the source references the arn of a SQS queue, you can drop this resource as it is not needed for SQS triggers)
Using AWS, I'm building a cloud formation stack defining:
A Managed Policy called MyPolicy
A Role called MyRole that should attach that policy
The stack will be created by an admin ; and once created, the goal is to allow (from outside the stack) some users to assume MyRole.
My question: How should the role be defined in order to attach that policy ?
The AWS help page of the role properties suggests to use the ManagedPolicyArns, but I get various errors depending on how I refer to MyPolicy:
If I use the GetAtt function to retrieve the policy's arn, I get an error at the template validation:
"ManagedPolicyArns": [ { "Fn::GetAtt" : [ "MyPolicy", "Arn" ] } ]
Template error: resource MyPolicy does not support attribute type Arn in Fn::GetAtt
And If I use the Join function to build the policy's arn, I get an error during the role creation.
"ManagedPolicyArns": [ { "Fn::Join" : [ "", [ "arn:aws:iam::", { "Ref": "AWS::AccountId" }, ":policy/", { "Ref": "MyPolicy" } ] ] } ]
ARN arn:aws:iam::aws:policy/arn:aws:iam::«my-account-id»:policy/MyPolicy is not valid. (Service: AmazonIdentityManagement; Status Code: 400; Error Code: InvalidInput; Request ID: «an-id»)
Below is my stack definition using JSON format:
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Resources" : {
"MyPolicy" : {
"Type": "AWS::IAM::ManagedPolicy",
"Properties": {
"ManagedPolicyName" : "MyPolicy",
"PolicyDocument" : {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [ "s3:*" ],
"Resource": "arn:aws:s3:::the-bucket"
}
]
}
}
},
"MyRole" : {
"Type": "AWS::IAM::Role",
"RoleName": "MyRole",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": {"Fn::Join" : [ "", [ "arn:aws:iam::", { "Ref": "AWS::AccountId" }, ":root" ] ] } },,
"Action": [ "sts:AssumeRole" ]
}
]
},
"ManagedPolicyArns": [
{ "Fn::GetAtt" : [ "MyPolicy", "Arn" ] }
]
}
}
}
{"Ref": "MyPolicy"} will return the ARN of the managed policy created by your stack. Your error message indicates that. Also, check this AWS documentation.
I am trying to create an IAM role using the below template. I am able to create the role with managed policies. When I try to add inline policy in my template I get the error
"Property PolicyDocument cannot be empty."
{
"Resources": {
"test": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess",
"arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole",
],
"Policies": [
"PolicyName" : "create_snapshot",
"PolicyDocument" : {
"Version" : "2012-10-17",
"Statement": [ {
"Effect" : "Allow",
"Action": [
"ec2:DeleteSnapshot",
"ec2:CreateTags",
"ec2:CreateSnapshot"
],
"Resource" : "*"
} ]
}
],
"RoleName": "test"
}
}
}
}
Policies is a list of policy objects which is written as follows, with each individual policy object embedded in curly braces inside the [] list:
"Policies": [ {
"PolicyName" : "policy01",
"PolicyDocument" : { ... }
}, {
"PolicyName" : "policy02",
"PolicyDocument" : { ... }
} ]
From the console, I am invoking a lambda which submits a batch job. The batch job fails, indicating that ECS is unable to assume the role that is provided to execute the job definition.
For the role, I've added the lambda and ECS services.
The error message:
"ECS was unable to assume the role
'arn:aws:iam::749340585813:role/golfnow-invoke-write-progress' that
was provided for this task. Please verify that the role being passed
has the proper trust relationship and permissions and that your IAM
user has permissions to pass this role."
"TrainingJobRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "golfnow-invoke-write-progress",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com",
"ecs.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/"
}
}
The batch job:
"TrainingJob": {
"Type": "AWS::Batch::JobDefinition",
"Properties": {
"Type": "container",
"JobDefinitionName": {
"Fn::Sub": "c12e-golfnow-${Environment}-job"
},
"ContainerProperties": {
"Image": {
"Fn::Join": [
"",
[
"{{ image omitted }}",
{
"Ref": "AWS::Region"
},
".amazonaws.com/amazonlinux:latest"
]
]
},
"Vcpus": 2,
"Memory": 2000,
"Command": [
"while", "True", ";", "do", "echo", "'hello';", "done"
],
"JobRoleArn": {
"Fn::GetAtt": [
"TrainingJobRole",
"Arn"
]
}
},
"RetryStrategy": {
"Attempts": 1
}
}
},
"JobQueue": {
"Type": "AWS::Batch::JobQueue",
"Properties": {
"Priority": 1,
"ComputeEnvironmentOrder": [
{
"Order": 1,
"ComputeEnvironment": {
"Ref": "ComputeEnvironment"
}
}
]
}
}
Is the issue with the way it's being invoked? My user has admin privileges, so I don't think this is an issue with my user having insufficient permissions.
You have to add the principal "ecs-tasks.amazonaws.com" to the trust policy for the role that's submitting a Batch job (not "ecs.amazonaws.com").
Revised role:
"TrainingJobRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "golfnow-invoke-write-progress",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com",
"ecs-tasks.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/"
}
},
And for those who are writing CDK script in Java, while defining the TaskDefinition you don't have to explicitly provide any taskRole and executionRole. CDK will create appropriate Role for you.
You would need to add a trust policy to ECS to call the Batch service.
"Principal": {
"Service": [
"batch.amazonaws.com"
]
},
My issue was resolved by adding role name in the CDK script.
const ecsFargateServiceRole = new iam.Role(this, 'execution-role', {
assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
roleName: "execution-role"
});
ecsFargateServiceRole.addToPolicy(executionRolePolicy);
I'm creating an ec2 instance with a role that provides access to kinesis streams and Dynamodb offset Tables. I am using aws cloudformation for that.
Problem I'm having is while creating the Streaming Access IAM Role itself.
So, I will have following structure,
has
StreamingAccessRole ----------> RolePolicy1(kinesis:*), RolePolicy2(dynamodb:*)
The template to create the AWS IAM role with two policies, one for kinesis and the other for dynamodb :
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"teamIdentifier": {
"Type": "String",
"Default": "a28",
"Description": "Identifier for the team"
}
},
"Resources": {
"StreamingAccessRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/a28/",
"Policies": [
{
"PolicyName": "Stream-ConsumerOffset-RW-AccessPolicy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "kinesis:*",
"Resource": "arn:aws:kinesis:us-west-2:*:stream/a28-*"
},
{
"Effect": "Allow",
"Action": "dynamodb:*",
"Resource": "arn:aws:dynamodb:us-west-2:*:table/a28-*"
}
]
}
}
]
}
}
}
}
It creates the Access Role but without role-policies.
$ aws iam get-role --role-name a28-streaming-access-role-st-StreamingAccessRole-14QHMTIOIRN5X --region us-west-2 --profile aws-federated
{
"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
}
}
]
},
"RoleId": "AROAIFD6X2CJXTKLVQNLE",
"CreateDate": "2017-04-07T18:54:59Z",
"RoleName": "a28-streaming-access-role-st-StreamingAccessRole-14QHMTIOIRN5X",
"Path": "/a28/",
"Arn": "arn:aws:iam::500238854089:role/a28/a28-streaming-access-role-st-StreamingAccessRole-14QHMTIOIRN5X"
}
}
Listing the role-policies
$ aws iam list-role-policies --role-name a28-streaming-access-role-st-StreamingAccessRole-14QHMTIOIRN5X --region us-west-2 --profile aws-federated
{
"PolicyNames": []
}
which means it did not even create any policies,
aws iam list-policies --region us-west-2 --profile aws-federated | grep Stream-ConsumerOffset-RW-AccessPolicy
But if I supplied only kinesis:* statement in above example, it creates a policy, but not with dynamodb:* alone.
So, my question is how am supposed to provide multiple RolePolicies using one cloudformation AWS::IAM::Role template, or is this specific to dynamodb?
There's an intermittent race condition when you create the Policy in the Role. Create the Policy separately with AWS::IAM::Policy and set the Roles property to the Role. The problem will go away.
Your template worked perfectly fine for me.
I ran your template and then:
$ aws iam get-role --role-name stack1-StreamingAccessRole-1KDUTVG1OLLQM
{
"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
}
}
]
},
"RoleId": "AROAJADV75HTIM6C62YXQ",
"CreateDate": "2017-04-08T22:22:21Z",
"RoleName": "stack1-StreamingAccessRole-1KDUTVG1OLLQM",
"Path": "/a28/",
"Arn": "arn:aws:iam::123456789012:role/a28/stack1-StreamingAccessRole-1KDUTVG1OLLQM"
}
}
Listing the role-policies:
$ aws iam list-role-policies --role-name stack1-StreamingAccessRole-1KDUTVG1OLLQM
{
"PolicyNames": [
"Stream-ConsumerOffset-RW-AccessPolicy"
]
}
The policy is attached as an inline policy, so it will not appear in list-policies. Rather, use get-role-policy to view it:
$ aws iam get-role-policy --role-name stack1-StreamingAccessRole-1KDUTVG1OLLQM --policy-name Stream-ConsumerOffset-RW-AccessPolicy
{
"RoleName": "stack1-StreamingAccessRole-1KDUTVG1OLLQM",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "kinesis:*",
"Resource": "arn:aws:kinesis:us-west-2:*:stream/a28-*",
"Effect": "Allow"
},
{
"Action": "dynamodb:*",
"Resource": "arn:aws:dynamodb:us-west-2:*:table/a28-*",
"Effect": "Allow"
}
]
},
"PolicyName": "Stream-ConsumerOffset-RW-AccessPolicy"
}
The reason could be race condition as already answered in this answer by Tim Bassett, I simply wanted to add final solution that worked, and how to add AWS::IAM::Policy to cloudformation.
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Some Streaming api devops",
"Parameters": {
"environment": {
"Type": "String",
"Default": "staging",
"Description": "environment"
}
},
"Resources": {
"StreamingAccessRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "StreamingAccessRole",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/a28/"
}
},
"StreamConsumerOffsetRWAccessPolicy": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudwatch:*"
],
"Resource": [
"*"
]
},
{
"Effect": "Allow",
"Action": "kinesis:*",
"Resource": "arn:aws:kinesis:us-west-2:051620159240:stream/a28-*"
},
{
"Effect": "Allow",
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:BatchWriteItem",
"dynamodb:CreateTable",
"dynamodb:DeleteItem",
"dynamodb:DeleteTable",
"dynamodb:DescribeLimits",
"dynamodb:DescribeReservedCapacity",
"dynamodb:DescribeReservedCapacityOfferings",
"dynamodb:DescribeStream",
"dynamodb:DescribeTable",
"dynamodb:GetItem",
"dynamodb:GetRecords",
"dynamodb:GetShardIterator",
"dynamodb:ListStreams",
"dynamodb:ListTables",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem",
"dynamodb:UpdateTable"
],
"Resource": "arn:aws:dynamodb:us-west-2:051620159240:table/a28-*"
},
{
"Action": [
"sns:*Permission",
"sns:Create*",
"sns:Delete*",
"sns:Publish",
"sns:ReceiveMessage",
"sns:Set*"
],
"Resource": [
"arn:aws:sns:us-west-2:051620159240:a28-*"
],
"Effect": "Allow"
}
]
},
"PolicyName": "StreamConsumerOffsetRWAccessPolicy",
"Roles": [
{
"Ref": "StreamingAccessRole"
}
]
}
}
}
}