As a site reliability engineer at work, I hate to deal with servers maintenance in my leisure time for personal projects. So, serverless is the only option I have. What that said, considering the number of supported geolocations, AWS Lambda stack would be the clear winner.
However, after digging more and more into the AWS Lamdba, Cloudformation, and all other tools, I realized serverless is not perfect (at all!). Fortunately, there are some acceptable workarounds! (Believe me, it is not that easy for me to call something acceptable.)
This main purpose of this article is to illustrate how to set up an OAuth-supported AWS Cognito user pool using Serverless Framework, and how to get around the potential pitfalls down the road.
Cloudformation can NOT define everything!
In Cloudformation, I cannot add a new resource server in a Cognito user pool; I cannot create a custom domain; I cannot configure an app client to make use of a new resource server…Hey AWS, you called it Cloudformation and Infrastructure as Code, not joking right?
Writing AWS Lambda function for custom resources is not as straightforward as I thought!
Alright, after googling for a while, I think I can write my own in AWS Lambda. But wait, what is a Service Token? How can I pass arguments to the lambda function? Why is my custom resource taking one hour or more to fail?
Testing custom resources on Cloudformation could be time-consuming!
Right, if you don’t know how to send an update to Cloudformation, you’ll need to wait one hour for it to fail if there’s an error in your Lambda function. BTW,
cfn-response is suggested for sending Cloudformation updates, but it is NOT available if you want to deploy the lambda function from S3. In other words, you need to write the whole lambda function into the Cloudformation script, which is NOT acceptable to me at all.
- Install the Serverless Framework and set up your AWS credentials. Instruction
- Create a barebone serverless.yml file
- Create a simple Cognito definition
- Create a role for allowing Lambda to manipulate Cognito
Note 1: the
AssumeRolePolicyDocument is essential for almost all Lambda function, since it allows AWS Lambda to manipulate your AWS resources on your behalf.
Note 2: the
PolicyDocument allows the Lambda function to use CloudWatch for logging and do anything to the user pool you just created.
- Create a custom resource! (finally)
Node.js script to add a resource server and an app client to the Cognito user pool. All users authenticate via this OAuth app will be granted
admin:full scope for testing purpose.
CF template for custom resource:
Putting everything together in serverless.yml!
serverless deploy, everything should be up & running now!
Moment of Truth
Send a request to the endpoint from Postman!
Awesome! Something came back! Let’s check the
The scope is
To be honest, set this whole thing up is a lot harder than I expected it to be. The custom resource thing looks a bit hacky and not perfect, but at least I can set up or destroy the whole Cognito deployment by just
serverless deploy or
serverless remove without any other commands now!