How to use Lambda URLs to simplify basic request/response patterns at scale.

aws_templates/lambda_urls_blog at main · cloudlifter95/aws_templates

Getting served data has never been this simple.

A couple months ago, AWS introduced lambda URLs as (yet another) way to invoke lambda functions, by placing an HTTPS endpoint in front. This article aims at documenting how lambda URLs can fit into an easy and secure solution for at-scale cross-account information sharing.

Way before the Lambda URL feature was released, many solutions were made possible for microservice communication, by composing AWS services such as AWS API Gateway and AWS Cognito for authentication, or even by directly calling the Invoke action of the Lambda service (through SDKs or CLI). This second option often required you to have two lambda functions; one acting as a server and the other as a requester, and implementing proper authorization and authentication configurations.

Consequently, all these options came with the overhead of configuring additional services and, at the very least, the authentication layer.

Whereas this overhead is legitimate and necessary to implement complex business logics, basic cases do not require overhead such as advanced or dedicated authentication, and this is where lambda URLs enter the scene.

For more information on lambda URLs or if you’re interested in a comparison between Lambda URLs and API gateway, refer to:

Case study:

In order to demonstrate how simple it is to implement a lambda URL, let’s assume we need to expose some of the organization key information (to all the children accounts -existing and new- or to third-party applications, through a GET method of an HTTP method. More advanced examples would be WebHooks but we won’t cover it here.


Let’s also assume that, since organization information is sensitive, we don’t want users outside the organization to access it. We will, therefore, implement a lambda URL function with AWS_IAM authentication.

Lambda URL supports two types of authentications:

  • None: authentication is not handled by the lambda service. You can still implement your own authentication checks based on headers or other means. The checks will have to be embedded in the function code.
  • AWS_IAM: Authentication is handled by the lambda service through the AWS IAM service. Only allowed IAM users (or roles) can access the endpoint. Lambda service checks whether a valid AWS signature figures in the request. This implies you use an AWS user/role credentials to form the request.

Architecture & Implementation

I made all the code(Cloudformation file, python file, and deployer bash script) available on Github: https://github.com/cloudlifter95/aws_templates/tree/main/lambda_urls_blog).

The CF code below deploys a lambda function with its HTTPS endpoint and configures the authentication/authorization layers to be the AWS IAM service. The authentication/authorization type can also be set to “None” if the endpoint is exposing public data.  

Lambda permission ensures it can only be called from within a role belonging to the organization, by attaching a resource-based policy to the backing lambda function. Technically, this means we are exposing an endpoint to all users/roles within the organization, enabling cross-account information sharing, and even access outside the cloud.

This second case is easily demonstrated below with Postman, but it could really be anything from a browser to a third-party app querying the endpoint. So long as you have valid AWS credentials, you are allowed in. As you can see, the code is quite concise due to the usage of serverless.

The code is quite concise due to the usage of serverless:

Cloudformation definition of Serverless Lambda URL

Resulting resource-based policy and lambda function, along with the endpoint URL:

Resource based policy of Lambda URL
Lambda instantiation on AWS Console

Since we have set the authentication/authorization property to AWS_IAM, unauthenticated access is forbidden:

Unauthenticated access forbidden

Let’s try with authentication this time. Here we are passing a set of temporary credentials (recognizable with the “AWS_SESSION_TOKEN”), meaning we are using the credentials of an AWS IAM role (short-term credentials are generally preferred over long-term credentials for security purposes). IAM user/role must have the lambda:InvokeFunctionUrl allowed.

Postman call

The endpoint returns a success status. It is in fact returning a list of children accounts of the organization, which is what we intended the function for.

Authenticated requests return 200 status code OK

Notes:

  • As you know by now, Lambda generates a random URL for the endpoint. If you need a “friendly” or “guessable” name, you can leverage route53 to point to the generated URL.
  • As of the time this article was written, there is no notion of private HTTPS endpoints on AWS. If you need to expose some data which cannot leave AWS backbone, you’ll have to fall back to API gateway or Lambda VPC (along with their respective private endpoints).
  • In terms of monitoring, Cloudwatch provides basic metrics such as Request counts and errors. Whereas, Cloudtrail logs by default management events (create/update/delete of the function). InvokeFunctionUrl action falls under the data event category, which means it is only logged by CloudTrail if the option is turned on.

Valuable references:

Leave a Reply

Your email address will not be published. Required fields are marked *