serverless - how to properly add iamrolestatements per function - aws-lambda

my package.json
{
"devDependencies": {
"serverless-iam-roles-per-function": "^3.2.0-e97ab49",
"serverless-s3-deploy": "^0.10.1"
}
}
my serverless.yml - I'm trying to do a variation of the "hello world" and adding a second function that retrieves a string from an AWS S3 Bucket.
#plugins:
# - serverless-s3-deploy
functions:
hello:
handler: api/cms.hello
events:
- http:
path: /
method: any
getblog:
handler: api/cms.getblog
events:
- http:
path: /
method: any
cors: true
- http:
path: /{any+}
method: any
cors: true
iamRoleStatementsName: LambdaGetS3BucketCmsDemo
iamRoleStatements:
- Effect: Allow
Action:
- s3:GetObject
Resource: arn:aws:s3:::cmsdemo/*
Gives error:
Warning: Invalid configuration encountered
at 'functions.getblog': unrecognized property 'iamRoleStatementsName'
at 'functions.getblog': unrecognized property 'iamRoleStatements
If I uncomment the #plugins, I get missing plugin, and install it and get this error:
Error:
Serverless plugin "serverless-s3-deploy" not found. Make sure it's installed and listed in the "plugins" section of your serverless config file. Run "serverless plugin install -n serverless-s3-deploy" to install it.
c:\GitHub\Relatix\Apps\CMSBackend\cmsbackend-service>serverless plugin install -n serverless-s3-deploy
✔ Plugin "serverless-s3-deploy" installed (4s)
c:\GitHub\Relatix\Apps\CMSBackend\cmsbackend-service>sls deploy
Environment: win32, node 18.13.0, framework 3.27.0, plugin 6.2.3, SDK 4.3.2
Docs: docs.serverless.com
Support: forum.serverless.com
Bugs: github.com/serverless/serverless/issues
Error:
TypeError: Cannot read properties of undefined (reading 'assets')
at new Assets (c:\GitHub\Relatix\Apps\CMSBackend\cmsbackend-service\node_modules\serverless-s3-deploy\index.js:20:49)
at PluginManager.addPlugin (C:\Users\nwalt\AppData\Roaming\npm\node_modules\serverless\lib\classes\plugin-manager.js:91:28)
at C:\Users\nwalt\AppData\Roaming\npm\node_modules\serverless\lib\classes\plugin-manager.js:137:69
at Array.forEach (<anonymous>)
at PluginManager.loadAllPlugins (C:\Users\nwalt\AppData\Roaming\npm\node_modules\serverless\lib\classes\plugin-manager.js:137:44)
at async Serverless.init (C:\Users\nwalt\AppData\Roaming\npm\node_modules\serverless\lib\serverless.js:146:5)
at async C:\Users\nwalt\AppData\Roaming\npm\node_modules\serverless\scripts\serverless.js:607:7
c:\GitHub\Relatix\Apps\CMSBackend\cmsbackend-service>
I have another serverless project where the iamroles work, but it has the string "serve:" between the "functions:" and the first function.
functions:
serve:
# Any web request regardless of path or method will be handled by a single Lambda function
handler: handler.serve
events:
- http:
path: /
method: any
cors: true
- http:
path: /{any+}
method: any
cors: true
iamRoleStatementsName: LambdaGetS3BucketCognitivePsychologyCmsDemo
iamRoleStatements:
- Effect: Allow
Action:
- s3:GetObject
Resource: arn:aws:s3:::cognativepsychologycmsdemo/*
When I add that "serve:", I get this error:
× Stack cmsbackend-dev failed to deploy (2s)
Environment: win32, node 18.13.0, framework 3.27.0, plugin 6.2.3, SDK 4.3.2
Credentials: Local, "default" profile
Docs: docs.serverless.com
Support: forum.serverless.com
Bugs: github.com/serverless/serverless/issues
Error:
Either "handler" or "image" property needs to be set on function "serve"

Related

Serverless Offline: The "path" argument must be of type string. Received undefined

Not sure why this started happening but I have a very simple serverless app that was working, but now when I run sls offline start I get the error above. I have found the culprit and it is the events inside the functions.
Here is the serverless.yml file:
service: hello-world-offline
provider:
name: aws
runtime: nodejs12.x
region: eu-east-1
stage: dev
plugins:
- serverless-offline
functions:
hello-world:
handler: handler.handle # required, handler set in AWS Lambda
events:
- http:
path: hello-world
method: get
cors: true
Here is the handler.js file:
module.exports.handle = async (event, ctx, cb) => {
cb(null, {
statusCode: 200,
body: JSON.stringify({ message: "hello world" })
})
}
If I get rid of the events in the function hello-world everything works just fine with sls offline start except for the fact I can't actually hit the endpoint locally of course. I've tried making it a hard string by adding quotes but that did nothing.
EDIT: Turns out this happens when using yarn workspaces. If I put this in a packages/my-serverless-app structure and cd into the folder to run the sls offline start command this happens. If I remove it from the structure it works just fine.
Change
events:
- http:
path: hello-world
method: get
cors: true
TO
events:
- httpApi:
path: hello-world
method: get
And this should work!

Call service from existing api gateway using base path mappings

Our API has the following endpoints:
POST /users - create a user
GET /users/{userId} - get a particular user
GET /posts/{postId} - get a particular post
GET /posts/{postId}/users - get the users who contributed to this post
I have defined two services: users-service and posts-service. In these two services I define the lambdas like so. I'm using the serverless-domain-manager plugin to create base path mappings:
/users-service/serverless.yaml:
service: users-service
provider:
name: aws
runtime: nodejs10.x
stage: dev
plugins:
- serverless-domain-manager
custom:
customDomain:
domainName: 'serverlesstesting.example.com'
basePath: 'users'
stage: ${self:provider.stage}
createRoute53Record: true
functions:
create:
name: userCreate
handler: src/create.handler
events:
- http:
path: /
method: post
get:
name: userGet
handler: src/get.handler
events:
- http:
path: /{userId}
method: get
/rooms-service/serverless.yaml:
service: posts-service
provider:
name: aws
runtime: nodejs10.x
stage: dev
plugins:
- serverless-domain-manager
custom:
customDomain:
domainName: 'serverlesstesting.example.com'
basePath: 'posts'
stage: ${self:provider.stage}
createRoute53Record: true
functions:
get:
name: postsGet
handler: src/get.handler
events:
- http:
path: /{postId}
method: get
getUsersForPost:
handler: userGet ?
events: ??
The problem is that the GET /posts/{postId}/users actually calls the same userGet lambda from the users-service. But the source for that lambda lives in the users-service, not the posts-service.
So my question becomes:
How do I reference a service from another service using base path mappings? In other words, is it possible for the posts service to actually make a call to the parent custom domain and into the users base path mapping and its service?
Consider or refer below approach
https://serverless-stack.com/chapters/share-an-api-endpoint-between-services.html

How to use an external layer with the Serverless Framework?

I would like to use an external layer arn:aws:lambda:eu-central-1:347034527139:layer:tf_keras_pillow:1 in my Serverless project.
I do so by having the following in my serverless.yml:
functions:
api:
handler: functions/api/handler.run
layers: arn:aws:lambda:eu-central-1:347034527139:layer:tf_keras_pillow:1
events:
- http:
path: /image/{id}/{mode}
method: get
request:
parameters:
paths:
id: true
mode: true
However, when checking the AWS Lambda function in the console, there is no layer added after deployment. Any ideas?
The only way to add the layer is by manually doing so in the GUI.
The layers value is an array, per the documentation: https://serverless.com/framework/docs/providers/aws/guide/layers#using-your-layers.
functions:
api:
handler: functions/api/handler.run
layers:
- arn:aws:lambda:eu-central-1:347034527139:layer:tf_keras_pillow:1
events:
- http:
path: /image/{id}/{mode}
method: get
request:
parameters:
paths:
id: true
mode: true
Should work.

AWS - API keys available on the Serverless Offline framework?

I use Serverless Offline to develop a Web project.
I need of API Keys to access to resource on Serverless AWS Lamda.
I have a serverless.yml with my service and my provider.
In Postman, I access to my route (http://127.0.0.1:3333/segments/UUID/test), and I haven't any error (as Forbidden message), the Lambda is executed...
test:
handler: src/Api/segment.test
events:
- http:
path: segments/{segmentUuid}/test
method: post
request:
parameters:
paths:
segmentUuid: true
private: true
The route in question is not protected by private.
https://www.npmjs.com/package/serverless-offline#token-authorizers
Serverless-offline will emulate the behaviour of APIG and create a
random token that's printed on the screen. With this token you can
access your private methods adding x-api-key: generatedToken to your
request header. All api keys will share the same token. To specify a
custom token use the --apiKey cli option.
Command will look like this:
sls offline --apiKey any-pregenerated-key
For local dev use this inside serverless.yml:
custom:
serverless-offline:
apiKey: 'your-key-here'
Or this inside serverless.ts:
custom: {
'serverless-offline': {
apiKey: 'your-key-here',
},
},
Given latest changes this configuration worked for me with serverless offline:
provider: {
name: 'aws',
region: region,
runtime: 'nodejs14.x',
stage: stage,
apiGateway:{
apiKeys: [{
name: 'test name',
value: 'sadasfasdasdasdasdafasdasasd'
}],
},
},
https://github.com/dherault/serverless-offline/issues/963

Exclude Lambda function from deploy to a particular stage

I am trying to exclude a Lambda function from being deployed via serverless to my prod stage within AWS.
A snippet from my serverless yaml looks something like -
functions:
some-prod-function:
handler: prodFunction.handler
events:
- http:
path: /prod-function
method: post
some-dev-function:
handler: devFunction.handler
events:
- http:
path: /dev-function
method: post
Is there a way to exclude some-dev-function from being deployed to prod?
You can put those definitions on a different property and use variables in order to choose which definitions to use.
environment-functions:
prod:
some-prod-function:
handler: prodFunction.handler
events:
- http:
path: /prod-function
method: post
dev:
some-dev-function:
handler: devFunction.handler
events:
- http:
path: /dev-function
method: post
functions: ${self:environment-functions.${opt:stage}}
You may need to change this depending on how you specify your stage on deployment (${opt:stage} or ${env:stage}).
I'm using SLS 1.32.0
I wasn't able to get functions: ${self:environment-functions.${opt:stage}} to work. (Not sure why)
It returns the following:
A valid service attribute to satisfy the declaration 'self:environment-functions.dev' could not be found.
However, using the same logic in dashmug's answer, file worked for me:
serverless.yml:
functions: ${file(serverless-${opt:stage}.yml)}
serverless-dev.yml:
some-dev-function:
handler: devFunction.handler
events:
- http:
path: /dev-function
method: post
serverless-prod.yml:
some-prod-function:
handler: prodFunction.handler
events:
- http:
path: /prod-function
method: post
If you are using Serverless framework you could use serverless plugin
serverless-plugin-ifelse
Then
plugins:
- serverless-plugin-ifelse
If you want to exclude say func1
functions:
func1:
name: Function 1
handler: lambda.func1
events:
- http:
path: "path1"
method: "post"
authorizer:
arn: arn:aws:cognito-idp:us-east-1:123456789012:userpool/us-east-1_0acCDefgh
func2:
name: Function 2
handler: lambda.func2
events:
- http:
path: "path2"
method: "post"
func3:
name: Function 3
handler: lambda.func2
events:
- http:
path: "path3"
method: "post"
for us-east-1 . Then use below code snippet
- If: '"${self:provider.region}" == "us-east-1"'
Exclude:
- functions.func1
Create a file for example
env-functions.yml
and add content as below
prod:
some-prod-function:
handler: prodFunction.handler
events:
- http:
path: /prod-function
method: post
dev:
some-dev-function:
handler: devFunction.handler
events:
- http:
path: /dev-function
method: post
After this in serverless.yml set
functions: ${file(env-functions.yml):${opt:stage, self:provider.stage}}

Resources