Stacktape

Sign up



Edge lambda functions

Overview and basic concepts

  • Edge lambda function is a scalable and highly available computing resource that runs your code closer to users of your application, improving performance and latency.

  • Functions are globally distributed across regional CDN cache locations (13 locations spread across the globe), which makes it possible to execute them closer to the end user

  • Lambda functions are "serverless" and fully managed. You don't have to worry about provisioning and managing servers, container and OS security, patching, scaling & many other DevOps tasks.

  • Supported runtimes are Node.js (Javascript and Typescript) and Python.

  • Use-cases for Edge lambda functions: performing user authentication, cookie inspection, validation of requests, and many more.

Advantages

  • Low latency - By running code closer to end user, latency and overall performance is improved.
  • Scalability - Run your code without neccessity to manage any infrastructure. Similarly to regular functions, Edge lambda functions provide high scalability.
  • Pay-per-use - You only pay for the compute time you consume (rounded to 1ms). Refer to Lambda@Edge pricing in AWS docs.

Disadvantages

  • Limited execution environment - (Applies to onRequest/onResponse lambdas) Your Edge lambda functions are limited to 128MB of memory and maximum execution time of 5 seconds.

Basic usage

  • You can associate edge-lambda-function with CDN to be executed:

    • onRequest - function is executed when CDN receives a request from a client(viewer) before checking CDN cache
    • onResponse - function is executed before returning the response to the client(viewer)
  • Potential use-cases for using edge functions:

    • generating immediate HTTP response without the need to check CDN cache or forward to origin
    • modifying request (i.e rewrite url, headers etc) before forwarding to the origin
    • inspection of cookies
    • inspection/validation of authorization headers and tokens

In the following example we are using edge-lambda-function to validate Authorization header of each incoming user request. If user is not authorized, he is redirected to login page.

Copy

resources:
authFunction:
type: edge-lambda-function
properties:
packaging:
type: stacktape-lambda-buildpack
properties:
entryfilePath: auth-function.ts
myBucket:
type: bucket
properties:
cdn:
enabled: true
edgeFunctions:
onRequest: authFunction

Copy

const validateAuthorizationToken = (token) => {
// perform some validation
return true;
};
export default async (event) => {
const { request } = event.Records[0].cf;
const { headers } = request;
const authorizationToken = headers.authorization?.[0]?.value;
const userAuthorized = validateAuthorizationToken(authorizationToken);
// if user is not authorized, redirect him to login page
if (!userAuthorized) {
return {
status: '302',
headers: {
location: [
{
key: 'Location',
value: '/login'
}
],
'cache-control': [
{
key: 'Cache-Control',
value: 'no-cache, no-store, max-age=0, must-revalidate'
}
]
}
};
}
// after we validated that user is authorized, we can return the request
// request will be forwarded to origin
return request;
};

Code of authorizer function authFunction

EdgeLambdaFunction  API reference
type
Required
properties.packaging
Required
properties.runtime
properties.memory
Default: 128
properties.timeout
Default: 3
properties.accessControl
properties.logging
overrides

Event structure

Event delivered to the function differs based on whether you are using onRequest or onResponse trigger:

On request trigger

When using onRequest trigger with edge-lambda-function you can:

  1. Return response from function - In this case the response is served to the client directly and the request is NOT forwarded to the origin.
  2. Forward request to origin - You can modify the request (path, body, headers ...) before forwarding to origin or you can forward it as is.

Following example code combines both options:

  • If user is authorized - forwards request to the origin
  • If user is not authorized - return redirect response to login page

Copy

const validateAuthorizationToken = (token) => {
// perform some validation
return true;
};
export default async (event) => {
const { request } = event.Records[0].cf;
const { headers } = request;
const authorizationToken = headers.authorization?.[0]?.value;
const userAuthorized = validateAuthorizationToken(authorizationToken);
// if user is not authorized, redirect him to login page
if (!userAuthorized) {
return {
status: '302',
headers: {
location: [
{
key: 'Location',
value: '/login'
}
],
'cache-control': [
{
key: 'Cache-Control',
value: 'no-cache, no-store, max-age=0, must-revalidate'
}
]
}
};
}
// after we validated that user is authorized, we can return the request
// request will be forwarded to origin
return request;
};

