How to get the latest lambda version in cloudformation yml? - amazon-web-services

I'm trying to reference an edge lambda for cloudfront distribution in cloudformation.
What I have now is:
LambdaFunctionARN:
Fn::GetAtt: [BasicAuthLambdaFunction,Arn]
But I get this error:
An error occurred: GGGCloudFrontDistribution - The function
ARN must reference a specific function version. (The ARN must end with
the version number.)
So.. is there some kind of technique to reference the latest version of the function?

You can't use the latest version. You have to use a specific version as the documentation you linked states:
You must specify the ARN of a function version; you can't specify a Lambda alias or $LATEST.
If you are creating the Lambda function in your template, you can also create a version and use that.
BasicAuthLambdaFunctionVersion:
Type: "AWS::Lambda::Version"
Properties:
FunctionName:
Ref: BasicAuthLambdaFunction
# ...
LambdaFunctionARN:
Fn::GetAtt: [BasicAuthLambdaFunctionVersion,Arn]
Note that when updating the stack, a new version will not be created when the Lambda function code changes. You have to manually create and use a new version by changing the name of BasicAuthLambdaFunctionVersion to BasicAuthLambdaFunctionVersion2 or something else. To automate this, you can edit the template with a script before using it.
If you are using the Serverless Framework, take a look at:
https://github.com/silvermine/serverless-plugin-cloudfront-lambda-edge
https://github.com/serverless/serverless/issues/3944

Related

Referencing serverless stack name after pseudo parameters plugin deprecation

I'm wondering what is the correct way to reference AWS Cloudformation pseudo parameters in a serverless.yml now that pseudo parameter plugin has been deprecated.
All pseudo parameters are not available with the dollar sign syntax (e.g. ${aws:stackName} is not) in a similar manner as ${aws:region} is, for example. The serverless documentation on pseudo parameters is very short and I am not sure I fully understand it. I have tried to use Ref: "AWS::StackName", but when I try to generate an output
Fn::Sub:
- "${Stack}-someOutputResourceName"
- Stack:
Ref: "AWS::StackName"
, I get an error with [...]/Fn::Sub/1/Stack] 'null' values are not allowed in templates.
The pseudo-plugin page claims that
All functionalities as provided by this plugin are now supported by Serverless Framework natively
If this is true, how should I go about using pseudo-parameters?
It seems that while the above method does not work, I am able to use the pseudo variable directly without using Ref:
Name: !Sub "${AWS::StackName}-someOutputResourceName"

Deleting Lambda Doesn't Reset Version Number

I'm working on a CloudFormation template and noticed an intricacy with Lambda that's new for me. Here's a snippet:
VersionLambdaRandom:
Type: AWS::Lambda::Version
Properties:
Description: Version testing.
FunctionName: !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${LambdaRandom}"
DependsOn: LambdaRandom
AliasLambdaRandom:
Type: AWS::Lambda::Alias
Properties:
FunctionName: !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${LambdaRandom}"
FunctionVersion: '1'
Name: TestDeploymentAlias
DependsOn:
- LambdaRandom
- VersionLambdaRandom
In the process of spinning this stack up and down, which deletes both the Version and Alias along with the Random Lambda that is not included here, I've noticed the version number doesn't reset when I create the stack again. Essentially, I'll create the stack again and will get a failure during the deployment along the lines of:
Function not found: arn:aws:lambda:us-east-1:<Acct#>:function:RandomLambdaFunction:1 (Service: AWSLambdaInternal; Status Code: 404; Error Code: ResourceNotFoundException)
Looking in the console, I can see a version of the newly created function was created successfully; however, it's now at version 2 rather than version 1. This seems like strange behavior to me since I completely deleted the stack, which includes deleting the lambda and the version.
What can I do to ensure the version I create when creating a stack always remains at one, besides switching the function name each time?
Lambda versions are immutable. That's the entire point of versioning - you can't change them once published, which includes deleting them. You have to delete your function as well to get read of its versions.

How to deploy a AWS Lambda Function conditionally, using Serverless Framework, only to prd stage

