語彙 (vocabulary.json)
ninka/vocabulary.json は、手形で利用するプロジェクト固有の語と、Decision Log にマスクせず記録してよい subject / resource 属性を宣言するファイルです。
このファイルは任意です。無い場合、role・action・resource type については、Ninka が可能な範囲のヒューリスティックな検査だけを行います。ファイルがある場合は閉世界の V1 検査が有効になり、ポリシーで使う role・action・resource type は対応する一覧に宣言されていなければなりません。属性については、attributes が空でない場合に閉世界として検査します。
{
"roles": ["employee", "member"],
"actions": ["view", "edit"],
"resource_types": ["invoice", "document"],
"attributes": {
"subject.user_id": "string",
"resource.owner_id": "string",
"resource.amount": { "type": "integer" }
},
"decision_log": { "unmasked": ["resource.amount"] }
}
なぜ語彙を宣言するのか
admin と administrator のような異なる文字列が、本当に同じ概念の表記揺れなのかどうかを、ヒューリスティックだけで確実に判断することはできません。そこで、使ってよい語をファイルに明示し、それ以外を受け付けない形にします。
レビュー上の利点は明確です。たとえば admin2 という role を新しく使うには、vocabulary.json にその値を追加する必要があります。新しい語が、誰かが文字列を書いただけでポリシー集合へ入り込むのではなく、レビュー対象の明示的な変更として現れます。
ただし、Ninka が語の意味まで推測するわけではありません。たとえば vocabulary に admin と Admin の両方を明示的に宣言すれば、それらは完全一致で比較される別の token です。閉世界の仕組みが保証するのは「使う語が宣言されていること」であって、「似た語を自動的に同一視すること」ではありません。
フィールド
ルートに置けるキーは次の 5 つだけです。未知のルートキーはエラーになります。綴り間違いを「設定が無い」として黙って無視しないためです。
| フィールド | 型 | 意味 |
|---|---|---|
roles | 文字列配列 | ポリシーで利用できる role |
actions | 文字列配列 | ポリシーで利用できる action |
resource_types | 文字列配列 | ポリシーで利用できる resource type |
attributes | オブジェクト | スコープ付き属性パスと、その値の型 |
decision_log | オブジェクト | Decision Log の開示設定。定義されているのは unmasked だけ |
5 つのフィールドはいずれも省略できます。
roles / actions / resource_types
vocabulary.json がある場合、ポリシー集合で利用する wildcard 以外の role・action・resource type は、それぞれ対応する一覧に宣言されている必要があります。未宣言の値を使うと V1 のコンパイルエラーになります。
role は外部 IdP が発行する文字列を、role の制約内でそのまま使えます。一方、action と resource type は Ninka 側で設計する語なので、手形の命名規則に従います。詳しくは 手形スキーマ を参照してください。
attributes
キーには subject.user_id や resource.owner_id のような、スコープ付きの属性パスを書きます。
値は短縮形とオブジェクト形式のどちらでも指定できます。
{
"subject.user_id": "string",
"resource.amount": { "type": "integer" }
}
指定できる型は次の 3 つです。
stringintegerboolean
オブジェクト形式に置けるキーは type だけです。未知のキーや未知の型は無視せず、エラーとして拒否します。
宣言した型は、ポリシーをまたいだ入力契約の検査 C4 にも使われます。同じスコープ付き属性について、ポリシー間で異なる型を主張していればエラーになります。
属性の閉世界検査には意図的な例外があります。attributes: {} が空の場合、それを「このプロジェクトは属性を一切使わない」という宣言とは扱いません。属性キーに対する V1 は、attributes に少なくとも 1 件の宣言がある場合に有効になります。既存プロジェクトへ段階的に語彙管理を導入できるようにするためです。
decision_log.unmasked
Decision Log へ、値をマスクせず記録してよい属性を明示的に列挙します。
一覧に無い subject / resource 属性はマスクされます。decision_log 自体が無い場合や unmasked が空の場合、Ninka が subject / resource 属性を暗黙に開示することはありません。
各項目は、次の条件を満たす必要があります。
attributesに宣言されていること- 同じ値を重複して列挙しないこと
action.nameとresource.typeではないこと
action.name と resource.type は、ポリシー選択に使うリテラルとして Decision Log の契約上もともと常に生の値で記録されます。そのため decision_log.unmasked に書くとエラーになります。
Ninka は unmasked の一覧を並べ替えてから manifest へ反映します。宣言順が成果物のバイト列へ影響しないようにするためです。ninka-authz verify はソースから値を再導出し、検査対象となる成果物パス上の manifest と比較します。Git で追跡されているかどうかは検査しません。
Decision Log を出力するとき、実際にこの開示設定を適用するのはランタイムです。詳しくは ランタイム API と .NET ランタイム API を参照してください。
ファイルの有無で検査はどう変わるか
vocabulary.json が無い | vocabulary.json がある | |
|---|---|---|
| 未宣言の role / action / resource type | 閉世界の宣言が無いため V1 では検査できない | エラー (V1) |
| ポリシー間の大小文字だけが異なる語 | フォールバックの C3 警告 | C3 は使わず、利用する token を vocabulary に明示する |
| 未宣言の属性キー | vocabulary による検査無し | attributes が非空なら エラー (V1) |
vocabulary が無い場合でも、そのモード用に定義された語彙ドリフトのヒューリスティックは関所が実行できます。vocabulary がある場合は「似て見える語を推測する」のではなく、「利用する語をすべて明示的に宣言する」という統制へ切り替わります。
「ファイルが無い」と「ファイルが壊れている」は別
vocabulary.json が無いこと自体は合法です。一方、ファイルが存在するのに内容が不正な場合、それを「無いもの」として扱うことはありません。
たとえば次はコンパイルを停止します。
- JSON として不正
- 未定義のルートキーがある
- 属性の型宣言が不正
- Decision Log の開示設定が不正
設定ミスによって、意図せず語彙管理や開示設定が無効になることを防ぐためです。