5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS API Gatewayに認証つきのサンプルを作った

Last updated at Posted at 2026-01-15

はじめに

ソーイ株式会社 村上です。

ソーイではAWSへのホスティングをメインにシステム構築を行っております。普段はWebフレームワーク内からAWSサービスを組み込むことが多いのですが、AWSサービス同士を連携させる構成も増えてきました。そこでこの記事では、API Gatewayで認証を設ける場合の検証を行いました。AWSのサーバーレスサービスを組み合わせて、認証付きAPIを構築して実行します。

既存システムの認証と組み合わせる場合、どういった方法があるか調査・検証し、シンプルなAPIを作成しました。

API Gatewayの認証について

調査したところAPI Gatewayでエンドポイントに認証を追加する場合、以下の選択肢がありました。

認証の選択肢

1. IAM認証

AWS内部やSDKを利用して呼び出す場合に適しています。AWSのIAMロールやIAMユーザーを使用して認証を行います。

特徴:

  • AWS SDKを使用した認証
  • AWS内部からの呼び出しに最適

フロー図:

2. Lambda Authorizer

ヘッダー、クエリパラメータ、IPアドレス、JWTなど、任意の情報を使って認可処理ができます。柔軟性が高く、カスタム認証ロジックを実装できます。

特徴:

  • カスタム認証ロジックを実装可能
  • ヘッダー、クエリパラメータ、IPアドレスなど様々な情報を利用
  • JWTトークンの検証も可能
  • 外部からの呼び出しに対応

フロー図:

参考: Lambda Authorizerの詳細

3. Cognito ユーザプール

ユーザー認証基盤をAWSに任せたい場合に最適です。ユーザー管理、パスワードリセット、MFAなどの機能が提供されます。

特徴:

  • ユーザー管理機能が充実
  • パスワードリセット、MFAなどの機能
  • ユーザー認証基盤をAWSに任せられる
  • 外部からの呼び出しに対応

フロー図:

今回の選択

今回はLambda Authorizerを使用します。認証システムをすでに実装しており運用中のシステムをAWSと組み合わせたい場合に一番利用しやすそうなためです。

今回はシンプルにリクエスト時の固定アクセストークンを検証することで認証の可否ができるものを作成します。

この記事で学べること

  • API GatewayでREST APIを構築する方法
  • Lambda AuthorizerでAPIを保護する方法
  • Step Functionsでワークフローを定義する方法
  • SAM(Serverless Application Model)によるインフラ管理

使用技術の概要

API Gateway

REST APIやHTTP APIを作成・管理するサービスです。リクエストを受け取り、バックエンドサービスにルーティングします。

Lambda Authorizer

API Gatewayのリクエストを、実際のAPI処理の前に検証するLambda関数です。今回はトークンベースの認証を実装し、認証トークンを含むリクエストのみを許可します。

Step Functions

複数のAWSサービスを組み合わせたワークフローを視覚的に定義・実行できるサービスです。今回はLambda関数を呼び出すシンプルなワークフローを作成します。

Lambda

サーバーレスでコードを実行できるサービスです。今回は2つのLambda関数を使用します:

  • Authorizer関数: 認証トークンを検証して認証を行う
  • Task関数: 実際の処理を実行

SAM (Serverless Application Model)

サーバーレスアプリケーションを定義するためのフレームワークです。YAMLファイルでインフラをコード化できます。

アーキテクチャ

このシステムの構成は以下の通りです:

Client (curl, Postman等)
  │
  ▼
API Gateway (/hello POST)
  │
  ├─▶ Lambda Authorizer (トークン検証)
  │   └─ 有効なトークン → 許可
  │   └─ 無効なトークン → 拒否 (401)
  │
  ▼
Step Functions (learning-api-workflow)
  │
  ▼
Lambda (task-function)
  └─ 処理を実行して結果を返す

前提条件

以下のツールがインストール・設定されている必要があります:

  • AWS CLI: AWSサービスをコマンドラインから操作
  • SAM CLI: サーバーレスアプリケーションのビルド・デプロイ
  • Python 3.14: Lambda関数の開発(ローカル環境)

プロジェクト構成

learning-api/
├── functions/
│   ├── authorizer/
│   │   └── app.py          # 認証処理
│   └── task/
│       └── app.py          # タスク処理
├── statemachine.asl.json   # Step Functions定義
├── template.yaml          # SAMテンプレート
├── samconfig.toml         # SAM設定
└── README.md

コード解説

1. Lambda Authorizer (functions/authorizer/app.py)

認証トークンを検証するLambda関数です。今回はトークンベースの認証を実装していますが、IPアドレスベースの認証やJWT認証にも対応可能です。

import os

VALID_TOKEN = os.environ.get('VALID_TOKEN', 'my-secret-token-123')

