メインコンテンツまでスキップ

手形スキーマ

手形 (Tegata) スキーマ、バージョン 0.1 の完全なリファレンスです。手形は <policy-id>.tegata.json という名前の JSON ドキュメントで、1 つの認可ポリシーを宣言します。本ページでは、すべてのフィールド・ 演算子・固定された評価セマンティクスを記載します。

導入は クイックスタート と ポリシーを書く を参照してください。

正規フィールドとメタデータ​

すべてのフィールドは 正規 (canonical) か メタデータ のいずれかです。

  • 正規 (canonical) フィールドは、コンパイル対象となる認可仕様を構成します。tegata_hash に 含まれます。
  • メタデータ フィールドは、人間によるレビューと監査コンテキストのためのものです。ハッシュから 除外され、コンパイルされません。

実務上の帰結: ルールの並べ替えや description の書き換えは tegata_hash を変えませんが、role・ action・condition・effect の変更は変えます。


トップレベル構造​

additionalProperties: false。必須: tegata、policy、rules。

フィールド型正規備考
tegatastringはいスキーマバージョン。const "0.1"。
policyobjectはいid 必須。下記参照。
attributesobject mapはい属性の型宣言。下記参照。
auditobjectいいえ人間・監査用メタデータ。コンパイルされない。下記参照。
rulesarrayはいminItems: 1。ルールオブジェクト 参照。

policy​

フィールド型正規備考
policy.idstringはいkebab-case ^[a-z][a-z0-9]*(-[a-z0-9]+)*$、maxLength: 64。
policy.descriptionstringいいえ自由記述。

attributes​

object map(正規)です。キーは ^(subject|resource|environment|custom).<name...> に一致し、値は "string" | "integer" | "boolean" です。ここで属性を宣言する必要があるのは、その型がルールの リテラルから導出できない場合だけです(例: relationship でのみ使う属性)。

relationship でのみ参照される属性を宣言しない場合、その Tegata にはその属性の型の情報源が ありません。宣言された型も無く、型を推論できる条件リテラルも無いからです。Sekisho は まさにそれを警告として述べ(S14)、追加すべき宣言を提示します。例: "attributes": { "subject.org_id": "string", "resource.org_id": "string" }。欠けている型を 供給できるのは書き手だけなので、この診断は Tegata の話で止まります。

型を持たない属性を生成 projection がどう表すかは、その projection の領分であり言語によって 異なります。コンパイラはここで consumer の言語の型名を挙げません。呼び出し側がそのプロパティの 静的チェックを失うことは変わらないので、表現の詳細は各言語の projection のリファレンスを参照して ください。

audit​

メタデータ(コンパイルされない)です。フィールド:

フィールド型備考
source_textstring元の自然言語の要件。
normalized_textstring正規化した言い換え。
ambiguitiesarray解釈メモ。各要素: code、message、任意の related_rules[]。

解釈ノートはレビューの表面です。エージェントが自分で決めたことは、移行時のパリティ判断や 意味論差の受容も含めて、すべてここに書きます。description だけに書いて済ませません。 related_rules[] の参照整合は関所が検証します(S13)。

ambiguities[].code は次のいずれかです: assumed_interpretation、missing_input、contradiction、 unexpressible_delegated、exception_scope。


ルールオブジェクト​

additionalProperties: false。必須: id、effect、subject、actions、resource。

フィールド型必須備考
idstringはいkebab-case、maxLength: 64、ファイル内で一意。
effectstringはい"allow" または "deny"。
descriptionstringいいえメタデータ。
subjectobjectはい任意の roles。下記参照。
actionsarrayはい下記参照。
resourceobjectはいtype 必須。下記参照。
relationshipsarrayいいえエンティティ間比較。Relationships 参照。
conditionsarrayいいえ属性制約。Conditions 参照。

subject​

subject.roles は任意の、空でない、一意な role 値の配列です。ID プロバイダが発行した外部所有の 語彙をそのままの形で保ちます(admin:operate、Domain Admins)。正規化が必要な識別子ではありません。 制約はレビュー可能性のためだけにあります: ASCII 可読、1〜64 文字、制御文字なし、前後の空白なし (内部の空白は可)。非ASCII は 0.x では意図的に非対応です。аdmin のキリル文字 а のような 同形異字は、レビューで admin と区別できないためです。role は any-of(列挙した いずれかの role を持てば一致)で照合されます。任意の subject に一致させるには roles を省略します。 その場合もルールには "subject": {} を残します。subject プロパティ自体は必須で、欠落したルールは Sekisho が拒否します。

actions​

必須です。空でない一意な snake_case 識別子の配列(any-of で照合)か、正確なワイルドカード ["*"] のいずれかです。

resource​

