Upgrade to Pro — share decks privately, control downloads, hide ads and more …

API GatewayのWebSocket API、REST APIと同じだと思ってたら 結構...

API GatewayのWebSocket API、REST APIと同じだと思ってたら 結構違いました

Avatar for drrndrrnprn

drrndrrnprn

October 16, 2025

More Decks by drrndrrnprn

Other Decks in Technology

Transcript

  1. 3 自己紹介 • 名前:池田瑞生 • 所属:日本アイ・ビー・エム システムズ・エンジニアリング 株式会社 • AWS歴

    - 2023年4月新卒入社 - インフラ担当者として基盤設計構築業務などに従事 • AWSの資格 - AWS Certified Cloud Practitioner - AWS Certified Solutions Architect – Associate - AWS Certified Developer – Associate
  2. 4 はじめに 概要: API GatewayでWebSocketAPIを使う機会があったのでRESTAPIしか経験のなかった担当者がどこに ハマったか難しかったかを共有します。 本日の構成: • 1. 背景と採用経緯:

    WebSocket導入の必要性と他手段の検討(なぜWebSocket APIを選んだか) • 2. WebSocketAPI基礎知識: WebSocket APIの仕組みとREST APIとの違い(接続方式やルーティ ングなど) • 3. システム構成概要: CloudFront配下でREST APIとWebSocket APIを併用した全体アーキテク チャ • 4. 直面した課題: Cookieが届かない問題、CloudFront経由403問題、PostToConnectionでの403 問題とその原因・対処 • まとめ
  3. 5 WebSocket APIを採用した経緯 • 採用理由 - リアルタイムな双方向通信(チャット機能)の実装が求められました。 - 既存の環境への変更を最小限に留める必要がありました。 -

    既存資産を活かせるAPI GatewayのWebSocket APIを、REST APIと併用する形で採用しまし た。 既存Webアプリにリアルタイムチャット機能を追加する必要があり、サーバー、クライアント間の双方向通信手 段が求められました
  4. 6 REST APIとWebSocket APIの違い HTTP APIとWebSocket APIにはいくつかの違いがあります。主な相違点を表にまとめます。 特徴・項目 REST API

    WebSocket API 状態管理 ステートレス ステートフル ヘッダーの利用 各リクエストにHTTPヘッダー付与可 能 初回接続時のみHTTPヘッダー送信可 能 認証タイミング 各リクエスト毎に認証情報を付与 $connect時にまとめて認証 ルーティング HTTPメソッド + パスでエンドポイン ト選択 メッセージ本文の内容でルート選択 (例: JSON中のaction値) オーバーヘッド 高(毎回HTTPヘッダーやTLSハンド シェイク) 低(接続維持、追加ヘッダーなし)
  5. 7 WebSocket APIを使う上での注意点 • WebSocket APIの要点 - HTTP Upgrade($connect時)でプロトコルを切り替え、持続的な接続を確立します -

    HTTPヘッダー(CookieやAuthorizationなど)は$connect時にのみ取得可能です - 接続後は、一意なConnectionIdでユーザーを識別・管理します - どの処理を実行するかは、メッセージ本文の`action`フィールドで決定します WebSocket通信は、初回接続時($connect)のハンドシェイクでコンテキストを確立します。接続後はHTTPヘッ ダーが送信されない点に注意が必要です。 クライアント APIGateway (WebSocketAPI) ECSなど統合先 $connect メッセージ通信 $disconnect 初回リクエスト (HTTPヘッダ送信可) 終了 転送処理
  6. 8 AWS Cloud Virtual private cloud (VPC) Private subnet 1

    WebSpcket API ECS Cluster Webアプリケーション ENI バックエンド (ビジネスロジック) VPCLink Private subnet 2 Public subnet 1 distribution Internet gateway NAT gateway ユーザー API Gateway RestAPI 今回のシステム構成 今回構築したシステムの全体アーキテクチャは以下のようになっていました。
  7. 9 遭遇した主な課題 • 課題A: Cookie(セッションID)がバックエンドに届かない - WebSocket接続では $connect 以降にヘッダーが送られないため、ブラウザからのセッション Cookieがバックエンドに届かず、ユーザーを識別できなくなりました。

    • 課題B: CloudFront経由だと403 Forbiddenが発生 - CloudFrontのカスタムドメイン経由で接続すると、HostやUpgradeヘッダーの扱いが合わず 403エラーが発生しました。直接API Gatewayに接続した場合は成功しました。 • 課題C: バックエンドからのPostToConnectionがForbidden - ECSのバックエンドから PostToConnection を呼び出しても403となり、サーバーからクライ アントへのメッセージ送信が拒否されました。IAMロールの設定やAPI-IDの不一致が原因でし た。 この3つが初期に発生した主な課題でした。
  8. 10 課題A: Cookieが届かない • 直接APIGW接続でのCookie消失 - バックエンド(ECS側)でCookieヘッダーが空になっている - ブラウザには認証セッションを示すCookieがセットされているのでハンドシェイクのリクエス トに含まれるはず

    • Mapping Template経由でも取得不可 - IntegrationのMapping Templateで “$input.params(‘Cookie’)” Cookieを読み取ってバックエ ンドに渡そうとしたが値が空になっている WebSocket接続時のCookie伝搬についていくつか問題が発生しました。 クライアント APIGateway (WebSocketAPI) ECSなど統合先 $connect メッセージ通信 $disconnect 初回リクエスト (HTTPヘッダ送信可) 終了 転送処理 Cookie ヘッダー: 空???
  9. 11 課題A: 原因と対処 • 原因 - WebSocketでは $connect 時のみHTTPヘッダーを扱い、接続確立後のメッセージにはヘッ ダーが付かないためCookieやAuthorization情報は失われる。

    - $input.params(‘Cookie’) はMapping Template内でのみ評価でき、Request Parametersでは 利用できない。 • 対策 - $connect ルートでCookieを検証し、認証とセッション確立を行う - ユーザーIDとConnectionIdを記録し以降のメッセージ処理ではConnectionIdをもとに認可 - API Gateway側では、$connectルートのIntegrationにMapping Templateを設定し、そこで Cookieやクエリ文字列を取り出してバックエンドに渡す WebSocketでは $connect 以外でヘッダーを扱えないため、接続時に認証を完了し、その結果をサーバー側で保 持する仕組みにしました。 $connect (Cookie検証) ユーザーIDと ConnectionIdを紐づけて 保存 通常メッセージは ConnectionIdで参照
  10. 12 VPC Link統合時のデータ伝搬 Mapping Templateの必要性 • API Gateway WebSocket APIでVPC

    Linkを用いたHTTP統合を使う際,Mapping Templateを設定 しないと$context変数(connectionId等)や本文以外の要素は統合先に届かない仕様 • Mapping Templateで connectionId・Cookie・body を含むJSONを組み立て、統合先へ渡します。 • “cookie”: “$input.params(‘Cookie’)”の書き方はテンプレート内で有効で、Request Parameters では評価されません。 • 以前のCLI指定は評価文脈の相違で失敗し、テンプレート方式に統一しました。 HTTP統合では自動伝搬に限りがあるため、必要な情報はMapping Templateで明示して渡すようにしました。 WebSpcket API VPCLink NLB ECSなど統合先 { "connectionId": "$context.connectionId", "cookie": "$input.params('Cookie')", "body": $input.json('$') }
  11. 14 課題B: CloudFrontでWebSocket APIを扱う際に意識しておくべきこと • WebSocketハンドシェイクに必要なヘッダーも存在 - Upgrade - Connection

    - Sec-WebSocket-Key - Sec-WebSocket-Version - Sec-WebSocket-Protocol - (今回はCookieも必須) • API Gatewayにカスタムドメインを設定していた場合は、Hostヘッダーをそのカスタムドメイン値 にして転送する必要があります。 原因としてはリクエストパスのミスでしたが、 CloudFrontでWebSocket APIを扱う際に気をつけることも見つ けたので書いておきます。 WebSpcket API distribution Upgrade Connection Sec-WebSocket-Key Sec-WebSocket-Version Sec-WebSocket-Protocol 初回リクエスト
  12. 15 WebSocketのルーティング方式 $request.body.action WebSocket APIでは、メッセージ本文の内容によって呼び出す処理(ルート)が決まります。 RESTのようにURLで決まるわけではありません。 •ルート選択式 $request.body.action を指定すると、受信したメッセージの action

    値に応じてルートが選ばれます。 •ルート定義 事前に API Gateway 上で sendMessage、joinRoom、leaveRoom など必要な RouteKey を登録し、それ ぞれの Integration に紐づけます。 •$defaultルート 定義されていない action が届いた場合は $default に振り分けられます。ログ出力やエラー応答などを 任せる場所です。 メッセージ例: { "action": "sendMessage", "roomId": "r1", "payload": { "text": "こんにちは" } } Integration A sendMessage Integration B Integration C joinRoom leaveRoom エラー処理など $default
  13. 16 課題C: PostToConnectionが403 • ECSから PostToConnection 実行時に ForbiddenException。 • 実施したが問題なかったもの

    - ネットワーク経路のチェック - 環境変数・エンドポイント設定の確認 - 署名と時刻の確認 • 原因 - Task Roleに execute-api:ManageConnections が未付与 PostToConnectionの403は、ECSのTask Roleに execute-api:ManageConnections が付与されていなかったこ とが原因でした WebSpcket API ECSなど統 合先 SDK呼び出し(SigV4) Task Role:ManageConnections 未付与で403
  14. 17 課題C: 原因と対処 • 必要なポリシー - execute-api:ManageConnections - 接続リソース(@connections)に対するPOST/GET/DELETE操作を許可します。 -

    REST APIの Invoke とは別の権限です。 • 付与先 - ECSの場合 Task Role サーバ側からクライアント接続(@connections)を操作するには、execute-api:ManageConnections が必要 です。Invoke 権限とは役割が異なります。 execute-api:Invoke execute-api:ManageConnections API Gateway ECSなど統合先 POST /@connections/{connectionId} GET /@connections/{connectionId} DELETE /@connections/{connectionId} PostToConnection 通常のAPI呼び出し用