Setup AWS API gateway custom authorizers in serverless framework - amazon-web-services

I need to add AWS API gateway custom authorizer to a Lambda function. Currently I have added the authorizer for each endpoint. As in the following serverless.yml.
serverless.yml
service: test-service
provider:
name: aws
runtime: nodejs6.10
stage: dev
region: us-east-1
functions:
bff:
handler: app.handler
events:
- http:
path: /home
method: get
cors: true
authorizer :
arn: arn:aws:lambda:us-east-1:xxxxxx:function:token-verifier
resultTtlInSeconds: 0
identitySource: method.request.header.Authorization
identityValidationExpression: '.*'
How can I add the custom authorizer to the entire lambda function
rather than adding separately to each endpoint?

You're confusing the boundary between AWS API Gateway and AWS Lambda. It's not your fault. Serverless Framework is that good that it almost blurs those two things.
Strictly speaking, AWS Lambda Functions DO NOT need custom authorizers.
Authorizers are used for securing API Gateway endpoints NOT for AWS Lambda functions.
Therefore, you need to define the authorizer for each endpoint you need to require authorization for.
If you're after making your serverless.yml more concise by not repeating the authorizer definition multiple times, you can define it once and just reference it in your endpoints.
service: test-service
custom:
authorizer:
arn: arn:aws:lambda:us-east-1:xxxxxx:function:token-verifier
resultTtlInSeconds: 0
identitySource: method.request.header.Authorization
identityValidationExpression: '.*'
provider:
name: aws
runtime: nodejs6.10
stage: dev
region: us-east-1
functions:
bff:
handler: app.handler
events:
- http:
path: /home
method: get
cors: true
authorizer: ${self:custom.authorizer}

Related

AWS API Gateway Responses via serverless framework

I'd like to be able to configure API Gateway Responses via serverless framework...
This is what my serverless.yml looks like:
#Deploy an api gateway with custom responses.
---
service: test-apigw
frameworkVersion: ">=3.20"
provider:
name: aws
stage: dev
region: us-east-1
stackName: ${self:service}
apiName: test-apigw
endpointType: REGIONAL
functions:
hello:
handler: handler.endpoint
events:
- http:
path: /hello-world
method: ANY
private: true
package:
individually: true
excludeDevDependencies: false
Now I read somewhere that one can configure resources in a serverless file, however by using CFN code I'd need the ARN or the Ref of an already deployed API Gateway or, declare the API Gateway with CFN code (which I want to avoid)...
Is there a way to configure these Gateway Responses (not integration responses!!) using the same api gateway that my serverless.yml is deploying? i.e. the one with name test-apigw?
It turns out the response I quoted actually works for me.
In the same serverless.yml file, put the GatewayResponses you want to configure.
resources:
Resources:
Unauthorized:
Type: "AWS::ApiGateway::GatewayResponse"
Properties:
ResponseParameters:
gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
ResponseTemplates:
"application/json": ${file(gateway-responses/responses.js):unauthorized}
ResponseType: UNAUTHORIZED
RestApiId: !Ref ApiGatewayRestApi
StatusCode: '401'
At least for version 3.20 of serverless framework, the created API name is ApiGatewayRestApi, this will only work of course, if you're only creating one API Gw in that file and I believe, the API Gateway has to be already deployed.
The correct way to do this is, as the official serverless documentation states, to create the API Gateway with Cloudformation code.

Unable to configure Method Response and Integration Response using AWS SAM

I am trying to deploy the api and lambda function using SAM. But the Method Response and Integration Response are empty. I am aiming to configure the api-gateway like below picture. In this I have manually configured the api-gateway and its working but when I use the SAM to generate the api-gateway it doesn't shpes the Method Response and Integration Response.
Without Sam:
With Sam:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Timeout: 500
MemorySize: 5000
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
GatewayResponses:
DEFAULT_4xx:
ResponseParameters:
Headers:
Access-Control-Expose-Headers: "'WWW-Authenticate'"
Access-Control-Allow-Origin: "'*'"
InferenceFunction:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
Events:
Inference:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /zero-shot-classification
Method: post
RestApiId: !Ref MyApi
Metadata:
Dockerfile: Dockerfile
DockerContext: ./zero-shot-classification
DockerTag: zero-shot-classification
The difference you see is the difference between how the payload is sent to the lambda and how API gateway processes the response from the lambda. Seeing as in your CloudFormation you do not specify a specification for your API endpoints, AWS SAM will construct this based on the events from your functions. However, AWS SAM will always use the LAMBDA_PROXY integration type, while you seem to be wanting to use the LAMBDA integration type.
I'd suggest you take your manually created API gateway and export it to an openapi/swagger definition. This can then be used as DefinitionBody in you MyApi. That way you can specify it uses the LAMBDA integration instead of the LAMBDA_PROXY integration. Don't forget to update the swagger definition so it uses the created function in your cloudformation and not the function that existed when you exported the API.
That being said, the LAMBDA_PROXY way is more widely used and also removes the need for template mappings in your API Gateway. It is also the only integration type for lambdas that is supported in the HTTP API (API Gateway v2), which is a lot cheaper than the classic REST API.

How to change an AWS Serverless application project to just deploy as lambda functions? (No API gateway and cloud formation)

Originally, we created the project as WebAPI, and were deploying as API Gateway...
Is there a way I could just change the project's deployment to deploy only as a lambda function and not anymore with API gateway and cloud formation?
I am trying not to redo the whole project.
Yep just don't add HTTP events to your functions.
functions:
postRoute:
handler: handler.postRoute
events:
-
http:
path: /someRoute
method: post
cors: true
anotherRoute:
handler: handler.anotherRoute
events:
-
http:
path: '/path'
method: get
cors: true
authorizer: // NO HTTP ROUTE
handler: handler.authorizer
resultTtlInSeconds: 0
lambdaLogger: // NO HTTP ROUTE
handler: handler.lambdaLoggerHandler

How to get URL endpoint detail as variable in Serverless Framework's `serverless.yml` file?

Using Serverless Framework to
deploy AWS Lambda functions, Serverless creates (or receives) the
specific URL endpoint string. I want to use that string (as a variable)
in another section of the serverless.yml specification file.
Is that URL endpoint available as a variable in serverless.yml?
The Serverless Framework documentation on AWS-related variables
does not seem to answer that case.
Details: my serverless.yml contains a provider: specification
similar to:
provider:
name: aws
runtime: python3.6
memorySize: 512
region: ${opt:region, 'eu-west-1'}
profile: ${opt:profile, 'default'}
stage: ${opt:stage, 'staging'}
and a functions: section starting with:
functions:
round-control:
name: ${self:provider.stage}-round-control
runtime: nodejs8.10
handler: round/control/app.lambdaHandler
events:
- http:
path: round/control
method: get
After a
serverless deploy --profile [my-aws-profile]
the Lambda function sample-experiments-staging-round-control
is reported to be available at endpoint
https://1a234bc5de.execute-api.eu-west-1.amazonaws.com/staging/round/control.
Question: is there a variable in Serverless available that contains
that 1a234bc5de, or 1a234bc5de.execute-api or perhaps even
1a234bc5de.execute-api.eu-west-1.amazonaws.com?
(Obviously, I can also construct the last two if I know the first.)
With that variable, I can construct the full URL endpoint, which I
need in another place in the serverless.yml file.
N.B. That 1a234bc5de isn't a dynamically generated random
string - my current project is (per stage, per region) 'fixed' to
the same string. Perhaps that string is generated at AWS Lambda or
AWS API Gateway?
I was able to pass the URL and unique ID for the API Gateway endpoint to a Lambda function as environment variables as follows:
mylambda:
handler: mylambda.handler
runtime: python3.7
events:
- http:
path: id
cors: true
environment:
APIG_UID: !Ref "ApiGatewayRestApi"
APIG_URL:
!Join
- ''
- - 'https://'
- !Ref ApiGatewayRestApi
- '.execute-api.'
- ${opt:region, self:provider.region}
- '.amazonaws.com/'
- ${opt:stage, self:provider.stage}
Thanks to goingserverless.
Here is a simpler and more modern alternative:
provider:
environment:
API_URL: !Sub 'https://${ApiGatewayRestApi}.execute-api.${aws:region}.amazonaws.com/${sls:stage}'
Note: the code above applies to REST API (API Gateway v1), not HTTP API.
If you are using the new HTTP API (API Gateway v2), the solution is simpler:
provider:
environment:
API_URL: !GetAtt HttpApi.ApiEndpoint

Best way to add a custom domain to lambda?

I am trying to create a lambda function using SAM, however I can't work out how to add a custom domain to it. Do I need to add a whole ApiGateway to my CloudFormation template just to change the domain or is there is an easier way?
My domain is in Route53 and I have a certificate for it in ACM.
My template is currently as follows:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: An AWS Serverless Application that uses the ASP.NET Core framework running in Amazon Lambda.
Resources:
ExampleWebApi:
Type: AWS::Serverless::Function
Properties:
Handler: Example.WebApi::Example.WebApi.LambdaEntryPoint::FunctionHandlerAsync
Runtime: dotnetcore2.1
CodeUri: ''
MemorySize: 128
Timeout: 10
Role: null
Policies:
- AWSLambdaFullAccess
Environment:
Variables: {}
Events:
PutResource:
Type: Api
Properties:
Path: "/{proxy+}"
Method: ANY
Yes, you need to use API Gateway in order to define a custom domain for a lambda function.