概要
APIGatewayのREST APIを使って構築したweb APIをIAM認証(accesskeyとsecretkeyを使った認証)で署名付きのリクエストを送信するサンプル。
参考にさせていただいた記事
- API GatewayでAPIにIAM認証をかけて、Node.jsでSigV4署名ヘッダを作成してリクエストしてみる
- AWS - Lambda function URLs を IAM 署名付きでリクエストしてみる
IAMは対象のLamda関数のARNを指定した、 lambda:InvokeFunctionUrl
のアクションのみを許可したユーザを作成しています。
javascriptとtypescriptのケース両方使うことがあるので、自分用のメモとして参考にさせていただいた記事のコードを少し書き直してます。
実装
javascript
$ npm install --dev aws-sdk axios
const core = require('aws-sdk/lib/core');
const aws = require('aws-sdk');
const axios = require('axios');
// アクセスキーとシークレットアクセスキーを設定
const accessKey = 'xxxxxxx';
const secretKey = 'xxxxxxx';
const credential = new aws.Credentials(accessKey, secretKey);
function main() {
const serviceName = "execute-api";
const url = "https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/";
const options = {
url: url,
headers: {}
};
const parts = options.url.split("?");
const host = parts[0].substr(8, parts[0].indexOf("/", 8) - 8);
const path = parts[0].substr(parts[0].indexOf("/", 8));
const querystring = parts[1];
const data = {
/* payload */
};
const now = new Date();
options.headers.host = host;
options.pathname = () => path;
options.methodIndex = 'post';
options.search = () => querystring ? querystring : "";
options.region = 'ap-northeast-1';
options.method = 'POST';
options.body = JSON.stringify(data);
const signer = new core.Signers.V4(options, serviceName);
signer.addAuthorization(credential, now);
axios.post(url, data, options).then((r) => {
console.log(r);
}).catch((e) => {
console.error("failed to request: ", e.response.status, e.code, e.response.data);
});
}
main();
Typescript
import axios from 'axios'
import { Credentials } from 'aws-sdk'
import { SignatureV4 } from '@aws-sdk/signature-v4'
import { Sha256 } from '@aws-crypto/sha256-js'
import { HttpRequest } from '@aws-sdk/protocol-http'
const main = async () => {
const accessKey = 'xxxxxxxxx'
const secretKey = 'xxxxxxxxx'
const creds = new Credentials(accessKey, secretKey)
const serviceName = 'execute-api'
const url =
'https://xxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/'
const parts = url.split('?')
const host = parts[0].substr(8, parts[0].indexOf('/', 8) - 8)
const path = parts[0].substr(parts[0].indexOf('/', 8))
const data = {
/* payload */
}
const req = new HttpRequest({
headers: {},
hostname: host,
method: 'POST',
path: path,
})
const signer = new SignatureV4({
credentials: creds,
region: 'ap-northeast-1',
service: serviceName,
sha256: Sha256,
})
const signedHttpRequest = await signer.sign(req)
try {
const r = await axios.post(url, data, signedHttpRequest)
console.log(r)
} catch (e: any) {
console.error(e)
}
}
main()