knqyf263's blog

自分のためのメモとして残しておくためのブログ。

OCI Referrers APIを試す

まだどのOCIレジストリも対応していないのですが、新しく仕様が策定されたOCI Referrers APIを試してみた記事です。SBOMなどが話題になる一方で活用方法が不明なまま数年が経過しましたが、この新仕様によってその辺りが多少改善されると思っています。

背景

DockerイメージはDocker HubなどのDocker Registry HTTP APIに対応したレジストリで配布されるのが一般的でした。しかしコンテナ技術が普及する中でコンテナ仕様の標準化をしようということで"Open Container Initiative (OCI)"が発足しました。OCIによりコンテナランタイムやコンテナイメージの標準仕様が策定され、その後コンテナイメージの配布方法もOCI Distribution Specificationによって定義されました。その辺はもはや昔話になりますし記事だけ置いておきます。

www.publickey1.jp

OCI Distribution Specificationに準拠しているレジストリはOCIレジストリと呼ばれるのですが、クラウドネイティブの普及に伴いコンテナイメージ以外もOCIレジストリで配布可能なように拡張されました。具体的にはKubernetesで使われるHelmチャートやOpen Policy Agentで使われるRegoポリシー、さらにはWebAssemblyモジュールなども配布可能になっています。これらはまとめてOCIアーティファクトと呼ばれています。

github.com

OCIアーティファクトとかっこよく言ってみても結局何でも置けてしまうのでただの何でも置けるストレージと化していますが、最近Docker HubもOCIアーティファクト対応したことでGHCRやECRなど主要なレジストリはOCI準拠となりました。HomebrewなどはバイナリファイルをGHCRで配布しており、コンテナイメージに限らず既に広く利用されています。

www.docker.com

上のDockerのアナウンスでも触れられているように、OCIアーティファクトの代表例としてSoftware Bill of Materials (SBOM)があります。SBOMについては最近解説記事が多いのでここでは詳しくは説明しませんが、今回の文脈だとコンテナイメージを構成するソフトウェアの一覧表を指します。ソフトウェアサプライチェーンセキュリティへの関心が高まる中で注目を集めているのがSBOMです。単なるソフトウェア部品表なのでコンテナイメージに限った話ではないのですが、今回はコンテナイメージに着目します。このSBOMはコンテナイメージのメタデータなので、コンテナイメージに紐付けられると都合が良いです。しかし現状ではこの方法は確立されていません。コンテナイメージを新たに作り直してイメージ内のファイルとしてSBOMを保存しているケースもありますが、標準として策定されているわけではありません。

また、コンテナイメージに紐付けたいメタデータというのはSBOMだけではありません。最近注目されているソフトウェア署名などもその一つです。署名については以前記事を書いています。

knqyf263.hatenablog.com

新たに付与したいメタデータが出てくるたびにコンテナイメージを作るのは好ましくありません。せっかくイミュータブルにコンテナイメージを作っているので、既存のイメージには手を加えずメタデータを付与したいところです。しかし現状のOCIの仕様ではそれが出来ないため、何とかしようとして生まれたのがReferrers APIです。

今回の記事ではこのAPIを試していくのですが、執筆時点と仕様が異なる可能性大です。というのも一旦仕様がマージされたものの、Googleの人達が好きじゃないということで仕様を変更しようとしているためです(2023/3/14現在)。詳細は後述します。

github.com

「いやいやそのレベルの指摘は仕様策定中にするべきだろう」という真っ当な意見が出るなど絶賛議論中です。ということでどうなるかはまだ分からないのですが、一旦現状のものを見ていきます。安定してから見れば良くない?と言われるとその通りなのですが、KubeCon EU 2023でOCI Referrers APIの発表を控えておりそういうわけにもいかない状況です。

Microsoftの人達がAzure Container Registry (ACR) でOCI Referrers API対応を進めてくれているので自分が実装を担当するクライアント側も急ピッチで実装が必要なのですが、仕様がまだ安定しておらず焦っています。

OCI Reference Types

上ではReferrers APIと言ったのですが仕様はもう少し複雑で、このメタデータを紐付けるための全体的な仕様を指してReference Typesと呼んでいます。以下のWorking Groupで議論が行われていました。

github.com