thank you for taking the time to read this post. I’m trying to deploy an AWS Lambda Function conditionally, based on stage (only for “prd” stage).
This lambda has a Role, which deploys conditionally too. I already achieved this by using cloudformation conditions on the resources block, as shown below:
However, I don’t know how to make it work for the lambda function, as it is in the functions block I don’t have idea how to reference the condition. From the serverless.yml reference I decided to do what is shown below, and it doesn’t work:
Can someone help me to understand what am I doing wrong? And also what would be the solution to make this work? Thanks in advance
This can be achieved using the serverless if-else plugin
https://www.serverless.com/plugins/serverless-plugin-ifelse
You can use the plugin by adding them to your plugin section of the serverless.yml
plugins:
- serverless-plugin-ifelse
and set up conditions to update values in the serverless.yml for the functions and exclude them.
The include option isn't available, so your condition would be something like -
custom:
currentStage: ${opt:stage, self:provider.stage}
serverlessIfElse:
- If: '"${self:provider.stage}" == "prd"'
Set:
functions.startXtractUniversalInstance.role: <custom role for prod>
ElseExclude:
- functions.startXtractUniversalInstance
if you check the serverless.yml reference, there's no support for "conditions" key in the lambda
Serverless Framework definitions ARE NOT a 1:1 to CloudFormation
you can override the AWS CloudFormation resource generated by Serverless, to apply your own options, link here
which more or less would look like this:
functions:
startXtractUniversalInstance:
...
resources:
extensions:
StartXtractUniversalInstanceFunction:
Condition: ...
make sure to double check the name generated to your function, the above StartXtractUniversalInstanceFunction could be wrong

AWS Lambda Rest API: A sibling ({id}) of this resource already has a variable path part -- only one is allowed Unable to create resource at path

I'm particular new to Lambda and to AWS in general. I'm trying to setup a simple REST API Service with Lambda. I've used CloudFormat and CodePipeline to have a simple Express app.
I'm trying to figure out why during the deployment phase, during ExecuteChangeSet I have this error:
Errors found during import: Unable to create resource at path '/stations/{stationId}/allowedUsers': A sibling ({id}) of this resource already has a variable path part -- only one is allowed Unable to create resource at path '/stations/{stationId}/allowedUsers/{userId}': A sibling ({id}) of this resource already has a variable path part -- only one is allowed
This is what I have inside the template.yml
Events:
AllowedUsers:
Type: Api
Properties:
Path: /stations/{stationId}/allowedUsers
Method: get
AddAllowedUsers:
Type: Api
Properties:
Path: /stations/{stationId}/allowedUsers
Method: post
DeleteAllowedUsers:
Type: Api
Properties:
Path: /stations/{stationId}/allowedUsers/{userId}
Method: delete
GetAllowedUser:
Type: Api
Properties:
Path: /stations/{stationId}/allowedUsers/{userId}
Method: get
I searched a bit for this error but I'm not sure how to solve it.
For me, the issue was different from what is described in the GitHub issue Bryan mentioned.
I was using two different parameter names. Finishing the refactoring and using a single id name fixed the issue.
Example:
DeleteAllowedUsers:
Type: Api
Properties:
Path: /stations/{stationId}/allowedUsers/{id}
Method: delete
GetAllowedUser:
Type: Api
Properties:
Path: /stations/{stationId}/allowedUsers/{userId}
Method: get
Here is the walk around for this problem. It was posted on github by pettyalex.
link :https://github.com/serverless/serverless/issues/3785
You might encounter this issue when updating a variable path while using serverless ( and serverless.yaml ) to provision the AWS gatewayApi, here is a walk-around:
comment out the endpoint function to remove it completely
uncomment and deploy again

Lambda aliases and CloudFront: The function ARN must reference a specific function version

I have a Lambda that is working as a CloudFront Origin Request handler when referenced using an ARN that contains the version (e.g. ...:function:MyFunction:123). I've created a PROD alias to version 123 which I would like to use instead.
Using the ...:function:MyFunction:PROD ARN yields the following error
com.amazonaws.services.cloudfront.model.InvalidLambdaFunctionAssociationException:
The function ARN must reference a specific function version. (The ARN
must end with the version number.) ARN:
...:function:MyFunction:PROD (Service: AmazonCloudFront; Status Code:
400; Error Code: InvalidLambdaFunctionAssociation; Request ID:
d407f350-bc7f-11e9-8498-e7f23762c03e)
Removing the version entirely (i.e. ...:function:MyFunction) which according to the docs should hit latest, using $LATEST or LATEST for the version all fail with the same error.
The documentation that I've found all suggests that this should just work, so I'm not sure what I could have screwed up here. Might it be a problem with permissions on the IAM role I created?
I have to apologize in advance for writing the answer that you were probably not hoping for, but according to AWS, it is unfortunately not currently possible to have CloudFront point to $LATEST or a specific alias of a function when using Labmda#Edge.
According to the official AWS documentation (found under LambdaFunctionARN on https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_LambdaFunctionAssociation.html):
You must specify the ARN of a function version; you can't specify a Lambda alias or $LATEST.
In case the following is an option for you and can also suit your needs, what we usually do at the company I'm a part of (not only the reason discussed in the context of this question) is having both the CloudFront distribution and the Lambda function defined under the same CloudFormation stack (in our case, managed using the Serverless framework). That way, deploying a change for a stack serving a specific environment (e.g production) creates a new version of the Lambda function and updates the CloudFront distribution to be associated with it, automatically.
Sharing just in case it can hopefully serve as an alternative solution.