■ 1. 発表概要
- 発表者: 石川諒(ishikawa-pro)、LayerX アカウント基盤開発部、2025年10月入社
- 担当領域: テナント・アカウント管理など共通管理、および認証・認可
- テーマ: Go の型安全性を活用し、複数プロダクトにまたがる権限管理をスケーラブルに実現する手法
■ 2. バクラクにおける権限管理の構造
- 各テナントで、アカウントごとに有効なプロダクトのロールを設定・管理する
- 権限の構成: 複数プロダクト × プロダクトごとに複数ロール × ロール固有の権限(Permission)
- プロダクト増加に伴いロールと権限の組み合わせも増加し、安全な管理が課題となる
■ 3. 文字列管理の問題点
- タイポが実行時まで検出できない
- 存在しない権限名を使用してもコンパイルが通る
- プロダクト増加に伴い管理が破綻する
■ 4. GoのDefined Typeによる型安全性の確保
typeキーワードで既存の型から新しい型を定義できる
- 例:
type Permission int32、type ProductRole int32PermissionとProductRoleは互換性のない別の型として扱われる- 効果:
- 異なる型同士の比較 → コンパイルエラー(mismatched types)
- 生の
int32の誤渡し → コンパイルエラー(cannot use int32 as Permission)- 正しい型で正しい値のみ渡せる状態をコンパイル時に強制できる
■ 5. protoによる権限・ロールの定義と自動生成
- proto の
enumで権限とロールを定義する:
Permissionenum: プロダクトごとに番号帯を割り当て(例: アカウント系=100番台、経費系=200番台)ProductRoleenum: プロダクトごとにロールを定義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 でもビジネスロジックでも一貫した権限チェックを実現する