Skip to content

Proposal: Add References #827

@dlorenc

Description

@dlorenc

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:

  1. User creates some payload representing the image.
  2. User signs this payload.
  3. User creates an Image containing this signature, with a meaningful mediaType for this signature. This signature must contain a protected reference to the subject.
  4. User uploads this via the normal upload flow.

Verification:

  1. User locates the object they wish to verify signatures for.
  2. User queries the new GET API for references
  3. User iterates through this looking for signature objects with the expected mediaType
  4. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions