[Node.js] [AWS SDK V3] APIGatewayのIAM認証へSigV4署名ヘッダを作成してリクエストする

2022.09.09

CX事業本部デリバリー部の吉川です。

API GatewayでAPIにIAM認証をかけて、Node.jsでSigV4署名ヘッダを作成してリクエストしてみる | DevelopersIO

上記行う機会があり、AWS SDKのV3で実現するサンプルを書いてみました。

環境

  • node 16.17.0
  • npm 8.18.0
  • typescript 4.8.2
  • @aws-sdk/protocol-http 3.162.0
  • @aws-sdk/signature-v4 3.162.0
  • @aws-sdk/credential-provider-node 3.162.0
  • @aws-crypto/sha256-universal 2.0.2
  • undici 5.10.0

HTTPクライアントにはundiciを使います。

依存パッケージをインストール

npm i @aws-sdk/protocol-http @aws-sdk/signature-v4 @aws-sdk/credential-provider-node @aws-crypto/sha256-universal undici

TypeScriptコード

SignatureV4 is calculating a different signature to AWS, and I don't understand why · Issue #2996 · aws/aws-sdk-js-v3

こちらのIssueやAWS SDKのリファレンスを参考に次のようにコードを書いてみました。

import { HttpRequest } from '@aws-sdk/protocol-http';
import { SignatureV4 } from '@aws-sdk/signature-v4';
import { Sha256 } from '@aws-crypto/sha256-universal';
import { defaultProvider } from '@aws-sdk/credential-provider-node';
import { request } from 'undici';

const main = async () => {
  const apiUrl = new URL('https://XXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/api/');
  const signatureV4 = new SignatureV4({
    service: 'execute-api',
    region: 'ap-northeast-1',
    credentials: defaultProvider(),
    sha256: Sha256,
  });
  const httpRequest = new HttpRequest({
    headers: {
      'content-type': 'application/json',
      host: apiUrl.hostname,
    },
    hostname: apiUrl.hostname,
    method: 'POST',
    path: apiUrl.pathname,
  });

  const signedRequest = await signatureV4.sign(httpRequest);

  console.log({ signedRequest });

  const response = await request(apiUrl.toString(), {
    headers: signedRequest.headers,
    method: 'POST',
  });
  console.log({
    statusCode: response.statusCode,
    body: await response.body.json(),
  });
};

main();

credentials: defaultProvider() の代わりにアクセスキーをそのままセットもできます。

  const signatureV4 = new SignatureV4({
    service: 'execute-api',
    region: 'ap-northeast-1',
-   credentials: defaultProvider(),
+   credentials: {
+     accessKeyId: 'XXXXXXXXX',
+     secretAccessKey: 'XXXXXXXXX',
+   },
    sha256: Sha256,
  });

冒頭のブログと同様に検証用API Gatewayを作成し、esbuild-registerで実行して意図通り動作することを確認しました。

参考