本記事は生成AIと共同で執筆しています。事実関係は可能な範囲で一次情報・実機と照合していますが、誤りが含まれている可能性があります。重要な判断を行う前にご自身でもご確認ください。
Ocean と EDC を並べた回の最後に、「触れていないもの」として他のデータスペースの系統を挙げました。そのうちの一つ、日本の実装を手元に建てました。
結論から
建った docker compose で 11 コンテナ。データ交換まで通った
動かない箇所 公式手順どおりでは 7 箇所で詰まった
うち ODS 側の問題と言えるのは 3 件。2 件は私の読み違い、
1 件は起動を止めない設定漏れ、1 件は原因を特定できていない
EDC との差 認可の問いが違う
EDC 「あなたは何を提示できるか」(クレデンシャルの中身)
ODS 「あなたは何と関係づけられているか」(関係タプル)
効いてくる差 許可の取り消しは ODS が圧倒的に簡単。ただし相手の事前登録が要る
実際、タプルを1本消すと同じリクエストが 200 → 403 に変わった
ODS とは何か
ODS(Open Data Spaces)は、IPA が「国や組織ごとの多様性を尊重する、オープンでスケーラブルな分散データマネジメントの技術コンセプト」と位置づけているものです。その下に、参照アーキテクチャ(ODS-RAM)、技術仕様(ODP)、参照実装の OSS、開発キット(SDK)が並びます。本記事が動かすのは、このうち参照実装と SDK です。
主体は三層に分かれています。
| 役割 | 主体 | 根拠 |
|---|---|---|
| 主導 | IPA デジタルアーキテクチャ・デザインセンター(DADC) | GitHub org の README に "DADC … serves as the neutral body leading ODS" |
| 資金 | NEDO | 「ウラノス・エコシステムの実現のためのデータ連携システム構築・実証事業」(2025〜2027年度) |
| 実装 | レイヤごとに複数の事業者 | 本記事で動かした L2/L3/SDK 群は NTT データグループ名義。Java のパッケージ名は nedo.ods.svc.* |
「ウラノスの実装」と一言で言うと不正確で、政策(経産省)・仕様(IPA DADC)・資金(NEDO)・実装(レイヤごとに複数の事業者)が別々です。
実装の名義はリポジトリごとに分かれています。本記事が動かす L2/L3/SDK 群は NTT データグループ名義ですが、決済(DCS-Payment)と通知(CF-Notifier)は ABtC(Automotive and Battery Traceability Center Association)、L4 のセマンティクス系(SPARQL・Discovery・クローラ)は Intent Exchange, Inc.、L3-PAP や L2-video-streaming などは Open Dataspaces 名義です。本記事が後で起動する決済サービスも ABtC 名義で、この org は複数事業者の相乗りです。org のプロフィールにも「特定個社へのベンダーロックインを回避し」と書かれています。
もう一つ、名前について注意が要ります。改称が公表されたのは 2025年10月15日、IPA のプレス発表「データスペースの技術コンセプト『Open Data Spaces』の共同推進を合意」です。同発表の「表2 Open Data Spacesの位置付けに係る新旧対応表」に、技術コンセプト名・アーキテクチャ名(ODS-RAM)・プロトコル名(ODP)の新旧が並べて示されています。略称の ODS・ODS-RAM・ODP 自体は改称前から使われており、変わったのは正式名称のほうです。
参照アーキテクチャの文書でいうと、V1(2025年2月28日公開)が旧名の「ウラノス・エコシステム・データスペーシズ リファレンスアーキテクチャモデル」、V2(2026年4月1日公開)が新名称「Open Data Spaces リファレンスアーキテクチャモデル(ODS-RAM)」を載せた最初の RAM 文書です。つまり V2 は改称の契機ではなく、改称後に出た最初の版という位置づけになります。
ただし包含関係は変わっていません。IPA のプレス発表は ODS を「ウラノス・エコシステムにより推進される、オープンで中立的な技術コンセプト」と位置づけており、ODS-RAM V2 自体も NEDO のウラノス実証事業の成果を基に編纂されたと明記しています。つまり ウラノス ⊃ ODS のままで、変わったのは中の技術層の呼び名が、国際相互運用性のために中立的な名前に付け替えられたことだけです。
コードは github.com/open-dataspaces にあり、20リポジトリのうち、プロフィール用の .github を除く19件がすべて MIT です。層で分かれています。
L2 トランザクション層 Web API 転送モジュール、映像ストリーミング
L3 アイデンティティ層 アイデンティティコンポーネント、ポリシー管理(PAP)
L4 セマンティクス層 SPARQL サービス、Discovery、クローラ、LLM チャット
SDK オンボーディング用(docker compose / Helm / クライアントライブラリ)
その他 精算・課金/決済、通知
L4 のセマンティクス層は EDC に存在しない層です。ここは後で効いてきます。
建て方
SDK-docker-compose が入口です。構成要素のソースを3つ並べて置き、compose を上げます。
git clone https://github.com/open-dataspaces/SDK-docker-compose.git ods-sdk
cd ods-sdk
git clone --branch=v1.0.0 --depth=1 https://github.com/open-dataspaces/L2-dp-webapi.git
git clone --branch=v1.0.0 --depth=1 https://github.com/open-dataspaces/L3-identity-component.git
git clone --branch=v1.0.0 --depth=1 https://github.com/open-dataspaces/DCS-Payment.git
docker network create shared-network-ods
docker compose up -d
Maven ビルドが2本走るので、初回は時間がかかります。立ち上がるのは11コンテナです。ただしコールドスタートの1回目では揃いません。ログドライバ(Fluentd)がまだ起動していないため gateway が失敗します。もう一度同じコマンドを打つと通ります。
以降に出てくるポート番号は、私の環境の値です。手元で動いている別のものと衝突したので、リポジトリには手を入れず docker-compose.override.yml で付け替えました。ODS の既定値は別です。読み替えてください。
| 用途 | 本記事 | ODS の既定 |
|---|---|---|
| ゲートウェイ | 8190 | 8090 |
| 決済 API | 8401 | 8001 |
| OpenFGA Playground | 3300 | 3000 |
| MinIO コンソール | 9501 | 9001 |
| 層 | サービス |
|---|---|
| L2 | gateway(Spring Cloud Gateway ベースの Web API 転送) |
| L3 | l3-app(認証コンポーネント)、keycloak 26.2.5、openfga(AuthZEN 版) |
| 決済 | payment-app、payment-db |
| 基盤 | PostgreSQL ×2、MinIO、Fluentd、Mockoon |
公式手順どおりでは詰まった箇所が7つ
README の動作確認環境は Windows 11 + WSL2(Ubuntu 24.04) です。macOS で動かすと、順に7箇所で詰まりました。うち 2 件は私の読み違いで、README どおりに進めていれば止まりませんでした(後述の 5・6)。ここではまず起動に関わる4件を挙げ、残りはデータ交換と GUI の節で扱います。
先に断っておきます。この記事を公開する前に、7件それぞれが本当に ODS 側の問題なのかを、リポジトリの実物と突き合わせて検証しました。その結果、2件は私の読み違いで、ODS の不具合ではありませんでした。該当箇所はそのように書き直してあります。動かなかった経緯は残しますが、原因の帰属は訂正しました。
起動に関わる4件のうち、2・4 は環境非依存の欠落です。1 は設定の欠落ではありますが、後述のとおり起動は止まりません。3 は移植性の問題で、README が WSL2 を動作確認環境と明示している以上、「環境の違いではない」とまでは言えません。
1. Keycloak の DB ユーザー名が設定されていない
l3/docker-compose.yml に KC_DB_PASSWORD はあるのに KC_DB_USERNAME がありません。
訂正(公開後に検証しました)。当初ここには「Keycloak はコンテナの OS ユーザー(
root)で接続しようとするためFATAL: role "root" does not existで落ちる。環境に関係なく必ず起きる」と書いていました。誤りです。Keycloak 26.2.5 のコンテナの OS ユーザーは
rootではなくkeycloak(uid=1000)です。KC_DB_USERNAMEを与えない場合、PostgreSQL の JDBC ドライバは既定でこの OS ユーザー名を使います。そしてl3/docker-compose.ymlのPOSTGRES_USERもkeycloakなので、偶然一致して起動が通ります。素の Keycloak 26.2.5 を
KC_DB_USERNAMEなしで同じ構成の PostgreSQL に向けたところ、Keycloak 26.2.5 on JVM ... started in 6.110sで正常に起動し、pg_stat_activity上の接続ユーザーもkeycloakでした。私が見た
FATAL: role "root" does not existは、docker execでpsqlを-Uなしに叩いたときのものでした(docker execの既定ユーザーがrootのため)。Keycloak 起因ではありません。
つまりこれは起動を止める不具合ではなく、明示されていないことによる潜在的な脆さです。POSTGRES_USER を keycloak 以外に変えた瞬間に壊れます。同梱の setup_l3.sh は psql に -U を明示しているので、スクリプト経路からこのエラーは出ません。
2. postgres:18 のマウント位置が旧規約のまま
決済サービスの DB が postgres:18-alpine を使っているのに、マウントは旧来の /var/lib/postgresql/data を指しています。PostgreSQL 18 の公式イメージは、データをメジャーバージョン別のディレクトリに置く仕様へ変わりました。
Error: in 18+, these Docker images are configured to store database data in a
format which is compatible with "pg_ctlcluster" ...
Counter to that, there appears to be PostgreSQL data in:
/var/lib/postgresql/data (unused mount/volume)
マウント先を /var/lib/postgresql にすれば起動します。
3. セットアップスクリプトが GNU 版の grep と sed を前提にしている
初期設定は setup/setup_l3.sh と setup/setup_l2.sh の2本です。ここで2度つまずきます。
grep: invalid option -- P # BSD grep には -P(PCRE)が無い
sed: 1: "...": extra characters at the end of n command # BSD sed の -i は構文が違う
厄介なのは、失敗したときに作りかけの OpenFGA ストアをロールバックすることです。何度か実行するうちに Keycloak 側だけ残って状態が食い違い、結局ボリュームごと消してやり直しました。
macOS では GNU 版を入れて PATH を通してから実行します。
brew install grep gnu-sed
cd setup
PATH="/opt/homebrew/opt/grep/libexec/gnubin:/opt/homebrew/opt/gnu-sed/libexec/gnubin:$PATH" bash setup_l3.sh
4. レルムとストアの束縛タプルが作られない
ここが一番分かりにくい箇所でした。セットアップは OpenFGA に4つのストアを作ります。
ODS-Auth-Admin API 認可
ODS Store - Realm Store Binding レルムとストアの束縛
ODS Store - Operator Plant Authorization 事業者-プラント認可
ODS-USER-STORE 利用者
ところが束縛用のストアとモデルは作るのに、肝心の束縛タプルを書きません。そのため認可 API がすべて 403 になります。
{"status":403,"title":"Realm 'master' is not bound to store '01KZW97298EDR6CZ9F36EXBJ83'."}
しかも L3 の認可 API 自体がその束縛を要求するので、API 経由では作れません。鶏と卵です。OpenFGA に直接書く必要がありました。
curl -X POST "http://localhost:8083/stores/$BINDING_STORE/write" \
-H 'Content-Type: application/json' \
-d '{"writes":{"tuple_keys":[{"user":"realm:master","relation":"bound_to","object":"store:'$API_STORE'"}]},"authorization_model_id":"'$MODEL'"}'
モデル定義(12-create-model-realm-store-binding.json)を読むと、store 型に bound_to という関係があり、そこに realm 型を直接結べる、と書いてあります。書くべきタプルの形はそこから読み取れます。
認証から認可まで通す
ここからは動きます。まずクライアント認証でトークンを取ります。
curl -X POST "http://localhost:8080/auth/token/client" \
-H 'Content-Type: application/json' -H 'API-Key: API-Key-Sample' \
-d '{"client_id":"system-auth-sample","client_secret":"'$SECRET'"}'
返るのは Keycloak の JWT です。有効期限は 60 秒(レルム設定の accessTokenLifespan)なので、以降の手順は取得と一続きにしないと、まず間に合いません。一度 401 Invalid or expired token を食らいました。
このトークンには open_system_id というクレームが1つ乗ります。セットアップスクリプトが Keycloak に作るプロトコルマッパーの仕事です。認証は Keycloak、認可は OpenFGA という分業なので、両者を橋渡しする識別子がここで注入されます。EDC がクレデンシャルの中身そのものを運ぶのとは対照的で、ODS の JWT が運ぶのは識別子だけ、権限は名簿を引いて決まります。
次に事業者を登録します。ODS ではデータを共有する主体をあらかじめ登録するのが前提です。
curl -X POST "http://localhost:8080/account/operator" \
-H 'Content-Type: application/json' -H 'API-Key: API-Key-Sample' \
-H "Authorization: Bearer $TOKEN" \
-d '{"login_user_id":"utokyo_test","operator_name":"東京大学(検証用)", ...}'
{"status":201,"data":{"operator_id":"23447708-5d13-430c-834a-06a696897f86", ...}}
そしてこの事業者に権限をタプルとして書きます。
curl -X POST "http://localhost:8080/authz/stores/$STORE/write" ... -d '{
"writes": {"tuple_keys": [
{"user":"user:23447708-...","relation":"member","object":"role:authz-tuples-admin"}
]}}'
最後に、判定が実際に分かれるかを確かめます。
登録した事業者 → authz-tuples-admin : True
登録した事業者 → authz-stores-admin : True
無関係な利用者 → authz-tuples-admin : False
登録した相手だけが通り、それ以外は通らない。ここまでが実機で確認できた範囲です。
データ交換を通す
認可の判定が効くことは確かめました。次はゲートウェイ越しに実際のリクエストを流します。ここでさらに2箇所つまずきます。
5. ルートに endpointId が要る(README ではなく、同梱スクリプトに無い)
訂正: この節は当初「README の例には無い」と書いていました。誤りです。
README.mdのルート登録例には"metadata": { "endpointId": "test.post" }が含まれており、その意味の解説まで付いています。私が実際に使ったのは README の例ではなく、同梱の補助スクリプトsetup/l2route/create_route_mock.shで、そちらにmetadataがありません。詰まったのは事実ですが、原因は README の不備ではありませんでした。
同梱の setup/l2route/create_route_mock.sh が登録するルートは、こういう形です。これをそのまま使うと、リクエストが 500 になります。
curl -X POST -H "X-API-KEY: your-secret-management-api-key" \
-d '{"id":"route00","uri":"http://mockoon:4011/test",
"predicates":[{"name":"Path","args":{"_genkey_0":"/test**"}}]}' \
http://localhost:8190/actuator/gateway/routes/route00
ゲートウェイのログを見ると、認可フィルタが例外で落ちています。
IllegalArgumentException: Gateway route metadata is missing or empty,
so cannot build resource of authorization request for AuthZEN.
at AuthzenAuthorizationGlobalFilter.buildResource(...:219)
ソースを読むと、application.yml に答えがありました。
resource-id-metadata-key: "endpointId" # 認可のリソースIDをルートのどのメタデータから取るか
ルートに metadata.endpointId を付けないと、認可要求そのものが組み立てられません。
{"id":"route00","uri":"http://mockoon:4011/test",
"predicates":[{"name":"Path","args":{"_genkey_0":"/test**"}}],
"metadata":{"endpointId":"endpoint-test"}}
これを足すと 500 が 403 に変わります。認可の仕組みが動き始めた合図です。
6. 認可の主体は X-ODS-UserId ではない(これは私の読み違い)
訂正: これを ODS 側の問題として数えていましたが、私の誤りです。
README.mdはX-ODS-xxxを「ロギング対象項目」と明記しており、認可の主体だとはどこにも書いていません。さらに同じ README は、タプルをuser:$OPERATOR_IDの形で書けと明示しています。読み落としたのは私のほうでした。以下は、間違えた経緯としてそのまま残します。
403 のままなので、誰を主体として判定しているのかを調べました。同じ application.yml にあります。
subject-id-attribute-name: "operator_id" # JWT のどのクレームを主体IDとするか
主体はヘッダの X-ODS-UserId ではなく、JWT の operator_id クレームです。事業者クライアントを発行すると、Keycloak 側にそのクレームを注入するマッパーが自動で作られます。
operator_id claim=operator_id value=23447708-5d13-430c-834a-06a696897f86
open_system_id claim=open_system_id value=utokyo_test_open_system_id
つまり、「どの事業者が」で判定していて、ヘッダのユーザ ID は別の用途です。ここを取り違えると、いつまでも 403 が続きます。
通った
正しい主体でタプルを1本書きます。
curl -X POST "http://localhost:8083/stores/$USER_STORE/write" \
-H 'Content-Type: application/json' \
-d '{"writes":{"tuple_keys":[{"user":"user:23447708-…","relation":"can_access","object":"endpoint:endpoint-test"}]},
"authorization_model_id":"'$MODEL'"}'
同じリクエストを投げ直すと通ります。
HTTP 200
{"message": "Request successfully delivered!"}
タプル1本で、許可が消えて戻る
ここが今回いちばん確かめたかったところです。同じリクエストを3回、タプルの有無だけ変えて投げます。
タプルあり : 200 {"message": "Request successfully delivered!"}
→ タプルを1本削除
タプルなし : 403 {"code":"[auth] Forbidden","message":"Access denied"}
→ タプルを書き戻し
復活後 : 200 {"message": "Request successfully delivered!"}
削除1回で権限が消え、書き戻すと復活します。再発行も失効リストも要りません。クレデンシャルを配る方式との違いが、いちばんはっきり出る場面です。
GUI はあるのか
コマンドラインだけの印象がありますが、画面も付いてきます。ただし ODS 自身が作ったものではなく、構成要素が持っているものです。
| GUI | URL | ログイン |
|---|---|---|
| Keycloak 管理コンソール | http://auth.localhost:8082/admin/master/console/ | admin / password |
| 決済 API の Swagger UI | http://localhost:8401/docs | 不要 |
| MinIO コンソール | http://localhost:9501 | 設定した資格情報 |
| OpenFGA Playground | http://localhost:3300/playground | 不要(ただし後述) |
ホスト名に注意が要ります。localhost:8082 で開くと 302 で auth.localhost:8082 に飛ばされます。compose が KC_HOSTNAME を http://auth.localhost:8082 に設定しているためで、最初から後者で開くのが確実です(*.localhost はループバックに解決されるので hosts の追記は不要)。
Keycloak の管理コンソールが一番役に立ちます。セットアップスクリプトが何を作ったのか — レルム、system-auth-sample クライアント、open_system_id を注入するプロトコルマッパー — が画面で確認できます。スクリプトが途中で失敗したときに、どこまで進んだかを見るのにも要ります。
7. Playground は付いてくるが、中身が見えない
OpenFGA には認可モデルとタプルを対話的に確かめる Playground が同梱されていて、ODS もポートを公開しています。ところが開くと、いきなり「Create store」を求められます。

