Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jbg/781792a2ecf2068c24c5ec7cf971a8e4 to your computer and use it in GitHub Desktop.
Save jbg/781792a2ecf2068c24c5ec7cf971a8e4 to your computer and use it in GitHub Desktop.
A Lambda@Edge function that signs the origin request with SigV4A, allowing the use of an S3 Multi-Region Access Point as a custom origin
import { CrtSignerV4 } from "@aws-sdk/signature-v4-crt";
const allowedHeaders = [
"accept-encoding",
"content-length",
"if-modified-since",
"if-none-match",
"if-range",
"if-unmodified-since",
"transfer-encoding",
"via",
];
const signer = new CrtSignerV4({
credentials: {
accessKeyId: process.env["AWS_ACCESS_KEY_ID"],
secretAccessKey: process.env["AWS_SECRET_ACCESS_KEY"],
sessionToken: process.env["AWS_SESSION_TOKEN"],
},
region: "*",
service: "s3",
signingAlgorithm: 1, // SigV4Asymmetric
});
export const handler = async (event) => {
const request = event.Records[0].cf.request;
const originHostname = request.origin.custom.domainName;
// Allow failover: if the origin is not a MRAP, skip SigV4A signing.
if (!originHostname.endsWith(".mrap.accesspoint.s3-global.amazonaws.com")) {
return request;
}
// X-Amz-Cf-Id will be added to the origin request after this function finishes.
// Therefore, we have to include it in the signature in order for the signature
// to verify successfully at the origin. However, we have to remove it from the
// headers we return below, as we're not allowed to set this header.
const cfRequestId = event.Records[0].cf.config.requestId;
const headersToSign = {
"Host": originHostname,
"X-Amz-Cf-Id": cfRequestId,
};
for (const key of allowedHeaders) {
if (key in request.headers) {
const header = request.headers[key][0];
headersToSign[header.key] = header.value;
}
}
const signedRequest = await signer.sign({
method: request.method,
protocol: "https",
hostname: originHostname,
path: request.uri,
headers: headersToSign,
});
const signedHeaders = {};
for (const [key, value] of Object.entries(signedRequest.headers)) {
if (key != "X-Amz-Cf-Id") {
signedHeaders[key.toLowerCase()] = [{key, value}];
}
}
request.headers = signedHeaders;
// We ignore the query string. If you choose to pass it through, add it to
// the signer.sign() call above.
delete request.querystring;
return request;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment