trust.go 3.3 KB

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