最近みんなReference Typesと呼ばずに単にReferrersと呼んでいたりしていて呼び方が変わったのかよく分かってないです。現状の正式名称を見つけられていないのですが、とりあえずReference Typesと呼んでおきます。

この辺についてわかりやすくまとめられた発表があり、これを見れば正直一発です。

youtu.be

今回はこの内容プラスアルファという感じなのですが、自分の理解を整理するためにも検証記録を残しておきます。

Reference Typesの実装方法としていくつかの提案があったので、まずこれらの提案を紹介していきます。提案を理解するためにはOCIアーティファクトのフォーマットを理解しておく必要がありますが、以下の記事などで軽く説明しているので今回は説明しません。

sigstoreによるコンテナイメージやソフトウェアの署名 - knqyf263's blog

提案 1: OCI Artifact Manifest

現状のOCIアーティファクトはOCIイメージがベースであり以下の要素で構成されています。

  • manifest
  • config
  • layers

この上のmanifestはOCI Image Manifestと呼ばれるものですが、SBOMなどコンテナイメージ以外を保存したい場合はconfigも要らないですしlayerというのもおかしいです。そこで、configを消してlayerをblobにしたOCIアーティファクト用の新しいマニフェストを使おうというのが一つ目の提案でした。

https://youtu.be/_c1OdmP9Ssg P.15より引用

この図における左が既存のOCI Image Manifestで、右が新たに提案されたOCI Artifact Manifestです。上で散々OCIアーティファクトと言ってきましたが、実態はOCIイメージのlayerに強引にblobを入れてアーティファクトとして扱っているだけだったので今回きちんとOCI Artifact Manifestを作ろうということですね。さらに subject というフィールドを定義することでそのOCIアーティファクトが参照しているOCIイメージを定義可能にしています。

そして新たに作られたOCI Referrers APIを使うことでOCIイメージに紐付けられたOCIアーティファクトの一覧を取得可能にします。矢印がOCI Image Manifestから伸びているのは、OCIイメージのダイジェストをAPIに渡すことで一覧を得るためです。この際、OCI Image側には変更を加えずにOCI Artifactを紐付けていけるというのが重要です。上で述べたイメージを作り直さずにメタデータを付与したいという要件を満たしています。

提案 2: OCI Image Manifestへのsubjectの追加

次の提案ですが、OCI Image Manifestにsubjectを追加するというものです。

https://youtu.be/_c1OdmP9Ssg P.16より引用

このsubjectは上で説明したものと同じで参照先のOCIイメージを定義するためのものです。しかしOCI Artifact Manifestは新たに作らずに既存のOCI Image Manifestに追加するというのが違いです。Referrers APIも上と同じです。

提案 3: Custom Tag

既存の仕様を変えずになんとかハックしようというのが最後の提案です(実際には他にもいくつか提案がありましたが最後まで残らなかったので割愛)。これはSigstoreが現在行っている方法を基にしているので再度Sigstoreの解説記事を貼っておきます。

knqyf263.hatenablog.com

上のブログで紹介したようにSigstoreではコンテナイメージのダイジェストからタグを作り出すといったワークアラウンドを使っています。詳しくは上の記事を見てほしいのですが、 ghcr.io/aquasecurity/trivy:latestメタデータを保存したい場合はまずイメージのダイジェストを計算します。 ダイジェストが sha256:4fc1d17f2b746f0e2acf638eaa7ccb4e2b6dc567746c3a086518f18047f00012 だとしたら、 ghcr.io/aquasecurity/trivy:sha256-4fc1d17f2b746f0e2acf638eaa7ccb4e2b6dc567746c3a086518f18047f00012.sig というタグを作りここに署名を保存します。分かりにくいですが、 sha256-4fc1d17f2b746f0e2acf638eaa7ccb4e2b6dc567746c3a086518f18047f00012.sig はイメージのタグです。何が嬉しいかと言うと、クライアントが自力でメタデータを探しに行ける点です。ghcr.io/aquasecurity/trivy:latest というイメージ名を渡されればそこからダイジェストを計算して署名のタグに辿り着けます。

ただし上のタグ名は .sig というサフィックスからわかるように署名のためのものです。 .sbom.attestation なども作っていくとタグが乱立することになりますしメタデータ一覧を取るのが少し面倒です。そこでメタデータを全て <alg>-<hash> に入れてしまおうというのがこの提案です。上のSigstoreのやり方から .sig を削っただけですね。 ghcr.io/aquasecurity/trivy:sha256-4fc1d17f2b746f0e2acf638eaa7ccb4e2b6dc567746c3a086518f18047f00012 のようになります。

