IAM 인증의 AWS API Gateway에 Python에서 SigV4 서명하고 액세스하려면

AWS API Gateway의 API 메서드 설정에서 IAM 인증을 사용하는 경우 API 요청 시 서명이 필요합니다.

API Gateway의 메소드 설정 화면은 이런 느낌입니다. 영어 매니지먼트 콘솔이라면 「Authorization」, 일본어라면 「인가」라는 란입니다.



기본값은 NONE으로 설정되어 있지만 AWS_IAM으로 설정하면 API Gateway는 도착한 요청의 서명을 확인합니다. 요청하는 사람이 서명해야 합니다.

API Gateway가 서명을 확인하게 되면 API Gateway의 리소스 정책에서 IAM 사용자 및 IAM 역할에 제한을 걸 수 있습니다.

Python에서 서명하고 API를 요청하는 샘플 코드를 작성합니다.

전제



IAM 사용자의 액세스 키가 ~/.aws/credentials로 설정되어 있고 해당 IAM 사용자에서 IAM 역할로 전환하는 IAM 권한이 있고 해당 IAM 역할에서 API Gateway에 액세스한다고 가정합니다. (.

파이썬 코드


import boto3
from botocore.awsrequest import AWSRequest
from botocore.auth import SigV4Auth
import urllib.request
import sys

endpoint_host = "xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com"
endpoint = "https://" + endpoint_host + "/stage"
path = "/hello"
url = endpoint + path

# .aws/credentials または環境変数でアクセスキーが設定されているIAMユーザのセッションを生成。
session = boto3.session.Session()
# .aws/credentials に複数のIAMユーザがある場合は profile_name を指定。
#session = boto3.session.Session(profile_name = "foo")

sts_client = session.client("sts")

# IAMロールのARNを指定して assume_role 。
# IAMロールが不要でIAMユーザのままでAPIリクエストする場合は、ここは不要。
assume_role_response = sts_client.assume_role(
    RoleArn = "arn:aws:iam::XXXXXXXXXXXX:role/ROLENAME",
    RoleSessionName = "test")

# assume_role で得られたトークンなどからIAMロールでのセッションを生成。
# IAMロールが不要でIAMユーザのままでAPIリクエストする場合は、ここは不要。
session = boto3.session.Session(
    aws_access_key_id = assume_role_response['Credentials']['AccessKeyId'],
    aws_secret_access_key = assume_role_response['Credentials']['SecretAccessKey'],
    aws_session_token = assume_role_response['Credentials']['SessionToken'])

# セッション情報からAPIリクエストに署名。
credentials = session.get_credentials()
awsreq = AWSRequest(method = "GET", url = url)
SigV4Auth(credentials, "execute-api", "ap-northeast-1").add_auth(awsreq)

# urllib.request.Request 生成。
# この4つのリクエストヘッダーが必須。
# IAMロールが不要でIAMユーザのままでAPIリクエストする場合は、X-Amz-Security-Token は不要。
req = urllib.request.Request(url, headers = {
    "Authorization": awsreq.headers['Authorization'],
    "Host": endpoint_host,
    "X-Amz-Date": awsreq.context['timestamp'],
    "X-Amz-Security-Token": assume_role_response["Credentials"]["SessionToken"]
})

# APIリクエスト実行
try:
    with urllib.request.urlopen(req) as response:
        # レスポンス出力
        sys.stdout.buffer.write(response.read())
except urllib.error.HTTPError as err:
    # 403などの場合はここに到達
    # エラーを出力
    print(err)
    # レスポンスヘッダを出力
    print(err.headers)

오류 메시지의 예



IAM 사용자에게 assume_role 할 권한이 없으면 assume_role을 호출하면
botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the AssumeRole operation

예외가 발생합니다.
~/.aws/credentials 가 필요한데 부족하면, 403 Forbidden 가 돌려주어져 응답 헤더에 다음과 같이 쓰여집니다.
x-amzn-ErrorType: UnrecognizedClientException

API Gateway 리소스 정책에서 이 IAM 역할의 요청을 거부하면 403 Forbidden이 반환되고 응답 헤더에 다음과 같이 작성됩니다.
x-amzn-ErrorType: AccessDeniedException

IAM 역할에 API Gateway에 액세스하는 IAM 권한이 없어도 API Gateway 리소스 정책에서 허용하면 AccessDeniedException이 아닌 성공적으로 처리 할 수 ​​있습니다.

링크



C#에서 기사도 썼습니다.
  • IAM 인증의 AWS API Gateway에 C#에서 IAM 사용자로 SigV4 서명하고 액세스하려면
  • IAM 인증의 AWS API Gateway에 C#에서 IAM 역할로 SigV4 서명하고 액세스하려면
  • 좋은 웹페이지 즐겨찾기