Serverless Framework + API Gatewayのアプリケーションに認可を追加する
しばらく合同勉強会の資料準備とシュバルツバース探索など優先順位が高いタスクが積まれていて、手をつけておりませんでしたが、ようやく再開。今回は完全に備忘録的なレベルです。
で、今回は、表題の通り認可を追加してみたいと思います。今回仮で組んだものとは違いますが、最終的な構成のイメージとしては以下の様な感じ。
- 認証のプロバイダはアプリケーション外
- アプリケーションは認証されていることを前提に個別に認可
つまり、アプリケーションは「その人が本人であること」を確認する責任をおいませんが、「その人がアプリケーションを使う権限をもつこと」を確認する責任はおいます。これが、Serverless SPAであればアプリケーション内に認証プロバイダを持ってもいいと思います。用途次第ということで。
いつもの如く、具体的なコードはこちらのリポジトリをご査収ください。
CognitoでUserPoolをつくる
とは言え、いくつもサービスが乱立してしまうのもまだ面倒いので、とりあえず認証プロバイダはアプリケーションのリソースに突っ込んで設定、アプリケーションのデプロイと同様にUserPoolもデプロイされる様にしました。認証プロバイダの切り離しはまたあとでやってみたいと思います。肥大しがちなserverless.ymlの分割とかも、プロジェクトのファイル構成の観点からやってみときたいし。
この記事を参考にしました。特に問題なくデプロイまで出来ます。その前にAWS Glueの検証してたのをすっかり忘れてて、違うリージョンみながら「デプロイされねーな」とか思ってた無駄な時間があったくらいです。
なお、記事にはクライアント側が書かれていませんが、私はクライアントのページを用意するのも面倒いので(フロントエンド苦手)、認証用のLambda関数を追加で作りました。sign_upとconfirmとsign_inとrefresh_tokenができる様にしあります。認可という観点でいうと、トークンがあれば作れるはずなので、このあたりがちょっと雑なのは否めません。
ただ、boto3での認証をどのAPIを使えばいいのかいまいちよくわからなかったので、すこしググりました。で、参考にしたのはイカです。Pythonの場合はクライアントサイドで動く訳ではないので、admin_initiate_authを使う、という解釈ですが、あってるのかな?
閑話:UserPool IDについて
認証系のLambda関数から読み出している COGNITO_POOL_CLIENT_ID
は作成したUserPoolのIDで、このサンプルを使う場合はデプロイ後に設定しておいてあげる必要があります。その意味で面倒な構成にはなっているのですが、認可の部分のコードをみていただければ分かる通り、認可に必要なのはトークンのみです。そのため、実際に認証プロバイダを切り離して構成する場合にはこのあたりの面倒くささはなくなるとおもいます。
閑話休題:認可を追加する
で、認可。認可ロジックをLambda関数として実装して、対象となるLambda関数のhttpイベントに authorizer
を追加すればいいだけでした。
認可ロジックでは、トークンからユーザ情報にアクセスできるか確認して、エラーがなければ対象となるLambda関数に実行権限を与えるためのJSONオブジェクトを返しています。このJSONオブジェクトをうけてAPI Gatewayがよしなにしてくれる模様。
実行する
認証プロバイダから彫られた認証済みトークンを Authorization
ヘッダに渡して、API GatewayのURLを叩くだけです。
curl -H "Authorization: xxx" -d '{"event": "今日はカポエイラに行く", "insight": "首が少し痛いので心配"}' -X POST https://xxxx.execute-api.ap-northeast-1.amazonaws.com/dev/my-assistant/life_log
Authorization
ヘッダがない場合は以下のエラーメッセージが返ります。
{"message":"Unauthorized"}
ちなみに、この認可はAPI Gatewayを通る場合に有効です。認可対象のLambda関数を直接実行する場合( sls invoke
コマンドなど)は、認可なしに実行可能となっています。
まとめ
Serverless FrameworkもAPI Gatewayもかなりよしなにしてくれるので、認証・認可周りは非常に楽に開始できるな、と感じました。まあ、認証基盤はそれだけで一大プロジェクトになる要素を持っているのですが、そこまで突っ込んでやるのが目的ではないですし。今回検証したかったことは認可の追加が楽かどうか、という観点なので、その点では知りたいことを確認できた感じです。