Adding lambda target role to AWS Eventbridge rule in Cloudformation fails - amazon-web-services

I am trying to create an AWS Eventbridge rule with a Lambda function as a target. I can add the rule and target fine but when I try to set the lambda permissions via RoleArn the Cloudformation stack deployment fails with:
RoleArn is not supported for target arn:aws:lambda:us-east-1:1234567890:function:contacts-lambda-consume-new-customer. (Service: AmazonCloudWatchEvents; Status Code: 400; Error Code: ValidationException; Request ID: xxxxx-ec5d-45e8-b45d-xxxxxx; Proxy: null)
Here is my Cloudformation stack code:
EventRuleNewCustomer:
Type: AWS::Events::Rule
Properties:
Name: new-customer
EventBusName: myEventBus
# RoleArn: !Join ["", ["arn:aws:iam::",!Ref "AWS::AccountId", ":role/my-role"] ] #no error but doesn't add the permissions
Description: "New customer event rule"
EventPattern:
detail-type:
- "NewCustomer"
State: "ENABLED"
Targets:
-
Arn: !Join ["", ["arn:aws:lambda:" ,!Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":function:contacts-lambda-consume-new-customer"] ]
Id: "NewCustomer"
RoleArn: !Join ["", ["arn:aws:iam::",!Ref "AWS::AccountId", ":role/my-role"] ]
I have tried setting a RoleArn on the rule itself which doesn't give an error when the stack is created but also doesn't add the necessary permissions to execute the Lambda.
The work-around I am using is to edit the lambda target in the AWS Eventbridge console. This seems to do some behind the scenes magic to add the correct permissions for Eventbridge to be able to execute the lambda
Any ideas gratefully appreciated.

This seems to do some behind the scenes magic to add the correct permissions for Eventbridge to be able to execute the lambda
In case of lambda, the permissions are set using Lambda's resource-based policy.
Thus you should use AWS::Lambda::Permission in CloudFormation to allow EventBridge to invoke your function, rather than using RoleArn.
So your permissions would be something as the following (just an example):
EventBridgeLambdaPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt function.Arn
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn: !GetAtt EventRuleNewCustomer.Arn

Related

AWS Cloudwatch event/rule trigger Lambda Cloudformation Template

Within AWS I've created a CloudTrail which is then filtered by an Eventbridge Rule to only look for certain events within CloudTrail that correspond to resources being created on AWS. Reason being is that I've created some code for Lambda that will automatically tag resources dependent on events passed to it from Eventbridge. When I manually connect eventbridge rule & lambda together it all works fine. However, when I deploy my stack using Cloudformation my Lambda doesn't show Eventbridge as an eventsource/trigger for the function and I don't know why. Below is my Cloudformation template alongside what is shown on AWS Lambda vs what I expect to be seen.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
# ---------------------------------------------------------------------------- #
# Input parameters #
# ---------------------------------------------------------------------------- #
Parameters:
ProjectName:
Type: String
Default: 'AutoTagger'
Description: ""
# ---------------------------------------------------------------------------- #
# Resources #
# ---------------------------------------------------------------------------- #
Resources:
AutoTaggerLambda:
Type: AWS::Serverless::Function
Name: auto-tagger-lambda
Properties:
CodeUri: release/archive.zip
Handler: auto-tagger/main.lambda_handler
Runtime: python3.9
Policies: [AWSLambda_FullAccess]
MemorySize: 128
Timeout: 30
Tags:
- Key: "project_name"
Value: !Ref ProjectName
TagEvents:
Type: "AWS::Events::Rule"
Properties:
Description: "Rule to trigger lambda"
Name: "TagEvents"
EventPattern: {
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["ec2.amazonaws.com", "rds.amazonaws.com", "lambda.amazonaws.com", "s3.amazonaws.com", "dynamodb.amazonaws.com", "elasticfilesystem.amazonaws.com"],
"eventName": ["CreateVolume", "RunInstances", "CreateImage", "CreateSnapshot", "CreateDBInstance", "CreateFunction20150331", "UpdateFunctionConfiguration20150331v2", "UpdateFunctionCode20150331v2", "CreateBucket", "CreateTable", "CreateMountTarget"]
}
}
State: "ENABLED"
Targets:
- Arn: !GetAtt AutoTaggerLambda.Arn
Id: "TagEventsTargetLambda"
Do I need to add an event to the lambda also? I'm a little confused.
You are missing permissions. An AWS::Lambda::Permission resource gives your EventBridge rule permission to invoke the Lambda. It is added to the Lambda's resource-based policy.
PermissionForEventsToInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt AutoTaggerLambda.Arn
Action: 'lambda:InvokeFunction'
Principal: 'events.amazonaws.com'
SourceArn: !GetAtt TagEvents.Arn

