github.com/openshift/moby-moby@v1.13.2-0.20170601211448-f5ec1e2936dc/cli/command/service/trust.go (about) 1 package service 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 7 "github.com/Sirupsen/logrus" 8 "github.com/docker/distribution/digest" 9 distreference "github.com/docker/distribution/reference" 10 "github.com/docker/docker/api/types/swarm" 11 "github.com/docker/docker/cli/command" 12 "github.com/docker/docker/cli/trust" 13 "github.com/docker/docker/reference" 14 "github.com/docker/docker/registry" 15 "github.com/docker/notary/tuf/data" 16 "github.com/pkg/errors" 17 "golang.org/x/net/context" 18 ) 19 20 func resolveServiceImageDigest(dockerCli *command.DockerCli, service *swarm.ServiceSpec) error { 21 if !command.IsTrusted() { 22 // Digests are resolved by the daemon when not using content 23 // trust. 24 return nil 25 } 26 27 image := service.TaskTemplate.ContainerSpec.Image 28 29 // We only attempt to resolve the digest if the reference 30 // could be parsed as a digest reference. Specifying an image ID 31 // is valid but not resolvable. There is no warning message for 32 // an image ID because it's valid to use one. 33 if _, err := digest.ParseDigest(image); err == nil { 34 return nil 35 } 36 37 ref, err := reference.ParseNamed(image) 38 if err != nil { 39 return fmt.Errorf("Could not parse image reference %s", service.TaskTemplate.ContainerSpec.Image) 40 } 41 if _, ok := ref.(reference.Canonical); !ok { 42 ref = reference.WithDefaultTag(ref) 43 44 taggedRef, ok := ref.(reference.NamedTagged) 45 if !ok { 46 // This should never happen because a reference either 47 // has a digest, or WithDefaultTag would give it a tag. 48 return errors.New("Failed to resolve image digest using content trust: reference is missing a tag") 49 } 50 51 resolvedImage, err := trustedResolveDigest(context.Background(), dockerCli, taggedRef) 52 if err != nil { 53 return fmt.Errorf("Failed to resolve image digest using content trust: %v", err) 54 } 55 logrus.Debugf("resolved image tag to %s using content trust", resolvedImage.String()) 56 service.TaskTemplate.ContainerSpec.Image = resolvedImage.String() 57 } 58 return nil 59 } 60 61 func trustedResolveDigest(ctx context.Context, cli *command.DockerCli, ref reference.NamedTagged) (distreference.Canonical, error) { 62 repoInfo, err := registry.ParseRepositoryInfo(ref) 63 if err != nil { 64 return nil, err 65 } 66 67 authConfig := command.ResolveAuthConfig(ctx, cli, repoInfo.Index) 68 69 notaryRepo, err := trust.GetNotaryRepository(cli, repoInfo, authConfig, "pull") 70 if err != nil { 71 return nil, errors.Wrap(err, "error establishing connection to trust repository") 72 } 73 74 t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole) 75 if err != nil { 76 return nil, trust.NotaryError(repoInfo.FullName(), err) 77 } 78 // Only get the tag if it's in the top level targets role or the releases delegation role 79 // ignore it if it's in any other delegation roles 80 if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole { 81 return nil, trust.NotaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", ref.String())) 82 } 83 84 logrus.Debugf("retrieving target for %s role\n", t.Role) 85 h, ok := t.Hashes["sha256"] 86 if !ok { 87 return nil, errors.New("no valid hash, expecting sha256") 88 } 89 90 dgst := digest.NewDigestFromHex("sha256", hex.EncodeToString(h)) 91 92 // Using distribution reference package to make sure that adding a 93 // digest does not erase the tag. When the two reference packages 94 // are unified, this will no longer be an issue. 95 return distreference.WithDigest(ref, dgst) 96 }