こんにちは。中山です。
いろいろ便利な世の中になったもので、ちょっと REST API を作りたいなぁと思ったら、AWS の API Gateway や Lambda のサービスを使って、パパーっと提供することができるようになりました。
一方でこの REST API を、しっかりしたセキュリティのもとで提供してほしい、というのはよくある話です。
こういう場合の対策として、たとえばこの API Gateway へのリクエストの際に、AWS の IAM 認証が必要となるように設定しておき、「IAM の認証情報(アクセスキー、シークレットキー)を知っている人だけが API にアクセスできるようにする」、という方法があります。
しかしこの IAM 認証付きの API Gateway というもの、設定してから実際に呼び出すまで、意外といろいろな手順がありましたので、ここにその記録を残しておきたいと思います。
REST API を新規作成する
REST API の新規作成
まずは API Gateway を用いて、REST API を新しく作成します。
「Amazon API Gateway」のコンソールページを開いて、「API タイプを選択」のところから「REST API」を選んで、その「構築」ボタンをクリックします。
次に表示されたページの、「プロトコルを選択する」の部分では「REST」をチェック、「新しい API の作成」は「新しい API」をチェックします。
「名前と説明」欄には、任意の API 名、説明を入力します。「エンドポイントタイプ」は「リージョン」とします。
これらを選択・入力したのち、「API の作成」をクリックします。
API にメソッドを追加
API の「枠」が作成できたところで、その API に「メソッド」を追加します。
「アクション」から「メソッドの作成」を選択します。
今回は「GET」メソッドを追加します。
ドロップダウンリストの中から「GET」を選択し、更新アイコン(チェックマークのアイコン)をクリックします。
GET メソッドの設定
追加した「GET」メソッドのセットアップのページで「統合タイプ」を設定します。
本来はここで「Lambda 関数」などを選択することになると思いますが、今回は検証用として「Mock」を選択します。
※ Lambda 関数を指定して、API を構築する手順については、以下のページなどをご参照ください。
「統合タイプ」を選択したのち、「保存」をクリックします。
メソッドリクエストの認可の設定
「GET」メソッド追加後、以下のようなページが表示されますので、その中の「メソッドリクエスト」をクリックします。
表示された「GET メソッドリクエスト」の設定ページで「認可」の部分の編集アイコン(鉛筆マークのアイコン)をクリックします。
表示されたドロップダウンリストの中から「AWS IAM」を選択します。(選択後、更新アイコン(チェックマークのアイコン)をクリックして変更を確定します。)
API のデプロイ
作成した API をデプロイします。
「アクション」から「API のデプロイ」を選択します。
「デプロイされるステージ」は「新しいステージ」、「ステージ名」は、今回は「test」とし、「ステージの説明」「デプロイメントの説明」には任意の説明文を入力します。選択・入力完了後、「デプロイ」をクリックします。
(ステージ名:「test」としたことで、この API にアクセスする URL のパスは「/test」となるようです。)
API のアクセス URL の確認
「ステージ」のページで、作成した API へアクセスする URL を確認します。
「URL の呼び出し」欄に、アクセス URL が表示されます。
のちほど、この URL に実際にアクセスして、API にリクエストしますので、コピーして保管しておきます。
IAM ユーザ・グループの作成
IAM グループの作成
次に、API Gateway の実行権限を持つ IAM グループを新規に作成します。
AWS の「IAM」コンソールページに移動して、「ユーザーグループ」ページから「グループを作成」をクリックします。
グループの設定
「ユーザーグループ名」に、任意の名称を入力します。
「ユーザーをグループに追加」はここでは行わず、その下の「アクセス許可ポリシーをアタッチ」の部分を編集します。
検索欄に「 APIGateway」などと入力し、表示されたリストの中から「AmazonAPIGatewayInvokeFullAccess」にチェックをつけて「グループを作成」をクリックします。
IAM ユーザの作成
続いて、「IAM」コンソールページの、「ユーザー」ページから「ユーザーを追加」をクリックします。
ユーザの設定(AWS 認証情報タイプの選択)
「ユーザー名」に任意のユーザー名を入力します。
「AWS 認証情報タイプの選択」の部分では、「アクセスキー - プログラムによるアクセス」にチェックをつけます。
入力・選択ののち、「次のステップ」をクリックします。
ユーザの設定(アクセス許可の設定)
「アクセス許可の設定」の部分で、「ユーザーをグループに追加」を選択します。
「ユーザーをグループに追加」の下のリストから、先ほど作成したグループ(今回は「api-test-group」)にチェックをつけ、「次のステップ」をクリックします。
ユーザを「api-test-group」に所属させることで、このユーザが API Gateway の実行権限を持つことになります。
ユーザの設定(タグの追加)
「タグの追加」は、そのまま何もせず「次のステップ」をクリックします。
ユーザの設定(設定内容の確認)
設定内容が想定どおりであることを確認して、「ユーザーの作成」をクリックします。
アクセスキーとシークレットキーの保存
ユーザーが作成され、そのユーザーに関連づけられるアクセスキーとシークレットキーが発行されます。
「.csv のダウンロード」ボタンをクリックして、発行されたアクセスキーとシークレットキーの情報をファイルとして保管します。
Postman からのリクエスト
Postman ツールから認証情報なしでリクエスト
Postman ツールを使って、まずはそのまま、先ほど保管した API の URL にリクエストしてみます。
この状態では、認証のための情報を何もリクエストに含めていないため、403(Forbidden)レスポンスが返されます。
Postman ツールから認証情報付きでリクエスト
再度 Postman ツールを使って、API にリクエストを行います。
今度は以下のように、発行したアクセスキー、シークレットキーの値を、認証情報としていっしょに渡してリクエストします。
具体的には、Postman ツールの「Authorization」タブのところで、以下のように設定します。
- TYPE: AWS Signature
- AccessKey: 発行したアクセスキーの値
- SecretKey: 発行したシークレットキーの値
- AWS Region: API が稼働しているリージョン情報。今回の場合は「ap-northeast-1」
これにより、正しく認証が行われ、無事に、API から 200(OK)レスポンスが返ってくることが確認できました。
Python スクリプトからのリクエスト
Postman ツールを使わずに API にリクエストする
Postman ツールに、アクセスキー、シークレットキーを指定することで、IAM 認証付きの REST API にリクエストし、結果を取得することができました。
しかしこのアクセスキー、シークレットキーをそのままリクエストヘッダなどに渡しているわけではありません。
これらの値を元に、毎回、動的に認証情報を生成し、それをリクエストしている、という仕組みです。(具体的には Signature Version 4 (SigV4) によるリクエストを行う、ということになります。Postman が、このあたりの認証情報生成を、うまいことやってくれている、というわけです。)
したがって、この IAM 認証付きの REST API に、Postman などのツールを使わずにリクエストする場合は、自分でこの認証情報を作成する必要があります。
今回は、Python でこの認証情報生成の仕組みを実装し、その Python スクリプトから、IAM 認証付きの REST API にリクエストしてみたいと思います。
必要なライブラリのインストール
今回、Python はバージョン 3.9 を利用しています。
まず、requests ライブラリを(まだインストールしてなければ)インストールします。
pip install requests
次に、Signature Version 4 (SigV4) によるリクエストを簡単に構築してくれるライブラリとして、今回は aws-requests-auth というライブラリを利用します。
このライブラリも同様にインストールします。
pip install aws-requests-auth
スクリプトの作成
以下のようなスクリプト「request_api.py」を作成します。
import requests from aws_requests_auth.aws_auth import AWSRequestsAuth # アクセスキー access_key = 'AKIAxxxxxxxx' # シークレットキー secret_key = 'wnWyxxxxxxxxxxxx' # リージョン region = 'ap-northeast-1' # ホスト名 hostname = 'xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com' # API の URL パス api_path = '/test' def request_api(): # 認証情報を生成 auth = AWSRequestsAuth(aws_access_key=access_key, aws_secret_access_key=secret_key, aws_host=hostname, aws_region=region, aws_service='execute-api') # API にリクエスト api_url = f'https://{hostname}{api_path}' response = requests.get(api_url, auth=auth) # レスポンスステータスコードを表示 print(f'response status: {response.status_code}') if __name__ == '__main__': request_api()
スクリプトの実行
以下のように実行します。
python request_api.py
以下のように、レスポンスステータスコード 200(OK)が出力されたら成功です。
response status: 200
まとめ
手順としては少なくはありませんが、一度実行できれば、あとは簡単にセキュアな API をどんどん作成していけるでしょう。
セキュリティ面もしっかり意識した、スマートな API を、ご一緒に作ってまいりましょう!