.nh .TH Signature access protocols .PP The \fBgithub.com/containers/image\fR library supports signatures implemented as blobs “attached to” an image. Some image transports (local storage formats and remote protocols) implement these signatures natively or trivially; for others, the protocol extensions described below are necessary. .SH docker/distribution registries—separate storage .SS Usage .PP Any existing docker/distribution registry, whether or not it natively supports signatures, can be augmented with separate signature storage by configuring a signature storage URL in \[la]containers\-registries.d.md\[ra]\&. \fBregistries.d\fR can be configured to use one storage URL for a whole docker/distribution server, or also separate URLs for smaller namespaces or individual repositories within the server (which e.g. allows image authors to manage their own signature storage while publishing the images on the public \fBdocker.io\fR server). .PP The signature storage URL defines a root of a path hierarchy. It can be either a \fBfile:///…\fR URL, pointing to a local directory structure, or a \fBhttp\fR/\fBhttps\fR URL, pointing to a remote server. \fBfile:///\fR signature storage can be both read and written, \fBhttp\fR/\fBhttps\fR only supports reading. .PP The same path hierarchy is used in both cases, so the HTTP/HTTPS server can be a simple static web server serving a directory structure created by writing to a \fBfile:///\fR signature storage. (This of course does not prevent other server implementations, e.g. a HTTP server reading signatures from a database.) .PP The usual workflow for producing and distributing images using the separate storage mechanism is to configure the repository in \fBregistries.d\fR with \fBlookaside-staging\fR URL pointing to a private \fBfile:///\fR staging area, and a \fBlookaside\fR URL pointing to a public web server. To publish an image, the image author would sign the image as necessary (e.g. using \fBskopeo copy\fR), and then copy the created directory structure from the \fBfile:///\fR staging area to a subdirectory of a webroot of the public web server so that they are accessible using the public \fBlookaside\fR URL. The author would also instruct consumers of the image to, or provide a \fBregistries.d\fR configuration file to, set up a \fBlookaside\fR URL pointing to the public web server. .SS Path structure .PP Given a \fIbase\fP signature storage URL configured in \fBregistries.d\fR as mentioned above, and a container image stored in a docker/distribution registry using the \fIfully-expanded\fP name \fIhostname\fP\fB/\fR\fInamespaces\fP\fB/\fR\fIname\fP{\fB@\fR\fIdigest\fP,\fB:\fR\fItag\fP} (e.g. for \fBdocker.io/library/busybox:latest\fR, \fInamespaces\fP is \fBlibrary\fR, even if the user refers to the image using the shorter syntax as \fBbusybox:latest\fR), signatures are accessed using URLs of the form > \fIbase\fP\fB/\fR\fInamespaces\fP\fB/\fR\fIname\fP\fB@\fR\fIdigest-algo\fP\fB=\fR\fIdigest-value\fP\fB/signature-\fR\fIindex\fP .PP where \fIdigest-algo\fP\fB:\fR\fIdigest-value\fP is a manifest digest usable for referencing the relevant image manifest (i.e. even if the user referenced the image using a tag, the signature storage is always disambiguated using digest references). Note that in the URLs used for signatures, \fIdigest-algo\fP and \fIdigest-value\fP are separated using the \fB=\fR character, not \fB:\fR like when accessing the manifest using the docker/distribution API. .PP Within the URL, \fIindex\fP is a decimal integer (in the canonical form), starting with 1. Signatures are stored at URLs with successive \fIindex\fP values; to read all of them, start with \fIindex\fP=1, and continue reading signatures and increasing \fIindex\fP as long as signatures with these \fIindex\fP values exist. Similarly, to add one more signature to an image, find the first \fIindex\fP which does not exist, and then store the new signature using that \fIindex\fP value. .PP There is no way to list existing signatures other than iterating through the successive \fIindex\fP values, and no way to download all of the signatures at once. .SS Examples .PP For a docker/distribution image available as \fBbusybox@sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e\fR (or as \fBbusybox:latest\fR if the \fBlatest\fR tag points to to a manifest with the same digest), and with a \fBregistries.d\fR configuration specifying a \fBlookaside\fR URL \fBhttps://example.com/lookaside\fR for the same image, the following URLs would be accessed to download all signatures: > - \fBhttps://example.com/lookaside/library/busybox@sha256=817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e/signature-1\fR > - \fBhttps://example.com/lookaside/library/busybox@sha256=817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e/signature-2\fR > - … .PP For a docker/distribution image available as \fBexample.com/ns1/ns2/ns3/repo@somedigest:digestvalue\fR and the same \fBlookaside\fR URL, the signatures would be available at > \fBhttps://example.com/lookaside/ns1/ns2/ns3/repo@somedigest=digestvalue/signature-1\fR .PP and so on. .SH (OpenShift) docker/distribution API extension .PP As of https://github.com/openshift/origin/pull/12504/ , the OpenShift-embedded registry also provides an extension of the docker/distribution API which allows simpler access to the signatures, using only the docker/distribution API endpoint. .PP This API is not inherently OpenShift-specific (e.g. the client does not need to know the OpenShift API endpoint, and credentials sufficient to access the docker/distribution API server are sufficient to access signatures as well), and it is the preferred way implement signature storage in registries. .PP See https://github.com/openshift/openshift-docs/pull/3556 for the upstream documentation of the API. .PP To read the signature, any user with access to an image can use the \fB/extensions/v2/…/signatures/…\fR path to read an array of signatures. Use only the signature objects which have \fBversion\fR equal to \fB2\fR, \fBtype\fR equal to \fBatomic\fR, and read the signature from \fBcontent\fR; ignore the other fields of the signature object. .PP To add a single signature, \fBPUT\fR a new object with \fBversion\fR set to \fB2\fR, \fBtype\fR set to \fBatomic\fR, and \fBcontent\fR set to the signature. Also set \fBname\fR to an unique name with the form \fIdigest\fP\fB@\fR\fIper-image-name\fP, where \fIdigest\fP is an image manifest digest (also used in the URL), and \fIper-image-name\fP is any unique identifier. .PP To add more than one signature, add them one at a time. This API does not allow deleting signatures. .PP Note that because signatures are stored within the cluster-wide image objects, i.e. different namespaces can not associate different sets of signatures to the same image, updating signatures requires a cluster-wide access to the \fBimagesignatures\fR resource (by default available to the \fBsystem:image-signer\fR role), .SH OpenShift-embedded registries .PP The OpenShift-embedded registry implements the ordinary docker/distribution API, and it also exposes images through the OpenShift REST API (available through the “API master” servers). .PP Note: OpenShift versions 1.5 and later support the above-described docker/distribution API extension \[la]#openshift\-dockerdistribution\-api\-extension\[ra], which is easier to set up and should usually be preferred. Continue reading for details on using older versions of OpenShift. .PP As of https://github.com/openshift/origin/pull/9181, signatures are exposed through the OpenShift API (i.e. to access the complete image, it is necessary to use both APIs, in particular to know the URLs for both the docker/distribution and the OpenShift API master endpoints). .PP To read the signature, any user with access to an image can use the \fBimagestreamimages\fR namespaced resource to read an \fBImage\fR object and its \fBSignatures\fR array. Use only the \fBImageSignature\fR objects which have \fBType\fR equal to \fBatomic\fR, and read the signature from \fBContent\fR; ignore the other fields of the \fBImageSignature\fR object. .PP To add or remove signatures, use the cluster-wide (non-namespaced) \fBimagesignatures\fR resource, with \fBType\fR set to \fBatomic\fR and \fBContent\fR set to the signature. Signature names must have the form \fIdigest\fP\fB@\fR\fIper-image-name\fP, where \fIdigest\fP is an image manifest digest (OpenShift “image name”), and \fIper-image-name\fP is any unique identifier. .PP Note that because signatures are stored within the cluster-wide image objects, i.e. different namespaces can not associate different sets of signatures to the same image, updating signatures requires a cluster-wide access to the \fBimagesignatures\fR resource (by default available to the \fBsystem:image-signer\fR role), and deleting signatures is strongly discouraged (it deletes the signature from all namespaces which contain the same image).