Verify input image/platform against attestation subjects before passing to rego (#148)

* feat: verify subjects before passing to rego
This commit is contained in:
James Carnegie
2024-09-04 10:20:00 +01:00
committed by GitHub
parent 41847ef238
commit 48e58a9115
7 changed files with 333 additions and 35 deletions

View File

@@ -1,11 +1,15 @@
package policy
import (
"context"
"fmt"
"github.com/distribution/reference"
"github.com/docker/attest/attestation"
"github.com/docker/attest/config"
"github.com/docker/attest/oci"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/package-url/packageurl-go"
)
func CreateImageDetailsResolver(imageSource *oci.ImageSpec) (oci.ImageDetailsResolver, error) {
@@ -36,3 +40,53 @@ func CreateAttestationResolver(resolver oci.ImageDetailsResolver, mapping *confi
}
return attestation.NewReferrersResolver(resolver)
}
// VerifySubject verifies if any of the given subject PURLs matches the image name and platform from resolver.
// Tags are not taken into account when attempting to match because sometimes the user may not have specified a tag, and maybe there
// isn't a purl subject with that particular tag (because of post build tagging?).
func VerifySubject(ctx context.Context, subject []intoto.Subject, resolver attestation.Resolver) error {
img, err := resolver.ImageName(ctx)
if err != nil {
return err
}
inputName, err := reference.ParseNormalizedNamed(img)
if err != nil {
return err
}
descriptor, err := resolver.ImageDescriptor(ctx)
if err != nil {
return err
}
platform, err := resolver.ImagePlatform(ctx)
if err != nil {
return err
}
for _, sub := range subject {
if sub.Digest[descriptor.Digest.Algorithm] != descriptor.Digest.Hex {
continue
}
purl, err := packageurl.FromString(sub.Name)
if err != nil {
continue
}
if purl.Type != "docker" {
continue
}
if purl.Qualifiers.Map()["platform"] != platform.String() {
continue
}
// ensure reference is normalized before comparing
subjectName, err := reference.ParseNormalizedNamed(purl.Name)
if err != nil {
continue
}
// this assumes that domain is part of the package URL (some say it should be a qualifier)
// buildkit puts the domain in the name, e.g. pkg:docker/ecr.io/foobar/alpine@latest?platform=linux%2Famd64
if inputName.Name() == subjectName.Name() {
// found a match
return nil
}
}
return fmt.Errorf("no matching subject found for image: %s", img)
}