1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Cedar Policy in RAR オブジェクト

1
Last updated at Posted at 2025-12-16

はじめに

Cedar Policy Language という、認可ポリシーを記述するための言語があります。この言語で書かれたポリシーを Cedar Policy と呼びます。本記事では、この Cedar Policy をアクセストークンに紐付け、Web API のアクセス制御に利用する方法について見ていきます。

Cedar Policy の利点

Cedar Policy の大きな利点の一つ目は、認可ロジックをビジネスロジックから切り離せることです。Cedar Policy は外部化が可能で、ビジネスロジックとは別の場所で管理することができます。実際に Cedar Policy を管理する商用サービスも存在します (Integrations 参照)。

Cedar Policy の大きな利点の二つ目は、細かい粒度で認可ロジックを記述できることです。例えば、「Jane の友達であれば、Jane の旅行アルバム内の写真を見てコメントすることを許可する」という認可ロジックを記述できます。下記は Cedar Policy Language Reference GuideExample scenario から抜粋した Cedar Policy の例で、この認可ロジックを表現しています。

Cedar Policy の例 — Jane の友達は Jane の旅行アルバムを閲覧してコメントできる
permit (
    principal in Group::"janeFriends",
    action in [Action::"view", Action::"comment"],
    resource in Album::"janeTrips"
);

Cedar Policy に when 節や unless 節を足してポリシーを適用する条件を指定することができます。それらの条件の中で、比較演算子、論理演算子、算術演算子、などを使うこともでき、高い表現力があります。

Cedar Policy の例 — 所有者本人または公開リソースであれば、どのリソースでも閲覧できる
permit (
    principal,
    action == Action::"read",
    resource
)
when {
    resource.owner == principal ||
    resource.tag == "public"
};

Cedar Policy in RAR オブジェクト

アクセストークンに scope (RFC 6749 Section 3.3) を紐付けることで、そのアクセストークンの粗粒度の権限を表現することができます。 同様にして、もしもアクセストークンに Cedar Policy を紐付けることができれば、 そのアクセストークンの細粒度の権限を表現することができるのではないでしょうか?

このアイディアを実現する手段として有力視されているのが、Cedar Policy を RAR オブジェクト (RFC 9396) として表現する方法です。

RFC 9396 OAuth 2.0 Rich Authorization Requests 仕様 (通称 RAR(ラー)) には、RAR オブジェクトという用語は出てきません。しかし、とあるイベントで当仕様の著者の一人が authorization_details 配列内の各要素のことをそう呼んでいて、便利だと思ったので、以降私も RAR オブジェクトという用語を使っています。

Cedar Policy を RAR オブジェクトとして表現する件については、IETF 個人ドラフト draft-cecchetti-oauth-rar-cedar (期限切れ) や IETF 119 OAuth WG など、過去にも議論されています。

IETF 119 OAuth WG | Cedar Profile of OAuth 2.0 Rich Authorization Requests

しかしながら、先行する議論を追ってみたものの、良い設計は見つかりませんでした。そこで、自分で設計することにしました。次節では、設計の際に考慮した点を書き記します。

Cedar Policy in RAR オブジェクトの設計

Cedar Policy 記法の選択

Cedar Policy のオリジナルの記法は独特です。その独特の記法のまま RAR オブジェクトに埋め込むべきか、それとも JSON (JSON Policy Format) に変換して埋め込むべきか、というのは判断が分かれるところです。

JSON 形式は RAR との親和性は高いですが、冗長なので (特に when/unless 条件部の表現)、Cedar コミュニティの大半の人々はオリジナル記法の方を好むと思われます。ですので、記法をどちらかに統一してしまうと、後から問題となりそうです。こういう場合はどちらの記法も利用可能に設計しておくのが無難です。

ここで、さらに設計の分岐点があります。記法の指定を、RAR オブジェクトで必須とされている type プロパティ (RFC 9396 Section 2) を用いておこなうか、それとも他のプロパティ (例えば format) を新設するか、という分かれです。

type プロパティを使う場合、その値は cedar-policy-nativecedar-policy-json という具合に、Cedar Policy であること及びその記法の種類という、二つの意味を併せ持つものになるでしょう。

二つの意味を併せて持たせるのは、直感的には悪い設計のような気がします。加えて、「Cedar の文脈で、RAR で表現したいのは Cedar Policy だけなのか?」という心配もあります。もしかすると、Cedar Policy と Cedar Policy Template を別物として扱いたくなるかもしれません。また、将来的に Cedar Schema を RAR オブジェクトとして表現したくなる可能性もあります。その場合、type プロパティは、それらを区別するために利用するのが良いでしょう。

結論としては、format というプロパティを用意し、その値として cedarjson を指定することで、オリジナル記法か JSON 記法かを選べるようにしました。また、オリジナル記法を好む人の方が多いだろうという予想のもと、format プロパティ省略時のデフォルト値を cedar とすることにしました。

type プロパティ

RAR オブジェクトでは type プロパティ (RFC 9396 Section 2) が必須です。このプロパティの値で RAR オブジェクトの内容が Cedar Policy だと示すことは決定していますが、その具体的な値を決めなければなりません。

最初に出てくる候補は cedar という文字列です。しかしながら、cedar にしてしまうと、前の節でも言及したように、Cedar Policy、Cedar Policy Template、Cedar Schema を区別したくなった場合に困ることが予想されます。

以上を踏まえると、Cedar Policy であることを示すため、type の値は cedar-policy とするのが良さそうです。

Cedar Policy Set

一つの RAR オブジェクトで一つの Cedar Policy を表現すべきか、もしくは Cedar Policy Set を表現すべきか、という分岐もあります。

Representing a policy set with JSON で示されている Cedar Policy Set の JSON 表現では、一つの JSON オブジェクト内に staticPoliciestemplatestemplateLinks が含まれています。これと同等の情報を一つの RAR オブジェクトに埋め込むことは可能です。

しかし、「そもそも RAR の文脈でテンプレートのサポートは不要かもしれない」という疑念が拭えませんでした。というのは、RAR に Cedar Policy を静的に埋め込む場合、テンプレート内のプレイスホルダーを解決した後に埋め込むことになるのではないか、と思うからです。

しかしながら、判断を下すのは難しかったため、判断を保留することにしました。当面、「authorization_details 配列内の複数の RAR オブジェクトで Cedar Policy Set を表現する」ことにしました。しばらく運用して、この方法では問題があることが分かった場合に、改めて Cedar Policy Set の RAR へのマッピングを設計することにしました。

principal, action, resource

Cedar Policy 内では、principalactionresource を参照します。これらの値はどうあるべきでしょうか?

RAR オブジェクトに埋め込まれた Cedar Policy が参照されるのは、その RAR オブジェクトが紐付けられているアクセストークンがリソースアクセスに利用されるときです。principalactionresource は、この文脈に沿う値を持つべきでしょう。

principal は、アクセストークンに紐付くサブジェクト (典型例は ユーザ ID) とするのが自然でしょう。よくある Cedar Policy の例に合わせるなら、エンティティ名は User にするのがよいでしょう。こうしておくと、「principal がユーザ user001 である」という条件は次のように表現できます。

principal == User::"user001"

ただし、Client Credentials フロー (RFC 6749 Section 4.4) で発行されたアクセストークンにはユーザが紐付かないので、その場合はエンティティ名を Client とします。

principal == Client::"app001"

アクセストークンにサブジェクトが紐付く場合とそうでない場合とを区別するのが良いのかどうか、現時点では確信に至っていません。

アクセストークンに groupsrolesentitlements (RFC 9068 Seciton 2.2.3) 属性があれば、それぞれを GroupRoleEntitlement エンティティにマッピングし、principal の親エンティティとして設定するのが良さそうです。そうしておけば、Cedar Policy の中で in を使えるからです。

principal in Group::"group1"

principal の値はアクセストークン発行時に認可サーバによって決定されます。一方で、actionresource はリソースサーバに属するものであり、それらの具体的な値はリソースサーバに決めさせるのがよいでしょう。

例えば、Shared Signals Framework を実装するサーバは、ストリームを作成するアクションを SSF::Stream::Action::"create" と定めるかもしれません。この場合、Cedar Policy に次のような記述を含めることができるでしょう。

action == SSF::Stream::Action::"create"

context

Cedar Policy の when 節や unless 節で参照する context が持つ変数として、どの環境でも最低限次のものは提供できるのではないかと考えています。

変数 説明
time Unix epoch からの経過ミリ秒数で表現された現在時刻
access_token アクセストークンの情報。サブプロパティとして isssubclient_id を持つ。
ip_address クライアントの IP アドレス

設計まとめ

プロパティ 要否 説明
type 必須 値は cedar-policy で固定
format 任意 cedar (デフォルト) または json
policy_id 任意 ポリシー ID
policy 必須 Cedar Policy。format プロパティの値が cedar であれば、Cedar オリジナル記法で書かれた Cedar Policy を表現する単一文字列。

format プロパティの値が json であれば、JSON Policy Format で記述された Cedar Policy を表す JSON オブジェクト。
エンティティ 説明
principal アクセストークンにサブジェクトが紐付いていれば (イントロスペクションレスポンスや JWT アクセストークンのペイロードに sub クレームがあれば)、principal のエンティティは User。そうでなければ Client

User エンティティの場合はアクセストークンの sub の値を一意識別子として扱う。Client エンティティの場合はアクセストークンの client_id の値を一意識別子として扱う。

アクセストークンの groupsrolesentitlements (RFC 9068 Section 2.2.3) の各要素はそれぞれ GroupRoleEntitlement エンティティにマッピングされ、principal の親エンティティとして設定される。 RFC 7643 Section 2.4 に従っていれば、各要素の値は JSON オブジェクトであり、value プロパティを持っているはずである (例: "groups":[{"value":"group1"}])。その value プロパティの値をエンティティの一意識別子として扱う。RFC 7643 Section 2.4 に従っていない場合、JSON 文字列と仮定し (例: "groups":["group1"])、その文字列の値をエンティティの一意識別子として扱う。
action action のエンティティはリソースサーバが定義する。
resource resource のエンティティはリソースサーバが定義する。
コンテキスト 説明
time Unix epoch からの経過ミリ秒数で表現された現在時刻
access_token アクセストークンの情報。サブプロパティとして isssubclient_id を持つ。
ip_address クライアントの IP アドレス

Cedar Policy in RAR オブジェクトの例

上記の設計に基づく Cedar Policy in RAR オブジェクトの例は次のようになります。

Cedar Policy in RAR オブジェクトの例
[
  {
    "type":      "cedar-policy",
    "format":    "cedar",
    "policy_id": "policy-0",
    "policy":    "permit (principal == User::\"12UA45\", action == Action::\"view\", resource);" 
  },
  {
    "type":      "cedar-policy",
    "format":    "json",
    "policy_id": "policy-1",
    "policy": {
      "effect":  "permit",
      "principal": { "op": "==", "entity": { "type": "User",   "id": "12UA45" } },
      "action":    { "op": "==", "entity": { "type": "Action", "id": "view"   } },
      "resource":  { "op": "All" }
    }
  }
]

この例には二つの RAR オブジェクトが含まれています。一つ目は Cedar オリジナル記法で Cedar Policy を記述しており、二つ目は JSON 記法で Cedar Policy を記述しています。ただし、表現しているポリシーの内容は全く同じです。

おわりに

Cedar Policy in RAR オブジェクトについて 5 ヶ月ほど前に LinkedIn に投稿したところ、大きな反響がありました。この Cedar Policy in RAR オブジェクトは、Authlete 社の新しい製品に実装済みで、実際に動いています。

2025 年 10 月 29 日に開催したオンライン勉強会『OAuth・OpenID 標準仕様による徹底的な API 保護』ではデモもおこなっていますので、ご興味があれば録画をご視聴ください。

OAuth・OpenID 標準仕様による徹底的な API 保護 | Cedar Policy
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?