type は必須で、snake_case 識別子またはワイルドカード "*" です。


Relationships​

relationships は任意の配列です。エンティティ間比較(subject 対 resource)が許されるのは ここだけ です。

フィールド必須正規備考
labelはいいいえ人間可読な名前。
subject_attributeはいはい識別子。
opはいはいeq、neq、gt、gte、lt、lte のいずれか。
resource_attributeはいはい識別子。

必須であることと正規であることは別です。label は書かなければならず、無い relationship は スキーマが弾きます。しかし意味は持ちません。ハッシュにも、生成される Rego にも、 subject_attribute・op・resource_attribute から作られるヘルパー名にも入りません。 label を書き換えても再承認は要りません。必須なのは、1 つのルールが複数の relationship を 持てるので、レビューする人にはそれぞれの名前が要るからです。

例。「請求書の提出者がリクエストしたユーザーである」を表すと、次のようになります。

{ "label": "own_submission", "subject_attribute": "user_id", "op": "eq", "resource_attribute": "submitted_by" }

Conditions​

conditions は任意の配列です。各 condition は op による判別共用体です。key は スコープ付きキー (subject.*、resource.*、environment.*、custom.*)です。

ファミリop の値値フィールド備考
スカラーeq, neqvalue(リテラル)等価 / 非等価。
順序gt, gte, lt, ltevalue(整数または文字列)boolean は不可。
集合in, not_invalues(空でない一意なリテラル配列)集合への所属。
配列メンバーシップcontains, not_containsvalue(リテラル)配列属性への所属。
存在exists, not_exists、値なし。

例:

{ "key": "resource.amount", "op": "lte", "value": 500000 }

識別子とリテラル​

  • 識別子(action・resource type・属性名)は snake_case です:アプリが設計し、呼び出し箇所に リテラルとして書く語彙です。
  • role 値は識別子ではありません: 所有者(あなたの IdP)が発行した語彙をそのまま保ちます (レビュー可能性のための制約は subject を参照)。
  • リテラル は string・integer・boolean です。
  • 整数のみ:v0.1 に浮動小数点数はありません。 金額やしきい値は整数です(例: JPY を整数として)。

評価セマンティクス​

これらは固定で、設定変更できません。

ルール挙動
ルール内すべての condition(と relationship)は AND されます。
同一 effect のルール間OR されます。その effect のルールがひとつでも一致すれば一致します。
allow 対 denydeny が allow を上書き(Deny-First)。
一致する allow がないdeny、Zero-Trust、デフォルト false。
roles / actionsany-of で照合。
ワイルドカード"*" はすべてに一致。関所は使用を情報として通知し (S8)、resource.type: "*" を持つポリシーは全リソース型を管轄と宣言します (C6)。

role の all-of が要るときは、ルールを分けるか、subject の属性への条件を使います。 roles と actions に all-of の形はありません。

1 回の判定が対象にするのは 1 件のリソース​

check() は 1 つのポリシーを名指し、属性を渡した具体的な 1 件のリソースに対して評価します。 集合に対する判定は Ninka にはありません。

一覧を絞り込むために候補ごとに check() を呼ぶのは正しい使い方です。その結果をまとめるのは 別です。複数の結果を OR して、集合全体に対する 1 つの認可判断を作らないでください。その答えは どのポリシーも評価していませんし、deny-overrides は 1 回の判定の中で効くのであって、 あとから行った OR には及びません。

deny-overrides が効くのも、名指したポリシーの中だけです。別のポリシーファイルに置いた deny は、 このポリシーの allow を制限しません。そこに置いた禁止は、決して効きません。関所はその配置を 拒否し、効かない禁止がそのまま出荷されるのを止めます。

入力が欠けているとき、ルールはどう動くか​

判定は、渡された入力から下されます。ルールが比較する値が欠けているとき、そのルールは 単に一致しないのではありません。挙動はルールの effect によって変わり、どちらの向きでも 欠損がアクセスを広げることはありません。

ルールの effect比較する値が欠けている結果
allow条件は成立しないその allow ルールは一致しない
deny条件は成立したものとして扱うその deny ルールが発火する

deny の行は初見で驚くので、はっきり書きます。「classification が banned のドキュメントは 閲覧禁止」という deny ルールがあるとき、判定はこうなります。

resource.classificationdeny は発火するか
"ok"しない
"banned"する
欠損する
""(空文字)する

欠損が deny を黙らせるなら、属性を送らないだけで禁止を回避できてしまいます。型が契約と 違う値も同じ扱いです。status を "banned" と比べる deny は、status が true や ["banned"] で届いたときにも発火します。

