This project contains source code and instructions to create a simple AWS Lambda application as a backend and API Gateway to invoke the Lambda. Also, instructions to configure AWS Cognito to secure the authentication between the API gateway and the client application. Furthermore, We are going to use AWS CodePipeline to configure the CI/CD pipeline. So this will be a fantastic journey.
- Node.js
- AWS Lambda
- AWS SAM
- AWS Cognito
- AWS API Gateway
- AWS CodeCommit
- AWS CodeBuild
- AWS CodePipeline
- An AWS Account
- Text Editor (I am using VS Code because it is incredible.)
These are the steps that I am going to cover. So, buckle up, folks!!!
- Create the repository in AWS
- Configure SAM template(
template.yaml) file- Configure parameters
- Configure Cognito resources
- Configure API gateway
- Configure the Lambda function
- Configure
buildspec.ymlfile - Configure the CI/CD pipeline (AWS CodePipeline)
We can use the AWS SAM template to create the project. Please visit AWS SAM official GitHub page for more details. Otherwise, you can fork this repo and test the functionality.
To see how we can create the AWS CodeCommit repository, please read my Medium post (Coming Soon).
Introuduction about SAM
For this example We are going to use these parameters. You can pass these values from the AWS CodePipeline as parameters.
IAMExecutionRole- AWS user role to execute the Lambda.CognitoUserPoolName- AWS Cognito userpool name.CognitoUserPoolClientName- The name for AWS Cognito User Pool client.CognitoUserPoolDomain- The domain prefix that we are going to use to get the token.CognitoUserPoolResourceServerName- Resource Server name for AWS Cognito User Pool Resource Server.CognitoUserPoolResourceServerIdentifier- Unique identifier for AWS Cognito User Pool Resource Server.
Configure template.yaml file with bellow configs if you need to have a dynamic template.
Parameters:
IAMExecutionRole:
Description: IAM role ARN of Lambda execution role.
Type: String
CognitoUserPoolName:
Description: Name for your Cognito user pool
Type: String
CognitoUserPoolClientName:
Description: Name for your Cognito user pool client
Type: String
CognitoUserPoolDomain:
Description: Domain name for your Cognito user pool
Type: String
CognitoUserPoolResourceServerName:
Description: Name for your Cognito user pool Cognito user pool resource server
Type: String
CognitoUserPoolResourceServerIdentifier:
Description: Identifier for your Cognito user pool resource server
Type: StringSince we plan to use AWS Cognito to authenticate the client app with the Lambda functions, we need to configure AWS Cognito User Pool.
MyCognitoUserPool: # You can choose your own name.
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: !Ref CognitoUserPoolName # Refferencing User Pool Name parameter.
Policies:
PasswordPolicy:
MinimumLength: 8
UsernameAttributes:
- email
Schema:
- AttributeDataType: String
Name: email
Required: falseTo get the token first, we need to have a client for our User Pool. You can use the below configurations to create the User Pool Client.
MyCognitoUserPoolClient: # You can choose your own name.
Type: AWS::Cognito::UserPoolClient
Properties:
UserPoolId: !Ref MyCognitoUserPool # Refferencing Cognito User Pool created previously.
ClientName: !Ref CognitoUserPoolClientName # Refferencing User Pool Client Name parameter.
GenerateSecret: true
AllowedOAuthFlows:
- client_credentials
AllowedOAuthFlowsUserPoolClient: true
AllowedOAuthScopes:
- !Join ["/", [!Ref CognitoUserPoolClientName, "create"]] # You can configure Authentication scopes also.
- !Join ["/", [!Ref CognitoUserPoolClientName, "update"]]
DependsOn: UserPoolResourceServerTo generate the token, we need to have a valid domain name configure with our AWS Cognito User Pool. You can configure your domain name, or you can choose a domain from AWS.
UserPoolDomain:
Type: AWS::Cognito::UserPoolDomain
Properties:
UserPoolId: !Ref MyCognitoUserPool # Refferencing Congnito User Pool domain name parameter.
Domain: !Ref CognitoUserPoolDomainConfigurations for Cognito user pool resource server.
UserPoolResourceServer:
Type: AWS::Cognito::UserPoolResourceServer
Properties:
UserPoolId: !Ref MyCognitoUserPool
Identifier: !Ref CognitoUserPoolResourceServerIdentifier
Name: !Ref CognitoUserPoolResourceServerName
Scopes:
- ScopeName: "create"
ScopeDescription: "create"
- ScopeName: "update"
ScopeDescription: "update"Since we will use OAuth 2.0 as the authentication mechanism, wh have to use the AWS::Serverless::HttpApi resource type when creating the API gateway.
MyApi:
Type: AWS::Serverless::HttpApi
Properties:
StageName: Prod
CorsConfiguration:
AllowOrigins:
- "http://*"
- "https://*"
AllowHeaders:
- authorization
AllowMethods:
- GET
MaxAge: 3600
Auth:
DefaultAuthorizer: JWTTokenAuthorizer
Authorizers:
JWTTokenAuthorizer:
JwtConfiguration:
issuer: !Sub https://cognito-idp.${AWS::Region}.amazonaws.com/${MyCognitoUserPool}
audience:
- !Ref MyCognitoUserPoolClient
IdentitySource: "$request.header.Authorization"HelloWorldFunction: # You can use any name that you preffered.
Type: AWS::Serverless::Function
Properties:
CodeUri: hello-world/ # Source code folder.
Handler: app.lambdaHandler
Runtime: nodejs12.x
Role: !Ref IAMExecutionRole # Lambda execution role.
Events:
HelloWorld:
Type: HttpApi
Properties:
ApiId: !Ref MyApi # Refferencing API Gateway configurations.
Path: /hello # API path
Method: get # HTTP methodWhen you are configuring the AWS CI/CD pipeline, you need to have a repository and instructions to execute when you need to build and store the artifacts. In buildspec.yaml you can configure all the build instructions that you need to execute.
version: 0.1
phases:
install:
commands:
- aws cloudformation package --template-file template.yaml --s3-bucket ADD_YOUR_BUCKET_NAME_HERE --output-template-file outputSamTemplate.yaml
artifacts:
type: zip
files:
- template.yaml
- outputSamTemplate.yamlPlease read my Medium post(Coming Soon) to configure the CI/CD pipeline.
Please add the bellow configuration to the CI/CD Pipeline as overridden parameters.
{
"IAMExecutionRole": "",
"CognitoUserPoolName": "",
"CognitoUserPoolClientName": "",
"CognitoUserPoolDomain": "",
"CognitoUserPoolResourceServerName": "",
"CognitoUserPoolResourceServerIdentifier": ""
}