Skip to content

Commit ae1176a

Browse files
committed
Add documentation for signature access protocols
This is primarily the only documentation of the sigstore layout; in addition it comments on the OpenShift API master REST API and the OpenShift docker/distribution API extension. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
1 parent 3149c1a commit ae1176a

1 file changed

Lines changed: 115 additions & 0 deletions

File tree

docs/signature-protocols.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Signature access protocols
2+
3+
The `github.com/containers/image` library supports signatures implemented as blobs “attached to” an image.
4+
Some image transports (local storage formats and remote procotocols) implement these signatures natively
5+
or trivially; for others, the protocol extensions described below are necessary.
6+
7+
## docker/distribution registries—separate storage
8+
9+
### Usage
10+
11+
Any existing docker/distribution registry, whether or not it natively supports signatures,
12+
can be augmented with separate signature storage by configuring a signature storage URL in [`registries.d`](registries.d.md).
13+
`registries.d` can be configured to use one storage URL for a whole docker/distribution server,
14+
or also separate URLs for smaller namespaces or individual repositories within the server
15+
(which e.g. allows image authors to manage their own signature storage while publishing
16+
the images on the public `docker.io` server).
17+
18+
The signature storage URL defines a root of a path hierarchy.
19+
It can be either a `file:///…` URL, pointing to a local directory structure,
20+
or a `http`/`https` URL, pointing to a remote server.
21+
`file:///` signature storage can be both read and written, `http`/`https` only supports reading.
22+
23+
The same path hierarchy is used in both cases, so the HTTP/HTTPS server can be
24+
a simple static web server serving a directory structure created by writing to a `file:///` signature storage.
25+
(This of course does not prevent other server implementations,
26+
e.g. a HTTP server reading signatures from a database.)
27+
28+
The usual workflow for producing and distributing images using the separate storage mechanism
29+
is to configure the repository in `registries.d` with `sigstore-staging` URL pointing to a private
30+
`file:///` staging area, and a `sigstore` URL pointing to a public web server.
31+
To publish an image, the image author would sign the image as necessary (e.g. using `skopeo copy`),
32+
and then copy the created directory structure from the `file:///` staging area
33+
to a subdirectory of a webroot of the public web server so that they are accessible using the public `sigstore` URL.
34+
The author would also instruct consumers of the image to, or provide a `registries.d` configuration file to,
35+
set up a `sigstore` URL pointing to the public web server.
36+
37+
### Path structure
38+
39+
Given a _base_ signature storage URL configured in `registries.d` as mentioned above,
40+
and a container image stored in a docker/distribution registry using the _fully-expanded_ name
41+
_hostname_`/`_namespaces_`/`_name_{`@`_digest_,`:`_tag_} (e.g. for `docker.io/library/busybox:latest`,
42+
_namespaces_ is `library`, even if the user refers to the image using the shorter syntax as `busybox:latest`),
43+
signatures are accessed using URLs of the form
44+
> _base_`/`_namespaces_`/`_name_`@`_digest-algo_`=`_digest-value_`/signature-`_index_
45+
46+
where _digest-algo_`:`_digest-value_ is a manifest digest usable for referencing the relevant image manifest
47+
(i.e. even if the user referenced the image using a tag,
48+
the signature storage is always disambiguated using digest references).
49+
Note that in the URLs used for signatures,
50+
_digest-algo_ and _digest-value_ are separated using the `=` character,
51+
not `:` like when acessing the manifest using the docker/distribution API.
52+
53+
Within the URL, _index_ is a decimal integer (in the canonical form), starting with 1.
54+
Signatures are stored at URLs with successive _index_ values; to read all of them, start with _index_=1,
55+
and continue reading signatures and increasing _index_ as long as signatures with these _index_ values exist.
56+
Similarly, to add one more signature to an image, find the first _index_ which does not exist, and
57+
then store the new signature using that _index_ value.
58+
59+
There is no way to list existing signatures other than iterating through the successive _index_ values,
60+
and no way to download all of the signatures at once.
61+
62+
### Examples
63+
64+
For a docker/distribution image available as `busybox@sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e`
65+
(or as `busybox:latest` if the `latest` tag points to to a manifest with the same digest),
66+
and with a `registries.d` configuration specifying a `sigstore` URL `https://example.com/sigstore` for the same image,
67+
the following URLs would be accessed to download all signatures:
68+
> - `https://example.com/sigstore/library/busybox@sha256=817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e/signature-1`
69+
> - `https://example.com/sigstore/library/busybox@sha256=817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e/signature-2`
70+
> -
71+
72+
For a docker/distribution image available as `example.com/ns1/ns2/ns3/repo@somedigest:digestvalue` and the same
73+
`sigstore` URL, the signatures would be available at
74+
> `https://example.com/sigstore/ns1/ns2/ns3/repo@somedigest=digestvalue/signature-1`
75+
76+
and so on.
77+
78+
## OpenShift-embedded registries
79+
80+
The OpenShift-embedded registry implements the ordinary docker/distribution API,
81+
and it also exposes images through the OpenShift REST API (available through the “API master” servers).
82+
83+
As of https://github.com/openshift/origin/pull/9181,
84+
signatures are exposed through the OpenShift API
85+
(i.e. to access the complete image, it is necessary to use both APIs,
86+
in particular to know the URLs for both the docker/distribution and the OpenShift API master endpoints).
87+
88+
To read the signature, any user with access to an image can use the `imagestreamimages` namespaced
89+
resource to read an `Image` object and its `Signatures` array. Use only the `ImageSignature` objects
90+
which have `Type` equal to `atomic`, and read the signature from `Content`; ignore the other fields of
91+
the `ImageSignature` object.
92+
93+
To add or remove signatures, use the cluster-wide (non-namespaced) `imagesignatures` resource,
94+
with `Type` set to `atomic` and `Content` set to the signature. Signature names must have the form
95+
_digest_`@`_per-image-name_, where _digest_ is an image manifest digest (OpenShift “image name”),
96+
and _per-image-name_ is any unique identifier.
97+
98+
Note that because signatures are stored within the cluster-wide image objects,
99+
i.e. different namespaces can not associate different sets of signatures to the same image,
100+
updating signatures requires a cluster-wide access to the `imagesignatures` resource
101+
(by default available to the `system:image-signer` role),
102+
and deleting signatures is strongly discouraged
103+
(it deletes the signature from all namespaces which contain the same image).
104+
105+
## (OpenShift) docker/distribution API extension
106+
107+
As of https://github.com/openshift/origin/pull/12504/ , the OpenShift-embedded registry also provides
108+
an extension of the docker/distribution API which allows simpler access to the signatures,
109+
using only the docker/distribution API endpoint.
110+
111+
This API is not inherently OpenShift-specific (e.g. the client does not need to know the OpenShift API endpoint,
112+
and credentials sufficient to access the docker/distribution API server are sufficient to access signatures as well),
113+
and in the future it will be the preferred way to implement signature storage in registries.
114+
115+
More detailed documentation of this API will be added later (after `github.com/containers/image` implements it).

0 commit comments

Comments
 (0)