https://youtu.be/_c1OdmP9Ssg P.17より引用

実際には上図だと一つのOCIアーティファクトしか保存できないので、例えばSBOMを一つ保存したらそれで終わってしまい実用的ではありません。その辺については後述します。

発表ではCustom Tagと呼ばれていましたが、仕様ではreferrers tagと呼ばれています。本記事内ではCustom Tagと呼んでおきます。

github.com

採用された案

繰り返しになりますが、これは現状の案であって変更される可能性が高いです。まず図を見てみます。

https://youtu.be/_c1OdmP9Ssg P.20より引用

結果として全部盛りになりました。上で説明した提案1-3が全て採用されています。まず提案1で説明したように、subjectフィールドを持ったOCI Artifact Manifestが新たに足されています。それに加えて提案2のようにOCI Image Manifestにもsubjectが足されています。それら全てを取得可能なようにReferrers APIも生えています。さらに、提案3のようにCustom Tagでも動くことが期待されます。

Referrers APIがあればCustom Tag要らなくない?というのは正しいのですが、OCIレジストリがReferrers APIに対応するのは時間がかかる可能性があります。そのような場合にも動作できるように後方互換性のためにCustom Tagが足されたという背景です。Custom Tagの場合はOCIレジストリへの変更は不要でクライアントが頑張る必要があります。この場合は subject フィールドも対応されていないはずなので単に提案3の通りに動くというイメージです。

クライアントに期待される動作としては、まずOCIレジストリがReferrers APIに対応しているかを確認し対応している場合はAPIを使ってReferrersを取得する。その際のReferrersのマニフェストはImage ManifestかもしれないしArtifact Manifestかもしれない。もしReferrers APIに対応していない場合はCustom Tagにフォールバックする、というものになります。具体的にはAPIが404を返したら〜などになるのですが、そのへんは細かいので仕様を参照してください。

github.com

Custom Tagについては先ほど説明しませんでしたが、1つのタグで複数のOCIアーティファクトを保存できる必要があります。そうでないとSBOMを1つ保存して終わってしまうので、その仕組みについて説明しておきます。OCIにはImage Index Specificationというものが存在し、OCIイメージの複数アーキテクチャ対応などに使われています。例えば alpine:3.17 をpullする際には内部で勝手にホストに合致するアーキテクチャのイメージを取ってくるようになっています。つまり alpine:3.17 というのはOCI Image ManifestではなくOCI Image Indexになっています。craneというツールでマニフェストを見てみると以下のように linux/amd64linux/arm64 などのマニフェストへのリンクになっています。

$ crane manifest alpine:3.17 | jq .
{
  "manifests": [
    {
      "digest": "sha256:e2e16842c9b54d985bf1ef9242a313f36b856181f188de21313820e177002501",
      "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
      "platform": {
        "architecture": "amd64",
        "os": "linux"
      },
      "size": 528
    },
    {
      "digest": "sha256:e8748b26b68a624c7d2622ff045ce32b76ea31b50bba8e74989cd9ec84e33bb0",
      "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
      "platform": {
        "architecture": "arm",
        "os": "linux",
        "variant": "v6"
      },
      "size": 528
    },
    ...
    {
      "digest": "sha256:fe2da55ca9a717feb2da5d65171cee518cc157c5fcfe35c02972d9c4aa48aa1d",
      "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
      "platform": {
        "architecture": "s390x",
        "os": "linux"
      },
      "size": 528
    }
  ],
  "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
  "schemaVersion": 2
}

これを応用してReferrrersをこの中に詰め込みます。

ということでReference Typesについての説明は以上です。以下で実際に試してみます。

検証

上の提案2と提案3のそれぞれを個別に試します。Custom Tagは既存のOCIレジストリの実装で動くことが期待されているので先にそっちからやっていきます。これも上の動画でデモとして行われていたことをそのままやっているだけです。

Custom Tag

OSSでOCIレジストリの実装が提供されているのでこれを使って試してみます。現時点ではReferrers APIには対応していません。

github.com

