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

手形スキーマ

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

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

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

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

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

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


トップレベル構造

additionalProperties: false。必須: tegatapolicyrules

フィールド正規備考
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解釈メモ。各要素: codemessage、任意の related_rules[]

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

ambiguities[].code は次のいずれかです: assumed_interpretationmissing_inputcontradictionunexpressible_delegatedexception_scope


ルールオブジェクト

additionalProperties: false。必須: ideffectsubjectactionsresource

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

subject

subject.roles は任意の、空でない、一意な role 値の配列です。ID プロバイダが発行した外部所有の 語彙をそのままの形で保ちます(admin:operateDomain 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はいはいeqneqgtgteltlte のいずれか。
resource_attributeはいはい識別子。

必須であることと正規であることは別です。label は書かなければならず、無い relationship は スキーマが弾きます。しかし意味は持ちません。ハッシュにも、生成される Rego にも、 subject_attributeopresource_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 を参照)。
  • リテラルstringintegerboolean です。
  • 整数のみ: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 の属性への条件を使います。 rolesactions に 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 の行は初見で驚くので、はっきり書きます。「classificationbanned のドキュメントは 閲覧禁止」という deny ルールがあるとき、判定はこうなります。

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

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

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

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

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

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

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

そのキーを参照しているもの導出結果
値を比較する演算子(eqneqgtgteltlteinnot_incontainsnot_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" }
}
]
}

関連項目