Amazon EventBridge Policies for AWS Services as targets using CF/SAM - amazon-web-services

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"
}
}

Related

AWS: Trigger step function state machine on s3 object creation using Event Bridge Not Working

I enabled notifications for Amazon EventBridge on my s3 bucket.
Then I created an EventBridge rule with the following event pattern:
{
"detail": {
"bucket": {
"name": ["arn:aws:s3:::my-bucket"]
}
},
"detail-type": ["Object Created"],
"source": ["aws.s3"]
}
Then I added my state machine as the target of this rule. I also attached an IAM role with the following policy for this event target.
"Statement": [
{
"Effect": "Allow",
"Action": [ "states:StartExecution" ],
"Resource": [ "arn:aws:states:*:*:stateMachine:*" ]
}
]
Then I attached the following policy to my state machine step function as well:
{
"Action": "events:*",
"Resource": "arn:aws:events:us-east-1:my-account-id:event-bus/default",
"Effect": "Allow"
}
After doing all of this, still my state machine is not getting invoked.
What am I missing here? How can I debug where the issue might be?
Have you checked if your custom pattern matches the event?
I think you do not need arn in the name.
Try with
{
"detail": {
"bucket": {
"name": ["my-bucket"]
}
},
"detail-type": ["Object Created"],
"source": ["aws.s3"]
}

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.

Cloudformation template to attach existing policy to existing IAM role

I want to attach an aws managed policy to an existing role. I am achieving this using template:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "AWS CloudFormation template to modify Role",
"Parameters": {
"MyRole": {
"Type": "String",
"Default": "MyRole",
"Description": "Role to be modified"
}
},
"Resources": {
"S3FullAccess": {
"Type": "AWS::IAM::ManagedPolicy",
"Properties": {
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"s3:*",
"s3-object-lambda:*"
],
"Resource": "*"
}]
},
"Roles": [
"MyRole"
]
}
}
}
}
This template will create a policy with s3FullAccess and attach it to MyRole. But I do not want to create a new policy, if I want to use the policy already present with aws for s3 full access, how can I do that.
And if I use this template:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "AWS CloudFormation template to modify Role",
"Resources": {
"IAMRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"Path": "/",
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/ReadOnlyAccess"
],
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": "*"
}
}]
},
"RoleName": "RoleName"
}
}
}
}
This will attempt to create a new role and attach ReadOnlyPolicy to it. But if I want to attach a policy to existing role, how to refer that role in the template.
You use your AWS::IAM::Role's ManagedPolicyArns property, where you just specify the ARN of the manage policy to attach.
To use existing role in CloudFormation, you have to import it. Then you will be able to manage it from CloudFormation.
In general, CloudFormation service is for creating resources. There is not a native support to do something with already created resources if you don't import them.
If you don't want to import them, then, you have an option to write CloudFormation custom resource. You can create a lambda function-backed custom resource passing in the ARNs of the IAM policy and the IAM role you want to attach the policy to by IAM AttachRolePolicy API. More details are in AWS documentation.

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.

aws cloudformation 2 sqspolicy for a single queue

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.