FastAPI認証・認可の本番設計:JWT運用、権限制御、監査ログまで含めた実装パターン

FastAPI は実装が速い反面、認証・認可を最小構成のまま本番に出してしまい、後からセキュリティ事故に発展するケースが少なくありません。特に「JWT を入れたから安全」という誤解は危険です。

本記事では、開発速度を落とさずに本番で耐える認証基盤を作るための設計を、コード例と運用手順込みで解説します。

1. 認証と認可を分離して設計する

最初に押さえるべきは責務分離です。

  • 認証(Authentication): 誰かを確認する
  • 認可(Authorization): 何をしてよいか判定する

この2つを混ぜると、実装も監査も破綻します。FastAPI では dependency を分け、get_current_userrequire_permission を独立させるのが基本です。

2. JWT は「短命 + リフレッシュ + 失効管理」で使う

アクセストークンを長寿命にすると、漏えい時の被害が大きくなります。実運用では以下が標準です。

  • Access Token: 5〜15分
  • Refresh Token: 7〜30日
  • Refresh Token は DB 保存し、ローテーション時に旧トークンを失効

sub だけでなく、jti(トークンID)や scope を持たせると管理しやすくなります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from datetime import datetime, timedelta, timezone
import jwt

ALGORITHM = "HS256"


def create_access_token(user_id: str, scopes: list[str], secret: str) -> str:
    now = datetime.now(timezone.utc)
    payload = {
        "sub": user_id,
        "scope": " ".join(scopes),
        "iat": int(now.timestamp()),
        "exp": int((now + timedelta(minutes=10)).timestamp()),
        "jti": "generated-uuid"
    }
    return jwt.encode(payload, secret, algorithm=ALGORITHM)

3. 鍵管理とローテーション

秘密鍵を .env に固定して数年運用するのは典型的な事故パターンです。最低限、次を実施します。

  • KMS/Vault など外部シークレット管理を利用
  • kid をヘッダに持たせ、複数鍵を並行運用
  • 鍵ローテーション手順を runbook 化

ローテーションの要点:

  1. 新鍵を追加(検証側は新旧どちらも受理)
  2. 発行側を新鍵へ切替
  3. 旧鍵の有効期限を過ぎたら削除

この手順にすると、無停止で切替できます。

4. FastAPI Dependencyで認可を明示化

ロジック中で if user.role == "admin" を乱立させると、抜け漏れが起こります。権限チェックは dependency 化し、ルート定義に明示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from fastapi import Depends, HTTPException, status


def require_permission(required: str):
    def checker(user=Depends(get_current_user)):
        if required not in user.permissions:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="insufficient permissions"
            )
        return user
    return checker


@router.delete("/projects/{project_id}")
def delete_project(
    project_id: str,
    user=Depends(require_permission("project:delete"))
):
    ...

ルート単位で要件が見えるため、レビュー効率と監査性が上がります。

5. RBAC/ABAC の使い分け

小規模なら RBAC(role-based)で十分ですが、顧客単位データや組織階層があると ABAC(属性ベース)を併用した方が安全です。

  • RBAC: admin, editor, viewer
  • ABAC: tenant_id, resource_owner_id, department

実務では「ロールで粗く許可し、属性で絞る」が扱いやすいです。

6. マルチテナントで必須の防御

マルチテナント API では、ID 推測よりもテナント境界漏れが主要リスクです。対策は次の通りです。

  • すべての DB クエリに tenant_id 条件を必須化
  • 管理者 API でも境界を明示的に超える操作だけ許可
  • 監査ログに tenant_id, actor_id, resource_id を残す

SQLAlchemy でも repository 層で共通フィルタを強制すると漏れを減らせます。

7. 監査ログを設計段階で入れる

認証系は障害後に「誰が何をしたか」が必要になります。後付けだと間に合いません。最低限、次を記録します。

  • ログイン成功/失敗(IP, user-agent, reason)
  • 権限エラー(403)
  • 重要操作(削除、権限変更、請求情報更新)
  • トークン失効・再発行

フォーマットは JSON 構造化に統一し、SIEM や OpenSearch に流せる形にしておくと分析が速いです。

8. レート制限とブルートフォース対策

パスワード認証がある場合、レート制限なしは危険です。slowapi などを使い、ログイン系エンドポイントに制限を入れます。

1
2
3
4
5
6
7
8
9
from slowapi import Limiter
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)

@router.post("/auth/login")
@limiter.limit("5/minute")
def login(...):
    ...

さらに次を組み合わせると強化できます。

  • 失敗回数に応じた遅延(progressive delay)
  • CAPTCHA(必要時のみ)
  • 異常IP/ASN の遮断

9. よくある実装ミス

ミスA: 署名検証はしているが aud/iss 未検証

結果:

  • 他システム向けトークンを誤受理

対処:

  • issuer/audience を厳格検証
  • 想定外クレームは拒否

ミスB: refresh token の使い回しを検知しない

結果:

  • 漏えい時に長期間乗っ取られる

対処:

  • ローテーション時に旧トークン失効
  • 再利用検知時はセッション全失効

ミスC: 認可チェックが一部エンドポイントで抜ける

結果:

  • 水平権限昇格

対処:

  • dependency ベースで強制
  • 重要ルートにセキュリティテスト追加

10. テスト戦略(必須)

認証はユニットテストだけでなく、統合テストで権限境界を確認します。

  • 有効トークン/期限切れ/改ざんトークン
  • role ごとのアクセス可否
  • tenant 越境アクセス拒否
  • refresh token 再利用検知

pytest では fixture で role 別トークンを用意し、回帰を防ぎます。

11. 障害時 runbook(最低限)

インシデント時に迷わないよう、次を文書化しておきます。

  1. 鍵漏えい疑い時の全トークン失効手順
  2. 認証基盤障害時のフェイル動作(許可しすぎを防ぐ)
  3. 監査ログの検索手順
  4. 関係者通知テンプレート

特に「認証サーバーが落ちたとき、API をどうするか」は事前に決めておく必要があります。

12. 導入チェックリスト

  • access token は短寿命(<=15分)
  • refresh token は DB 管理 + ローテーション
  • 鍵ローテーション手順がある
  • ルート単位で認可 dependency が明示されている
  • tenant 境界を DB レイヤーで強制している
  • 監査ログ(認証/認可/重要操作)を構造化保存
  • レート制限と異常検知がある
  • 権限境界の統合テストがある

FastAPI の認証・認可は、フレームワーク機能だけでは守り切れません。トークン寿命設計、鍵運用、境界強制、監査、テスト、runbookまで含めて初めて、本番で信頼できるセキュリティ基盤になります。