image: expose in-toto attestation statements via the API - #52636
Conversation
dce3aca to
e394bdd
Compare
|
Our ultimate goal is to evaluate policies during the container lifecycle with the same information as is available to Buildkit build policies. Buildkit does the heavy lifting of finding all the relevant attestations for the image and sending them to the builder: Since it's looking like an Engine API change would be needed regardless of which approach we take, I propose we add a new endpoint (strawman: |
820ce5a to
d92302f
Compare
| } | ||
|
|
||
| func (p *localReferrersProvider) FetchReferrers(ctx context.Context, dgst digest.Digest, opts ...remotes.FetchReferrersOpt) ([]ocispec.Descriptor, error) { | ||
| return nil, nil |
There was a problem hiding this comment.
This would silently return empty results for DHI-style attestations? Should we detect that case and return a proper error/warning?
There was a problem hiding this comment.
@vvoland, FetchReferrers does return empty here, but ResolveSignatureChain then errors out for DHI indexes with "no attestation referrers found for DHI manifest < digest >", and we propagate that as a 500. So users do see something, just not a great error.
To address this, we could detect DHI explicitly and return errdefs.NotImplemented (HTTP 501) with a clear message. policy-helpers already has the detection logic (currently as a private isDHIIndex), so we could export it as IsDHIIndex in a policy-helpers PR and then bump the dependency in moby/moby to use it.
Would you be okay with that approach? And if so, would you prefer it as part of this PR or as a follow-up?
vvoland
left a comment
There was a problem hiding this comment.
LGTM!
Before merging, could you please rebase and squash the commits?
f0704dd to
5e76dbb
Compare
26afddc to
4c330b8
Compare
Add a new Engine API endpoint that returns the in-toto attestation
statements attached to an image for a given platform. The endpoint
locates the attestation manifest(s) referencing the requested platform's
image manifest, enumerates the statement layers, and returns each
layer's OCI descriptor (including media type, digest, size, and
annotations) together with its in-toto predicate type.
Query parameters:
- platform: JSON-encoded OCI platform; defaults to the daemon's host
platform if omitted.
- type: comma-separated list of in-toto predicate type URIs; if
omitted, all statements are returned.
- statement: boolean, defaults to false. When true, the daemon reads
each matching statement blob and includes the verbatim in-toto JSON
in the response. When false (or omitted), statement blobs are not
read and the Statement field is absent from each entry.
The manifest-chain walk (locating the platform image manifest and its
associated attestation manifest) is delegated to policy-helpers'
image.ResolveSignatureChain so that moby and BuildKit agree on how to
interpret the attestation storage format. The statement-layer iteration
and blob reading is inlined: when statement bodies are requested it
fails fast on the first unreadable blob and reads matching blobs
eagerly into memory; otherwise statement-layer blobs are never read
from the content store.
The endpoint is implemented for the containerd image store. The legacy
graphdriver store returns errdefs.NotImplemented (HTTP 501).
Signed-off-by: Sopho Merkviladze <[email protected]>
4c330b8 to
a0b6dbc
Compare
Both query parameters are now collectionFormat: multi arrays in the swagger so they can accept multiple values later without an API version bump. The server still operates on a single platform and rejects requests passing more than one; type is read directly as a list of repeated values instead of a comma-separated string. Signed-off-by: Sopho Merkviladze <[email protected]>
|
Windows failure is unrelated (no need to re-run CI for that); |
- What I did
Added a new Engine API endpoint,
GET /images/{name}/attestations, which returns the in-toto attestation statements attached to an image for a given platform.Query parameters:
platform: JSON-encoded OCI platform; defaults to the daemon’s host platform if omitted.type: comma-separated list of in-toto predicate type URIs; if omitted, all statements are returned.statement: boolean, defaults tofalse. Whentrue, the daemon reads each matching statement blob and includes the verbatim in-toto JSON in the response. When omitted orfalse, only the descriptor and predicate type are returned and statement blobs are not read.The response is a JSON array of statement objects. Each object contains the layer's OCI descriptor (including media type, digest, size, annotations), the in-toto predicate type, and when
statement=trueis set, the verbatim statement JSON. Withstatement=truethe caller gets the full content inline and avoids additional registry round-trips; without it, the response is metadata only.- How I did it
The manifest-chain walk (locating the image manifest for the platform and the associated attestation manifest) is delegated to
policyimage.ResolveSignatureChainfrom policy-helpers, ensuring that both Moby and BuildKit agree on how to interpret the attestation storage format.The statement-layer iteration and blob reading are implemented in
daemon/containerd/image_attestations.go. WhenIncludeStatementis set, the daemon fails fast on the first unreadable blob and reads matching blobs eagerly into memory; otherwise the content store is not touched for statement bodies.The endpoint is implemented for the containerd image store. The legacy graphdriver store returns
errdefs.NotImplemented(HTTP 501), allowing clients to distinguish backend non-support from images that have no attestations.HTTP status codes:
200- success (empty array when the image has no attestations)400- malformed platform value, or API version below 1.55404- unknown image, or no manifest for the requested platform500- server error (e.g., blob read failure)501- legacy graphdriver backend; attestations not supportedThe Go client SDK exposes
(*Client).ImageAttestations(...), returning anImageAttestationsResultwrapper that contains anItemsslice.- How to verify it
Build an image with attestations.
Query the endpoint:
Include statement bodies:
Or filter by predicate type:
Automated coverage:
daemon/containerd/image_provenance_test.gocover layer iteration, filtering behavior, and error propagation.integration/image/attestation_test.goexercise the HTTP endpoint end-to-end via the client SDK.- Human readable description for the release notes