一方クライアントはCustom Tagのことを理解して動作する必要があるのでReference Types対応のものを使います。今回は regctl というツールを使いますが oras などでも同様のことが出来ます。regctl は適当にインストールしておいてください。

OCIレジストリのセットアップ

コンテナイメージとして提供されているのでDockerで簡単に立ち上げることが出来ます。以下のコマンドを打つと localhost:5001 で起動します。

$ docker run -d --rm --label demo=referrers -e REGISTRY_STORAGE_DELETE_ENABLED=true -e REGISTRY_VALIDATION_DISABLED=true -p 127.0.0.1:5001:5000 registry:2

検証目的なのでTLSは使っていません。regctl はデフォルトだとTLS必須なので無効化しておきます。もちろん本番環境では推奨されません。

$ regctl registry set --tls=disabled localhost:5001

イメージのコピー

Docker Hubからイメージをこちらのローカルレジストリにコピーします。この際、なぜかバージョンによってはタグ指定だとエラーを吐くのでダイジェストを使います。

$ digest=$(regctl image digest --platform linux/arm64 regclient/regctl:edge)
$ regctl image copy regclient/regctl@${digest} localhost:5001/demo-referrers-2023:app

何の変哲もないですが一応マニフェストを確認しておきます。OCI Image Manifestです。

$ regctl manifest get localhost:5001/demo-referrers-2023:app --format body | jq .
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "size": 3101,
    "digest": "sha256:f7c0b1830b92185f1805c1998ed5a2ef6d64608d0f9d079b8f07bef5f7c7803d"
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 85,
      "digest": "sha256:3d67ddc212ffba510628b93c0936f90dabcab9993f095cc1899fb1bcbe86b42a"
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 938,
      "digest": "sha256:212a3e17813e7f1c89fbb652011b1f6f9ced25df1ed44364238cf7cb7e42a105"
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 123550,
      "digest": "sha256:3a5d0be4319d4dee0c58b0a5eee8cff9a2f20c7c7d9601cdcd4d6300e2540a3c"
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 142,
      "digest": "sha256:97d03c30220c7b4e9ad7c12532a179b2ad4da999668e13d4f2fb5ec9ed98af84"
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 3201405,
      "digest": "sha256:e06533488547d1d6ec75c184591a7a8ccc9721564e381f9fc1c68d72e1cde954"
    }
  ]
}

Referrerの保存

regctl には artifact put というサブコマンドがありReferrerを簡単に保存することが出来ます。適当なツールでSBOMを作成して保存してみます。今回は Trivy を使います(自分が作っているので)。SBOMのフォーマットはCycloneDXです。

$ trivy image -q -f cyclonedx localhost:5001/demo-referrers-2023:app \
         | regctl artifact put --subject localhost:5001/demo-referrers-2023:app \
             --artifact-type application/vnd.cyclonedx+json \
             -m application/vnd.cyclonedx+json \
             --annotation "org.opencontainers.artifact.description=CycloneDX JSON SBOM"

--subject で参照しているOCIイメージを指定しているのがポイントです。

他にも適当にSPDXなどを保存しておきます。

$ trivy image -q -f spdx-json localhost:5001/demo-referrers-2023:app \
         | regctl artifact put --subject localhost:5001/demo-referrers-2023:app \
             --artifact-type application/vnd.spdx+json \
             -m application/vnd.spdx+json \
             --annotation "org.opencontainers.artifact.description=SPDX JSON SBOM"

Referrerの表示

regctl のコマンドでReferrerの一覧を表示できます。以下の例では localhost:5001/demo-referrers-2023:app を参照するOCIアーティファクトの一覧を取得しています。

$ regctl artifact list localhost:5001/demo-referrers-2023:app --format body | jq .
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 621,
      "digest": "sha256:799b560abaef3cbb9d4658736078791d1e5b14e15f9192fbea98922754660b65",
      "annotations": {
        "org.opencontainers.artifact.description": "CycloneDX JSON SBOM"
      },
      "artifactType": "application/vnd.cyclonedx+json"
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 606,
      "digest": "sha256:96d2e43b5ebd582ede2d4f69be78cd44c023335f306c854523b5ecbfcd8bd7d7",
      "annotations": {
        "org.opencontainers.artifact.description": "SPDX JSON SBOM"
      },
      "artifactType": "application/vnd.spdx+json"
    }
  ]
}

