AWS Cloudformation: Give Cloudwatch * Permissions to invoke Lambda - amazon-web-services

This is what I am trying to do:
LambdaInvokePermission:
Type: AWS::Lambda::Permission
Properties:
--snip--
SourceArn: !Sub arn:aws:events:${AWS::Region}:${AWS::AccountId}:rule/*-${Environment}
However it seems to dislike the * syntax.
I have tried just SourceArn: !Sub arn:aws:events:${AWS::Region}:${AWS::AccountId}:rule/* and SourceArn: '*' but these also give failure messages like
The rule * could not be found.
Does anyone know the correct syntax for this?

You need to specify the exact name of the cloudwatch rule that will trigger this lambda function.
Example: arn:aws:events:us-east-1:123456789012:rule/my-scheduled-rule.
The SourceArn property of AWS::Lambda::Permission expects a String value: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-permission.html#cfn-lambda-permission-sourcearn.
You cannot have multiple cloudwatch rules as the SourceArn(not a list) in a single AWS::Lambda::Permission block with a wildcard '*'. To have multiple cloudwatch rules trigger the same lambda function, you will need to add another AWS::Lambda::Permission block in your cloudformation template.

Related

In AWS Cloudformation, is it possible to set a wildcard for LogGroupName for AWS::Logs::LogGroup?

I have many Lambdas and I would like to set the log retention policy in AWS Cloudformation using AWS::Logs::LogGroup for all of them, but the only examples I have seen set LogGroupName for each one. Is it possible to set a retention policy for all Lambdas logs using a wildcard or without having to specify each Lambda function?
I tried this:
LambdaLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: '/aws/lambda/*'
RetentionInDays: 14
However, this fails to deploy (stack fails) unsurprisingly with the following error: "Model validation failed (#/LogGroupName: failed validation constraint for keyword [pattern])".
I also tried:
LambdaLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /aws/lambda/
RetentionInDays: 14
However, that only sets the policy for the top, not for any individual Lambda.
Sadly its not possible in plain CFN. You would have to do it using custom resource in CloudFormation.

How can I define step function execution name from an EventBridge rule?

I'm using the EventBridge to trigger a step function. My EventBridge rule in the CloudFormation template looks as follows:
JobStepFunctionTrigger:
Type: AWS::Events::Rule
Properties:
EventBusName: !GetAtt JobTaskEventBus.Name
Name: !Sub ${DeploymentName}-new-job-created
State: ENABLED
EventPattern:
source:
- !Sub ${DeploymentName}-my-service
detail-type:
- 'NEW_JOB'
Targets:
- Arn: !GetAtt JobOrchestrator.Arn
Id: !GetAtt JobOrchestrator.Name
RoleArn: !Ref MyAwesomeRole
Unfortunately the step function "execution name" is randomly generated in this case making it very difficult to link the specific event to the specific step function execution. in my event I have a property $.detail.id and $.detail.state I would love to be able to use these, to issue the step function execution name in the format ${detail.id}_${detail.state}_someRandomValueToGuaranteeNameUniqueness, but reading the docs about the rule targets I don't see how this would work...
This isn't possible today. The simplest workaround is to redirect to an known API Gateway endpoint[1], and then use API-Gateway's transformations to then trigger the right step-functions[2].
I've got limited knowledge on how API/GW transformations work, so personally prefer using a lambda to call the right step-function. This could be your back up option as well.
[1] https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-api-gateway-target.html
[2] https://docs.aws.amazon.com/apigateway/latest/developerguide/rest-api-data-transformations.html

Creating a AWS WorkMail Lambda invoke permission in CloudFormation

When I create a Lambda::Permission resource in Cloudformation I have an issue with validating the principal. Currently I have it set to use the !Sub function and that's not a valid principal according to CloudFormation. Does any one have any experience with creating a workmail invoke permission?
AWSTemplateFormatVersion: 2010-09-09
Resources:
WorkmailInvokePermission:
Type: 'AWS::Lambda::Permission'
Properties:
Action: 'lambda:InvokeFunction'
FunctionName: arn:aws:<region>:<function_arn>
Principal: !Sub workmail.${AWS::Region}.amazonaws.com
Outputs: {}
I figured it out, it was a pretty simple, the problem was I was in a region where Workmail wasn't actually available so it ended up creating an error.

Give Lambda Invoke permission to ApiGateway with one deployment

I wrote resources in my serverless.yml like below:
resources:
Resources:
RestApi :
Type : AWS::ApiGateway::RestApi
Properties :
Body : ${file(./swagger.yaml)}
LoginApiToInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName: login
Action: lambda:InvokeFunction
Principal: apigateway.amazonaws.com
When I sls deploy, below error occured:
An error occurred: LoginApiToInvokeLambda - Function not found: arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:api-dev-login (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException
In the initial deployment, I thought that permissions were set before creating lambda functions. Therefore, I commented out LoginApiToInvokeLambda in my serverless.yml. I sls deploy again, it succeeded. But ApiGateway does not have permission to invoke lambda. After that I restored the commented out part, and sls deploy. Finally I was able to give ApiGateway the permission of Lambda invoke.
Is there a way to accomplish this at the same time?
You can use DependsOn functionality of CloudFormation in the resources section.
resources:
Resources:
# ...
LoginApiToInvokeLambda:
Type: AWS::Lambda::Permission
DependsOn: LoginLambdaFunction
Properties:
FunctionName: login
Action: lambda:InvokeFunction
Principal: apigateway.amazonaws.com
I've assumed your lambda function key is login which gets translated to LoginLambdaFunction. If not, check the serverless documentation on how the resources get named.
In short serverless translates your configuration to a CloudFormation template, and the resources section allows you to customise what gets generated, which is why you can use DependsOn to solve your issue.

AWS cloudformation error: Template validation error: Template error: resource NotificationsTopic does not support attribute type Arn in Fn::GetAtt

I am trying to create an AWS cloudformation stack using a yaml template.
The goal is to create a sns topic for some notifications.
I want to output the topic arn, to be able to subscribe multiple functions to that topic by just specifying the topic arn.
However I am getting an error when I try to create the stack from the aws console:
"Template validation error: Template error: resource NotificationsTopic does not support attribute type Arn in Fn::GetAtt"
I have done exactly the same for s3 buckets, dynamodb tables, and all working good, but for some reason, with SNS topic I cannot get the ARN.
I want to avoid hardcoding the topic arn in all functions that are subscribed. Because if one day the the ARN topic changes, I'll need to change all functions, instead I want to import the topic arn in all functions and use it. This way I will have to modify nothing if for any reason I have a new arn topic in the future.
This is the template:
Parameters:
stage:
Type: String
Default: dev
AllowedValues:
- dev
- int
- uat
- prod
Resources:
NotificationsTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName: !Sub 'notifications-${stage}'
Subscription:
- SNS Subscription
TopicName: !Sub 'notifications-${stage}'
Outputs:
NotificationsTopicArn:
Description: The notifications topic Arn.
Value: !GetAtt NotificationsTopic.Arn
Export:
Name: !Sub '${AWS::StackName}-NotificationsTopicArn'
NotificationsTopicName:
Description: Notifications topic name.
Value: !Sub 'notifications-${stage}'
Export:
Name: !Sub '${AWS::StackName}-NotificationsTopicName'
Not all resources are the same. Always check the documentation for the particular resource. It has the "Return Values" section and you can easily verify that SNS topic has ARN as a Ref value, so you don't have to use GetAtt function
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html
Edit: Thanks for the comment which points out that not every resource provides its ARN. A notable example is the Autoscaling group. Sure, the key thing in my answer was "check the documentation for each resource", this is an example that not every resource has every attribute.
Having said that, ARN missing for the ASG output is a really strange thing. It cannot be also constructed easily, because the ARN also contains GroupId which is a random hash. There is probably some effort to solve this at least for the use-case of ECS Capacity Providers https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/548 and https://github.com/aws/containers-roadmap/issues/631#issuecomment-648377011 but I think that is is an significant enough issue that it should be mentioned here.
For resources that don't directly return ARN, I found a workaround which consists of building the ARN myself.
For instance, to get the ARN of my codepipeline:
!Join [ ':', [ "arn:aws:codepipeline", !Ref AWS::Region, !Ref AWS::AccountId, !Ref StackDeletePipeline ] ]