Lambda#Edge through Go SDK - amazon-web-services

I am trying to associate a Lambda#Edge Function using the AWS Go SDK.
Creating the Function by hand in the console and assigning it to the Cloudfront distro using the SDK => works.
Creating the Function (using the same IAM role from 1.) in the code w/o assigning to cloudfront => works.
Assigning the created function from 2. by hand in the console => fails.
Assigning the created function from 2. via the SDK => fails.
Deploying the created function from 2. by hand in the lambda console (Actions => deploy to lambda#edge) => works. => after this the function can be assigned by hand and by code w/o problems...
The error in 3. and 4. is the same:
InvalidLambdaFunctionAssociation: Lambda#Edge cannot retrieve the specified Lambda function. Update the IAM policy to add permission: lambda:GetFunction for resource: arn:aws:lambda:us-east-1:123456789:function:example:1 and try again.
What confuses me is that I am reusing the same role that was created during 1.
This is how I create the function by code:
lam := lambda.New(session)
lam.CreateFunction(&lambda.CreateFunctionInput{
FunctionName: aws.String("example"),
Handler: aws.String("index.handler"),
Runtime: aws.String("nodejs12.x"),
Role: aws.String("arn:aws:iam::123456:role/service-role/existing-role"),
Code: &lambda.FunctionCode{
S3Bucket: aws.String("bucket-xyz"),
S3Key: aws.String("source.zip"),
},
}) // works w/o issues
lam.AddPermission(&lambda.AddPermissionInput{
FunctionName: aws.String("example"),
StatementId: aws.String("AllowExecutionFromCloudFront"),
SourceArn: aws.String("arn:aws:cloudfront::12333456:distribution/CDNID1234"),
Principal: aws.String("edgelambda.amazonaws.com"),
Action: aws.String("lambda:GetFunction"),
}) // also works w/o error
// assigning the created lambda function would now fail
using
go 1.13
github.com/aws/aws-sdk-go v1.31.8

I found the issue.
The error has absolutely nothing to do with the actual problem. Very misleading error if you ask me.
All that's been missing is a published version of the lambda function at hand.
To achieve that using the Go SDK you have to do:
lam := lambda.New(session)
lam.PublishVersion(&lambda.PublishVersionInput{
FunctionName: aws.String("example"),
Description: aws.String("Dont forget to publish ;)"),
})
using the CLI you would want to do the following:
aws lambda publish-version --function-name example --description "Dont forget to publish"
It actually makes sense that you cannot use a function that hasn't been published. However the error from AWS didn't really help there.
Hopefully this can help anybody!

This error occurred for me because the IAM user didn't have adequate permissions to access versions of the Lambda function.
Before (only one resource specifying the Lambda function):
arn:aws:lambda:<region>:*:function:<function_name>
After (additional wildcard resource for versions of the Lambda function):
arn:aws:lambda:<region>:*:function:<function_name>
arn:aws:lambda:<region>:*:function:<function_name>:*

Related

Get updated AWS Lambda URL after deployment

I have set up CI/CD for an AWS Lambda function such that the new version is automatically deployed using GitHub actions. By default, AWS creates a new Lambda ID (and thus URL) for this lambda function. This means that the front-end portion of my code will need to be updated to contain the updated URL. Is there a way to automatically perform such updating? By e.g. saving the URL as an environment variable and inserting it in the code with a GitHub action?
Or is there alternatively a way to re-use the old Lambda function URL for new deployments?
You can get the updated Lambda URL by using SAM template outputs as follows:
Resources:
MyFunction:
Type: 'AWS::Serverless::Function'
Outputs:
MyFunctionUrlEndpoint:
Description: "My Lambda Function URL Endpoint"
Value: !GetAtt MyFunctionUrl.FunctionUrl
Then you can access the output as described in this answer:
aws cloudformation describe-stacks --stack-name stack_name --query 'Stacks[0].Outputs[?OutputKey==`MyFunctionUrlEndpoint`].OutputValue' --output text
which can then be further processed in e.g. your front-end code.
There may be easier methods, but this should work!

How to programmatically set up EventsBridge events for Lambdas

I have set up 2 lambda functions, deployed with AWS SAM. The first one uses the JS AWS SDK to run putRule and putTarget to trigger the second lambda with a cron job. When I run the first lambda, I see both the rule and target correctly set up in EventsBridge.
I also create the following permission for the second Lambda in my AWS SAM template
InvokePermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref MyLambda
Action: lambda:InvokeFunction
Principal: 'events.amazonaws.com'
and can see the Policy in the console
The only result I see of this cron event (at the timestamp I've chosen for the rule) is a failed invocation of the second Lambda, and CloudWatch doesn't provide any useful information
Any idea of why this is failing or how to retrieve any error? Might "events.amazonaws.com" be the wrong Principal for that?
I am looking into EventSourceMapping but I can't see my case anywhere in the docs

Serverless Framework AWS StepFunction not working

I have a problem that so far I'm unable to identify the root cause.
I have an AWS step machine that should be invoked once a file is uploaded to an S3 bucket.
So far when I upload the file to the S3 bucket, the lambda function that is defined in the StartAt key (StartAt: ImgUploadedEvent) starts as I can see in the lambda logs.
Here is the code:
stepFunctions:
stateMachines:
ValidateImageStateMachine:
loggingConfig:
level: ALL
includeExecutionData: true
destinations:
- Fn::GetAtt: [ StepFuncLogGroup, Arn ]
definition:
Comment: "This state function validates the images after users upload them to S3"
StartAt: ImgUploadedEvent
States:
ImgUploadedEvent:
Type: Task
Resource:
Fn::GetAtt: [ImgUploaded, Arn]
End: true
Below is the lambda function that is declared as the start of the StepMachine
This lambda function as I can see from the logs indeed get called once I modified an Object in S3
functions:
ImgUploaded:
handler: src/stepfunctions/imageWasUploadedEvent.handler
events:
- s3:
bucket: !Ref AttachmentsBucket
existing: true
iamRoleStatements:
- Effect: "Allow"
Action:
- "states:StartExecution"
Resource:
- "*"
To check that the Step Function was working I created a log group and added it to the Step Function.
resources:
Resources:
StepFuncLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /aws/stepfunctions/${self:service}-${self:provider.stage}
I see this cloud watch log group correctly associated with the Step function in the AWS Console.
However when I upload an object to S3, I do see in the logs of the lambda functions that it was invoked, but I can not see any logs on the Step Function log group
My question is:
Is the Step Function indeed working and it is just an issue with the logs in the Step Function?
Or it is that the Step Function itself is not working and the lambda function is working just a lambda function totally independent of the Step Function?
What I have to do so the lambda function gets trigger as part of the Step Function?
BR
After studying how StepFunctions work I finally arrived to the conclusion that this is a wrong pattern.
In no place on the documentation of the plugins or Amazon it says that what I did is a pattern
StepFunctions can be started by events on CloudWatch and those events could be originated on a change on S3. That is not what I did here
There is no a direct link between an action on S3 and a StepFunction
The link in AWS documentation could confuse someone to think otherwise. Here is the title Starting a State Machine Execution in Response to Amazon S3 Events
But the state machine does not start because an S3 events but because the CloudWatch log that this event generates
A lambda proxy function is a good way of invoking an State Machine. This is a easy to use pattern and very common as we can use it with SQS etc
So the correct response to this question is
The state machine does not start because it is never invoked. We just called a lambda function that was used as the StartAt for an StateMachine. This does mean I invoked the State Machine.
That is the reason why there is no logs for the state machine meanwhile there are correct logs for the lambda function
Hope this response helps
I will add more details and reference to this response
BR
Or it is that the Step Function itself is not working and the lambda function is working just a lambda function totally independent of the Step Function?
To verify whether lambda was invoked as part of step function or not can't you just check execution history from the step function console. Also unless you have explicitly configured s3 to publish events to lambda, your lambda will not be automatically invoked upon uploading files to s3.
What I have to do so the lambda function gets trigger as part of the Step Function?
To be able to call trigger step function on file-upload to s3 you can follow this tutorial: https://docs.aws.amazon.com/step-functions/latest/dg/tutorial-cloudwatch-events-s3.html

Unable to add cloudfront as trigger to lambda function

Hi I've followed this instruction try to resize image with Cloudfront and lambda#edge. When I tried to test the resized image, I keep getting the error message below:
The Lambda function associated with the CloudFront distribution is
invalid or doesn't have the required permissions.
So I checked the lambda functions created by cloud formation provided by the article I mentioned in the beginning, and I found there's no trigger in it.
I've tried to set it manually but getting the error message below:
CloudFront events cannot be associated with $LATEST or Alias. Choose
Actions to publish a new version of your function, and then retry
association.
I followed the instruction in the error message; publish, and add Cloudfront as trigger but it seems there's no way to apply it. It's still running the one without Cloudfront as the trigger.
Is there any way to set Cloudfront as trigger and make this work properly?
For people Googling "The Lambda function associated with the CloudFront distribution is invalid or doesn't have the required permissions":
I got that error and struggled to debug it. It turned out there were some programmatic errors inside my Lambda that I had to resolve. But, how do you debug it if, when hitting Cloudfront you keep getting "The Lambda function associated with the CloudFront distribution is invalid or doesn't have the required permissions". That, and there's nothing inside the Cloudwatch logs.
My Lambda was defined in Cloudformation inside a AWS::Lambda::Function's ZipFile attribute. I ended up going to the Lambda service inside AWS and creating a Lambda test payload corresponding to my Cloudfront event as documented here: Lambda#Edge Event Structure. Then, I could debug the Lambda inside the Lambda console without having to hit Cloudfront or having to navigate to Cloudwatch logs.
I see a couple of you guys stating that the root cause of the issue was not a permissions issue and an issue with your code. Which is likely the correct root cause. Cloud front tends to use a 403 error for everything even a basic 404 will show up as a 403 in most cases.
I have also seen some of the comments above stating that you could not find any logs associated with the error in lambda. I think this is most likely because you guys are looking for the logs on us-east-1 and dont live on the east coast of the USA. The logs will be in your local region where they are executed. So choose the region in closest proximity to where you are sitting and you will likely find the log group there.
For other ppl suffering from the poor quality of dev articles from aws blog; I found it's due to the wrong S3 bucket policy. The article says:
ImageBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref ImageBucket
PolicyDocument:
Statement:
- Action:
- s3:GetObject
Effect: Allow
Principal: "*"
Resource: !Sub arn:aws:s3:::${ImageBucket}/*
- Action:
- s3:PutObject
Effect: Allow
Principal:
AWS: !GetAtt EdgeLambdaRole.Arn
Resource: !Sub arn:aws:s3:::${ImageBucket}/*
- Action:
- s3:GetObject
Effect: Allow
Principal:
AWS: !GetAtt EdgeLambdaRole.Arn
Resource: !Sub arn:aws:s3:::${ImageBucket}/*
It turns out you have to grant the permissions to allow other actions besides of GetObject and PutObject, because it needs to create folders in the bucket.
Simply the problem is resolved by changing it to s3:*
For me, the missing cloud front trigger on the lambda screen was because I was not in us-east-1 region
I ran into the same error message with no log in CloudWatch. I finally noticed that my Python runtime handler was index.handler while my index.py defined lambda_handler. After changing my Python runtime handler to index.lambda_handler, the error went away. HTH.
If you found this answer googling "The Lambda function associated with the CloudFront distribution is invalid or doesn't have the required permissions", this can be caused if your function is not wired correctly from cloudformation. For example given yaml:
Code: ./src/ # or CodeUri ./src/
Handler: foo.bar
Double check that ./src/foo.js has exports.bar = function...
When I changed "Include body" in Lambda Function Trigger from "Yes" to "No" it started working.
I had to delete and create CloudFront trigger again to change that setting.
just reading an article from here.
If you create a lambda in one region and use it with cloudfront (and later be requested by user in other edge-region), the issue is due to lambda does not have enough cloudwatch log permission.
Check this, all credits go to author.
https://dev.to/aws-builders/authorizing-requests-with-lambdaedge-mjm

Serverless / AWS Lambda - Create the triggers for the published lambda versions

I'm using the Serverless framework to deploy my functions on the AWS Lambda
I'm trying to create a trigger automatically for each version of my Lambda functions published.
When I deploy my serverless app, the Lambda function and the triggers are created (in this case my AWS IOT trigger), as we can see on the following image:
But for my published version of the lambda function the trigger doesn't exist, only the resources:
I don't want to create new triggers every time I publish a new lambda version.
So, there is any way to create the triggers for my versioned lambdas too? And if is possible, disable the old ones using the Serverless framework?
my serverless.yml file:
service: serverless-lambdas
provider:
name: aws
runtime: nodejs6.10
iamRoleStatements:
- Effect: "Allow"
Action:
- "ses:*"
- "iot:*"
Resource:
- "*"
functions:
function1:
name: "function1"
handler: function1/handler.function1
events:
- iot:
name: "iotEvent1"
sql: "SELECT EXAMPLE"
sqlVersion: "2016-03-23"
enabled: true
UPDATE
I got a similar problem when I was trying to create triggers programmatically using my own AWS Lambda.
I got stuck on this when I saw that the problem was with my trigger that which had no permission to invoke the published Lambda function. So I needed to add the permission for the trigger first with the method add-permission. (This is not clearly written on the AWS docs :/).
So, before I added the the trigger on the Lambda, I used the following method (in node.js):
const addPermission = (ruleName) => {
const thingArn = `arn:aws:iot:${IOT_REGION}:${SOURCE_ACCOUNT}:rule/${ruleName}`;
const params = {
Action: "lambda:InvokeFunction",
FunctionName: LAMBDA_NAME,
Principal: "iot.amazonaws.com",
SourceAccount: SOURCE_ACCOUNT,
SourceArn: thingArn,
StatementId: `iot-sd-${Math.random().toString(36).substring(2) + Date.now().toString(36)}`
};
return new Promise((resolve, reject) => {
lambda.addPermission(params).promise().then(result => {
resolve(result)
}).catch(err => reject(err))
});
};
I tested the same function for the Serverless framework, and Shazam! my triggers were published! We can do something like this for now while the Serverless code is not updated.
In this way, this problem will need to be solved on the Serverless source-code and I will try to do it ASAP.
From what I checked this is the default behavior for the AWS Lambda functions, so there is no issue with the Serverless framework.
Every time I publish a Lambda function, there is no way to create the trigger events automatically.
For further information, we can read the documentation of Versioning aliases.