確かに先程保存したCyclonDXとSPDXのSBOMが表示されています。タグの一覧を見てみます。

$ regctl tag list localhost:5001/demo-referrers-2023
app
sha256-a5cb013fa8479e343bfc8505163a53c68d344813576b6efb602828f34d80843d

自分で保存した app 以外に sha256- から始まるタグが生成されています。これが上の提案3で説明したCustom Tagです。curl でも同じ一覧を取得可能です。

$ curl -sS -H "Accept: application/vnd.oci.image.index.v1+json" http://localhost:5001/v2/demo-referrers-2023/manifests/sha256-a5cb013fa8479e343bfc8505163a53c68d344813576b6efb602828f34d80843d | jq .
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 621,
      "digest": "sha256:d76f4e5a298e3e98000220a4295b8c6d0dc3f829f6e3a7af533e3ff02225c13f",
      "annotations": {
        "org.opencontainers.artifact.description": "CycloneDX JSON SBOM"
      },
      "artifactType": "application/vnd.cyclonedx+json"
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 606,
      "digest": "sha256:96d2e43b5ebd582ede2d4f69be78cd44c023335f306c854523b5ecbfcd8bd7d7",
      "annotations": {
        "org.opencontainers.artifact.description": "SPDX JSON SBOM"
      },
      "artifactType": "application/vnd.spdx+json"
    }
  ]
}

先ほどと同じリストが返ってきています。 regctlレジストリがReferrers APIに対応していないことを検知してCustom Tagに切り替えたということです。

Referrers API

今度はReferrers APIに対応したOCIレジストリを使います。zotというOSSのOCIレジストリがあるのでこちらを使っていきます。

github.com

OCIレジストリのセットアップ

なぜか zot 自体のイメージはOCI Image Indexに対応してなさそうだったので自分のアーキテクチャに合ったイメージを選択します。今回は ghcr.io/project-zot/zot-linux-arm64 を使っています。先程同様にTLSを無効にしておきます。

$ docker run -d --rm --name reg2 --label demo=referrers -p 127.0.0.1:5002:5000 ghcr.io/project-zot/zot-linux-arm64:latest
$ regctl registry set --tls=disabled localhost:5002

イメージのコピー

先程Custom Tagの検証で作ったローカルのイメージからコピーします。このとき、 --referrers を付けることでReferrersも同時にコピーしてくれます。今回のレジストリはReferrers APIに対応しているため、zotはそれを検知して localhost:5001 のCustom TagからReferrersを取得して localhost:5002subject を付与したOCI ImageとしてReferrersを保存してくれます。

$ regctl image copy --referrers localhost:5001/demo-referrers-2023:app localhost:5002/demo-referrers-2023:app

Referrerの表示

Custom Tagの検証とは異なり既にReferrersは保存されているので確認します。

$ regctl artifact list localhost:5002/demo-referrers-2023:app --format body | jq .
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 621,
      "digest": "sha256:d76f4e5a298e3e98000220a4295b8c6d0dc3f829f6e3a7af533e3ff02225c13f",
      "annotations": {
        "org.opencontainers.artifact.description": "CycloneDX JSON SBOM"
      },
      "artifactType": "application/vnd.cyclonedx+json"
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 606,
      "digest": "sha256:96d2e43b5ebd582ede2d4f69be78cd44c023335f306c854523b5ecbfcd8bd7d7",
      "annotations": {
        "org.opencontainers.artifact.description": "SPDX JSON SBOM"
      },
      "artifactType": "application/vnd.spdx+json"
    }
  ]
}

先ほどと同じ一覧が取得できています。ではタグ一覧を見てみます。

$ regctl tag list localhost:5002/demo-referrers-2023
app

今度はCustom Tagがありません。それにも関わらずReferrersが取得できています。これは regctl が内部でReferrers APIに対応していることを検知してそちらを利用しているためです。

$ curl -sS -H "Accept: application/vnd.oci.image.index.v1+json" http://localhost:5002/v2/demo-referrers-2023/manifests/sha256-a5cb013fa8479e343bfc8505163a53c68d344813576b6efb602828f34d80843d | jq .
{
  "errors": [
    {
      "code": "MANIFEST_UNKNOWN",
      "message": "manifest unknown",
      "description": "This error is returned when the manifest, identified by name\n\t\t\tand tag is unknown to the repository.",
      "detail": [
        {
          "reference": "sha256-a5cb013fa8479e343bfc8505163a53c68d344813576b6efb602828f34d80843d"
        }
      ]
    }
  ]
}

