Add trusted identity to images#51737
Conversation
go.mod
Outdated
| github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect | ||
| github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect | ||
| github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect | ||
| github.com/go-openapi/analysis v0.24.1 // indirect |
There was a problem hiding this comment.
I managed to remove ~800k lines of dependencies from sigstore verification. This is the main part of the remaining. I don't see any quick way to get rid of it unfortunately. Sigstore folks were ok to consider alternatives but this would be quite fundamental change in their upstreams.
| module github.com/moby/moby/v2 | ||
|
|
||
| go 1.24.3 | ||
| go 1.25.0 |
There was a problem hiding this comment.
This was unfortunately forced on us in recent sigstore update (that we need to reduce dependencies) moby/policy-helpers#12 (review)
| v, err := policyverifier.NewVerifier(policyverifier.Config{ | ||
| StateDir: confDir, | ||
| }) |
There was a problem hiding this comment.
I think we should be able to configure the update interval on daemon side and have a good default? Maybe require online as well? https://github.com/moby/policy-helpers/blob/9fcc1a9ec5c9573385c30ab81cac41e9da124f0e/verifier.go#L28-L29
There was a problem hiding this comment.
Not against, but I think these are sort of advanced features that could be added later in a follow up.
1b38ba6 to
80981ff
Compare
80981ff to
50459c7
Compare
api/types/image/image_inspect.go
Outdated
| // DockerReference is the Docker image reference associated with the signature. | ||
| // This is an optional field only present in older hashedrecord signatures. | ||
| DockerReference string `json:"DockerReference,omitempty"` |
There was a problem hiding this comment.
What's a "Docker image reference"? Is that a "distribution" reference (name / tag) of the image? https://pkg.go.dev/github.com/distribution/reference
Wouldn't that always match the image that's inspected, or is this for situations where an image is tagged under multiple names?
Wondering if this should be a more generic term (not sure if we should consider this "docker" if it's defined by distribution 🤔)
There was a problem hiding this comment.
This is actually an old signature format, only used by DHI atm for new images.
Wouldn't that always match the image that's inspected, or is this for situations where an image is tagged under multiple names?
No, as this is part of the reference, then it is immutable. It is like the name the signer gave to the image while singing. Eg. in DHI this is the upstream name of the image. If you mirror or copy DHI image under your org, this will remain the upstream name. So even if you pulled from your org, the signature can confirm that this is still the same image that was originally tagged as specific DHI name.
There was a problem hiding this comment.
This is actually an old signature format, only used by DHI atm for new images.
Yeah it is recommended to use the Sigstore Bundle Format instead. Simple Signing is kinda deprecated now.
daemon/containerd/image_inspect.go
Outdated
| identity, err := i.imageIdentity(ctx, target.Digest) | ||
| if err != nil { | ||
| log.G(ctx).WithError(err).Warn("failed to determine Identity property") | ||
| } |
There was a problem hiding this comment.
Given that this information is a new addition, and (technically) not available in older API versions, should we add an option to ImageInspectOpts to make inclusion optional (and gate it by API version?)?
moby/daemon/server/imagebackend/image.go
Lines 56 to 60 in 4d09d8c
There was a problem hiding this comment.
I don't think so. I think it is good that this doesn't require CLI side changes. The output is already a block of JSON for this specific API.
There was a problem hiding this comment.
Oh, sorry, I was probably not clear; this is a backend option (so not user-facing) my thinking here was to add a boolean, then in the router set that boolean to true for API >= 1.53
There was a problem hiding this comment.
That still means that it would require new CLI I think. I think it is nice that there aren't extra limitations like that (@colinhemmings). This is not an API where there would be some backward compatibility issues or changes in the current fields.
There was a problem hiding this comment.
Older clients won't unmarshal it because it's not in the types they use, so the information won't be there, unless they dump the raw response.
There was a problem hiding this comment.
I think it's fine just to version gate it and just set the Identity to nil on older versions.
This way we avoid complicating the backend implementation but still keep the backwards compatibility.
There was a problem hiding this comment.
Older clients won't unmarshal it because it's not in the types they use, so the information won't be there, unless they dump the raw response.
No, this is not the case. I haven't built any new CLI in anywhere this has been tested. It would be impossible to use it atm if this was the case.
There was a problem hiding this comment.
The CLI dumps the raw JSON, but clients following the API spec, or implementations using the unmarshaled response as returned by the client won't have the info.
| identity := &imagetypes.ImageIdentity{} | ||
|
|
||
| for k, v := range info.Labels { | ||
| if ref, ok := strings.CutPrefix(k, exporter.BuildRefLabel); ok { |
There was a problem hiding this comment.
Format here is something like moby/build.ref.docker.io/library/ubuntu:latest ? Is that also because the image can be tagged under different names?
I was curious why the ref wasn't part of the JSON value that's stored in the label 😅
There was a problem hiding this comment.
This is not distribution reference. BuildRef is just a unique identifier for the build. You can make extra requests against buildkit with the identifier to extract more data.
I was curious why the ref wasn't part of the JSON value that's stored in the label 😅
There can be multiple refs for the same image contents. Putting it to the same value would mean it needs to be reencoded on each modification and creates race conditions and possible size limits. Easier if each build just adds own label.
e2d0bcb to
30314fa
Compare
crazy-max
left a comment
There was a problem hiding this comment.
LGTM
For TUF state/gc we can look at it as follow-up.
Can you PTAL @thaJeztah? Specially the api/swagger part? 🙏
|
rebased after #51857 was merged, and moved some touch-up diffs to the right commit; need a slight cleanup / squash (the renames); I'll have a look at that later. |
9710305 to
ecacf5f
Compare
|
|
||
| // SignerIdentity contains information about the signer certificate used to sign the image. | ||
| // This is certificate.Summary with deprecated fields removed and keys in Moby uppercase style. | ||
| // This is [certificate.Summary] with deprecated fields removed and keys in Moby uppercase style. |
There was a problem hiding this comment.
I noticed the "and keys in Moby uppercase style" ...
There was a problem hiding this comment.
Agh, this got lost when all the fields were copied again in #51737 (comment)
api/types/image/signer_identity.go
Outdated
There was a problem hiding this comment.
But that only applies to the first 3 fields, but not for the other fields, which are lowercase; was that intentional?
Also curious what the //nolint:tagliatelle was for; is that because of the mixed upper/lowercase ?
edit: ah, probably copied from https://pkg.go.dev/github.com/sigstore/sigstore-go/pkg/fulcio/certificate#Extensions
ba403e8 to
72ce3a5
Compare
|
Squashed the last 3 commits with the first one. |
|
thaJeztah
left a comment
There was a problem hiding this comment.
LGTM
but could use another review, because I pushed the last changes
vvoland
left a comment
There was a problem hiding this comment.
LGTM, but a follow up with some integration tests for this wouldn't hurt 😅
|
Issue / glitch with docker hub auth, or just another GitHub actions glitch? |
|
Looks like Hub |
|
Yup; I see there's an incident; not sure if they already updated the status page though. |
|
Ah! They did https://www.dockerstatus.com
|
72ce3a5 to
dc56d93
Compare
|
|
||
| // Reference to specific build instructions that are responsible for signing. | ||
| BuildSignerURI string `json:"buildSignerURI,omitempty"` // 1.3.6.1.4.1.57264.1.9 | ||
| BuildSignerURI string `json:"BuildSignerURI,omitempty"` // 1.3.6.1.4.1.57264.1.9 |
There was a problem hiding this comment.
@tonistiigi can you squash these case changes with the first commit, and I think the second commit also needs to be updated as the Swagger may be using lowercase.
Or should we make all fields match the upstream (and lowercase)? Not sure if it's a standard / spec that we should match?
There was a problem hiding this comment.
Should be ok now.
Or should we make all fields match the upstream (and lowercase)?
It looks out of place in Inspect output then as all other fields are uppercase.
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Enable inspect endpoint to verify image signatures and expose signature information for inspection. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
dc56d93 to
8890f81
Compare

This PR adds a new Identity property to images visible with inspect command. This information describes the origin of the image contents, is verified by the daemon, and is immutable for the user. If the user retags the image to a different name, its identity remains immutable to the initial information.
This allows users to understand if the image content really is what it claims to be and can be used to make policy decisions.
Currently the image origin can be provided in three different ways:
Examples
Locally built image:
Pulled image:
Image signed with Docker Github Builder (currently experimental), proving artifact integrity against the source reference:
Manual cosign signature I created in laptop:
changelog:
--
I think we should also add a caching layer to avoid the cost of rerunning the signature verification. Initially I thought we should add temporary opt-in for this until we have caching. But when testing I don't see any extra slowness for the user experience. I think caching is a requirement if we want to have a summary of identity information to the image list endpoint. If we want to give us more time to make potential changes in the struct I'm still ok with a temporary opt-in, but I'm not really sure if it should be in client or daemon side.
@dmcgowan @crazy-max @thaJeztah @colinhemmings