背景
特定のユーザーだけがAPIを利用できるようにするため、AWS API Gatewayに設定を加えて、特定のIAMロールからのリクエストだけを受け付けるシステムを構築しました。
この記事では、AWS API Gatewayを使って、特定のIAMロールからのみリクエストを許可する方法を解説します。
前提条件
この記事の手順を実行するには、以下の環境が必要です。
開発環境
- Python 3.x
- AWS CLI
- 以下のPythonパッケージ
- boto3
- requests
- botocore
AWS環境
- AWSアカウント
- AWS API Gatewayの基本的な知識と利用経験
- IAMの基本的な知識(ロール、ポリシーの概念)
認証情報と権限
- AWS CLIの認証情報が設定済み
~/.aws/credentials
(Windows の場合は%UserProfile%\.aws\credentials
)~/.aws/config
(Windows の場合は%UserProfile%\.aws\c
onfig)
- 使用するIAMユーザー/ロールに必要な権限が付与されていること
- API Gatewayへのアクセス権限(
execute-api:Invoke
)
- API Gatewayへのアクセス権限(
必要な情報
- AWS API GatewayのID
- 対象のIAMロール名
- AWSアカウントID
- API GatewayのエンドポイントURL
- デプロイ先のリージョン情報
上記の環境が整っていることを確認してから、本文の手順に進んでください。
手順
1. API Gatewayでリソースポリシーを設定する
まず、API Gatewayのアクセスポリシーを以下のように設定します。この設定により、特定のIAMロール以外からのリクエストを拒否します。
具体的な方法は、AWSの公式サイト「API Gateway リソースポリシーを作成して API にアタッチする」に記載されています。
ポリシー例
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:<リージョン>:<AWSアカウントID>:<API ID>/*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::<AWSアカウントID>:role/<IAMロール名>"
}
}
}
]
}
補足(以下の項目を書き換えてください)
<リージョン>
: API Gatewayが配置されているリージョンを入力します。- 例 :
ap-northeast-1
- 例 :
<AWSアカウントID>
: 対象IAMロールのAWSアカウントIDを入力します。<API ID>
: 対象のAPI GatewayのIDを入力します。<IAMロール名>
: 対象のIAMロール名を入力します。
2. AWS SigV4署名プロトコルを使用してリクエストをする
(1)でアクセスポリシーを設定すると、通常のcurl
コマンドでAPIにアクセスすることはできません。
API Gatewayがリクエストを許可するためには、「このリクエストは正当なものだ」と示す署名が必要です。この署名はAWSのSigV4署名プロトコルを使います。
SigV4署名とは?
AWSのサービスにアクセスする際に、リクエストが正規のものであることを証明するための仕組みです。これにより、偽造されたリクエストや不正なアクセスを防ぐことができます。
詳しくは、AWS公式サイト「API リクエストに対する AWS Signature Version 4」にて解説されています。
Pythonコードによる実装
以下は、署名付きリクエストを作成し、API Gatewayに送信するPythonコードの例です。
import boto3
import requests
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
def make_api_request(method='GET', endpoint='', path='', params=None, body=None):
"""
API Gatewayにリクエストを送信する関数。
AWSの認証情報を使ってリクエストを署名し、API Gatewayに送信します。
Args:
method (str): HTTPメソッド (GET, POSTなど)
endpoint (str): API GatewayのエンドポイントURL
path (str): APIのパス
params (dict): クエリパラメータ
body (str): リクエストボディ
Returns:
Response: APIからのレスポンスオブジェクト
"""
# AWSプロファイルを指定してセッションを作成
# ローカルのAWS CLI設定で指定したプロファイルを使用します。
session = boto3.Session(profile_name='<プロファイル名>')
credentials = session.get_credentials()
# リクエストのURLを構築
url = f"{endpoint}{path}"
# 必要なヘッダーを設定
headers = {
'Content-Type': 'application/json', # JSON形式のデータを送信することを指定
}
# AWSRequestオブジェクトを作成
# これによりリクエストの詳細を保持します。
aws_request = AWSRequest(
method=method,
url=url,
data=body,
params=params,
headers=headers
)
# SigV4署名を生成してリクエストに追加
# AWSの認証情報を使ってリクエストに署名します。
sigv4 = SigV4Auth(credentials, 'execute-api', '<リージョン>')
sigv4.add_auth(aws_request)
# リクエストを送信
# requestsライブラリを使って実際にAPIを呼び出します。
response = requests.request(
method=method,
url=url,
headers=dict(aws_request.headers),
params=params,
data=body
)
return response
# このコードを実行する場合の例
if __name__ == "__main__":
# APIエンドポイントとリクエストパスを設定
API_ENDPOINT = "<APIのエンドポイントURL>" # API GatewayのURLを指定
API_PATH = "<APIのパス>" # 実行したいAPIのパスを指定
try:
# GETメソッドでAPIを呼び出す
response = make_api_request(method='GET', endpoint=API_ENDPOINT, path=API_PATH)
# ステータスコードを表示
print(f"ステータスコード: {response.status_code}")
# APIレスポンスの内容を表示
print(f"レスポンス: {response.text}")
except Exception as e:
# エラーハンドリング
print(f"エラーが発生しました: {str(e)}")
コードのポイント
<プロファイル名>
: AWS CLIで設定したプロファイル名を指定します。<リージョン>
: API Gatewayが配置されているリージョンを入力します(例:ap-northeast-1
)。<APIのエンドポイントURL>
: API GatewayのURLを入力します。<APIのパス>
: APIの特定のエンドポイントを指定します。
初心者向け補足
- API Gatewayとは?
AWSが提供するマネージド型のAPI管理サービスです。APIの認証、アクセス制御、トラフィック管理を簡単に設定できます。 - IAMロールとは?
AWSリソースへのアクセスを制御するための仕組みです。特定のロールに必要なアクセス権を割り当てることができます。 - SigV4署名プロトコルの必要性
SigV4署名を使うことで、不正なリクエストを防ぎ、APIへの安全なアクセスを実現します。
注意点
- 設定を変更した後は、必ず動作確認を行ってください。
- アクセスポリシーの条件に誤りがあると、正当なリクエストでも拒否される場合があります。
まとめ
今回は、AWS API Gatewayを使って、特定のIAMロールからのみリクエストを許可する方法を解説しました。
他にも、送信元のIPアドレスなどで制限することも出来るので、AWS公式サイト「API Gateway リソースポリシーの例」を参考に適切なリソースポリシーを設定してみましょう!