ENGINEER BLOG ENGINEER BLOG
  • 公開日
  • 最終更新日

【API Gateway】awscurl + IAM 認可を使用し、API Gateway にリクエストを送信する

この記事を共有する

目次

はじめに

こんにちは!パーソル&サーバーワークスの遠藤です。
Amazon API Gateway (以下、API Gateway) を構築する機会があり、改めて API Gateway について整理したいと思いましたので本記事を作成いたしました!
また、今回認可機能として IAM を、動作確認では awscurl ツールを使用したため、こちらについても併せてまとめました。

前提知識

API Gateway とは

まずは API Gatewayについてです!API Gateway は、REST API や HTTP API、 WebSocket API を簡単に構築、公開、管理できる、AWS が提供するサービスです。
バックエンドとして AWS Lambda や HTTP エンドポイントと連携し、認証、アクセス制御、スロットリング、モニタリングなどの機能も標準で備えています。

API Gateway がサポートする API タイプには、ステートレスである REST および HTTP と、ステートフルである WebSocket があります。
次の項では、今回設定する HTTP API の機能概要をまとめたいと思います。

HTTP API とは

HTTP API は、 REST ベースの API をより簡素かつ高速に提供する軽量な API タイプです。
REST API より機能は限定されますが、コストが抑えられます。利用可能な機能については、REST API と HTTP API のどちらかを選択するをご参照ください。
認可機能については、IAM 、Amazon Cognito(※)、Lambda 、JSON ウェブトークン(JWT)が利用可能です。
※ JWT の ID プロバイダーとして、Amazon Cognito を利用することが可能です。

IAM 認可とは

今回構築する API Gateway では、HTTP API タイプ + IAM 認可の組合わせを利用しました。
IAM 認可は、前項でご紹介したとおり HTTP API で利用可能なアクセス制御手法の一つです。
標準の AWS IAM ロールとポリシーをして、どのユーザーが API を呼び出せるか、また作成および管理ができるかをコントロールできます。

IAM 認可が有効である場合、API に接続する際には以下の条件を満たす必要があります。

  • Signature Version 4 (以下、SigV4) (※) を使用し、AWS 認証情報でリクエストに署名する
  • 接続に使用する IAM ロールやユーザーに execute-api アクションが許可されている

※ SigV4は、AWSサービスへのリクエスト認証プロトコルです。

awscurl とは

署名付き AWS API リクエストを作成することで、署名を作成することも可能ですが、左記の公式リファレンス内記載のとおり少々手間がかかります。
しかし、awscurl を使用することで、署名のプロセスが自動化され、従来の curl と同じようにリクエストができます。 これにより、煩雑な署名手順を意識せずに、API Gateway や他 AWS サービスへ署名付きリクエストを簡単に送信することが可能となります。

今回はこの awscurl を EC2 インスタンスにインストールし、動作確認していきたいと思います。

APIの実装

CloudFormation で API 処理用の API Gateway と Lambda および動作確認用の EC2 インスタンスを構築しました。
awscurl は EC2 の UserData にインストールコマンドを入力し、事前にインストールしておきます。
※VPCなどのネットワークリソースは事前に作成しているものを使用します。

テンプレートは以下を展開し、ご確認ください。

ここを押すと展開します

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
  Function:
    Runtime: python3.11
    Timeout: 10
    MemorySize: 128
# Amazon Linux 2023 の最新AMIを参照
Parameters:
  AmiId:
    Type: AWS::SSM::Parameter::Value
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
  AllowedSSHCidr1:
    Type: String
    Default: XX.XX.XX.XX/32
    Description: SSH Allow CIDR Block