4つのストアが実在するのに、Playground からは1つも見えない
訂正: 当初ここに「原因はポートの不一致で、Playground は同じオリジンに API がある前提で動く」と書いていました。誤りです。Playground が返す HTML の中身を見ると、iframe の
srcにfga_api_host=127.0.0.1%3a8083が入っており、API のポートは正しく 8083 と認識されています。
http://localhost:3300/playground → 200
└ 中身は https://play.fga.dev/sandbox/?fga_api_host=127.0.0.1%3a8083&… への iframe 1行
http://localhost:8083/stores → 200 (API 本体。4ストアが返る)
同梱の Playground は、HTTPS の play.fga.dev を iframe で読み込み、そこから手元の http://127.0.0.1:8083 を呼ぶ構造です。ブラウザが混在コンテンツとして遮断していると考えるのが自然ですが、コンソールを確認していないので断定はしません。分かっているのは「4つのストアが実在するのに、Playground からは見えない」という結果だけです。
いずれにせよ、タプルを目で確かめたい場合は API を直接叩くほうが早いです。
curl -s http://localhost:8083/stores | jq '.stores[].name'
EDC と何が違うのか
前回 EDC の Minimum Viable Dataspace を動かしたときと並べると、差がはっきりします。
その前に、比較の土台を確認しておきます。そもそも両者は、別のプロトコルの実装です。
EDC は Eclipse / IDSA 系の Dataspace Protocol(DSP) の実装です。DSP には適合性試験(Dataspace TCK)があり、メタデータ・カタログ・契約交渉・転送の 4 領域で仕様の記述を検査します。
一方 ODS は、ODS-RAM V2 に基づく独自のプロトコル群 ODP(Open Data Spaces Protocols) を定義しています。そして、公式ドキュメント全文にも、手元に clone した参照実装一式にも、DSP・IDSA・Catena-X・Gaia-X への言及は 1 件もありません(eclipse という語が出てくるのは、L4 の JSON-LD context の urn:samm:org.eclipse.esmf と、Java イメージの eclipse-temurin だけです)。DSP TCK に相当する公開の適合性試験も見当たりませんでした。
素のままでは繋がらないことは、実例でも裏づけられます。2025 年 3 月に IPA と Catena-X が公表した相互運用の実証は、「認証」「プロトコル」「データモデル」の技術差を特定したうえで、中間レイヤを置いて双方に手を入れずにデータを交換した、という形でした。
以下で比べる認可モデルの差は、この「プロトコルが別物」という前提の上にあります。
認可の問いが違う
EDC 「あなたは何を提示できるか」
提示された検証可能クレデンシャルの中身を、ODRL のポリシーとその評価器で走査する
(手元の MVD 0.17.0 は実験的な CEL 式を組み込んだ構成)
例: ManufacturerCredential の part_types が 'all' か
ODS 「あなたは何と関係づけられているか」
関係タプルのグラフを辿って判定する
例: user:23447708… と role:authz-tuples-admin の間に member 関係があるか
前者は持参した証明書を読む方式、後者は名簿を引く方式です。OpenFGA は Google の Zanzibar 系で、もともと「誰がどのドキュメントを編集できるか」を大規模に解くための仕組みです。
効いてくるのは「取り消し」と「事前登録」
| EDC | ODS | |
|---|---|---|
| 権限を与える | 発行者がクレデンシャルを発行する | 管理者がタプルを書く |
| 権限を取り消す | 発行者の失効 API を叩く(POST .../credentials/{id}/revoke)。MVD には revoke / suspend / resume / status の 4 本が同梱され、失効リスト配信用のポート(9999 /statuslist)も立つ。ただし README のウォークスルーに失効の筋書きは無く、私は実行していない | タプルを1行消すだけ |
| 相手を事前に知る必要 | 発行者を事前に知る必要がある。相手そのものは事前に知らなくてよい | 相手を事前に知る必要がある。事業者として登録されていないと始まらない |
| 登録の単位 | 発行者を信頼リストに載せる。保持者は都度でよい | 参加者ごとに登録する |
アーカイブの実務から見ると、この対比は他人事ではありません。「一度出した許可を取り消す」は現実に起きます — 寄贈者からの申し出、権利者の異議、不適切な利用の発覚。
どちらにも手段はありますが、性質が 3 点で違います。
反映の速さ ODS タプルを消せば次の判定から効く
EDC 失効リストを取りに行き、検証する経路を通る
粒度 ODS 主体 × 資源の 1 関係だけを外せる
EDC クレデンシャル単位。1 枚に複数の資格が乗っていれば巻き添えになる
誰が握るか ODS 資源側の管理者が消せる
EDC 失効の権限は発行者にある。利用させる側が単独では止められない
3 つ目がアーカイブには効きます。「この資料を、この人に見せるのをやめる」を所蔵館の判断だけで実行できるかという問いだからです。
一方で ODS は参加者の事前登録が要ります。閲覧室の利用者のように事前登録が前提の場面では痛くありませんが、オンライン公開資料の閲覧者や他機関経由の利用者まで含めると、そうとも限りません。
そのほかの違い
- セマンティクス層:ODS は L4(SPARQL・Discovery・クローラ)を層として抱えています。ただし「EDC に無い」とは言えません。EDC 側にも
FederatedCatalogがあり、参加者を巡回するクローラでカタログを集約します。DSP 自体も DCAT と ODRL の上に構築されています。違うのは有無ではなく、RDF/SPARQL をどこまで正面に据えるかで、文化資源のメタデータとは相性が良い層です - 決済:ODS は精算・課金/決済サービスを同梱。EDC は対象外で外部に委ねる
- 起動の重さ:EDC の MVD は Kubernetes 必須、ODS は docker compose で済む
- 初期化:MVD は seed ジョブが自動で走る。ODS は人がスクリプトを2本実行する
共通していたこと
両方とも、公式手順どおりでは動きませんでした。MVD は事前ビルド済みイメージが非公開で、main がビルドできず、Gateway API のバージョンが噛み合わなかった。ODS は起動に関わる4件。
どちらも「参照実装」であって製品ではない、ということだと思います。動かすたびに、仕様書には書かれていないことが分かります。
アーカイブにとっての含意
EDC 側でアーカイブの利用許諾を ODRL とポリシー評価式で書いてみたとき、判定の軸は3つ、門は2段になりました。同じものを ODS 側で書くと、まったく別の形になります。
EDC ReadingClearanceCredential.level = restricted (証明書の中身を見る)
ODS user:<利用者> --can_read--> holding:<資料> (関係を書く)
そして ODS 側では、閲覧許可の取り消しが delete 1回で済みます。これは実務的にかなり大きい。
ただし ODS 側で「目録には出るが閲覧はできない」を表現するには、関係の型を分けて設計する必要があります(can_see と can_read を別の関係にする、など)。EDC のようにカタログと契約という2段の門が最初から用意されているわけではありません。
触れていないもの
- L4 セマンティクス層。SPARQL サービスと Discovery は起動していません
- ODS と EDC の相互接続。それぞれ別々に動かした結果です
- ODS のプロトコル(ODP)の詳細。仕様書は GitBook にありますが、本記事は実装を動かした記録です
出典
- github.com/open-dataspaces — 参照実装(MIT)
- ODS ドキュメント(GitBook)
- IPA: Open Data Spaces
- 経済産業省: ウラノス・エコシステム
- NEDO: ウラノス・エコシステムの実現のためのデータ連携システム構築・実証事業
- OpenFGA — 関係ベース認可
- AuthZEN(OpenID Foundation)
- IPA プレス発表: 技術コンセプト「Open Data Spaces」の共同推進を合意(2025年10月15日) — 表2 新旧対応表
- Eclipse Dataspace TCK — DSP の適合性試験
- eclipse-edc/FederatedCatalog — EDC 側のクローラとカタログ集約
本記事は公開後に、複数エージェントによるファクトチェック(一次資料照合・実測・整合・裁定)を経て修正しています。とくに「EDC では失効が未解決」「KC_DB_USERNAME が無いと必ず起動に失敗する」という当初の記述は、いずれも実機で反証されたため書き直しました。

コメント
…