AWS Lambda function URLs with .NET minimal api

In this article we are going to create a fully functional Github actions pipeline that deploys a .NET minimal api in AWS Lambda.

We will be using a Lambda feature released on (April 2022)— Lambda function Urls and CloudFront in order to configure a custom domain for that lambda. We will be embracing a full IaC approach with CloudFormation

TL;DR

You will find the complete repo with Github workflow here

👉https://github.com/ziedbentahar/aws-lambda-url-net6-minimal-api-sample

About Running Asp.net on AWS Lambda

Serverless functions should be simple and single responsibility oriented. Having a full fledged asp.net core application hosted as a Lambda might break that principle. Lambda functions should have a bounded responsibility so that it doesn’t do more work than it should. That way we avoid bloated Lambda-lith that may lead to long cold starts and performance issues.

But writing a single serverless function that performs CRUD operations (like createItem, updateItem, getItem) instead of creating a function for each operation can have some benefits: A better developer experience and a reduced workflow complexity.

Asp.net minimal api works well in that way : First It makes bootstrapping lambda code easy and with « minimal » boilerplate. Second, the low ceremony nature of minimal api matches the serverless functions philosophy.

Lambda function Urls

In this article we will be using lambda function URLs. This feature lets you configure an HTTPS endpoint in front of the function without configuring an Api Gateway or an Application Load balancer.

When enabled, Lambda generates a unique URL with this format

https://<a-uniquely-generated-url-id.lambda-url.<your-region>.on.aws

We will use a CloudFront distribution configured with a custom domain and we will set the lambda url as the distribution origin.

️️⚠️ A word of caution: Lambda function URLs does not provide features such as rate limiting, IP filtering or request authorization. Rate limiting and IP filtering can be managed with AWS WAF configuration used with CloudFront

Architecture overview

  • S3 Serves as a lambda deployment bucket
  • The Lambda is configured with functions URL feature
  • CloudFront distribution is configured with our custom domain. We have to use a proper cache behavior that prevents from caching Lambda responses
  • ACM Certificate for our custom domain, this certificate must be created in us-east-1 since it will be used by CloudFront
  • An SSM Parameter where we will store the certificate Arn
  • In this example we will deploy all the other components to eu-west-1region

As a prerequisite we will need to configure a public HostedZone for our domain name

Creating the .NET 6 minimal api

It’s pretty straight forward…and minimal

We will need to:

  • Use Amazon.Lambda.AspNetCoreServer.HostingNuget package, in order to be able to call AddAWSLambdaHosting extension method.
  • Specify HttpApi as the event source.
  • In this example I am enabling swagger and swagger ui. Depending on your use case, you will want to disable it for public access.

Creating the Lambda resource

Here are the relevant bits for the Lambda resource. In this example I am using AWS::Lambda::Function instead of AWS::Serverless::Function. We will use plain CloudFormation instead of AWS SAM.

On the Lambda Function resource, we will:

  • Specify dotnet6 as the Runtime
  • Define the assembly name as the value of Handlerproperty

On the lambda Url resource we will need to set:

  • AuthType to NONEas we want it publicly accessible
  • TargetFunctionArn to the Arn or the lambda function

And finally we will need to specify a lambda permission to allow Lambda invocation

Creating the Certificate

In order to use an ACM certificate with CloudFront. We must create it in us-east-1 region. To share the certificate Arn with another stack created in another region, we will use an SSM Parameter store. We will rely on a higher level construct (in our case the Github action job) that will “injects” the certificate Arn as a parameter of the stack defining the CloudFront resource

CloudFront distribution

The following template creates the CloudFront distribution

Here we define our custom domain as an alias for this distribution using the Aliases Property. The ViewerCertificate.AcmCertificateArn property will have the value of the certificate Arn defined earlier.

We will set the origin of this cf distribution to the function Url. The origin must be a domain name, so we will have to remove the non relevant parts of the Url : the leading https:// and the trailing /

And finally we disable lambda responses caching by using a managed cache policy CachePolicyId: '4135ea2d-6df8-44a3-9df3-4b5a84be39ad'. You can learn more about managed caching policy here

Defining the RecordSetGroup

The requests to our custom domain must be routed to the CloudFront distribution: We will create two recordsets A IPV4 and AAAAIPV6 aliases records pointing our custom domain to the CloudFront distribution

Alright, on the previous section we defined the CloudFormation resources. Let’s focus on the CI/CD pipeline now

Reminder

You can find the complete repo with Github workflow here: 👉https://github.com/ziedbentahar/aws-lambda-url-net6-minimal-api-sample

Github Actions Workflow

Before we start we will first add AWS Access Key and AWS Secret key to the project secrets. (As a best practice, you should use temporary security credentials instead of access keys, but this will not be covered in the article)

Defining the pipeline

This pipeline will be have three main jobs: build, publish to s3 and deploy

1 — The build step is pretty straight forward: dotnet builddotnet testdotnet publish → finally zip and upload the artifact

We are using the commit hash

2 — Publish to s3 will take the build step artifact and upload it to the lambda bucket

But first we will ensure that lambda bucket is created (or updated) and we will use the git commit SHA as part of the uploaded file name.

3 — And the final step, is where the deployment to AWS Lambda service happens

As mentioned earlier, we will need to create the ACM certificate to us-east-1 region and then write it’s Arn to a SSM parameter store. This is what Deploy certificate step does by invoking aws cloudformation deploy — template-file ./aws/cfn/certificate.yml …

Next, in the Get Certificate ArnGet step we will retrieve the certificate Arn from the parameter store and set it as en env variable. We can use it in the next step by injecting it as parameter of the Lambda stack.

And finally, Deploy Lambdastep will update (or create) the lambda stack 🎉

Update — 29/10/2022

If you want to use an API Gateway instead of exposing directly your Lambda through function URLs, you can find in this repo a complete solution with its Github actions CI/CD pipeline 👇

https://github.com/ziedbentahar/aws-lambda-api-gateway-net6-minimal-api-sample

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store