先ほどと同じようにcurlしてみても返ってきません。

Referrers API

/manifests ではなく代わりに /referrers を叩いてみます。これがReferrers APIです。

$ curl -sS -H "Accept: application/vnd.oci.image.index.v1+json" http://localhost:5002/v2/demo-referrers-2023/referrers/sha256:a5cb013fa8479e343bfc8505163a53c68d344813576b6efb602828f34d80843d | jq .
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 621,
      "digest": "sha256:d76f4e5a298e3e98000220a4295b8c6d0dc3f829f6e3a7af533e3ff02225c13f",
      "annotations": {
        "org.opencontainers.artifact.description": "CycloneDX JSON SBOM"
      },
      "artifactType": "application/vnd.cyclonedx+json"
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 606,
      "digest": "sha256:96d2e43b5ebd582ede2d4f69be78cd44c023335f306c854523b5ecbfcd8bd7d7",
      "annotations": {
        "org.opencontainers.artifact.description": "SPDX JSON SBOM"
      },
      "artifactType": "application/vnd.spdx+json"
    }
  ]
}

正しく取得できています。ではSBOMのOCIアーティファクトを見てみます。

$ regctl manifest get localhost:5002/demo-referrers-2023@sha256:e1fc5a3c972970f2bd77cbb3cc3d16199f4db566dbfb806bb5f6eba89373ea34 --format body | jq .
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "config": {
    "mediaType": "application/vnd.cyclonedx+json",
    "size": 2,
    "digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"
  },
  "layers": [
    {
      "mediaType": "application/vnd.cyclonedx+json",
      "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
    }
  ],
  "annotations": {
    "org.opencontainers.artifact.description": "CycloneDX JSON SBOM"
  },
  "subject": {
    "mediaType": "application/vnd.oci.image.manifest.v1+json",
    "size": 1024,
    "digest": "sha256:a5cb013fa8479e343bfc8505163a53c68d344813576b6efb602828f34d80843d"
  }
}

mediaTypeconfiglayers などの既存のフィールドに加え subject が追加されていることがわかります。これが提案2です。ということでReferrers APIも無事に検証できました。

OCI Artifact Manifestについて

今回の検証では提案1のOCI Artifact Manifestについては触れませんでした。というのも、今絶賛揉めているのがこのOCI Artifact Manifestだからです。

github.com

先述したようにGoogleの人達があとからやってきて「要らん!!」と言っています。あとから来て横暴だなーと思って見ていたのですが、正直自分も今回触ってみてOCI Artifact Manifest要らんくね...?となったので削除したくなる気持ちもわかります。しかしそれは仕様策定時にやるべき議論だよねというのも分かりますし、やはり大人数での議論は難しいなと感じています。

まだ結論は出ていないようですが、一旦削除してOCI Distribution Spec 1.1を出してから考えようという流れに見えます。なので一旦OCI Artifact Manifestについては忘れて生きています。元々OCI Image Manifestという名前の通りコンテナイメージのたに作られたものをアーティファクト全体に拡張したために仕様があまり美しい状態ではなく、それを受け入れるかどうかという議論な気もします。

その他

他にもReferrers APIでは artifactType でのフィルタ機能が提供されたりします。SHOULD なので提供されていない場合もありますが、提供されている場合は /v2/<name>/referrers/<digest>?artifactType=<mediaType> でReferrersのフィルタが可能です。

distribution-spec/spec.md at acfc11dad63159052f98dd9afab04adf59e6ed8f · opencontainers/distribution-spec · GitHub

そして元々の提案ではフィルタされた場合は annotationorg.opencontainers.referrers.filtersApplied を入れることになっていました。

github.com

HTTPリクエストのクエリに応じてマニフェストに変更が加わるの気持ち悪いな...と思っていたら後で削除されHTTPヘッダに入れるように変更されていました。

github.com

要所要所でこういう「ん...?」な仕様があるので、確かにこれはあとからでも直したくなるなーと眺めています。

まとめ

まだ議論中ではありますが、OCI Reference Typesはサプライチェーンセキュリティの向上に寄与することが期待されていますし嬉しい仕様追加です。