github.com/justincormack/cli@v0.0.0-20201215022714-831ebeae9675/cli/command/service/trust.go (about) 1 package service 2 3 import ( 4 "context" 5 "encoding/hex" 6 7 "github.com/docker/cli/cli/command" 8 "github.com/docker/cli/cli/trust" 9 "github.com/docker/distribution/reference" 10 "github.com/docker/docker/api/types/swarm" 11 "github.com/docker/docker/registry" 12 "github.com/opencontainers/go-digest" 13 "github.com/pkg/errors" 14 "github.com/sirupsen/logrus" 15 "github.com/theupdateframework/notary/tuf/data" 16 ) 17 18 func resolveServiceImageDigestContentTrust(dockerCli command.Cli, service *swarm.ServiceSpec) error { 19 if !dockerCli.ContentTrustEnabled() { 20 // When not using content trust, digest resolution happens later when 21 // contacting the registry to retrieve image information. 22 return nil 23 } 24 25 ref, err := reference.ParseAnyReference(service.TaskTemplate.ContainerSpec.Image) 26 if err != nil { 27 return errors.Wrapf(err, "invalid reference %s", service.TaskTemplate.ContainerSpec.Image) 28 } 29 30 // If reference does not have digest (is not canonical nor image id) 31 if _, ok := ref.(reference.Digested); !ok { 32 namedRef, ok := ref.(reference.Named) 33 if !ok { 34 return errors.New("failed to resolve image digest using content trust: reference is not named") 35 } 36 namedRef = reference.TagNameOnly(namedRef) 37 taggedRef, ok := namedRef.(reference.NamedTagged) 38 if !ok { 39 return errors.New("failed to resolve image digest using content trust: reference is not tagged") 40 } 41 42 resolvedImage, err := trustedResolveDigest(context.Background(), dockerCli, taggedRef) 43 if err != nil { 44 return errors.Wrap(err, "failed to resolve image digest using content trust") 45 } 46 resolvedFamiliar := reference.FamiliarString(resolvedImage) 47 logrus.Debugf("resolved image tag to %s using content trust", resolvedFamiliar) 48 service.TaskTemplate.ContainerSpec.Image = resolvedFamiliar 49 } 50 51 return nil 52 } 53 54 func trustedResolveDigest(ctx context.Context, cli command.Cli, ref reference.NamedTagged) (reference.Canonical, error) { 55 repoInfo, err := registry.ParseRepositoryInfo(ref) 56 if err != nil { 57 return nil, err 58 } 59 60 authConfig := command.ResolveAuthConfig(ctx, cli, repoInfo.Index) 61 62 notaryRepo, err := trust.GetNotaryRepository(cli.In(), cli.Out(), command.UserAgent(), repoInfo, &authConfig, "pull") 63 if err != nil { 64 return nil, errors.Wrap(err, "error establishing connection to trust repository") 65 } 66 67 t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole) 68 if err != nil { 69 return nil, trust.NotaryError(repoInfo.Name.Name(), err) 70 } 71 // Only get the tag if it's in the top level targets role or the releases delegation role 72 // ignore it if it's in any other delegation roles 73 if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole { 74 return nil, trust.NotaryError(repoInfo.Name.Name(), errors.Errorf("No trust data for %s", reference.FamiliarString(ref))) 75 } 76 77 logrus.Debugf("retrieving target for %s role\n", t.Role) 78 h, ok := t.Hashes["sha256"] 79 if !ok { 80 return nil, errors.New("no valid hash, expecting sha256") 81 } 82 83 dgst := digest.NewDigestFromHex("sha256", hex.EncodeToString(h)) 84 85 // Allow returning canonical reference with tag 86 return reference.WithDigest(ref, dgst) 87 }