/sam-alb

Support for Application Load Balancers in the AWS SAM framework

Primary LanguageGoMIT LicenseMIT

AWS SAM Application Load Balancer macro

The AWS Serverless Application Model (SAM) defines a simplified framework on top of CloudFormation for building serverless apps. It has great support for AWS API Gateway, but so far no support for Application Load Balancers.

This is unfortunate as ALBs are very handy! Depending on your definition of "serverless", they may or may not qualify: there is a minimum cost of about $20 per month, even if you use nothing. But there are several benefits relative to API Gateway REST APIs and HTTP APIs:

  • Cheaper at high volume. In this breakdown, the author estimates their ALB bill to be $166 instead of $4,163 per month for an API Gateway REST API serving 450 requests per second. The (currently beta) HTTP API would about $1,000/month.

  • Seamlessly transition from a serverful environment of EC2 or container targets behind an ALB to a Lambda behind that same ALB incrementally. ALBs let you shift traffic percentage-wise, or direct traffic based on host names, headers, paths, query strings or source IP addresses.

  • Enterprise-friendly. API Gateway has some limitations in its ability to be locked down in granular ways, so large enterprises often block it outright. Those same enterprises usually have no problem with internal ALBs - so you are no longer locked out of a serverless future.

  • Better (in my opinion) support for authentication through OpenID Connect and Cognito. While these are supported by API Gateway, they don't handle redirection of unauthenticated users.

  • Sticky weighted traffic. An ALB can make A/B testing easier by splitting traffic between multiple Lambdas - and ensuring that subsequent requests from the same client are forwarded to the same Lambda.

Installation

This operates as a CloudFormation macro. That means you must "install" it into your account (on a regional basis) before you can use it in your stacks.

The app is installable through the Serverless App Repository. It's named sam-alb and ARN is arn:aws:serverlessrepo:us-east-1:607481581596:applications/sam-alb.

Usage

Usage is pretty simple. You can see a complete example in demo.yml. There are two parts to it. First, you need to add a reference to the macro in the list of transforms in your template.

Replace this:

Transform: "AWS::Serverless-2016-10-31"

With this:

Transform: ["SamAlb", "AWS::Serverless-2016-10-31"]

Note that the order matters - SamAlb needs to come first. Next, you can now use a new event type. Here's what that looks like:

  Function:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: python3.7
      Events:
        Alb:
          Type: ALB
          Properties:
            ListenerArn: !Ref ListenerArn
            Priority: 50
            Conditions:
              Host: [example.com]

The value for ListenerArn should be a string that is of the form arn:aws:elasticloadbalancing:$REGION:$ACCOUNT_ID:listener/app/$ALBNAME/$RANDOM_HEX/$RANDOM_HEX.

The complete set of properties for the ALB event type are:

Property name Description
ListenerArn Type: String. Required. Should be the ARN of an AWS::ElasticLoadBalancingV2::Listener
Priority Type: Integer. Required. This needs to be a value between 1 and 50,000 inclusive. The priority must be unique (i.e. two events can't both be priority 100) and is used to determine rule order evaluation. Rules are evaluated in ascending order.
Oidc Type: AuthenticateOidcConfig. Optional. The properties of this type are the same as the CloudFormation type. One difference is that AuthorizationEndpoint, TokenEndpoint and UserInfoEndpoint are optional. If not provided, they are determined using the well-known endpoint of the Issuer.
Conditions Type: Array of Condition. Required. There must be at least one condition specified, i.e. an empty array is insufficient.

The Condition type has the following properties:

Property name Description
Host Type: Array of strings. Optional.
Path Type: Array of strings. Optional.
Method Type: Array of strings. Optional.
Ip Type: Array of strings. Optional.
Header Type: Key-value map. Values are arrays of strings. Optional.

Every property is optional, but at least one must be specified. Evaluation is similar to IAM policies: objects are ANDed and arrays are OR. The following example will match example.com/hello and amazon.com/hello:

Conditions:
  - Host: [example.com, amazon.com]
    Path: [/hello]

Roadmap

The following is planned:

  • Support for creating ALBs. Right now, the ALB must be created elsewhere - in the same template is fine. The plan is to support VpcConfig with the same structure as the AWS::Serverless::Function type.

  • Route 53 record set creation. Currently records must be created in Route 53 elsewhere.

  • Cognito authentication support.