Resources:
  # Lambda
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: HelloWorld-Function
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      InlineCode: |
        def handler(event, context):
            return {
                'statusCode': 200,
                'headers': {'Content-Type': 'text/plain'},
                'body': 'Hello, World'
            }
      Events:
        HelloApiEvent:
          Type: HttpApi
          Properties:
            Path: /
            Method: GET
            ApiId: !Ref HelloHttpApi
            Auth:
              Authorizer: AWS_IAM
  # APIGateway
  HelloHttpApi:
    Type: AWS::Serverless::HttpApi
    Properties:
      Name: HelloWorld-HttpApi
      FailOnWarnings: true
      Auth:
        EnableIamAuthorizer: true
        DefaultAuthorizer: AWS_IAM
      CorsConfiguration:
        AllowMethods: ['GET', 'OPTIONS']
        AllowOrigins: ['*']
  # Lambda 権限付与
  LambdaInvokePermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref HelloWorldFunction
      Action: lambda:InvokeFunction
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HelloHttpApi}/$default/*/*'
  # Lambda 用 IAM ロール
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: HelloWorld-ambdaRole
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Path: '/'
      Policies:
        - PolicyName: AllowLambdaLogs
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: arn:aws:logs:*:*:*
  # EC2 用 IAM ロール
  Ec2IamRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: Test-EC2Role
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      Path: '/'
      Policies:
        - PolicyName: AllowInvokeApi
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - execute-api:Invoke
                Resource: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*'
  Ec2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref Ec2IamRole
      Path: '/'
  # KeyPair
  MyKeyPair:
    Type: AWS::EC2::KeyPair
    Properties:
      KeyName: Test-KeyPair
      KeyType: ed25519
      KeyFormat: pem
      Tags:
        - Key: Name
          Value: Test-KeyPair
  # EC2
  Ec2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.small
      ImageId: !Ref AmiId
      IamInstanceProfile: !Ref Ec2InstanceProfile
      KeyName: !Ref MyKeyPair
      SecurityGroupIds:
        - !Ref InstanceSecurityGroup
      SubnetId: !ImportValue TestPublicSubnetIdExport
      Tags:
        - Key: Name
          Value: Test-EC2
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          # システムアップデート
          dnf update -y
          # Python3-pip インストール
          dnf install -y python3-pip
          # awscurl pip3 インストール
          pip3 install awscurl
          echo 'export PATH=$PATH:~/.local/bin' >> /home/ec2-user/.bash_profile
          chown -R ec2-user:ec2-user /home/ec2-user/.local
          # 確認用
          sudo -u ec2-user bash -lc 'awscurl --version'
  Ec2EIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
  Ec2EIPAssociation:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId: !GetAtt Ec2EIP.AllocationId
      InstanceId: !Ref Ec2Instance
  # インスタンス用セキュリティグループ
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: SSH only from specific CIDR
      VpcId: !ImportValue TestVpcIdExport
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref AllowedSSHCidr
      Tags:
        - Key: Name
          Value: Test-EC2-SG
Outputs:
  ApiEndpoint:
    Description: 'HTTP API Endpint URL'
    Value: !Sub 'https://${HelloHttpApi}.execute-api.${AWS::Region}.amazonaws.com/'
  KeyPairParameterName:
    Description: 'KeyPiar ParameterName'
    Value: !Sub '/ec2/keypair/${MyKeyPair}'

動作確認

動作確認用の EC2 インスタンスに接続し、awscurl ツールでレスポンスを確認します。

  • SigV4 署名ありの場合
 [ec2-user@ip-XX-XX-XX-XX ~]$ awscurl --service execute-api \
  --region ap-northeast-1 \
  https://XXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/
Hello, World

レスポンスとして、Lambda 関数に登録した Hello, World が返ってきていれば、正常に認可されている状態となります。

  • SigV4 署名なしの場合
 curl -v https://XXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/
* ...
*   Trying XXX.XXX.XXX.XXX:443...
* Connected to XXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com (XXX.XXX.XXX.XXX) port 443 (#0)
* ALPN: curl offers h2,http/1.1
* ...
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
< HTTP/2 403 
< date: Tue, 03 Jun 2025 12:10:32 GMT
< content-type: application/json
< content-length: 23
< apigw-requestid: XXXXXXXXXXXX
< 
* Connection #0 to host XXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com left intact
{"message":"Forbidden"}

curl -v コマンドで レスポンスの詳細を確認すると、以下が返却されました。

  • ステータスコード:403
  • エラーメッセージ:{"message":"Forbidden"}

正常に認可されていない状態となり、想定どおりの動作となっています!

おわりに

今回は API Gateway ( HTTP API )での IAM 認可 に関して記事を作成いたしました。
本記事が何かのご参考になりましたら幸いです。

参考情報

この記事は私が書きました

S.Endo

記事一覧

コーヒーを飲みながら仕事をしています

S.Endo

この記事を共有する

クラウドのご相談

CONTACT

クラウド導入や運用でお悩みの方は、お気軽にご相談ください。
専門家がサポートします。

サービス資料ダウンロード

DOWNLOAD

ビジネスをクラウドで加速させる準備はできていますか?
今すぐサービス資料をダウンロードして、詳細をご確認ください。