descope-fga-schema について
Descope FGAスキーマの設計と適用を支援するスキルです。草案、ドライラン、確認、承認の手順を通じて、安全な編集と検証を重視します。
主な機能
- 01FGA DSLスキーマの作成
- 02ドライランによる検証
- 03適用前の削除リスク確認
- 04文法と命名規則の遵守
- 05権限と組み込み制約の優先
活用シーン
- 01新しい認可スキーマの作成
- 02既存スキーマの安全な拡張
- 03スキーマ変更によるデータ損失の確認
MCP 対応
Descope Management MCPが必要です。GetFGASchema、DryRunSchema、CreateFGASchema操作でスキーマの読み取り、検証、適用を行います。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ descope/ skills --skill descope-fga-schemaインストール後、Claude Code で/descope-fga-schemaを入力して読み込まれたか確認します。
詳細
FGA DSL の作成
Descope FGA スキーマの設計と適用をユーザーに支援します。ワークフローは次のとおりです。要件を把握する → DSL を作成する → ドライランで検証する → ユーザーに提示し、データ損失に関する警告があれば伝える → 確認を得る → 適用する。
MCP の設定 — まず確認し、見つからなければ停止
ほかの作業を始める前に、名前に FGASchema または DryRunSchema が含まれるツール(例:mcp__descope__DryRunSchema)を探し、Descope Management MCP が接続されているか確認してください。正確なプレフィックスはユーザーによる MCP のインストール方法によって異なりますが、操作 ID は DryRunSchema、CreateFGASchema、GetFGASchema です。
ツールが見つからない場合: 以下のメッセージのみを出力し、その時点でターンを終了してください。スキーマを生成したり、「接続されたら適用する内容はこちらです」と述べたり、設計作業を行ったり、処理を続けたりしてはいけません。
Descope Management MCP が必要です。まだインストールしていない場合は、インストールして認可し、AI エージェントを再起動して
/descope-fga-schemaを再実行してください。設定手順については https://docs.descope.com/mcp/mcp-server#connecting を参照してください。 すでにインストール済みの場合は、認可が必要な可能性があります。Descope MCP を認可し、AI エージェントを再起動して/descope-fga-schemaを再実行してください。
ツールが見つかった場合: ほかの作業を始める前に、接続性を確認するため直ちに GetFGASchema を呼び出してください。この呼び出しで認可エラーが返された場合は、以下のメッセージのみを出力し、その時点でターンを終了してください。
Descope MCP はインストールされていますが、認可されていません。認可して Claude Code を再起動し、
/descope-fga-schemaを再実行してください。
FGA の操作はすべて MCP ツール呼び出しを通じて行ってください。HTTP リクエストを直接送信してはいけません。
接続後、編集を始める前に GetFGASchema ツールを使って現在のスキーマを読み取ってください。既存のスキーマを変更するようユーザーから依頼された場合は、必ず行ってください。
文法
すべてのスキーマは、次の内容で始める必要があります。
model AuthZ 1.0
API が受け付ける名前とバージョンは、これ以外にありません。
全体構造:
model AuthZ 1.0
[constraint <Name>[:<Kind>][(args...)]]*
[condition <Name>(<param type, ...>) { <CEL bool expr> }]*
type <TypeName>
[relation <name>: <TypeRef> [| <TypeRef>]* [with <condExpr>]]*
[permission <name>: <expr> [with <condExpr>]]*
キーワード:model type relation permission condition constraint with
演算子:
- Permission 式:
|は和集合、&は積集合、-は差集合です。演算子は括弧と組み合わせて使用できます:a | (b - c) - セット矢印:
relation.permission— 保存されたリレーションをたどり、サブジェクト自身の権限に到達します(例:parent.can_view)。 - ターゲットセット:
Type#relation— 以下の専用セクションを参照してください。 with節(リレーションおよび権限):&は AND、|は OR、!は NOT です。括弧も使用できます:with A & (B | !C)。条件はチェック時に評価されます。withは、評価時にリレーションまたは権限を有効とするかどうかを判定します。リレーションまたは権限定義ごとに使用できるwith節は 1 つだけです。複数の条件を組み合わせるには、その節の中で&/|/!を使用してください。
コメントは使用できません — DSL パーサーにはコメント用のトークンがありません。
命名規則:Type、Condition、Constraint には PascalCase を使用してください。リレーションと権限には snake_case を使用してください。
ターゲットセットのパターン(Type#relation)
リレーションをグループのメンバーが持つようにする場合(例:「この Team のすべてのメンバー」)、リレーション定義に Type#relation を直接記述してください。これにより個々のメンバーのサブジェクトが保存され、権限チェックに適した粒度になります。
間接的な方法では、グループ自体を保存し、権限を通じてメンバーシップを導出します。リレーションの展開結果は正しくなりますが、独自の意味を持たない contributor_team リレーションが追加されます。意味のあるエンティティは個々のメンバーだけです。ターゲットセット構文はより簡潔で、意図を直接表現できます。
避ける(意味上の価値がない余分なリレーション):
type Repository
relation contributor_team: Team
permission contributor: contributor_team.member
推奨(簡潔で直接的):
type Repository
relation contributor: Team#member
直接のサブジェクトとターゲットセットのサブジェクトは組み合わせられます:relation editor: User | Team#member
避けるべき ABAC のアンチパターン
条件を表すために、「blocked」リレーションと減算を決して組み合わせないでください
with 条件はチェック時、つまりリクエストで渡されたコンテキストに対して権限チェックを行う際に評価されます。リレーションは常に無条件で保存され、条件は権限の評価時にそのリレーションが有効と見なされるかどうかにのみ影響します。
blocked リレーションと減算を組み合わせるパターンは誤りです。除外するユーザーごとに、DB 内で別個の blocked エッジを手動で管理する必要があるためです。これは適切な方法ではありません。代わりに、アクセスを許可するリレーションに with !Condition を使用してください。追加のリレーションを保存することなく、チェック時に自動で評価されます。
// NEVER do this — requires maintaining a separate "blocked" edge per user in the DB
relation creator: User
relation blocked: User with NorthKorea
permission can_delete: creator - blocked
// Right — condition evaluated automatically at check time; no extra edges
relation creator: User with !NorthKorea
permission can_delete: creator
組み込みの制約で対応できる場合に、カスタム CEL を書かないでください
数値範囲をチェックするカスタム condition は、単に NumRange(または NumAtLeast/NumAtMost)を再発明しているだけです。組み込みの制約はより簡潔で、エラーが起こりにくく、人とエージェントの両方にとってスキーマを読み解き、推論しやすくする共通の語彙になります。組み込みの制約を使用してください。
誤り:
condition DuringBusinessHours(seconds_since_midnight int) { seconds_since_midnight >= 32400 && seconds_since_midnight < 61200 }
正しい例:
constraint BusinessHours:NumRange(32400, 61200)
(制約にわかりやすい名前を付けたい場合は、名前付きエイリアスを使用してください。)
リレーションとパーミッション
リレーションは、純粋なリレーショングラフにエッジを追加します。パーミッションは既存のリレーションを再利用する派生ルールです。ReBAC グラフにのみエッジを追加し、純粋なグラフのエッジは新たに追加しません。純粋なグラフのエッジが少ないほど、チェック時に走査する対象が減り、スキーマ内のすべてのチェックでキャッシュヒットする可能性が高まります。そのため、パーミッションはより簡潔であり、純粋なグラフを軽量に保つことで、システムの拡張に伴う全体的なチェック性能の向上につながる傾向があります。可能な限り、パーミッションで要件を満たすことを優先してください。直接保存するリンクが本当に必要な場合にのみ、新しいリレーションを追加してください。
あるパーミッションが別のパーミッションの厳密な上位集合である場合は、展開した内容を繰り返すのではなく、より狭いパーミッションを参照して表現してください。これにより、スキーマが簡潔になり、アクセス階層が自己文書化されます。読者は can_admin が can_write を含み、さらに can_write が can_read を含むことをすぐに理解できます。
避けるべき例(パーミッション間でリレーションを繰り返す):
permission can_admin: owner
permission can_write: owner | editor
permission can_read: owner | editor | viewer
推奨例(各パーミッションが前のものを基に構成される):
permission can_admin: owner
permission can_write: can_admin | editor
permission can_read: can_write | viewer
組み込み制約
カスタム CEL を使用する前に、組み込み制約を使用してください。
| 制約 | ランタイムパラメーター(引数なし形式) | ハードコード形式 |
|---|---|---|
IpRange | ip ipaddress, ip_range string | IpRange("10.0.0.0/8") |
IpList | ip ipaddress, allowed_ips list | IpList("1.2.3.4","5.6.7.8") |
DateExpiryEpochSeconds | now_epoch_seconds int, expiry_epoch_seconds int | DateExpiryEpochSeconds(1735689600) |
StringMatchRegex | str string | StringMatchRegex("^admin_.*")(正規表現が必要です) |
NumAtLeast | num double, min int | NumAtLeast(18) |
NumAtMost | num double, max int | NumAtMost(100) |
NumRange | num double, min int, max int | NumRange(0,100)(min ≤ max) |
BoolCheck | bool bool, expected bool | BoolCheck(true) |
GeoCountry | country_code string, allowed_countries list | GeoCountry("US","GB")(ISO 3166-1 alpha-2) |
IntList | int int, allowed_ints list | IntList(1,2,3) |
LabelList | label string, allowed_labels list | LabelList("foo","bar") |
同じ種類の制約を複数使用する場合: 名前付きエイリアスなしでは、同じ種類の制約を複数宣言できません。区別するためにエイリアスが必要です。名前付きエイリアスは、元の種類と同じランタイムパラメーター名を共有します(エイリアスによって変わるのは制約の識別子のみで、パラメーターは変わりません)。両方の制約が同じパラメーターを対象とする場合は問題ありません。実質的に異なるパラメーターを対象とする2つの制約が必要な場合は、代わりに一意のパラメーター名を使ったカスタム CEL 条件を使用してください:
// Two GeoCountry constraints sharing the same country_code param — alias required, shared param is intentional
constraint FiveEyes:GeoCountry("US","GB","CA","AU","NZ")
constraint Sanction:GeoCountry("KP","IR","SY","RU")
// Need a second IP check with a different param name? Use a custom condition
condition OfficeNetwork(office_ip ipaddress, office_range string) { office_ip.in_cidr(office_range) }
カスタム CEL — 組み込み制約でロジックをカバーできない場合、またはエイリアスによるパラメーターの分離では不十分な場合にのみ使用してください:
condition InNetwork(user_ip ipaddress, allowed_range string) { user_ip.in_cidr(allowed_range) }
CEL のパラメーター型:int、string、bool、double、list、ipaddress。本体は bool を返す必要があります。評価器によってコスト制限が適用されるため、ネストされた exists は避けてください。
編集時の安全性プロトコル
既存のスキーマを編集する場合は、まず GetFGASchema で現在のスキーマを読み取り、実際の状態を確認してください。
- ユーザーが、すでに存在するものの追加を依頼した場合は、何が存在するかを正確に伝えて終了してください。黙って上書きしてはいけません。
- スキーマから型全体またはリレーション定義を削除すると、その型またはリレーションのすべてのリレーションタプルがデータベースから完全に削除されます。リレーション定義の対象型を編集することは、その定義を削除して再作成することと同じです。同じデータ損失のリスクが適用されます。必ずユーザーに確認し、続行する前に影響を理解していることを確認してください。
- 例外:リレーションの
with条件のみを編集しても、タプルは削除されません。 リレーションは無条件で保存され、条件はチェック時に評価されます。他に変更のないリレーションのwith CondAをwith CondBに変更しても、既存のタプルはすべて保持され、新しい条件に基づいて評価されるようになります。これはリレーション全体を編集するより安全ですが、注意は必要です。古い条件の動作に依存していた呼び出し元は、変更後に異なるアクセス結果を得ることになります。 - 権限の削除または編集によってリレーションタプルが削除されることはありませんが、その権限に依存していた下流の権限やチェックは、気づかれないまま機能しなくなります。ユーザーに確認してください。
- 新しい型、リレーション、権限の追加は、一般に安全です。
検証と適用のワークフロー
DSL を生成または編集するたびに、次の手順に従ってください。
ステップ 1 — ドライラン
提案する DSL を使って MCP ツール DryRunSchema を実行します。これにより、スキーマが検証され、適用した場合に削除されるデータが報告されます。
- エラーの場合:スキーマは無効です。エラーメッセージを読み、DSL を修正して再試行してください。試行は最大5回までです。それでも失敗する場合は停止し、最後のエラーをユーザーに表示してください。
- 成功した場合:ステップ2に進みます。
レスポンスには次の内容が含まれます:
{
"deletesPreview": {
"hasDeletes": true,
"relations": ["folder#viewer", "doc#editor"],
"types": ["LegacyRole"]
}
}
Step 2 — ユーザーに提示する
次の内容を提示します。
- 提案する DSL 全体(コードブロックで整形)
hasDeletesが true の場合 — データベースから完全に削除されるすべてのリレーション型と名前空間型を列挙した、明確な警告
警告の例:
警告:このスキーマを適用すると、次の型の保存済みリレーションがすべて完全に削除されます。
folder#viewerdoc#editorこの操作は元に戻せません。続行するには承認してください。
hasDeletes が false の場合は、スキーマを提示して承認を求めるだけです。
Step 3 — 承認を得る
Step 2 の後で応答を終えてください。DryRunSchema と同じターンで CreateFGASchema を呼び出してはいけません。先にユーザーがスキーマと削除に関する警告を確認できるようにしてください。ユーザーが明示的な承認(「はい」、「適用」、「進めてください」など)を返信するまで待ちます。
Step 4 — 適用する
CreateFGASchema を呼び出す前に、次の 3 つすべてを満たしていることを確認してください。
- 以前のターンで DSL 全体をコードブロックに表示した(このターンではない)
- ドライランの応答に含まれる削除に関する警告をすべて提示した(または
hasDeletesが false であることを確認した) - ユーザーの最新のメッセージが、承認を求める確認への明示的な承認である
いずれかを満たしていない場合は、CreateFGASchema を呼び出さないでください。Step 2 に戻ってください。
3 つすべてを確認できたら、ドライランと同じ DSL を指定して CreateFGASchema を呼び出します。成功したことをユーザーに伝えてください。
この確認プロセスが重要なのは、CreateFGASchema が取り消せないためです。スキーマ変更によって削除されたリレーションタプルは復元できません。変更が些細に見える場合でも、承認を省略するのは決して安全ではありません。
例
階層構造を使った基本的な ReBAC
model AuthZ 1.0
type User
type Folder
type Doc
relation owner: User
relation parent: Folder
permission can_view: owner | parent.owner
permission can_edit: owner
ターゲットセットを介したグループメンバーシップ
model AuthZ 1.0
type User
type Team
relation member: User
type Repository
relation owner: User
relation contributor: User | Team#member
permission can_push: owner | contributor
permission can_read: can_push
ABAC:時間制限付きアクセス
model AuthZ 1.0
constraint ShiftHours:NumRange
type User
type PatientRecord
relation viewer: User with ShiftHours
relation owner: User
permission can_view: viewer | owner
エイリアスを使った制約の種類の再利用 — およびパーミッションでの with
model AuthZ 1.0
constraint FiveEyes:GeoCountry("US","GB","CA","AU","NZ")
constraint Sanction:GeoCountry("KP","IR","SY","RU")
constraint OfficeOnly:IpRange("10.0.0.0/8")
type User
type Resource
relation allowed: User with FiveEyes & !Sanction
relation owner: User
permission can_access: allowed
permission can_delete: owner with OfficeOnly
allowed はリレーションに地理的な制限を適用します。このリレーションを使用するすべてのパーミッションに適用されます。can_delete はパーミッション自体に with を使うため、IP 制限は削除にのみ適用され、アクセスには適用されません。
with を使ったネストされたパーミッション — 条件の積み重ね
model AuthZ 1.0
constraint BusinessHours:NumRange(32400, 61200)
constraint OfficeNetwork:IpRange("10.0.0.0/8")
type User
type Document
relation reader: User
permission can_read: reader with BusinessHours
permission can_edit: can_read with OfficeNetwork
can_edit には、can_read の BusinessHours と can_edit 独自の with による OfficeNetwork の両方が必要です。チェック時には両方の条件を満たす必要があります。ネストされたパーミッションの with 句は累積されます。