【備忘録】IAM認証ありのAWS API GatewayをLambdaから実行する

はじめに

本記事は備忘録として、不確かな情報を含め記載する。

言語はpythonで説明する。

ベストプラクティスみたいなものは見つけられなかったので、一例として紹介する。

aws-samplesにコードがありました。(別解)

API GatewayのIAM認証でググると、直にAWS credentialsを利用するサンプルが多かったので、本記事ではLambdaのRoleからcerdentialsを取得してそれを利用するコードを示す。

コード

import os
import boto3
import requests
from requests_aws4auth import AWS4Auth

def lambda_handler(event, context):

    credentials = boto3.Session().get_credentials()
    v4auth = AWS4Auth(
        credentials.access_key,
        credentials.secret_key,
        os.environ['AWS_REGION'],
        'execute-api',
        session_token=credentials.token,
    )

    res = requests.get('url',
                       auth=v4auth)
    res.raise_for_status()
    print(res.text)

    return {}

refreshable_credentials を使う別案。詳細な検証はしていないので、想定とは異なるかもしれないが、こっちのほうがよいかも。

import os
import boto3
import requests
from requests_aws4auth import AWS4Auth

# グルーバル定義(コールドスタート時)
credentials = boto3.Session().get_credentials()

def lambda_handler(event, context):

    # 有効期限はいい感じにやってくれるかも?
    v4auth = AWS4Auth(
        region=os.environ['AWS_REGION'],
        service='execute-api',
        refreshable_credentials=credentials,
    )

    res = requests.get('url',
                       auth=v4auth)
    res.raise_for_status()
    print(res.text)

    return {}

ちょっと解説

  • get_credentials()
    • このlambdaの実行Roleを boto3.Session() で参照される
    • 返り値としてアクセストークンなどが取得される
  • AWS4Auth
    • AuthBaseを継承しているので、 requests ライブラリと互換あり
  • 対象のlambdaの実行ロールに、 Allow: execute-api:Invoke が必要
  • requests.getauth 引数に指定
    • よしなに認証ヘッダーを作成してくれているはず。。(SigV4がよくわかってない)

Signature Version 4 分かる範囲で

例: 認証ヘッダー

こんな感じのヘッダーを最終的には作られているはず。ハッシュや細かい挙動は理解できていない。

Authorization: AWS4-HMAC-SHA256
Credential=AKIAIOSFODNN7EXAMPLE/20220830/us-east-1/ec2/aws4_request,
SignedHeaders=host;x-amz-date,
Signature=calculated-signature

PostmanでIAM認証をつけたとき

AWS Signatureで設定する。

ヘッダーが自動的に生成される。

上記コードでも同じようなことをしていると思っている。

aws-samples/sigv4a-signing-examples

sigv4a-signing-examples/python at main · aws-samples/sigv4a-signing-examples

from sigv4a_sign import SigV4ASign

# pip install requests
import requests

service = 's3'
region = '*'
method = 'GET'
url = 'https://<MRAP_alias>.accesspoint.s3-global.amazonaws.com/<s3-object-key>'

headers = SigV4ASign().get_headers_basic(service, region, method, url)
r = requests.get(url, headers=headers)
print(f'status_code: {r.status_code} \\nobject text: {r.text}')
import boto3
from botocore import crt, awsrequest

class SigV4ASign:

    def __init__(self, boto3_session=boto3.Session()):
        self.session = boto3_session

    def get_headers(self, service, region, aws_request_config):
        sigV4A = crt.auth.CrtS3SigV4AsymAuth(self.session.get_credentials(), service, region)
        request = awsrequest.AWSRequest(**aws_request_config)
        sigV4A.add_auth(request)
        prepped = request.prepare()

        return prepped.headers

    def get_headers_basic(self, service, region, method, url):
        sigV4A = crt.auth.CrtS3SigV4AsymAuth(self.session.get_credentials(), service, region)
        request = awsrequest.AWSRequest(method=method, url=url)
        sigV4A.add_auth(request)
        prepped = request.prepare()

        return prepped.headers
  • SigV4ASign を自作
  • requests.getheaders にセット
  • SigV4A。マルチリージョン対応っぽい。

終わりに

requests_aws4authsigv4a-signing-examples の2通りを説明した。

どちらを使うべきかの判断基準はわからないので、今後考えたい。

参考

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

Lambda から IAM 認証が有効な API Gateway にアクセスしてみた | DevelopersIO

requests-aws4auth

https://github.com/tedder/requests-aws4auth#dynamic-sts-credentials-using-botocore-refreshablecredentials

無料相談実施中
AWSを使用したサーバーレスアプリケーションの構築
サーバーレス開発内製化、AWSへの移行等
様々な課題について無料でご相談お受けいたします。
最新情報をチェックしよう!