def lambda_handler(event, context):
    print(f"Event: {event}")

    token = event.get('authorizationToken', '')
    method_arn = event['methodArn']

    # Bearer プレフィックス除去
    if token.startswith('Bearer '):
        token = token[7:]

    if token == VALID_TOKEN:
        return generate_policy('user', 'Allow', method_arn)
    else:
        return generate_policy('user', 'Deny', method_arn)

def generate_policy(principal_id, effect, resource):
    return {
        'principalId': principal_id,
        'policyDocument': {
            'Version': '2012-10-17',
            'Statement': [
                {
                    'Action': 'execute-api:Invoke',
                    'Effect': effect,
                    'Resource': resource
                }
            ]
        },
        'context': {
            'userId': principal_id
        }
    }

ポイント:

  • authorizationToken からトークンを取得(API Gatewayが Authorization ヘッダーから自動的に取得)
  • 環境変数 VALID_TOKEN と比較
  • 一致すれば Allow、不一致なら Deny のポリシーを返す
  • 返却値はIAMポリシードキュメント形式で返す必要がある(API GatewayがIAMポリシーを使用してアクセス制御を行うため)

IAMポリシードキュメント形式について:

Lambda Authorizerの返却値は、必ずIAMポリシードキュメント形式である必要があります。これはAPI GatewayがIAMポリシーを使用してアクセス制御を行うためです。

