メインコンテンツへスキップ
kt-tech.blog
【設計】ECS Fargate + Next.js + FastAPI のアクセス制御設計 — SSR内部通信の認証をどう解決するか
設計
(更新: 2026/3/22)· 約6分で読めます

【設計】ECS Fargate + Next.js + FastAPI のアクセス制御設計 — SSR内部通信の認証をどう解決するか

Share
📌
概要: AWS ALB + Cognito OIDC で認証されたNext.js + FastAPI構成において、SSR内部通信では認証ヘッダーが届かない問題をどう解決するか。Next.js middleware / Server Component / CSR の3パターンを比較検討し、最適な設計を選定した記録。

はじめに

AWS ECS Fargate上でNext.js(フロントエンド)とFastAPI(バックエンド)を動かし、ALB + Cognito + Entra IDでOIDC認証を行っている環境に、「許可されたメールアドレスのみアクセス可能」というアクセス制御を導入することになった。

一見シンプルな要件だが、SSR(Server Side Rendering)の内部通信がALBを経由しないため、認証ヘッダーが届かないという根本的な問題に直面した。

この記事でわかること

  • ALBが付与する x-amzn-oidc-data ヘッダーの特性と制約

  • SSR内部通信で認証情報が失われる理由

  • Next.js middleware / Server Component / CSR での認可チェックの比較

  • x-internal-api-key パターンによるSSR内部通信の認証設計

対象読者

  • AWS ECS + ALB OIDC環境でNext.jsアプリを運用している方

  • SSRとCSRで認証の扱いが異なることに困っている方

  • アプリ層でのアクセス制御設計を検討している方

前提条件

  • AWS ECS Fargate + ALB(Cognito OIDC認証)

  • Next.js 16(App Router, standalone mode, basePath: /sm

  • FastAPI(Python)

  • 同一VPC内でCloud Map経由のサービス間通信

通信経路の整理

まず、リクエストがどの経路を通るかを理解する必要がある。

ブラウザ → ALB → バックエンド(CSR)

ブラウザからのAPI呼び出しはALBを経由する。ALBはCognito認証後に x-amzn-oidc-data ヘッダー(JWT)を自動付与するため、バックエンドはこのJWTからメールアドレスを取得できる。

Next.js SSR → バックエンド(内部通信)

Server Componentからのデータ取得はECS内部のCloud Map DNS経由で直接バックエンドに接続する。ALBを経由しないため、x-amzn-oidc-data ヘッダーは存在しない。

# CSR: ALB経由 → ヘッダーあり
ブラウザ → ALB(x-amzn-oidc-data付与) → FastAPI

# SSR: 内部通信 → ヘッダーなし
Next.js SSR → Cloud Map → FastAPI

この「SSR内部通信にはOIDCヘッダーがない」という事実が、設計の核心的な課題となる。

検討した3つのパターン

パターンA: Next.js middleware で認可チェック

middleware.tsで全リクエストをインターセプトし、x-amzn-oidc-data からメールを取得。バックエンドの /auth/check に内部通信で問い合わせる方式。

問題点:

  • middlewareはEdge Runtimeで動作し、api-server.ts(Node.js Runtime)を直接importできない

  • 内部通信用のfetchを別途実装する必要があり、ヘッダー転送やエラー処理が複雑化

  • basePath(/sm)の二重化問題が発生しやすい

  • 実際にstg環境で複数の問題が発生しデプロイ不可に

パターンB: CSR コンポーネントで認可チェック

layout.tsx<Authenticator>クライアントコンポーネントを配置。useEffectでマウント後にブラウザからALB経由で/auth/checkを呼ぶ方式。

メリット: 実装が最もシンプルで、SSR内部通信の問題が完全に無関係。

デメリット: SSRのデータフェッチが認可チェック前に実行され、ローディング表示が一瞬入る。

パターンC: Server Component(layout.tsx)で認可チェック【採用】

ルートのlayout.tsxをasync関数にし、headers()x-amzn-oidc-dataを取得してメールを抽出。api-server.ts経由でバックエンドに許可チェックする方式。

メリット: Node.js Runtimeで動作し、api-server.tsを直接importできる。Edge Runtime制約なし、basePath問題なし。未許可ユーザーにはページのレンダリング自体が実行されない。

比較表

評価軸 A: middleware B: CSR C: Server Component
セキュリティ
UX コンテンツ見えない ローディング挟む コンテンツ見えない
実装の複雑さ 低〜中
SSR内部通信 fetchを別途実装 無関係 api-server.ts流用
Edge Runtime制約 あり なし なし

採用した設計: x-internal-api-key パターン

パターンCを採用し、SSR内部通信には共有秘密鍵(x-internal-api-key)で「信頼された内部通信」と識別する設計とした。

バックエンドの認証ミドルウェアは、リクエストを上から順に判定する:

  1. x-internal-api-key がある → 信頼された内部通信、認証スキップ

  2. x-amzn-oidc-data がある → JWT検証 → メール抽出 → 許可リストチェック

  3. どちらもない → 401

フロントエンドでは、layout.tsxheaders()からOIDCヘッダーを取得し、api-server.ts経由でバックエンドに認可チェックを行う。

// (authenticated)/layout.tsx
export default async function AuthenticatedLayout({ children }) {
  const { authorized, is_admin } = await checkAuth();
  if (!authorized) redirect("/unauthorized");

  return (
    <AuthProvider isAdmin={is_admin ?? false}>
      <Header />
      <main>{children}</main>
    </AuthProvider>
  );
}

Edge RuntimeとNode.js Runtimeの違い

Next.jsには2つのサーバーサイド実行環境がある:

  • Edge Runtime: 軽量だが制約あり。fsnet等のNode.js APIが使えない。middlewareはデフォルトでこちら

  • Node.js Runtime: フル機能。Server Components、API Routesはこちら

middlewareからはapi-server.tsを直接importできないが、layout.tsx(Server Component)からは同じNode.js Runtimeなのでそのまま使える。

Tips

  • ALBのx-amzn-oidc-dataはALB→ターゲット間でのみ付与される。SSR内部通信では使えない

  • x-internal-api-keyはECS内部通信でのみ使用し、セキュリティグループで外部からのアクセスを遮断する前提

  • Server ComponentのルートグループでCSR/SSRの認証パスを分離すると見通しがよい

まとめ

  • SSR内部通信ではALBのOIDCヘッダーが届かないため、別の認証手段が必要

  • Next.js middlewareはEdge Runtime制約があり、Server Componentでの認可チェックが最もシンプル

  • x-internal-api-keyパターンでSSR内部通信を信頼済みとして扱う設計が有効

  • layout.tsxでの認可チェックにより、未許可ユーザーにはレンダリング自体が実行されないセキュリティを実現

この記事が役に立ったら共有しよう

Share
Koki

Koki

フルスタックエンジニア / React, Next.js, TypeScript