Stacktape
Stacktape


Edge lambda functions



An Edge Lambda Function is a compute resource that runs your code at CDN edge locations, bringing it closer to your users to reduce latency and improve performance. These functions are globally distributed, ensuring that requests are handled by the nearest location.

Edge Lambdas are serverless, which means Stacktape manages the infrastructure, security, and scaling for you. They support Node.js and Python runtimes and follow a pay-per-use model, so you only pay for the execution time you consume.

Common use cases include user authentication, request validation, and cookie manipulation.

Under the hood

Stacktape uses Lambda@Edge to power Edge Lambda Functions. These functions are associated with a CDN and are triggered by CDN events—either when a request is made to the CDN (onRequest) or when the CDN is about to send a response back to the user (onResponse).

When to use

Advantages

  • Low latency: By executing code closer to the end-user, you can significantly improve your application's performance.
  • Scalability: Edge Lambdas automatically scale with the number of incoming requests.
  • Pay-per-use: You are billed only for the compute time you use, measured in milliseconds.

Disadvantages

  • Limited execution environment: Edge lambdas triggered by onRequest or onResponse events are limited to 128MB of memory and a 5-second maximum execution time.

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 the 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, an Edge Lambda Function validates the Authorization header of each incoming request. If the header is missing or invalid, the user is redirected to a login page.

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
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 the authFunction authorizer.

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

Event structure

The event payload delivered to your function depends on the trigger:

On request trigger

When a function is triggered by an onRequest event, you can either:

  1. Return a response directly from the function: This bypasses the origin and serves the response immediately to the client.
  2. Modify the request and forward it to the origin: You can alter the request (e.g., add headers) before it continues to the origin.

The following example demonstrates both:

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;
};

If the user is authorized, the request is forwarded to the origin. Otherwise, a redirect response is returned.

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 configuration for the authorizer function.

On response trigger

A function triggered by an onResponse event can modify the response from the origin before it's sent to the client. In this example, the function adds a Set-Cookie header to the response:

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 for the function that sets a cookie.

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 configuration for the onResponse trigger.

Packaging

Packaging for Edge Lambda Functions follows the same process as for regular Lambda functions. For more details, see the packaging documentation.

For functions triggered by onRequest or onResponse, the zipped package size cannot exceed 1MB.

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

disabled
retentionDays
Default: 180
logForwarding

Accessing other resources

By default, Edge Lambda Functions cannot access other AWS resources. Permissions must be granted explicitly using IAM. Stacktape automatically handles permissions for essential services like logging.

You can grant additional permissions in two ways:

Using connectTo

The connectTo property simplifies granting access to other Stacktape-managed resources. It automatically configures the necessary IAM permissions and injects environment variables with connection details.

resources:
authFunction:
type: edge-lambda-function
properties:
packaging:
type: stacktape-lambda-buildpack
properties:
entryfilePath: auth-function.ts
connectTo:
# access to the dynamo table
- myDynamoTable
# access to AWS SES
- aws:ses
myDynamoTable:
type: dynamo-db-table
properties:
primaryKey:
partitionKey:
name: id
type: string

By referencing resources (or services) in connectTo list, Stacktape automatically:

  • configures correct compute resource's IAM role permissions if needed
  • sets up correct security group rules to allow access if needed
  • injects relevant environment variables containing information about resource you are connecting to into the compute resource's runtime
    • names of environment variables use upper-snake-case and are in form STP_[RESOURCE_NAME]_[VARIABLE_NAME],
    • examples: STP_MY_DATABASE_CONNECTION_STRING or STP_MY_EVENT_BUS_ARN,
    • list of injected variables for each resource type can be seen below.

Injecting of environment variables does not work for edge lambda functions.

Using connectTo with resources which are protected within VPC does not work, as edge lambda functions are distributed across globe and are not part of VPC.


Granted permissions and injected environment variables are different depending on resource type:


Bucket

  • Permissions:
    • list objects in a bucket
    • create / get / delete / tag object in a bucket
  • Injected env variables: NAME, ARN

DynamoDB table

  • Permissions:
    • get / put / update / delete item in a table
    • scan / query a table
    • describe table stream
  • Injected env variables: NAME, ARN, STREAM_ARN

MongoDB Atlas cluster

  • Permissions:
    • Allows connection to a cluster with accessibilityMode set to scoping-workloads-in-vpc. To learn more about MongoDB Atlas clusters accessibility modes, refer to MongoDB Atlas cluster docs.
    • Creates access "user" associated with compute resource's role to allow for secure credential-less access to the the cluster
  • Injected env variables: CONNECTION_STRING

Relational(SQL) database

  • Permissions:
    • Allows connection to a relational database with accessibilityMode set to scoping-workloads-in-vpc. To learn more about relational database accessibility modes, refer to Relational databases docs.
  • Injected env variables: CONNECTION_STRING, JDBC_CONNECTION_STRING, HOST, PORT (in case of aurora multi instance cluster additionally: READER_CONNECTION_STRING, READER_JDBC_CONNECTION_STRING, READER_HOST)

Redis cluster

  • Permissions:
    • Allows connection to a redis cluster with accessibilityMode set to scoping-workloads-in-vpc. To learn more about redis cluster accessibility modes, refer to Redis clusters docs.
  • Injected env variables: HOST, READER_HOST, PORT

Event bus

  • Permissions:
    • publish events to the specified Event bus
  • Injected env variables: ARN

Function

  • Permissions:
    • invoke the specified function
  • Injected env variables: ARN

Batch job

  • Permissions:
    • submit batch-job instance into batch-job queue
    • list submitted job instances in a batch-job queue
    • describe / terminate a batch-job instance
    • list executions of state machine which executes the batch-job according to its strategy
    • start / terminate execution of a state machine which executes the batch-job according to its strategy
  • Injected env variables: JOB_DEFINITION_ARN, STATE_MACHINE_ARN

User auth pool

  • Permissions:
    • full control over the user pool (cognito-idp:*)
    • for more information about allowed methods refer to AWS docs
  • Injected env variables: ID, CLIENT_ID, ARN

Upstash Kafka topic

  • Injected env variables: TOPIC_NAME, TOPIC_ID, USERNAME, PASSWORD, TCP_ENDPOINT, REST_URL

Upstash Redis

  • Injected env variables: HOST, PORT, PASSWORD, REST_TOKEN, REST_URL, REDIS_URL

aws:ses(Macro)

  • Permissions:
    • gives full permissions to aws ses (ses:*).
    • for more information about allowed methods refer to AWS docs

Using iamRoleStatements

For more granular control, you can provide raw IAM role statements to define custom permissions.

Be mindful of latency when accessing other resources. While your stack is deployed in a specific region, your Edge Lambda may execute in a different edge location across the globe, which can increase the time it takes to communicate with your other resources.

API reference

StpIamRoleStatement  API reference
Resource
Required
Sid
Effect
Action
Condition

Contents