aws cloudformation 2 sqspolicy for a single queue - amazon-web-services

I use cloudformation templates to create a sqs queue and apply two policies based on the user parameters. I created 2 sqs QueuePolicy resources and which refer to the queue. However when I try to apply two policies to a queue using Cloudformation templates, only the second one comes into effect. The cloudformation stack says two sqs policy resources have been created. However the admin console for sqs shows only the second one. The aws documentation for SQS says multiple policies could be applied to a single queue; however the cloudformation QueuePolicy does not have explicit mention on whether this is allowed or not. I tried swapping the policies and the second comes into effect all the time. My policy snippet has been attached.
"QueuePolicy1": {
"Type": "AWS::SQS::QueuePolicy",
"Properties": {
"PolicyDocument": {
"Id": "QueuePolicy1",
"Statement": [
{
"Sid": "QueuePolicy1-ReceiveMesasges",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"sqs:GetQueueAttributes",
"sqs:GetQueueUrl",
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:ChangeMessageVisibility"
],
"Resource": "*",
"Condition": {
"ArnEquals": {
"aws:SourceArn": {
"Ref": "QOwnerArnParam"
}
}
}
}
]
},
"Queues": [
{
"Ref": "Queue1"
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "124145a7-3ad1-48e4-9478-04a930498db5"
}
},
"Condition": "Condition1"
},
"QueuePolicy2": {
"Type": "AWS::SQS::QueuePolicy",
"Properties": {
"PolicyDocument": {
"Id": "QueuePolicy2",
"Statement": [
{
"Sid": "QueuePolicy2-SendMessage-To-Queue-From-SNS-Topic",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"sqs:SendMessage"
],
"Resource": "*",
"Condition": {
"ArnEquals": {
"aws:SourceArn": {
"Ref": "TopicArnParam"
}
}
}
}
]
},
"Queues": [
{
"Ref": "Queue1"
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "124145a7-3ad1-48e4-9478-04a930498db5"
}
},
"Condition": "Condition2"
},

There's not really a question here, but I'll add that you can add multiple statements to a single policy. I think a Queue has only a single policy containing multiple statements.

In my experience so far I've found that the AWS docs are very precise (sometimes almost too precise) and I think this is one of those cases.
The AWS CF docs for QueuePolicy say The AWS::SQS::QueuePolicy type applies a policy to SQS queues.
I know that when you first read this it might seem like your standard self-explanatory, didnt-know-what-else-to-write doc comment, but I think this is written very literally to imply / explain that the policy is simply set - i.e. it's not added to a list of policies.
I know this is probably not ideal for what you wanted to achieve, but I think your solution for the time being would be to merge the 2 policies.

Related

AWS Role with a PolicyDocument assuming itself

I am trying to understand code written by coworker that has left.
Can anyone tell me why we have a Policy that assume the role it's attached too, what is it suppose to do?
{
"Role1": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
}
}
]
},
"ManagedPolicyArns": [],
"Policies": []
},
"AssumeRolePermissions": {
"Type": "AWS::IAM::Policy",
"DependsOn": "Role1",
"Properties": {
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": { "Fn::GetAtt": [ "Role1", "Arn" ] }
}
]
},
"PolicyName": "Assume_Role",
"Roles": [{ "Ref": "Role1" }]
}
}
}
}
I know a trust policy is useful in the case I want Role2 to assume Role1's permissions.
From the new update (https://aws.amazon.com/blogs/security/announcing-an-update-to-iam-role-trust-policy-behavior/) if seems in that case I need both of them in the trust policy but what if I don't do that, is there a use case for assuming its own role?
Thanks
"Role1": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": { "Fn::GetAtt": [ "Role1", "Arn" ] }
}
}
]
},
"ManagedPolicyArns": [],
"Policies": []
}
Thanks to #JohnRotenstein and AWS support:
A role assuming itself is a rare use case that while valid isn't an AWS best practice, with AWS recommending using multiple roles instead.
Some of these use cases involve self-assuming in conjunction with a 'scoped-down' policy to obtain a different privilege level, or using a single role and policy throughout the development => build => test => production environment, or can be used to rotate the access/secret keys used by the role since when you role chain the session only last one hour.
All that being said in the majority of cases a self assuming role is a step that depends on use case.

Jobs from specific AWS Batch permissions

How to allow only jobs from a certain AWS Batch queue (and based on a specific job description) to publish to the specific SNS topic?
I though about attaching to jobs IAM policy with the statement:
{
"Effect": "Allow",
"Action": "sns:Publish",
"Resource": ["<arn of the specific SNS topic"]
"Condition": {"ArnEquals": {"aws:SourceArn": "arn:aws:???"}}
}
But what should be the source ARN? ARN of the job queue, ARN of the job definition? Or maybe this should be set up completely differently?
I had a similar experience when worked with AWS Batch jobs executed in Fargate containers which follow the same principles as ECS in scope of assigning roles and permissions.
If you are going to publish messages into specific topic from the code executed inside of your container, then you should create a role with necessary permissions and then use its ARN in the JobRoleArn property of your job definition.
For example (there can be minor mistakes in the code below, but I am just trying to explain the concept here):
Role cloudformation:
"roleresourceID": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": "*"
}
}
],
"Version": "2012-10-17"
},
"RoleName": "your-job-role"
}
}
Policy attached to the role:
"policyresourceid": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": "sns:Publish",
"Effect": "Allow",
"Resource": "<arn of the specific SNS topic>"
}
],
"Version": "2012-10-17"
},
"PolicyName": "your-job-role-policy",
"Roles": [
{
"Ref": "roleresourceID"
}
]
}
}
And finally attach role to the Job Definition:
....other job definition properties
"JobRoleArn": {
"Fn::GetAtt": [
"roleresourceID",
"Arn"
]
}
Of course you may structure and format roles and policies in way you like, the main idea of this explanation is that you need to attach proper role using JobRoleArn property of your job definition.

