/note/tech

Goの型安全性で実現する複数プロダクトの権限管理

要約:

■ 1. 発表概要

  • 発表者: 石川諒(ishikawa-pro)、LayerX アカウント基盤開発部、2025年10月入社
  • 担当領域: テナント・アカウント管理など共通管理、および認証・認可
  • テーマ: Go の型安全性を活用し、複数プロダクトにまたがる権限管理をスケーラブルに実現する手法

■ 2. バクラクにおける権限管理の構造

  • 各テナントで、アカウントごとに有効なプロダクトのロールを設定・管理する
  • 権限の構成: 複数プロダクト × プロダクトごとに複数ロール × ロール固有の権限(Permission)
  • プロダクト増加に伴いロールと権限の組み合わせも増加し、安全な管理が課題となる

■ 3. 文字列管理の問題点

  • タイポが実行時まで検出できない
  • 存在しない権限名を使用してもコンパイルが通る
  • プロダクト増加に伴い管理が破綻する

■ 4. GoのDefined Typeによる型安全性の確保

  • type キーワードで既存の型から新しい型を定義できる
    • 例: type Permission int32type ProductRole int32
  • PermissionProductRole は互換性のない別の型として扱われる
  • 効果:
    • 異なる型同士の比較 → コンパイルエラー(mismatched types)
    • 生の int32 の誤渡し → コンパイルエラー(cannot use int32 as Permission)
    • 正しい型で正しい値のみ渡せる状態をコンパイル時に強制できる

■ 5. protoによる権限・ロールの定義と自動生成

  • proto の enum で権限とロールを定義する:
    • Permission enum: プロダクトごとに番号帯を割り当て(例: アカウント系=100番台、経費系=200番台)
    • ProductRole enum: プロダクトごとにロールを定義
  • protoc-gen-go が Defined Type(type Permission int32)と定数群を自動生成する
  • 新しい権限の追加は proto に1行追記するだけで完結する
  • ロールと権限の対応関係も proto のカスタムオプションで宣言的に定義する
  • 自社製プラグインが map[Permission]map[ProductRole]bool の逆引きマップを自動生成する
    • キーは Permission、値のキーは ProductRole — 両方が Defined Type

■ 6. RPC定義への権限宣言と権限チェックの流れ

  • RPC 定義のカスタムオプションで、そのRPCに必要な Permission を proto 上で宣言する
  • Interceptor が全 RPC の実行前に自動的に権限チェックを実行する:
    • 認証トークンから []ProductRole を取得
    • RPC に必要な Permission を特定
    • 逆引きマップで Permission に対応する Set[ProductRole] を検索
    • トークンの ProductRole が Set に含まれるか判定し、含まれなければ 403 Forbidden を返す
  • HasPermission 関数は引数・マップ・トークンすべてを Defined Type で統一して実装する
  • Interceptor でもビジネスロジックでも、同じ型・同じ関数で一貫した権限チェックが記述できる

■ 7. まとめ

  • Defined Type × コード生成によりスケールしても壊れない権限管理を実現する
  • Defined Type: 型の混在・タイポをコンパイル時に検知する
  • proto × コード生成: 2000個超の定数と逆引きマップを自動管理する
  • 認証トークン × 生成マップを同じ Defined Type でつなぎ、Interceptor でもビジネスロジックでも一貫した権限チェックを実現する

関連: