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