必須フィールド:

  • principalId: リクエスト元を識別するID(文字列)
  • policyDocument: IAMポリシードキュメント
    • Version: ポリシー言語のバージョン(通常は "2012-10-17"
    • Statement: ポリシーステートメントの配列
      • Effect: "Allow" または "Deny"
      • Action: "execute-api:Invoke"(API Gatewayのアクション)
      • Resource: 許可/拒否するリソース(通常は methodArn

オプションフィールド:

  • context: 後続のLambda関数や統合に渡す追加情報(キー・バリューのマップ)

2. Task Lambda (functions/task/app.py)

実際の処理を実行するLambda関数です。

import json
from datetime import datetime

def lambda_handler(event, context):
    print(f"Received event: {json.dumps(event)}")

    result = {
        'status': 'success',
        'message': 'Task completed successfully',
        'processedAt': datetime.now().isoformat(),
        'inputReceived': event
    }

    return result

ポイント:

  • Step Functionsから渡されたイベントを受け取る
  • 処理結果をJSON形式で返す
  • 実際のアプリケーションでは、ここにビジネスロジックを実装

3. Step Functions定義 (statemachine.asl.json)

ワークフローを定義するJSONファイルです。

{
  "Comment": "Learning workflow - Simple Lambda invocation",
  "StartAt": "ProcessTask",
  "States": {
    "ProcessTask": {
      "Type": "Task",
      "Resource": "${TaskFunctionArn}",
      "ResultPath": "$.taskResult",
      "Next": "Success"
    },
    "Success": {
      "Type": "Succeed"
    }
  }
}

ポイント:

  • StartAt: ワークフローの開始状態
  • ProcessTask: Task関数を呼び出す状態
  • Success: 成功を表す終了状態
  • ${TaskFunctionArn}: SAMテンプレートから置換される値

4. SAMテンプレート (template.yaml)

インフラを定義するYAMLファイルです。主要な部分を解説します。

グローバル設定

Globals:
  Function:
    Timeout: 30
    Runtime: python3.14
    Architectures:
      - arm64

すべてのLambda関数に適用される共通設定です。

パラメータ

Parameters:
  ValidToken:
    Type: String
    Default: my-secret-token-123
    NoEcho: true

デプロイ時に指定できるパラメータです。NoEcho: true により、CloudFormationコンソールで表示されません。認証に使用するトークンを設定します。

API Gateway設定

LearningApi:
  Type: AWS::Serverless::Api
  Properties:
    Name: learning-api
    StageName: dev
    Auth:
      DefaultAuthorizer: LambdaAuthorizer
      Authorizers:
        LambdaAuthorizer:
          FunctionArn: !GetAtt AuthorizerFunction.Arn
          Identity:
            Header: Authorization
            ReauthorizeEvery: 300
  • DefaultAuthorizer: すべてのエンドポイントに適用される認証
  • ReauthorizeEvery: 300: 300秒ごとに再認証(キャッシュ時間)

注意点:
デバッグ中にトークンを変更しても認証が通り続ける現象が発生しました。原因は ReauthorizeEvery: 300 による認証結果のキャッシュでした。開発中は ReauthorizeEvery: 0 に設定するか、キャッシュを意識してテストする必要があります。本番環境ではパフォーマンスのためキャッシュを有効にすることをお勧めします。

Lambda関数定義

AuthorizerFunction:
  Type: AWS::Serverless::Function
  Properties:
    FunctionName: learning-api-authorizer
    CodeUri: functions/authorizer/
    Handler: app.lambda_handler
    Environment:
      Variables:
        VALID_TOKEN: !Ref ValidToken
  • CodeUri: 関数のコードが格納されているディレクトリ
  • Handler: エントリーポイント(ファイル名.関数名)
  • Environment: 環境変数の設定(VALID_TOKENに認証トークンを設定)

Step Functions定義

ProcessingStateMachine:
  Type: AWS::Serverless::StateMachine
  Properties:
    Name: learning-api-workflow
    DefinitionUri: statemachine.asl.json
    DefinitionSubstitutions:
      TaskFunctionArn: !GetAtt TaskFunction.Arn
    Events:
      ApiEvent:
        Type: Api
        Properties:
          RestApiId: !Ref LearningApi
          Path: /hello
          Method: POST
  • DefinitionUri: ステートマシン定義ファイル
  • DefinitionSubstitutions: 定義ファイル内の変数を置換
  • Events: API Gatewayからのイベントを受け取る設定

デプロイ手順

1. ビルド

sam build

このコマンドで:

  • Lambda関数のコードをパッケージ化
  • 依存関係を解決
  • デプロイ用のアーティファクトを生成

2. デプロイ(初回)

sam deploy --guided

初回は --guided オプションを使用します。対話形式で以下を設定:

  • Stack Name: learning-api
  • AWS Region: ap-northeast-1 など
  • Parameter ValidToken: 認証トークン(デフォルト: my-secret-token-123
  • その他の設定

注意: 実際に使用する場合は、セキュアなトークンを設定してください。デフォルトのトークンは学習用のため、本番環境では使用しないでください。

3. デプロイ(2回目以降)

sam deploy

設定は samconfig.toml に保存されているため、オプションを指定する必要はありません。

デプロイの確認

デプロイが成功すると、以下のような出力が表示されます:

Successfully created/updated stack - learning-api in ap-northeast-1

動作確認

1. APIエンドポイントの取得

API_URL=$(aws cloudformation describe-stacks \
  --stack-name learning-api \
  --query 'Stacks[0].Outputs[?OutputKey==`ApiEndpoint`].OutputValue' \
  --output text)

echo $API_URL

2. 認証なしでリクエスト(401エラー)

認証トークンを含めずにリクエストを送信すると、401エラーが返されます。

curl -X POST $API_URL \
  -H "Content-Type: application/json" \
  -d '{"message": "hello"}'

結果:

{"message": "Unauthorized"}

ステータスコード: 401

3. 認証ありでリクエスト(200 OK)

認証トークンを含めてリクエストを送信すると、正常に処理されます。

curl -X POST $API_URL \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer my-secret-token-123" \
  -d '{"message": "hello"}'

結果:

{
  "executionArn": "arn:aws:states:...",
  "startDate": "2024-01-08T...",
  ...
}

ステータスコード: 200

補足: リクエストヘッダーに Authorization: Bearer <token> を含める必要があります。トークンはデプロイ時に設定した ValidToken パラメータと一致している必要があります。

4. Step Functions実行結果の確認

# 最新の実行を取得
STATE_MACHINE_ARN=$(aws cloudformation describe-stacks \
  --stack-name learning-api \
  --query 'Stacks[0].Outputs[?OutputKey==`StateMachineArn`].OutputValue' \
  --output text)

aws stepfunctions list-executions \
  --state-machine-arn $STATE_MACHINE_ARN \
  --max-results 1

実行詳細を確認:

aws stepfunctions describe-execution --execution-arn <EXECUTION_ARN>

認証トークンの変更

下記コマンドでパラメータを上書きして反映できます。

sam deploy --parameter-overrides ValidToken=your-custom-token

Step Functionsにステップを追加

statemachine.asl.json を編集して、より複雑なワークフローを定義できます。

例:入力検証を追加

{
  "StartAt": "ValidateInput",
  "States": {
    "ValidateInput": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.message",
          "IsPresent": true,
          "Next": "ProcessTask"
        }
      ],
      "Default": "InvalidInput"
    },
    "ProcessTask": {
      "Type": "Task",
      "Resource": "${TaskFunctionArn}",
      "Next": "Success"
    },
    "InvalidInput": {
      "Type": "Fail",
      "Error": "InvalidInput",
      "Cause": "message field is required"
    },
    "Success": {
      "Type": "Succeed"
    }
  }
}

編集後、再デプロイ:

sam build
sam deploy

再度CURLでリクエストすると、下記のようにStep Functionsの実行が成功しました。

CleanShot 2026-01-13 at 11.27.58@2x.png

クリーンアップ

実行まで成功したため、リソースを削除します。

sam delete --stack-name learning-api

これで、作成したすべてのリソースが削除されます。

まとめ

Lambda Authorizerを利用してAPI Gatewayに認証を追加することができました。Lambdaを更新することで任意の認証処理を挟むことができます。Lambda Authorizerの返却値はIAMポリシー形式の必要があるため、注意が必要です。また、SAMを使うことで管理とデプロイが容易になるため積極的に使っていきたいです。

お知らせ

技術ブログを週1〜2本更新中、ソーイをフォローして最新記事をチェック!
https://qiita.com/organizations/sewii

参考リンク

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?