S3 Request Signing Example

Overview

This example demonstrates how to sign requests to an S3 origin using AWS v4 signature algorithm.

This is a simple example of an HTML file stored on Amazon S3. The file is served by an edge function that signs the request using AWS v4 signature algorithm.

Router Configuration

The router handles incoming requests. Requests to the /s3/* path are forwarded to an edge function for processing.

// This file was added by edgio init.
// You should commit this file to source control.
import { Router, edgioRoutes } from '@edgio/core';

export default new Router()
  // Built-in Edgio routes
  .use(edgioRoutes)

  // Specifies the edge function for /s3/* paths
  .get('/s3/:anything*', {
    edge_function: './edge-functions/main.js',
  })

  // Serves the main.html file for the root path
  .get('/', ({ serveStatic }) => serveStatic('public/main.html'));
    

Edge Function

The edge function makes an authenticated request to S3, removing the /s3 prefix and using AWS v4 signature algorithm for signing.

import { AwsV4Signer } from './lib/awsv4';

/**
 * This edge function signs an S3 request using the AWS v4 signature algorithm
 * and forwards the request to the S3 origin. Authentication credentials are
 * read from environment variables set in the Edgio Console.
 */
export async function handleHttpRequest(request, context) {
  const { S3_HOSTNAME, S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY } = context.environmentVars;

  const initialUrl = new URL(request.url);

  // Remove the /s3 prefix from the path before signing since we only
  // want to sign the path relative to the bucket.
  const s3Path = initialUrl.pathname.replace(/^\/s3/, '');
  const s3Url = new URL(s3Path, `https://${S3_HOSTNAME}`);

  const signer = new AwsV4Signer({
    url: s3Url.href,
    method: request.method,
    region: S3_REGION,
    service: 's3',
    accessKeyId: S3_ACCESS_KEY_ID,
    secretAccessKey: S3_SECRET_ACCESS_KEY,
    signQuery: true,
  });

  const signedDetails = await signer.sign();

  return fetch(signedDetails.url, {
    method: signedDetails.method,
    headers: signedDetails.headers,
    edgio: {
      origin: 's3',
    },
  });
}
    

Environment Variables

Environment variables are critical for the edge function to authenticate and sign requests correctly.

When running the project locally, these variables can be defined in a .env file or directly in the environment. For deployment on Edgio, these should be set in the Edgio Console.