simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

AWS:はじめてのAPI Gateway⇄Lambda

概要

前回の Lambda と ElastiCache は VPC 内に引きこもるため(そういうセキュリティグループに配置したので)、インターネットからアクセスすることはできません。
simplestar-tech.hatenablog.com
API Gateway からトークン認証付きで Lambda を呼べるようにして、高速かつ安全に ElastiCache 操作をインターネットから実現してみます。

API Gateway を作る

適当な REST API を作成すると、アクションメニューからリソース or メソッドを作成できるようになります。

f:id:simplestar_tech:20190916211231p:plain
アクションでリソースとメソッド作成を選択

リソースは階層を形成し、メソッドは HTTP メソッドに対応し GET や POST, PUT を意味します。
今回はリソースに cubewalkblocks を追加し、そこに GET メソッドを追加しました。GET メソッドを選択すると次のデザイナー表示が確認できます。

f:id:simplestar_tech:20190916211742p:plain
API Gateway のデザイナー
いや、もうすでに色々いじってしまっていますが…

Authorizer 機能を持つ Lambda を作る

目的は公開する API ですから、秘密の文字列を知る者だけが呼び出し可能となるようにするためです。
手順はこちら
docs.aws.amazon.com

Lambda を作ったら、その後は API Gateway の「オーソライザー」にて新しく Authorizer を作ります。

f:id:simplestar_tech:20190916224738p:plain
Authorizer の作成(Lambdaを選ぶ)
ここで注意したいのが Lambda を呼べるように API Gateway を許可すること
新規作成時に許可ダイアログが出るからいいけど、既存のものをコピーすると気づかず、API 呼び出しにてサーバー内エラー 500 ステータスコードが返るから気をつけて(ハマった)

ここでトークンのソースを token としているので、リクエストヘッダーには token を入れないといけなくなります。
また、正規表現でチェックしているので、まずはこれに引っかからない者は、Lambda 呼び出し前に弾かれることになります。(攻撃されてもお金かからなくて良い)
ここで指定した token の値が Lambda の var token = event.authorizationToken; の値として手に入るというワケ
いろいろと繋がりましたでしょうか?

作った Authorizer を次の通り API のメソッドリクエストから選べれば OK

f:id:simplestar_tech:20190916212558p:plain
Authorizer の選択

API Gateway と Lambda との接続

メソッドの実行を開いて、Lambda を選ぶだけで OK

f:id:simplestar_tech:20190916225600p:plain
統合
権限付与する話を進めれば、このとおり Lambda の方も勝手に API Gateway とつながったことになります。
f:id:simplestar_tech:20190916225737p:plain
API Gateway と Lambda の接続

Lambda 側の注意点として、レスポンスは status code 200 の json とすること
今回は python 実装だったので、こんな感じ

    return { "statusCode": 200, "body": "\"\"" }

理由は統合レスポンスを「パススルー」に設定しているから

f:id:simplestar_tech:20190916230028p:plain
統合レスポンスの設定
これで Lambda の戻り値をそのまま、呼び出し元に与えることができます。

デプロイ

ずっと作ってきた API ですが、デプロイしない限りは外部から呼び出すことができません。
アクション > API のデプロイ を選択してデプロイします。
デプロイ先は prod にするのが一般的みたい

デプロイに成功すると url が確定します。

f:id:simplestar_tech:20190916230341p:plain
url の確認

curl で呼び出しテスト

curlコマンドラインで http 通信を試せるツールですが(色々な環境にインストール可能なもので、 Windows なら git for windows 入れたら git bash のコンソールから叩ける)
さて、Authorizer の Lambda の実装に依存しますが、ここまで作ってきた API を外部から呼び出すと次の通り

$ curl -X GET -H 'token:cubewalk-allow' https://xxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/cubewalkblocks -v
{ [35 bytes data]
100    35  100    35    0     0     39      0 --:--:-- --:--:-- --:--:--    39{"statusCode": 200, "body": "\"\""}

OK

ちなみに token を間違えると。。。

$ curl -X GET -H 'token:arere' https://xxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/cubewalkblocks -v
{ [26 bytes data]
100    26  100    26    0     0    101      0 --:--:-- --:--:-- --:--:--   101{"message":"Unauthorized"}

こんな感じで、認証エラーのメッセージが返ってきます。

まとめ

REST APIAPI Gateway から作るまでは簡単
・Authorizer の Lambda も手順通りなら作れるがAPI Gateway にて Authorizer を作り切るところまでが覚えゲートークンソースと Authorizer Lambda実装がつながればこっちのもの)
・Lambda 呼び出し権限の付与には注意(特に既存の API をコピーしたときは)
・レスポンスをパススルーするなら json で statusCode 200 も返すこと
・デプロイして初めて外部から呼び出せる API の url が確定する

ひとまずこれで、認証付き API から Lambda が呼び出せるようになりました。
前の記事で Lambda から ElastiCache の Redis の get/set してましたけど、今回の API Gateway からつないで実行することができました。