Calling AWS Lambda Function URLs with IAM Auth
In a previous article, I detailed the process of utilizing GitHub Actions and AWS CDK to deploy Python code to AWS Lambda, including the setup of function URLs. However, I encountered a challenge when attempting to call this Lambda function from another application written in Node.js. Despite extensive research, I struggled to find clear, working examples that addressed my specific use case. This led to a day-long journey of trial and error before I finally cracked the code.
One crucial lesson learned during this process was the importance of consistency in request signing: the body used in generating the signature must be identical to the body included in the actual request. This seemingly small detail proved to be a critical factor in successfully calling the Lambda function.
import { SignatureV4 } from '@smithy/signature-v4';
import { Sha256 } from '@aws-crypto/sha256-js';
app.get('/test', async (req, res) => {
const API_URL = 'https://yourLambdaFunctionUrl/gogogo';
const apiUrl = new URL(API_URL);
console.log('apiUrl =>', apiUrl);
const sigv4 = new SignatureV4({
service: 'lambda',
region: 'us-east-1',
credentials: {
accessKeyId: 'YourAccessKeyId',
secretAccessKey: 'YourSecretAccessKey',
},
sha256: Sha256
});
const signed = await sigv4.sign({
method: 'POST',
hostname: apiUrl.hostname,
path: apiUrl.pathname,
protocol: apiUrl.protocol,
headers: {
'Content-Type': 'application/json',
'Host': apiUrl.host
},
body: JSON.stringify({hi: 'hello'})
});
console.log('signed =>', signed);
const requestOptions = {
method: signed.method,
headers: {
'Content-Type': 'application/json',
'X-Amz-Content-Sha256': signed.headers['x-amz-content-sha256'],
'Authorization': signed.headers['authorization'],
'X-Amz-Date': signed.headers['x-amz-date'],
},
// headers: signed.headers,
body: JSON.stringify({hi: 'hello'}),
redirect: 'follow'
};
console.log('requestOptions =>', requestOptions);
const response = await fetch(API_URL, requestOptions);
const body = await response.json();
console.log('body =>', body);
return res.send({
status: 200,
message: body
});
});