container-signature(5) format container-signature(5)
Miloslav Trmač March 2017
NAME
container-signature - Container signature format
DESCRIPTION
This document describes the format of container signatures, as imple-
mented by the github.com/containers/image/signature package.
Most users should be able to consume these signatures by using the
github.com/containers/image/signature package (preferably through the
higher-level signature.PolicyContext interface) without having to care
about the details of the format described below. This documentation ex-
ists primarily for maintainers of the package and to allow independent
reimplementations.
High-level overview
The signature provides an end-to-end authenticated claim that a con-
tainer image has been approved by a specific party (e.g. the creator of
the image as their work, an automated build system as a result of an au-
tomated build, a company IT department approving the image for produc-
tion) under a specified identity (e.g. an OS base image / specific ap-
plication, with a specific version).
A container signature consists of a cryptographic signature which iden-
tifies and authenticates who signed the image, and carries as a signed
payload a JSON document. The JSON document identifies the image being
signed, claims a specific identity of the image and if applicable, con-
tains other information about the image.
The signatures do not modify the container image (the layers, configura-
tion, manifest, …); e.g. their presence does not change the manifest di-
gest used to identify the image in docker/distribution servers; rather,
the signatures are associated with an immutable image. An image can
have any number of signatures so signature distribution systems SHOULD
support associating more than one signature with an image.
The cryptographic signature
As distributed, the container signature is a blob which contains a cryp-
tographic signature in an industry-standard format, carrying a signed
JSON payload (i.e. the blob contains both the JSON document and a signa-
ture of the JSON document; it is not a “detached signature” with inde-
pendent blobs containing the JSON document and a cryptographic signa-
ture).
Currently the only defined cryptographic signature format is an OpenPGP
signature (RFC 4880), but others may be added in the future. (The blob
does not contain metadata identifying the cryptographic signature for-
mat. It is expected that most formats are sufficiently self-describing
that this is not necessary and the configured expected public key pro-
vides another indication of the expected cryptographic signature format.
Such metadata may be added in the future for newly added cryptographic
signature formats, if necessary.)
Consumers of container signatures SHOULD verify the cryptographic signa-
ture against one or more trusted public keys (e.g. defined in a pol-
icy.json signature verification policy file ⟨containers-pol-
icy.json.5.md⟩) before parsing or processing the JSON payload in any
way, in particular they SHOULD stop processing the container signature
if the cryptographic signature verification fails, without even starting
to process the JSON payload.
(Consumers MAY extract identification of the signing key and other meta-
data from the cryptographic signature, and the JSON payload, without
verifying the signature, if the purpose is to allow managing the signa-
ture blobs, e.g. to list the authors and image identities of signatures
associated with a single container image; if so, they SHOULD design the
output of such processing to minimize the risk of users considering the
output trusted or in any way usable for making policy decisions about
the image.)
OpenPGP signature verification
When verifying a cryptographic signature in the OpenPGP format, the con-
sumer MUST verify at least the following aspects of the signature (like
the github.com/containers/image/signature package does):
• The blob MUST be a “Signed Message” as defined RFC 4880 section
11.3. (e.g. it MUST NOT be an unsigned “Literal Message”, a
“Cleartext Signature” as defined in RFC 4880 section 7, or any
other non-signature format).
• The signature MUST have been made by an expected key trusted
for the purpose (and the specific container image).
• The signature MUST be correctly formed and pass the crypto-
graphic validation.
• The signature MUST correctly authenticate the included JSON
payload (in particular, the parsing of the JSON payload MUST
NOT start before the complete payload has been cryptographi-
cally authenticated).
• The signature MUST NOT be expired.
The consumer SHOULD have tests for its verification code which verify
that signatures failing any of the above are rejected.
JSON processing and forward compatibility
The payload of the cryptographic signature is a JSON document (RFC
7159). Consumers SHOULD parse it very strictly, refusing any signature
which violates the expected format (e.g. missing members, incorrect mem-
ber types) or can be interpreted ambiguously (e.g. a duplicated member
in a JSON object).
Any violations of the JSON format or of other requirements in this docu-
ment MAY be accepted if the JSON document can be recognized to have been
created by a known-incorrect implementation (see ⟨#optionalcreator⟩ be-
low) and if the semantics of the invalid document, as created by such an
implementation, is clear.
The top-level value of the JSON document MUST be a JSON object with ex-
actly two members, critical and optional, each a JSON object.
The critical object MUST contain a type member identifying the document
as a container signature (as defined below ⟨#criticaltype⟩) and signa-
ture consumers MUST reject signatures which do not have this member or
in which this member does not have the expected value.
To ensure forward compatibility (allowing older signature consumers to
correctly accept or reject signatures created at a later date, with pos-
sible extensions to this format), consumers MUST reject the signature if
the critical object, or any of its subobjects, contain any member or
data value which is unrecognized, unsupported, invalid, or in any other
way unexpected. At a minimum, this includes unrecognized members in a
JSON object, or incorrect types of expected members.
For the same reason, consumers SHOULD accept any members with unrecog-
nized names in the optional object, and MAY accept signatures where the
object member is recognized but unsupported, or the value of the member
is unsupported. Consumers still SHOULD reject signatures where a member
of an optional object is supported but the value is recognized as in-
valid.
JSON data format
An example of the full format follows, with detailed description below.
To reiterate, consumers of the signature SHOULD perform successful cryp-
tographic verification, and MUST reject unexpected data in the critical
object, or in the top-level object, as described above.
{
"critical": {
"type": "atomic container signature",
"image": {
"docker-manifest-digest": "sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e"
},
"identity": {
"docker-reference": "docker.io/library/busybox:latest"
}
},
"optional": {
"creator": "some software package v1.0.1-35",
"timestamp": 1483228800,
}
}
critical
This MUST be a JSON object which contains data critical to correctly
evaluating the validity of a signature.
Consumers MUST reject any signature where the critical object contains
any unrecognized, unsupported, invalid or in any other way unexpected
member or data.
critical.type
This MUST be a string with a string value exactly equal to atomic con-
tainer signature (three words, including the spaces).
Signature consumers MUST reject signatures which do not have this member
or this member does not have exactly the expected value.
(The consumers MAY support signatures with a different value of the type
member, if any is defined in the future; if so, the rest of the JSON
document is interpreted according to rules defining that value of criti-
cal.type, not by this document.)
critical.image
This MUST be a JSON object which identifies the container image this
signature applies to.
Consumers MUST reject any signature where the critical.image object con-
tains any unrecognized, unsupported, invalid or in any other way unex-
pected member or data.
(Currently only the docker-manifest-digest way of identifying a con-
tainer image is defined; alternatives to this may be defined in the fu-
ture, but existing consumers are required to reject signatures which use
formats they do not support.)
critical.image.docker-manifest-digest
This MUST be a JSON string, in the github.com/opencontainers/go-di-
gest.Digest string format.
The value of this member MUST match the manifest of the signed container
image, as implemented in the docker/distribution manifest addressing
system.
The consumer of the signature SHOULD verify the manifest digest against
a fully verified signature before processing the contents of the image
manifest in any other way (e.g. parsing the manifest further or down-
loading layers of the image).
Implementation notes: * A single container image manifest may have sev-
eral valid manifest digest values, using different algorithms. * For
“signed” docker/distribution schema 1 ⟨https://github.com/docker/distri-
bution/blob/master/docs/spec/manifest-v2-1.md⟩ manifests, the manifest
digest applies to the payload of the JSON web signature, not to the raw
manifest blob.
critical.identity
This MUST be a JSON object which identifies the claimed identity of the
image (usually the purpose of the image, or the application, along with
a version information), as asserted by the author of the signature.
Consumers MUST reject any signature where the critical.identity object
contains any unrecognized, unsupported, invalid or in any other way un-
expected member or data.
(Currently only the docker-reference way of claiming an image iden-
tity/purpose is defined; alternatives to this may be defined in the fu-
ture, but existing consumers are required to reject signatures which use
formats they do not support.)
critical.identity.docker-reference
This MUST be a JSON string, in the github.com/docker/distribution/refer-
ence string format, and using the same normalization semantics (where
e.g. busybox:latest is equivalent to docker.io/library/busybox:latest).
If the normalization semantics allows multiple string representations of
the claimed identity with equivalent meaning, the critical.iden-
tity.docker-reference member SHOULD use the fully explicit form (includ-
ing the full host name and namespaces).
The value of this member MUST match the image identity/purpose expected
by the consumer of the image signature and the image (again, accounting
for the docker/distribution/reference normalization semantics).
In the most common case, this means that the critical.identity.docker-
reference value must be equal to the docker/distribution reference used
to refer to or download the image. However, depending on the specific
application, users or system administrators may accept less specific
matches (e.g. ignoring the tag value in the signature when pulling the
:latest tag or when referencing an image by digest), or they may require
critical.identity.docker-reference values with a completely different
namespace to the reference used to refer to/download the image (e.g. re-
quiring a critical.identity.docker-reference value which identifies the
image as coming from a supplier when fetching it from a company-internal
mirror of approved images). The software performing this verification
SHOULD allow the users to define such a policy using the policy.json
signature verification policy file format ⟨containers-policy.json.5.md⟩.
The critical.identity.docker-reference value SHOULD contain either a tag
or digest; in most cases, it SHOULD use a tag rather than a digest.
(See also the default ⟨containers-policy.json.5.md#signedby⟩.)
optional
This MUST be a JSON object.
Consumers SHOULD accept any members with unrecognized names in the op-
tional object, and MAY accept a signature where the object member is
recognized but unsupported, or the value of the member is valid but un-
supported. Consumers still SHOULD reject any signature where a member
of an optional object is supported but the value is recognized as in-
valid.
optional.creator
If present, this MUST be a JSON string, identifying the name and version
of the software which has created the signature (identifying the low-
level software implementation; not the top-level caller).
The contents of this string is not defined in detail; however each im-
plementation creating container signatures:
• SHOULD define the contents to unambiguously define the software
in practice (e.g. it SHOULD contain the name of the software,
not only the version number)
• SHOULD use a build and versioning process which ensures that
the contents of this string (e.g. an included version number)
changes whenever the format or semantics of the generated sig-
nature changes in any way; it SHOULD not be possible for two
implementations which use a different format or semantics to
have the same optional.creator value
• SHOULD use a format which is reasonably easy to parse in soft-
ware (perhaps using a regexp), and which makes it easy enough
to recognize a range of versions of a specific implementation
(e.g. the version of the implementation SHOULD NOT be only a
git hash, because they don’t have an easily defined ordering;
the string should contain a version number, or at least a date
of the commit).
Consumers of container signatures MAY recognize specific values or sets
of values of optional.creator (perhaps augmented with optional.time-
stamp), and MAY change their processing of the signature based on these
values (usually to accommodate violations of this specification in past
versions of the signing software which cannot be fixed retroactively),
as long as the semantics of the invalid document, as created by such an
implementation, is clear.
If consumers of signatures do change their behavior based on the op-
tional.creator value, they SHOULD take care that the way they process
the signatures is not inconsistent with strictly validating signature
consumers. (I.e. it is acceptable for a consumer to accept a signature
based on a specific optional.creator value if other implementations
would completely reject the signature, but it would be very undesirable
for the two kinds of implementations to accept the signature in differ-
ent and inconsistent situations.)
optional.timestamp
If present, this MUST be a JSON number, which is representable as a
64-bit integer, and identifies the time when the signature was created
as the number of seconds since the UNIX epoch (Jan 1 1970 00:00 UTC).
signature Container container-signature(5)
Generated by dwww version 1.16 on Tue Dec 16 07:52:07 CET 2025.