"Error occurred while GetObject. S3 Error Code: PermanentRedirect. S3 Error Message: The bucket is in this region: us-east-1

I try to follow this workshop https://gitflow-codetools.workshop.aws/en/, every thing well but when I try to create the lambda usinging cloudformation I got an error:
Resource handler returned message: "Error occurred while GetObject. S3 Error Code:
PermanentRedirect. S3 Error Message: The bucket is in this region:
us-east-1. Please use this region to retry the request (Service: Lambda,
Status Code: 400, Request ID: xxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxx,
Extended Request ID: null)" (RequestToken: xxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxx, HandlerErrorCode: InvalidRequest)
I'm using eu-west-1 for this workshop, but I don't understand why the cloudformation create the bucket in us-east-1.
When I deploy the cloudformation in us-east-1 I don't get this error.
Any idea how should avoid this error ?
the template looks like this:
AWSTemplateFormatVersion: '2010-09-09'
Resources:
LambdaRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: 'sts:AssumeRole'
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/IAMFullAccess
- arn:aws:iam::aws:policy/AWSLambda_FullAccess
- arn:aws:iam::aws:policy/AWSCodeCommitReadOnly
- arn:aws:iam::aws:policy/AWSCodePipelineFullAccess
- arn:aws:iam::aws:policy/CloudWatchEventsFullAccess
- arn:aws:iam::aws:policy/AWSCloudFormationFullAccess
PipelineCreateLambdaFunction:
Type: 'AWS::Lambda::Function'
Properties:
FunctionName: 'gitflow-workshop-create-pipeline'
Description: 'Lambda Function to create pipelines on branch creation'
Code:
S3Bucket: 'aws-workshop-gitflow'
S3Key: 'pipeline-create.zip'
Handler: 'pipeline-create.lambda_handler'
Runtime: 'python3.7'
Role:
Fn::GetAtt:
- LambdaRole
- Arn
PipelineCreateLambdaPermission:
Type: 'AWS::Lambda::Permission'
DependsOn: PipelineCreateLambdaFunction
Properties:
Action: 'lambda:InvokeFunction'
Principal: "codecommit.amazonaws.com"
FunctionName: 'gitflow-workshop-create-pipeline'
PipelineDeleteLambdaFunction:
Type: 'AWS::Lambda::Function'
Properties:
FunctionName: 'gitflow-workshop-delete-pipeline'
Description: 'Lambda Function to delete pipelines on branch deletion'
Code:
S3Bucket: 'aws-workshop-gitflow'
S3Key: 'pipeline-delete.zip'
Handler: 'pipeline-delete.lambda_handler'
Runtime: 'python3.7'
Role:
Fn::GetAtt:
- LambdaRole
- Arn
PipelineDeleteLambdaPermission:
Type: 'AWS::Lambda::Permission'
DependsOn: PipelineDeleteLambdaFunction
Properties:
Action: 'lambda:InvokeFunction'
Principal: "codecommit.amazonaws.com"
FunctionName: 'gitflow-workshop-delete-pipeline'
First things first, Lambda and S3 need to be in the same region.
Secondly, it looks like you're not the bucket owner (you haven't created the bucket yourself by looking at the template).
This means, the bucket you're using to retrieve the Lambda source code from is (I suppose coming from the workshop), and they decided to create that bucket in the region us-east-1. Enforcing you to also deploy your stack in the region us-east-1 (if you want to follow the workshop).
But what if you really wanted to deploy this stack to eu-west-1?
That would mean you need to create a bucket in region eu-west-1 with and copy the objects from the workshop bucket into your newly created bucket and update your CloudFormation template to point and retrive the Lambda source code from your newly created bucket (note you might need to name the bucket differently as bucket names are globally shared).
I hope this is a bit clear.

Serverless add assumed role to allow cloudwatch to call lambda

I am trying to allow cloudwatch to execute a lambda function in a serverless.yml. I can do this via the CLI. How can I do this within a serverless.yml?
CLI command from here:
aws lambda add-permission --function-name XXX --statement-id MyId --action 'lambda:InvokeFunction' --principal events.amazonaws.com --source-arn arn:aws:events:us-east-1:1232132323:rule/XXXX
I tried from here which immediately gave deployment errors:
functions:
generateFile:
handler: api/handler.generateFile
tags:
LiveOrTest: test
# to allow cloudwatch to invoke lambdas
resources:
Resources:
cleanLambdaPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName:
"Fn::GetAtt": [cleanLambdaFunction, Arn]
Action: "lambda:InvokeFunction"
Principal: "events.amazonaws.com"
SourceArn: "*"
The only apparent issue in your AWS::Lambda::Permission is incorrect ARN:
SourceArn: "*"
You can't have * as ARN, instead it should be:
SourceArn: "arn:aws:events:us-east-1:1232132323:rule/XXXX"
Alternatively, you can just remove the entire SourceArn property.

