😸

[サンプルコード付き]IAM認証をかけたAmazon API Gatewayにアクセスする

2021/02/12に公開

Amazon API Gateway(以下、API Gateway)の HTTP API で IAM 認証をかけてアクセスする方法について紹介します。

IAM 認証の設定

API Gateway のマネジメントコンソールから API の詳細に行き、「認可」選択して、下図のようにオーソライザーに「IAM(組込み型)」をアタッチします。

api-gateway-iam-auth

設定後 API Gateway の URL をたたくと Forbidden になります(設定前は誰でもアクセスできる状態でした)。

api-gateway-iam-auth

必要な権限

管理ポリシー AmazonAPIGatewayInvokeFullAccess をアタッチしておく必要があります。最低でも execute-api:Invoke が必要です。

Postman でアクセスする

ローカル環境でアクセスする場合 Postman を使うと簡単です。前もって AWS アクセスキーとシークレットキーを取得して控えておいてください。スイッチロールなどでアクセスキーを発行していない場合は aws sts assume-role で表示された AccessKeyIdSecretAccessKeySessionToken を控えておいてください。

$ aws sts assume-role \
    --role-arn arn:aws:iam::123456789012:role/SwitchRoleName \
    --role-session-name "SwitchRole" \
    --query 'Credentials'

Postman を開き、以下のように Authorization タブから「AWS Signature」を選択します。

postman

AccessKey, SecretKey に先ほど控えたアドレスとシークレットキーを入力します。スイッチロールの場合は Session Token も入力します(Expire される度に変わるので毎回入力する必要があります)。AWS Region は API Gateway があるリージョンを入力します。

postman

「Send」ボタンを押下すると画面下部にレスポンス結果が表示されていることが確認できます。

postman

Python でアクセスする

プログラムから API Gateway をアクセスしたい場合、署名バージョン4によるリクエストをする必要があります。自分で署名を生成してHTTPリクエストできますが、Python ではライブラリが提供されているのでそれを利用したほうが楽です。

以下にいくつかサンプルコードを載せておきます。

ローカル環境からアクセスする場合

Postman でアクセスしたのと同じように AWS アクセスキーとシークレットキーを取得して控えておいてください。スイッチロールなどでアクセスキーを発行していない場合は aws sts assume-role に出力表示された AccessKeyIdSecretAccessKeySessionToken を控えておいてください。

requests-aws4auth

import os
import requests
from requests_aws4auth import AWS4Auth

url = 'https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/'
auth = AWS4Auth(
    os.environ.get('AWS_ACCESS_KEY_ID'),
    os.environ.get('AWS_SECRET_ACCESS_KEY'),
    os.environ.get('AWS_REGION'),
    'execute-api',
    session_token=os.environ.get('AWS_SESSION_TOKEN'),
)
response = requests.get(url, auth=auth)
print(response.text)

aws-requests-auth

import os
import requests
from aws_requests_auth.aws_auth import AWSRequestsAuth

aws_host = 'xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com'
url = 'https://{}'.format(aws_host)
auth = AWSRequestsAuth(aws_access_key=os.environ.get('AWS_ACCESS_KEY_ID'),
                       aws_secret_access_key=os.environ.get(
                           'AWS_SECRET_ACCESS_KEY'),
                       aws_token=os.environ.get('AWS_SESSION_TOKEN'),
                       aws_host=aws_host,
                       aws_region=os.environ.get('AWS_REGION'),
                       aws_service='execute-api')
response = requests.get(url, auth=auth)
print(response.text)

EC2/AWS Lambda からアクセスする場合

API Gateway と同じ AWS アカウントで IAM ロールがアタッチされている EC2/AWS Lambda から API Gateway にアクセスする場合です。

requests-aws4auth

import boto3
import requests
from requests_aws4auth import AWS4Auth

session = boto3.Session()
credentials = session.get_credentials()
region = 'ap-northeast-1'

url = 'https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/'
auth = AWS4Auth(
    credentials.access_key,
    credentials.secret_key,
    region,
    'execute-api',
    session_token=credentials.token,
)
response = requests.get(url, auth=auth)
print(response.text)

aws-requests-auth

import requests
from aws_requests_auth.boto_utils import BotoAWSRequestsAuth

region = 'ap-northeast-1'
aws_host = 'xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com'
url = 'https://{}'.format(aws_host)
auth = BotoAWSRequestsAuth(aws_host=aws_host,
                           aws_region=region,
                           aws_service='execute-api')

response = requests.get(url, auth=auth)
print(response.text)

別 AWS アカウントからアクセスする場合

API Gateway がある AWS アカウントとは異なる AWS アカウントからアクセスするには、AssumeRole によるクロスアカウントで API Gateway への Invoke 権限を使えるようにします。

requests-aws4auth

import boto3
import requests
from requests_aws4auth import AWS4Auth

sts_client = boto3.client('sts')
response = sts_client.assume_role(
    # AssumeRole先(API Gatewayがある側)のIAMロールのARN 
    RoleArn="arn:aws:iam::123456789012:role/api_gateway_invoke_role",
    RoleSessionName="assume_role_api_gateway",
)

session = boto3.Session()
credentials = session.get_credentials()
region = 'ap-northeast-1'

url = 'https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/'
auth = AWS4Auth(
    response['Credentials']['AccessKeyId'],
    response['Credentials']['SecretAccessKey'],
    region,
    'execute-api',
    session_token=response['Credentials']['SessionToken'],
)
response = requests.get(url, auth=auth)
print(response.text)

aws-requests-auth

import boto3
import requests
from aws_requests_auth.aws_auth import AWSRequestsAuth

sts_client = boto3.client('sts')
response = sts_client.assume_role(
    # AssumeRole先(API Gatewayがある側)のIAMロールのARN 
    RoleArn="arn:aws:iam::123456789012:role/api_gateway_invoke_role",
    RoleSessionName="assume_role_api_gateway",
)

region = 'ap-northeast-1'
aws_host = 'xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com'
url = 'https://{}'.format(aws_host)
auth = AWSRequestsAuth(
    aws_access_key=response['Credentials']['AccessKeyId'],
    aws_secret_access_key=response['Credentials']['SecretAccessKey'],
    aws_token=response['Credentials']['SessionToken'],
    aws_host=aws_host,
    aws_region=region,
    aws_service='execute-api'
)
response = requests.get(url, auth=auth)
print(response.text)

参考 URL

Discussion