Amazon EventBridge Policies for AWS Services as targets using CF/SAM

I'm using AWS CloudFormation to setup an EventBridge Bus + Rules + Targets (say SNS). For SNS as a target, per the doc at https://docs.aws.amazon.com/eventbridge/latest/userguide/resource-based-policies-eventbridge.html#sns-permissions, I need to apply resource policies outside of CloudFormation and I don't think CF supports this yet?
For CW Logs Group as a target, Im using the aws logs put-resource-policy to set this up in a script. Is there a better way to automate this?
The link you've provided refers to setting up permissions for SNS topic. Setting such permissions is supported by the CloudFormation by means of AWS::SNS::TopicPolicy.
However, you also state that you want to set resource-based policies on the CloudWatch Logs (aws logs put-resource-policy). If this is the case, then you are correct and it is not supported in CloudFormation.
You would have to use custom resource based on a lambda function to add such functionality to your templates.
Here is a snippet from my SAM:
{
"MyDevQueue": {
"Properties": {
"QueueName": "my-dev-queue",
"ReceiveMessageWaitTimeSeconds": 20,
"Tags": [
{
"Key": "env",
"Value": "dev"
}
],
"VisibilityTimeout": 300
},
"Type": "AWS::SQS::Queue"
},
"MyDevQueuePolicy": {
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"SQS:SendMessage"
],
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:events:<region>:<AccountID>:rule/my-dev-queue/my-dev-queue"
}
},
"Effect": "Allow",
"Principal": {
"Service": [
"events.amazonaws.com"
]
},
"Resource": [
{
"Fn::GetAtt": [
"MyDevQueue",
"Arn"
]
}
]
}
]
},
"Queues": [
"MyDevQueue"
]
},
"Type": "AWS::SQS::QueuePolicy"
}
}

Cross account Cloudformation macro

I am trying to create a cross account macro which will will be used in Cloudformation.
According to the doc - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-macros.html we have to create macros in different accounts but the underlying lambda can be re-used by making it cross account accessible.
Sample Example:
Account A
In Account_A(2
22222222222) I have created a lambda function "TestMacroFunction" which is used in the macro.
I have added following trust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com",
"AWS": "arn:aws:iam::483427547108:role/service-role/TestLambdaInvoker-role-lu7aa94t"
},
"Action": "sts:AssumeRole"
}
]
}
Account B
In Account_B(111111111111) which will have a cloudformation stack for Macro and another stack which will use the macro.
CFN for macro
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"SageMakerEndpointAlarmsMacro": {
"Type": "AWS::CloudFormation::Macro",
"Properties": {
"Name": "ExternalMacro",
"FunctionName": "arn:aws:lambda:us-east-2:111111111111:function:TestMacroFunction",
"LogGroupName": "MacroLogGroup"
}
}
}
}
CFN for Stack using macro:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": [
"ExternalMacro"
],
"Resources": {
"TestBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {}
}
}
}
While running the CFN stack I provide a Role which has following policy attached:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"lambda:InvokeFunction"
],
"Resource": "arn:aws:lambda:us-east-2:111111111111:function:TestMacroFunction",
"Effect": "Allow"
}
]
}
But still I am getting error in cloudformation. The transform in not executing. Also the lambda function is not getting invoked.
Has anyone created a lambda which is used by macros in other account?

AWS CFT template IAM Policy

I'm using CFT to create an IAM policy that allows access to only one S3 bucket alone (which is also created in the same CFT itself). Here is the part of the CFT where the problem lies
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"BucketCreation":{
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName":"samplebucket",
}
},
"IAMPolicy":{
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "ListS3BucketsPolicy",
"PolicyDocument": {
"Statement": [{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": "Fn::GetAtt" : [ "BucketCreation" , "Arn" ]
}]
}
}
}
}
}
Now the above cft creates a IAM policy with a resource statement "Resource": "arn:aws:s3:::bucketname" well this gives only bucket access and not object level access. What I need is the resource section to look like this "Resource": "arn:aws:s3:::bucketname/*".Is this possible in CFT?
Yes you can, see here
You can use wildcards as part of the resource ARN. You can use
wildcard characters (* and ?) within any ARN segment (the parts
separated by colons). An asterisk (*) represents any combination of
zero or more characters, and a question mark (?) represents any single
character. You can use multiple * or ? characters in each segment, but
a wildcard cannot span segments.
This ARN uses the wildcard * in the relative-ID part of the ARN to
identify all objects in the example bucket.
Update:
To concatinate /* look at intrinsic functions like Join
Thanks to #titogeo. I've found the solution.Here it is
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"BucketCreation":{
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName":"samplebucket"
}
},
"IAMPolicy":{
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "ListS3BucketsPolicy",
"PolicyDocument": {
"Statement": [{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource":{
"Fn::Join":["",[
{
"Fn::GetAtt" : [ "BucketCreation" , "Arn" ]
},
"/*"
]
]
}
}]
}
}
}
}
}
P.S: Sorry for the poor indendation. I'm Frustrated with it, if someone could fix it, that would be helpful.