AWS API Gateway not invoking specified lambda

I recently deployed a new API endpoint and linked it to a specified lambda via cloud formation.
x-amazon-apigateway-integration:
uri: !Join
- ''
- - 'arn:aws:apigateway:'
- !Ref 'AWS::Region'
- ':lambda:path/2015-03-31/functions/arn:aws:lambda:'
- !Ref 'AWS::Region'
- ':'
- !Ref 'AWS::AccountId'
- ':function:'
- !Ref lbdBusinessPersonAccountsFunctionName
- '-'
- !Ref EnvName
- ':live'
- /invocations
When I check the API Gateway console, It seems like the lambda is correctly integrated to the API endpoint. But when I check the lambda console itself, no API GW trigger event was generated.
When I try manually link it to the gateway, it doesn't let me specify the resource I want to link it to, but instead creates a new resource under the lambda name.
Is there a manual linking step that I am missing?
On your cloudformation template, assuming you are using YAML; add the permissions mapping resource below. This gives apigateway the permission to add trigger/invoke your lambda (this is in addition to the appropriate IAM permissions).
FunctionInvokePermissions:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt "Function.Arn"
Principal: "apigateway.amazonaws.com"
SourceArn: !Sub
- "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${RestApiId}/${pathpart}/${method}"

cloudwatch event trigger cloudformation

I am having some trouble writing the cloudformation script for cloudwatch event trigger to kick off my lambda script, I know I can do it through the console but my requirement is that I need to provision everything in cloudformation. I followed the documentation and it still haven't worked for me and I kept getting the error:
Template contains errors.: Invalid template property or properties
[rPermissionForEventsToInvokeLambda, rLambdaScheduledRule]
can someone point out what is the issue with this part of my cloudformation script? I followed the document almost to the letter and still having error, even the example in the documentation have the same error when I tried to validate it. my cloudformation code is below, any help is appreciated!
rLambdaScheduledRule:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: rate(1 hour)
State: ENABLED
Targets:
Ref:
Fn::ImportValue:
Fn::Sub: rUploadLambda
Action: lambda:InvokeFunction
rPermissionForEventsToInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName:
Ref:
Fn::ImportValue:
Fn::Sub: rUploadLambda
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn:
Fn::GetAtt:
- rLambdaScheduledRule
- Arn
1) You must export the Lambda function ARN in the CloudFormation template in which you create the lambda function. You need to pass the Lambda function ARN as input to the cloudwatch event (The AWS::Events::Rule Targets attribute requires a resource ARN).
See a sample script below:
Resources:
# Create Controlled Lambda Function
myLambda:
Type: "AWS::Lambda::Function"
Properties:
Code:
S3Bucket: "lambda-bucket"
S3Key: "myhandler.zip"
Description: "Lambda handler"
FunctionName: "myhandler"
Handler: myhandler.myhandler
MemorySize: 128
Role: "arn:aws:iam::xxxxxxxxxxx:role/myLambdaExecutionRole-NC7FA7TUSZ5B"
Runtime: "python3.6"
Timeout: 10
# Output of the cf template
Outputs:
myLambdaArn:
Description: Arn of the my_lambda_function
Value: !GetAtt myLambda.Arn
Export:
Name: !Sub "${AWS::StackName}-LambdaArn"
2) When you create the CloudWatch Event, you need to pass the ARN of the lambda function created in Step1 as the Target.
See a sample script below:
Resources:
# Cloudwatch event to trigger lambda periodically
rLambdaScheduledRule:
Type: "AWS::Events::Rule"
Properties:
Description: "CloudWatch Event to trigger lambda fn"
ScheduleExpression: "rate(1 hour)"
State: "ENABLED"
Targets:
-
Arn:
Fn::ImportValue:
!Sub "${NetworkStackName}-LambdaArn"
Id: "targetevent_v1"
PermissionForEventsToInvokeLambda:
Type: "AWS::Lambda::Permission"
Properties:
FunctionName:
Fn::ImportValue:
!Sub "${NetworkStackName}-LambdaArn"
Action: "lambda:InvokeFunction"
Principal: "events.amazonaws.com"
SourceArn:
Fn::GetAtt:
- rLambdaScheduledRule
- Arn
The value of ${NetworkStackName} should be the StackName from Step1.
Some of the issues you need to correct in your template:
correct the Targets property of resource rLambdaScheduledRule.
remove Action property from resource rLambdaScheduledRule.
correct the FunctionName property of resource rPermissionForEventsToInvokeLambda.
Keeping above sample as reference, correct your template and try again.