From 667c0cec7f72c596909677326e51ac0b5cde4227 Mon Sep 17 00:00:00 2001 From: Justin Chadwell Date: Wed, 8 Feb 2023 14:19:31 +0000 Subject: [PATCH] exporter: set custom config media type on attestation manifests This patch sets the media type for attestation manifests to "application/vnd.docker.attestation.config.v1+json" instead of faking a "application/vnd.oci.image.config.v1+json" type. This updates the attestation manifests inline with the OCI artifact type defined at https://github.com/opencontainers/artifacts. Aside from just making us inline with the spec here, we would hopefully be able to see better integrations in registries that just handle config media types and don't inspect the custom buildkit attestations. Additionally, this makes it *firmly* impossible for runtimes to accidentally download and run the attestation manifest, treating it as an image manifest. Signed-off-by: Justin Chadwell --- exporter/containerimage/writer.go | 31 ++++--------------------------- solver/llbsolver/solver.go | 2 +- util/attestation/types.go | 3 ++- util/imageutil/config.go | 2 +- util/push/push.go | 2 +- 5 files changed, 9 insertions(+), 31 deletions(-) diff --git a/exporter/containerimage/writer.go b/exporter/containerimage/writer.go index 068d86958f8f7..6c2c1ee28896b 100644 --- a/exporter/containerimage/writer.go +++ b/exporter/containerimage/writer.go @@ -456,7 +456,7 @@ func (ic *ImageWriter) commitDistributionManifest(ctx context.Context, opts *Ima func (ic *ImageWriter) commitAttestationsManifest(ctx context.Context, opts *ImageCommitOpts, p exptypes.Platform, target string, statements []intoto.Statement) (*ocispecs.Descriptor, error) { var ( manifestType = ocispecs.MediaTypeImageManifest - configType = ocispecs.MediaTypeImageConfig + configType = attestationTypes.MediaTypeOCIAttestationConfig ) if !opts.OCITypes { manifestType = images.MediaTypeDockerSchema2Manifest @@ -473,7 +473,7 @@ func (ic *ImageWriter) commitAttestationsManifest(ctx context.Context, opts *Ima } digest := digest.FromBytes(data) desc := ocispecs.Descriptor{ - MediaType: attestationTypes.MediaTypeDockerSchema2AttestationType, + MediaType: attestationTypes.MediaTypeAttestationLayer, Digest: digest, Size: int64(len(data)), Annotations: map[string]string{ @@ -488,10 +488,7 @@ func (ic *ImageWriter) commitAttestationsManifest(ctx context.Context, opts *Ima layers[i] = desc } - config, err := attestationsConfig(layers) - if err != nil { - return nil, err - } + config := []byte("{}") configDigest := digest.FromBytes(config) configDesc := ocispecs.Descriptor{ Digest: configDigest, @@ -511,11 +508,7 @@ func (ic *ImageWriter) commitAttestationsManifest(ctx context.Context, opts *Ima Versioned: specs.Versioned{ SchemaVersion: 2, }, - Config: ocispecs.Descriptor{ - Digest: configDigest, - Size: int64(len(config)), - MediaType: configType, - }, + Config: configDesc, }, } @@ -586,22 +579,6 @@ func defaultImageConfig() ([]byte, error) { return dt, errors.Wrap(err, "failed to create empty image config") } -func attestationsConfig(layers []ocispecs.Descriptor) ([]byte, error) { - img := ocispecs.Image{ - Architecture: intotoPlatform.Architecture, - OS: intotoPlatform.OS, - OSVersion: intotoPlatform.OSVersion, - OSFeatures: intotoPlatform.OSFeatures, - Variant: intotoPlatform.Variant, - } - img.RootFS.Type = "layers" - for _, layer := range layers { - img.RootFS.DiffIDs = append(img.RootFS.DiffIDs, digest.Digest(layer.Annotations["containerd.io/uncompressed"])) - } - dt, err := json.Marshal(img) - return dt, errors.Wrap(err, "failed to create attestations image config") -} - func parseHistoryFromConfig(dt []byte) ([]ocispecs.History, error) { var config struct { History []ocispecs.History diff --git a/solver/llbsolver/solver.go b/solver/llbsolver/solver.go index 2f7ba61e5f8f3..3bd156086c488 100644 --- a/solver/llbsolver/solver.go +++ b/solver/llbsolver/solver.go @@ -212,7 +212,7 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend if err != nil { return nil, nil, err } - w, err := s.history.OpenBlobWriter(ctx, attestation.MediaTypeDockerSchema2AttestationType) + w, err := s.history.OpenBlobWriter(ctx, attestation.MediaTypeAttestationLayer) if err != nil { return nil, nil, err } diff --git a/util/attestation/types.go b/util/attestation/types.go index 35f4404cd6273..7223a7e9aa1ae 100644 --- a/util/attestation/types.go +++ b/util/attestation/types.go @@ -1,7 +1,8 @@ package attestation const ( - MediaTypeDockerSchema2AttestationType = "application/vnd.in-toto+json" + MediaTypeAttestationLayer = "application/vnd.in-toto+json" + MediaTypeOCIAttestationConfig = "application/vnd.docker.attestation.config.v1+json" DockerAnnotationReferenceType = "vnd.docker.reference.type" DockerAnnotationReferenceDigest = "vnd.docker.reference.digest" diff --git a/util/imageutil/config.go b/util/imageutil/config.go index 76e0a5da350c8..ab0fddc68190f 100644 --- a/util/imageutil/config.go +++ b/util/imageutil/config.go @@ -174,7 +174,7 @@ func childrenConfigHandler(provider content.Provider, platform platforms.MatchCo descs = append(descs, index.Manifests...) } case images.MediaTypeDockerSchema2Config, ocispecs.MediaTypeImageConfig, docker.LegacyConfigMediaType, - attestation.MediaTypeDockerSchema2AttestationType: + attestation.MediaTypeAttestationLayer, attestation.MediaTypeOCIAttestationConfig: // childless data types. return nil, nil default: diff --git a/util/push/push.go b/util/push/push.go index 881b2fd86f164..4d8e0d8472326 100644 --- a/util/push/push.go +++ b/util/push/push.go @@ -250,7 +250,7 @@ func childrenHandler(provider content.Provider) images.HandlerFunc { case images.MediaTypeDockerSchema2Layer, images.MediaTypeDockerSchema2LayerGzip, images.MediaTypeDockerSchema2Config, ocispecs.MediaTypeImageConfig, ocispecs.MediaTypeImageLayer, ocispecs.MediaTypeImageLayerGzip, - attestation.MediaTypeDockerSchema2AttestationType: + attestation.MediaTypeAttestationLayer, attestation.MediaTypeOCIAttestationConfig: // childless data types. return nil, nil default: