新プログラミング言語『Zero』を開発しました! 本サイトの記事数は「589」!!

API GatewayのIAM認証をTypeScriptで通過する方法!※Angular編

             
  • 2020.04.26
  • AWS
API GatewayのIAM認証をTypeScriptで通過する方法!※Angular編
Advertisement

 

久々に頭を悩ませた。。

まじで死にかけた。。

AWSの公式が死ぬほど分かりにくくて発狂した。

あと情報少なすぎて死にかけた。

皆やらないの?

API GatewayのIAM認証なんて普通にやるでしょ?

皆ガバガバセキュリティでやってんの?

 

ってことで今回は、API GatewayのIAM認証をTypeScriptで通過する方法を解説します。

ちなみにフレームワークは「Angular」でやります。

 

僕のプロフィールはこちら

 

 

まずAPI Gatewayって何?

ググれ。

 

 

API GatewayのIAM認証って?

API Gatewayには認証を設定できます。

認証を付けないと誰でもAPIを実行できるので、当然認証を付けるわけです。

で、認証には有名どころだと「Cognitoのオーソライザー」「AWS_IAM」などがあります。

 

Cognitoのオーソライザー

Cognitoの説明は割愛するとして、要はCognitoから発行されるIDトークンをリクエストヘッダに載せることで認証を通過できます

Cognitoを使用しているフロントが良く使う認証です。

 

AWS_IAM

そのままですが、AWSのIAM認証を設定できます。

AWS_IAMの認証を通過するには、署名を作成し、その署名をリクエストヘッダに載せてリクエストを実行する必要があります。

要は、署名を作成する必要があるってことです。

どうやら、リクエストに載せた署名と同じ作成手順をAWS側が行い、署名が正しいかどうかを検証しているようです。

 

 

署名はどうやって作る?

さて、ここからは僕のストーリーのお話。

まずは、必殺奥義「ググる」を繰り出して、分かりやすいサイトがないかを調べてみました。

色々調べてみると、何通りか方法があるようです。

・ライブラリを使用して署名を作成する

・API GatewayのSDK出力機能から出力されたソースを使用する

・署名作成処理を自作する

 

ライブラリを使用して署名を作成する

Angularの話、というかnode_modulesの話、というかnpmの話、になるのかな?

まあ、署名処理をよろしくやってくれるライブラリを2つほど見つけました。

aws4」と「aws-sdk/lib/coreのSigners.V4クラス」です。

が、結論どっちもうまくいきませんでした。

「aws-sdk/lib/coreのSigners.V4クラス」に関してはうまくいかなかった理由がはっきりしないのですが、とりあえずイライラしすぎたのでやめました。

「aws4」に至ってはライブラリ使おうとしたらエラー出ました。

イライラが爆発して禿げそうだったのでライブラリを使用するやり方は撤退しました

 

API GatewayのSDK出力機能から出力されたソースを使用する

これは正直論外です

API GatewayはSDKというファイル群を出力でき、これを使えば面倒な署名処理をやってくれるんですが、実はこれAPI Gatewayの設定に依存したソースコードです。

一部だけなので問題ないっちゃないんですが、厄介なのはAPI Gatewayの設定を変えたらソースも置きなおす必要があることです。

また、フロントから叩くAPI Gatewayが複数あった場合、両方のAPI GatewayからSDKを出力する必要があります。

何よりファイル名おんなじっす。

ってことで、これはイケてないってことで却下

ただ、SDKのソースコードは便利なので重宝しました。

というのも、このソースコードを使えば署名処理をしなくていいということは、このソースコードのどこかに署名処理を行っている箇所があるってことです。

知る必要がないので割愛しますが、まあ中のソースコードを貪りましたよ、ほんとに。

 

 

SDKの生成

ちなみに↑からSDKのソースコードを生成できます。

 

署名作成処理を自作する

一番大変そうですが、結果これでやりました。

