LoginSignup
4
5

More than 5 years have passed since last update.

AWS_IAM認証つきのAPIGatewayにAWS署名付きのリクエストを送る

Posted at

AWS APIGatewayはIAMでアクセスコントロールをすることができます。
apigateway.png

AWS_IAMを設定したAPIGatewayのエンドポイントにはAWS署名バージョン4の仕様に沿ったAuthorizationヘッダを付加してリクエストする必要があります。
ところがこの署名を生成するプロセスって結構面倒なのですよね。そんなものAWSSDKで用意されているのだろうと思いきや、

これ、privateやん…というところが動機でした。

npm request が AWS署名をサポートしていた

node.jsにはメジャーなHTTPClientライブラリとして、requestというnpmモジュールがあります。こいつのREADMEをよく眺めてみると、

  • aws - object containing AWS signing information. Should have the properties key, secret. Also requires the property bucket, unless you’re specifying your bucket as part of the path, or the request doesn’t use a bucket (i.e. GET Services). If you want to use AWS sign version 4 use the parameter sign_version with value 4 otherwise the default is version 2. Note: you need to npm install aws4 first.

サポートしているではありませんか。

"use strict"

const co = require("co");
const request = require("request-promise-native");
const AWS = require("aws-sdk");

co(function*(){
  const cred = yield getCredential();
  console.log(cred.accessKeyId, cred.secretAccessKey, cred.sessionToken);
  return yield request({
    uri: " https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/trial/getinfo/1234",
    aws: {
      sign_version: 4,
      key: cred.accessKeyId,
      secret: cred.secretAccessKey,
    }
  })
}).then(console.log).catch(console.error);

function getCredential() {
  const credChain = new AWS.CredentialProviderChain();
  return new Promise((resolve, reject) => {
    credChain.resolve((err, creds) => {
      if(err) {
        reject(err);
      } else {
        resolve(creds);
      }
    })
  })
}

こんなので無事リクエストが受け入れられ、レスポンスが返ってきました。
サンプルソースはPromise,co,function*,yieldをガシガシ使っており、Node.js 4.x前提です。

ちなみに、署名をつけていないと、

[StatusCodeError: 403 - "{\"message\":\"Missing Authentication Token\"}"]

署名が間違っていると、

[StatusCodeError: 403 - "{\"message\":\"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.

こんな感じのエラーになります。

しかし、少し不都合がある

二点困ったことがありました。

  1. APIGatewayにカスタムドメインを設定しているケースではエラーになる
  2. IAMロールでAPIのInvokeができるように設定したEC2インスタンスからの実行するケースではエラーになる

困ったのでプルリクエスト投げました。
https://github.com/request/request/pull/2339

上記がマージされるまではnpm install newgyu/requestでnpmモジュールをインストールすると上記の問題に対処できます。

"use strict"

const co = require("co");
const request = require("request-promise-native");
const AWS = require("aws-sdk");

co(function*(){
  const cred = yield getCredential();
  console.log(cred.accessKeyId, cred.secretAccessKey, cred.sessionToken);
  return yield request({
    uri: "https://api.newgyu.xyz/trial/getinfo/1234",
    aws: {
      sign_version: 4,
      key: cred.accessKeyId,
      secret: cred.secretAccessKey,
      //トークンの指定
      sessionToken: cred.sessionToken,
      //service,regionの指定
      service: "execute-api",    //APIGatewayの場合にはexecute-apiを指定する
      region: "ap-northeast-1"
    }
  })
}).then(console.log).catch(console.error);

function getCredential() {
  const credChain = new AWS.CredentialProviderChain();
  return new Promise((resolve, reject) => {
    credChain.resolve((err, creds) => {
      if(err) {
        reject(err);
      } else {
        resolve(creds);
      }
    })
  })
}
4
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5