-
Notifications
You must be signed in to change notification settings - Fork 739
Description
OCI References
New March 27th 2021: The Testing
section below now shows some validation to attempt to prove that this does not break existing clients.
New March 28th 2021: The Backwards Compatibility
section contains how I'm defining backwards-compatibility for the purposes of this proposal.
Background
This document contains two high level proposals that allow for artifacts in a registry to be linked together.
They are meant to be mostly equivalent to the linking portion of the proposed OCI artifact manifest changes.
This document takes a different approach in a few areas:
- Backwards compatibility with existing types. We allow for the existing types (Image, Index, Descriptor) to reference each other and to be referenced, rather than only supporting the new ArtifactManifest type. Backwards compatibility is defined in more detail below.
- No other changes are included here (renames, reorganization). These proposals represent the bare minimum format and API changes required to enable linking of objects, including in a registry. While some of the renaming/reorganization may be desirable, it is also less critical and may be a point of contention that could further delay this work.
Additionally, this document contains further design and discussion for the "query" portion of the API.
This should be compatible with the OCI artifact manifest changes, and can serve as inspiration or as an addition to that proposal if we decide to move forward with that change (either instead of or in addition to this one).
We start out with the proposed API and format changes, then discuss the requirements they were designed against and the CUJs they address.
Proposed Design
This proposal accompanies a pull request which contains the actual proposed changes to the specifications and types in this repository.
We propose adding a new field and a new GET API (in the distribution-spec).
Each change is described below.
Image Spec
Refer to the linked PR for the full changes.
We propose adding a new field (reference
) to the Image Manifest
, Index
and Descriptor
types.
This field will contain a Descriptor
that points to the linked object.
Here is an example:
{
"mediaType": "application/vnd.example.signature+json",
"size": 3514,
"digest": "sha256:19387f68117dbe07daeef0d99e018f7bbf7a660158d24949ea47bc12a3e4ba17",
"reference": {
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"size": 1201,
"digest": "sha256:b4f9e18267eb98998f6130342baacaeb9553f136142d40959a1b46d6401f0f2b"
}
}
Distribution Spec
We propose adding a new, read-only API to the Distribution Spec to query the registry for references to a given object.
The API will look like:
GET /v2/<name>/manifests/<ref>/references
The response from this API will be a list of Descriptors
that matches the existing Manifest Index
specification:
{
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"size": 1201,
"digest": "sha256:b4f9e18267eb98998f6130342baacaeb9553f136142d40959a1b46d6401f0f2b"
}
]
}
There will be an accompanying PR to the distribution-spec with more details on this API if we decide to move forward.
It is currently located here to keep the entire proposal in one place.
Requirements
The proposal above was designed with the following requirements in mind.
There was also an overarching constraint to make these API changes as small as possible, but no smaller:
- Able to attach multiple notes/references to an existing object
- Able to query the registry for all notes/references attached to a specific object
- Attaching notes/references DOES NOT mutate the initial object
- Notes/references should be able to be copied with an image between repositories
- Simple to understand
- Simple to implement
Backwards Compatibility
Updated March 28th
There is no formal definition for backwards-compatible changes in this repo. Here's how I'm thinking about it:
- A reference-aware client can push objects with the reference field to reference-aware servers
- A reference-aware client can retrieve objects that have the references-field set from reference-aware servers.
- A reference-aware client should be able to push objects with the reference field to non-reference-aware servers as per https://github.com/opencontainers/image-spec/blob/master/considerations.md#extensibility, but if servers fail/error here instead this is still fine.
- A non-reference aware client can pull objects that have the references-field set from reference-aware servers, without erroring. They should not break, and should simply ignore the field.
The final bullet here is the most important one. If clients break because of a new field being present, this is not backwards-compatible.
I've verified the following clients so far:
- Oras v0.11.1
- Docker 20.10.5
- Crane v0.4.1
Please suggest others!
Testing
New March 27th 2021
I've implemented this in a patch to distribution as a testbed to try to validate whether or not clients get broken with this. My patch is here: https://github.com/dlorenc/distribution/tree/references, and a registry image is available here: gcr.io/dlorenc-vmtest2/registry:references
You can pull and run that with:
docker run -p 5000:5000 gcr.io/dlorenc-vmtest2/registry:references
I made a client to test this with. It's available in a patch to ggcr here: https://github.com/dlorenc/go-containerregistry/tree/references
There's a simple command line tool to create an object that refers to another object. With that code checked out, and the registry running, you can do:
# Copy an image into your local registry for testing
$ go run ./cmd/crane/ cp ubuntu localhost:5000/ubuntu
# Add a reference to it!
$ go run ./cmd/ref localhost:5000/ubuntu localhost:5000/ref-to-ubuntu
Creating a reference to image: localhost:5000/ubuntu at: localhost:5000/ref-to-ubuntu
# Look at the glorious, referring manifest (the object here is just ubuntu as well, so we can run it)
$ go run ./cmd/crane manifest localhost:5000/ref-to-ubuntu | jq .
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 2724,
"digest": "sha256:01b9e61b93fb6b71b7278bc7a7e8a21417536169cc7c8df18f07c0774539fd69"
},
"layers": [
<hidden for brevity>
],
"reference": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 943,
"digest": "sha256:c65d2b75a62135c95e2c595822af9b6f6cf0f32c11bcd4a38368d7b7c36b66f5",
"platform": {
"architecture": "amd64",
"os": "linux"
}
}
}
# Now run it!
$ docker run -it localhost:5000/ref-to-ubuntu
Unable to find image 'localhost:5000/ref-to-ubuntu:latest' locally
latest: Pulling from ref-to-ubuntu
Digest: sha256:011b3069012baf7f4a8a7f7eea5b0a545d6cd98127e1a3651513ba88e983b246
Status: Downloaded newer image for localhost:5000/ref-to-ubuntu:latest
root@8876f9f8c13f:/# It works!
Example Use Cases
Signing and verifying an image
Signing:
- User creates some payload representing the image.
- User signs this payload.
- User creates an Image containing this signature, with a meaningful
mediaType
for this signature. This signature must contain a protected reference to the subject. - User uploads this via the normal upload flow.
Verification:
- User locates the object they wish to verify signatures for.
- User queries the new
GET
API for references - User iterates through this looking for signature objects with the expected
mediaType
- User verifies the attached signature (and included protected reference)
Attaching SBOMs to an artifact
to be filled in
More
Add more here!
Registry Implications
Registries may need to maintain a reverse index to efficiently satisfy queries for references to a given object.
Registries will need to parse and understand reference
fields in order to support this.
Registries are free to implement garbage collection of referenced objects as they see fit.
Alternatives Considered
Registry only changes
We also considered proposing a design where references are NOT included on the existing types.
It would have looked like:
GET /v2/<name>/manifests/<ref>/notes
POST /v2/<name>/manifests/<ref>/notes
PUT /v2/<name>/manifests/<ref>/notes
DELETE /v2/<name>/manifests/<ref>/notes
Pros
This would not require changes to the image spec
Cons
- Requires more changes to the registry API and registries
- Only works in a registry context, does not work on a filesystem or OCI layout
- Unclear how this would work when copying objects between registries, which is a critical requirement