Code of authorizer function

Copy

resources:
authFunction:
type: edge-lambda-function
properties:
packaging:
type: stacktape-lambda-buildpack
properties:
entryfilePath: auth-function.ts
myBucket:
type: bucket
properties:
cdn:
enabled: true
edgeFunctions:
onRequest: authFunction

Example config

On response trigger

When using onResponse trigger with edge-lambda-function you can modify the response before returning.

In following example we are using it to set response cookie.

Copy

export default async (event) => {
const { response } = event.Records[0].cf;
response.headers['set-cookie'] = [
{
key: 'Set-Cookie',
value: 'my-experimental-cookie=cookie-value'
}
];
return response;
};

Code of the function

Copy

resources:
cookieFunction:
type: edge-lambda-function
properties:
packaging:
type: stacktape-lambda-buildpack
properties:
entryfilePath: set-cookie.ts
myBucket:
type: bucket
properties:
cdn:
enabled: true
edgeFunctions:
onResponse: cookieFunction

Example config

Packaging

Refer to packaging docs.

When using cdn-lambda function with onReqeust or onResponse trigger the zipped package size is limited to 1 MB.

Logging

  • Information about the function invocation and function logs (stdout and stderr) are automatically sent to a pre-created CloudWatch log group.
  • By default, logs are retained for 180 days..
  • You can see the logs in the log group page in the AWS CloudWatch console. You can use stacktape stack-info command to get a direct link.

Edge lambda functions are executed in multiple locations (regions) across the world depending on the cdn edge location which serves the client request (usually the location closest to the client).

As a result the logs for the function executed in given region are delivered to a log group in that region. The list of regions where edge lambda can execute: us-east-1, us-east-2, us-west-1, us-west-2, ap-south-1, ap-northeast-1, ap-northeast-2, ap-southeast-1, ap-southeast-2, eu-west-1, eu-west-2, eu-central-1, sa-east-1

Accessing other resources

  • For most of the AWS resources, resource-to-resource communication is not allowed by default. This helps to enforce security and resource isolation. Access must be explicitly granted using IAM (Identity and Access Management) permissions.

  • Stacktape automatically handles IAM permissions for the underlying AWS services that it creates (i.e. granting cdn lambda function permission to write logs to Cloudwatch).

  • If your function needs to communicate with other infrastructure components, you need to add permissions manually. You can do this in 2 ways listed below.

AccessControl  API reference
Parent API reference: EdgeLambdaFunction
iamRoleStatements
allowAccessTo

Using allowAccessTo

  • List of resource names that this function will be able to access (basic IAM permissions will be granted automatically). Granted permissions differ based on the resource.
  • Works only for resources managed by Stacktape (not arbitrary Cloudformation resources)
  • This is useful if you don't want to deal with IAM permissions yourself. Handling permissions using raw IAM role statements can be cumbersome, time-consuming and error-prone.

Copy

resources:
authFunction:
type: edge-lambda-function
properties:
packaging:
type: stacktape-lambda-buildpack
properties:
entryfilePath: auth-function.ts
accessControl:
allowAccessTo:
- myDynamoTable
myDynamoTable:
type: dynamo-db-table
properties:
primaryKey:
partitionKey:
name: id
type: string

Using iamRoleStatements

  • IAM Role statements are a low-level, granular and AWS-native way of controlling access to your resources.
  • IAM Role statements can be used to add permissions to any Cloudformation resource.
  • Configured IAM role statement objects will be appended to the function's role.

Be advised when accessing resources from edge-lambda-functions. While your stack (and the resources you are accessing) are deployed in a specific region, the function can be executed in any edge location around the world. This might result in higher latencies when function is accessing the resource from a more distant region.


Example:

  1. You have stack with a bucket and a edge lambda function (which has access gratned to the bucket) deployed in region eu-west-1.
  2. Request to CDN comes to us-east-1 region.
  3. The function is executed in us-east-1 region. Due to network delays the communication between the function and the bucket might be slower.

API reference

StpIamRoleStatement  API reference
Parent API reference: AccessControl
Resource
Required
Sid
Effect
Action
Condition
Need help? Ask a question on SlackDiscord or info@stacktape.com.