trust.go 3.0 KB

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