欠損は「キーが無い」よりも広い言葉です。

  • 空文字は欠損として扱います
  • 空配列も欠損として扱います。subject.roles: [] は roles を送らない呼び出しと同じで、 role を参照する deny は発火します
  • オブジェクトは、空でも空でなくても欠損として扱います。手形の値はスカラーか配列だけで、 等しいゴミオブジェクト同士が relationship を成立させてはならないためです

exists と not_exists は例外です。存在そのものを検査するので、どちらの effect でも 字義どおりに評価します。exists の条件が不在で成立することはありません。

必須の入力と、任意の入力​

コンパイラは、ポリシーが必要とする入力キーをルール本文から導きます。宣言は要りませんし、 書くこともできません。生成される入力の型は、この導出から決まります。

そのキーを参照しているもの導出結果
値を比較する演算子(eq、neq、gt、gte、lt、lte、in、not_in、contains、not_contains)または relationship必須
exists / not_exists だけ任意。意図的な不在が正当な状態であるため
存在検査と値の比較の両方任意

action は常に必須です。resource_type も常に必須で、全ルールがワイルドカードのときだけ 任意になります。subject.roles は、いずれかのルールが role を挙げた時点で必須になります。

ここでの必須は「そのキーの由来ルールにおいて必須」という意味です。runtime が必須キーの欠落を 理由に呼び出しを弾くことはありません。approve のルールだけが要るキーの欠落で view の 要求を拒否しては、正当な要求を誤って拒むことになるからです。欠けた入力は診断のチャネルで 知らせ、判定は上の規則が決めます。


完全な例​

正規の ninka/invoice-access.tegata.json:

{
"tegata": "0.1",
"policy": {
"id": "invoice-access",
"description": "請求書の閲覧・削除・承認"
},
"attributes": {
"subject.user_id": "string",
"resource.submitted_by": "string"
},
"audit": {
"source_text": "従業員は自分が提出した請求書を閲覧できる。マネージャー・経理・管理者は全ての請求書を閲覧できる。マネージャーは50万円以内の請求書を承認できる。経理は金額によらず承認できる。管理者は請求書を削除できる。",
"ambiguities": [
{
"code": "assumed_interpretation",
"message": "「自分が提出した」を relationship(subject.user_id = resource.submitted_by)で表現した。代理提出・共同提出の概念はないものと仮定。",
"related_rules": ["allow-employee-view-own-invoice"]
},
{
"code": "assumed_interpretation",
"message": "マネージャー・経理・管理者の閲覧を、部署による制限のない全請求書と解釈した。部署でスコープするなら relationship を追加する。",
"related_rules": ["allow-staff-view-invoice"]
},
{
"code": "assumed_interpretation",
"message": "「50万円以内」を resource.amount lte 500000(整数・JPY)と解釈した。境界値50万円ちょうどは承認可に含む。含まない意図なら lt に変更が必要。",
"related_rules": ["allow-manager-approve-invoice-within-limit"]
},
{
"code": "missing_input",
"message": "resource.amount / resource.submitted_by は請求書レコード(DB)から、subject.user_id はセッションから供給される前提。通貨はJPY単一通貨を仮定。",
"related_rules": ["allow-employee-view-own-invoice", "allow-manager-approve-invoice-within-limit"]
}
]
},
"rules": [
{
"id": "allow-employee-view-own-invoice",
"effect": "allow",
"description": "従業員は自分が提出した請求書を閲覧できる",
"subject": { "roles": ["employee"] },
"actions": ["view"],
"resource": { "type": "invoice" },
"relationships": [
{ "label": "own_submission", "subject_attribute": "user_id", "op": "eq", "resource_attribute": "submitted_by" }
]
},
{
"id": "allow-staff-view-invoice",
"effect": "allow",
"description": "マネージャー・経理・管理者は全ての請求書を閲覧できる",
"subject": { "roles": ["manager", "finance", "admin"] },
"actions": ["view"],
"resource": { "type": "invoice" }
},
{
"id": "allow-manager-approve-invoice-within-limit",
"effect": "allow",
"description": "マネージャーは50万円以内の請求書を承認できる",
"subject": { "roles": ["manager"] },
"actions": ["approve"],
"resource": { "type": "invoice" },
"conditions": [ { "key": "resource.amount", "op": "lte", "value": 500000 } ]
},
{
"id": "allow-finance-approve-invoice",
"effect": "allow",
"description": "経理は金額によらず請求書を承認できる",
"subject": { "roles": ["finance"] },
"actions": ["approve"],
"resource": { "type": "invoice" }
},
{
"id": "allow-admin-delete-invoice",
"effect": "allow",
"description": "管理者は請求書を削除できる",
"subject": { "roles": ["admin"] },
"actions": ["delete"],
"resource": { "type": "invoice" }
}
]
}

関連項目​