これができれば、何かに依存することがなくなるのでベストです。

っていうのは分かっていたのですが、極力やりたくなかったんです。

なぜかって?

AWSの公式がクソ分かりくいからじゃーーーーーー。

 

(おまけ)世の中の記事について

色々と調べると、まあやりたいことに近しいサイトがそれなりにはありました。

ただ、SDKを利用したやり方とか、これから説明する認証情報取得のやり方をハショッたやり方とか、「え?そこ知りたいんだけど?」っていう部分が書かれていないものが多かったです。

SDKを使うやり方とか現実的じゃないし、署名作成処理も重要ですが、認証情報の取り方とかって結構知りたい部分なんですけどね。

アクセスキー・シークレットキーをべた書きしているソースコードとかもありましたが、ベストプラクティスに反してるし、誰がそんなやり方するねんって感じですよ、ほんと。

まあただの愚痴ですよ、ほんとに。

 

 

まずはAPI Gatewayを作りましょ

さて、ここから実際に作業していきます。

まずはAPI Gatewayを作りますが、詳細については以下を見てくださいまし。

※わざわざLambdaとかは作らなくてもいいです。
認証の通過を確認したいだけなのでMockで十分です。

 

 

API GatewayにAWS_IAM認証を付ける

さて、先ほどの手順で「APIを実行するとレスポンスが返却される」ところまでは確認しました。

次は、AWS_IAM認証を付けて、「APIがエラーを返す」ところまでを確認します。

 

 

AWS_IAM認証付与

リソース」から任意のメソッドを選択し、「メソッドリクエスト」をクリックします。

認可を「なし」から「AWS_IAM」に変更します。

変更したら「APIのデプロイ」は忘れないように。

 

 

APIをAWS_IAMが付いた状態で実行してみる

AWS_IAM認証を付けたので再度APIを実行してみます。

 

 

403エラー

ちゃんとエラーが返ってきますね。

ちなみに、APIのデプロイ後、反映されるのに数秒かかるので少し待ってから実行してください。

認証エラーは基本的に「403」エラーです。

リクエストヘッダに何も載せずに実行した場合は「{“message”: “Missing Authentication Token” }」というレスポンスが返却されます。

 

 

話は変わって認証(STS)の話をするよ

急に認証の話になって恐縮ですが、API Gatewayの設定以外にもやることがあります。

署名のソースコードを書いていくと分かるんですが、署名作成には認証情報(というか権限)が必要です。

AWSでは一時的な認証情報を「STS」と呼びます。
STSというサービスがあるわけではないので注意。

 

Angularの場合の認証情報

例えば、AngularであればS3にビルドした静的ファイルをデプロイすると思います。

Angularアプリから先ほど作成した認証付きAPI Gatewayへのアクセスが権限的に許可されていないと、そもそもAPIの実行ができません、というか署名が作成できないです。

つまり、AngularアプリはAPIを実行するためのパワーが必要ってことです。

 

CognitoのIDプールから一時的な権限を払い出してもらう

S3の話になりますが、S3にデプロイされたアプリに対して一時的な権限を払い出す方法として「CognitoのIDプール」を利用する方法があります。

CognitoのIDプールから払い出された認証情報を元に署名を作成し、APIを実行するという流れになります。

また、払い出される認証情報には「API Gatewayの実行権限」が付いている必要がありますが、ここは実際にやっていけば理解できるので今は気にしなくていいです。

 

(おまけ)他サービスの認証情報取得方法

S3の場合は先ほどお話しした通り、「CognitoのIDプール」を利用する方法が多いかと思います。

他のサービスでは以下のようになります。

・EC2:EC2に付与されているIAMロールから認証情報を取得する(IAMロールに適切なポリシーがアタッチされている前提)

・Lambda:予約環境変数からキー情報を取得する

 

 

CognitoのIDプールを作成する

ってことで、CognitoのIDプールを作成します。

 

 

IDプール

IDプールの管理」をクリックします。

 

 

新しいIDプール

新しいIDプールの作成」から、上記のように設定します。

IDプール名」は何でもいいですが、注意点として「認証されていない ID に対してアクセスを有効にする」には必ずチェックを入れてください。

今回は未認証のユーザに対して権限を払い出すためです。

 

 

IDプールのIAM

作成するとIAMの画面に遷移するので、そのまま「許可」をクリックします。

これでIDプールの作成は完了です。

 

 

IDプールの未認証IAMロールにポリシーをアタッチする

IDプールは作成できましたが、これだけでは設定が不十分です。

今回は未認証のユーザに対して「API Gatewayの実行権限が付与された認証情報」を払い出す必要があるためです。

 

 

API GatewayのARN

ってことで、IAMロールをいじりたいんですが、その前に作成したAPI GatewayのARNをメモしておいてください。

 

 

Cognito_testUnauth_Role

IAMの画面を開き、「ロール」をクリックすると、先ほどIDプール作成時に作られた未認証ユーザのIAMロールがあるはずなのでこれをクリックします。

僕の場合だと「Cognito_testUnauth_Role」です。

 

 

インラインポリシーの追加

インラインポリシーの追加」をクリックします。

 

 

サービス・アクション

サービスは「Execute API」、アクションは「Invoke」です。

 

 

ARNの追加

リソースですが、「ARNの追加」をクリックすると上記のような入力画面が出てくるので、ここに先ほどメモしたARNを貼り付けます。

上記のように設定できればOKなので、「追加」をクリック後、「ポリシーの確認」を押します。

 

 

ポリシーの確認

ポリシー名は適当ですが、分かりやすい名前を付けることをおススメします。

ポリシーの作成」をクリックし、すべて完了です。

 

 

Angularで署名作成処理を実装していく前に

ようやく本題です。

まず、AWSのクソ素晴らしい公式サイトを見てみましょう。

 

↑に記載のタスク1~4を実装する必要があります。

パッと見て「できそう!!」って思った方は天才なので、本記事を見る必要すらありません。

 

署名バージョン4とは?

元々署名バージョンは1から始まったみたいですが、現在の最新は「バージョン4」になります。

2と4が有名みたいですが、推奨はバージョン4なので4で署名を作成する必要があります

バージョンが上がるごとに複雑になっているみたいですが、言い換えるとセキュリティ的な面で向上しているとも言えます。

 

 

Advertisement

 

Angularで署名作成処理を実装

公式を見てもらってもいいですが、面倒だしクソファッキン分かりにくいので、別に見てもらわなくてもいいです。

 

実装部分以外の下準備

実装部分を載せる前に、処理の呼び出し元であったりのソースコードを載せておきます。

 

↑は呼び出し元のソース(の一部)です。

適当ですが、まあAPI叩けりゃ何でもいいっす。

 

 

httpService.ts」です。

僕はサービス化するのが好きなんですが、これも好みでOKです。

 

apig-sig-v4.service.ts

さて、下準備は終わったので、署名処理を担うサービスを作ります。

 

どや!!

解説したいところですが、説明はすべてAWSの公式に載っているので割愛!!

このサービスを「app.module.ts」などに読み込ませるのを忘れないように!

 

 

再度APIを実行してみる

APIを実行してみると、、、

 

再度APIを実行してみる

来た!!

403エラーは出ず、APIのレスポンスが正しく返却されてます。

これが表示するまでに3日かかりました。

 

 

まとめ

久々に頭を悩ませました。

AWSの公式にはPythonのサンプルコードはあるんですが、他の言語の方がニーズあると思うんですが。。

そもそもAPIを実行するのはフロントだし、サーバ側でやるにしてもPHPとかじゃない?

API GatewayのSDK出力機能がなかったら絶対できてなかった、難易度高すぎ。

さいなら。

Travelerを知らないの?