Skip to content

Commit

Permalink
Use notary library for trusted image fetch and signing
Browse files Browse the repository at this point in the history
Add a trusted flag to force the cli to resolve a tag into a digest via the notary trust library and pull by digest.
On push the flag the trust flag will indicate the digest and size of a manifest should be signed and push to a notary server.
If a tag is given, the cli will resolve the tag into a digest and pull by digest.
After pulling, if a tag is given the cli makes a request to tag the image.

Use certificate directory for notary requests

Read certificates using same logic used by daemon for registry requests.

Catch JSON syntax errors from Notary client

When an uncaught error occurs in Notary it may show up in Docker as a JSON syntax error, causing a confusing error message to the user.
Provide a generic error when a JSON syntax error occurs.

Catch expiration errors and wrap in additional context.

Signed-off-by: Derek McGowan <[email protected]> (github: dmcgowan)
  • Loading branch information
dmcgowan committed Jul 24, 2015
1 parent f5a4a8d commit ed13c3a
Show file tree
Hide file tree
Showing 15 changed files with 759 additions and 78 deletions.
34 changes: 28 additions & 6 deletions api/client/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/registry"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/utils"
)

func (cli *DockerCli) pullImage(image string) error {
Expand Down Expand Up @@ -95,20 +94,42 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
defer containerIDFile.Close()
}

repo, tag := parsers.ParseRepositoryTag(config.Image)
if tag == "" {
tag = tags.DEFAULTTAG
}

ref := registry.ParseReference(tag)
var trustedRef registry.Reference

if isTrusted() && !ref.HasDigest() {
var err error
trustedRef, err = cli.trustedReference(repo, ref)
if err != nil {
return nil, err
}
config.Image = trustedRef.ImageName(repo)
}

//create the container
serverResp, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil)
//if image not found try to pull it
if serverResp.statusCode == 404 && strings.Contains(err.Error(), config.Image) {
repo, tag := parsers.ParseRepositoryTag(config.Image)
if tag == "" {
tag = tags.DEFAULTTAG
}
fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", utils.ImageReference(repo, tag))
fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", ref.ImageName(repo))

// we don't want to write to stdout anything apart from container.ID
if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil {
return nil, err
}
if trustedRef != nil && !ref.HasDigest() {
repoInfo, err := registry.ParseRepositoryInfo(repo)
if err != nil {
return nil, err
}
if err := cli.tagTrusted(repoInfo, trustedRef, ref); err != nil {
return nil, err
}
}
// Retry
if serverResp, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil); err != nil {
return nil, err
Expand Down Expand Up @@ -139,6 +160,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
// Usage: docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
func (cli *DockerCli) CmdCreate(args ...string) error {
cmd := Cli.Subcmd("create", []string{"IMAGE [COMMAND] [ARG...]"}, "Create a new container", true)
addTrustedFlags(cmd, true)

// These are flags not stored in Config/HostConfig
var (
Expand Down
25 changes: 15 additions & 10 deletions api/client/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/registry"
"github.com/docker/docker/utils"
)

// CmdPull pulls an image or a repository from the registry.
Expand All @@ -18,31 +17,37 @@ import (
func (cli *DockerCli) CmdPull(args ...string) error {
cmd := Cli.Subcmd("pull", []string{"NAME[:TAG|@DIGEST]"}, "Pull an image or a repository from a registry", true)
allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
addTrustedFlags(cmd, true)
cmd.Require(flag.Exact, 1)

cmd.ParseFlags(args, true)
remote := cmd.Arg(0)

var (
v = url.Values{}
remote = cmd.Arg(0)
newRemote = remote
)
taglessRemote, tag := parsers.ParseRepositoryTag(remote)
if tag == "" && !*allTags {
newRemote = utils.ImageReference(taglessRemote, tags.DEFAULTTAG)
}
if tag != "" && *allTags {
tag = tags.DEFAULTTAG
fmt.Fprintf(cli.out, "Using default tag: %s\n", tag)
} else if tag != "" && *allTags {
return fmt.Errorf("tag can't be used with --all-tags/-a")
}

v.Set("fromImage", newRemote)
ref := registry.ParseReference(tag)

// Resolve the Repository name from fqn to RepositoryInfo
repoInfo, err := registry.ParseRepositoryInfo(taglessRemote)
if err != nil {
return err
}

if isTrusted() && !ref.HasDigest() {
// Check if tag is digest
authConfig := registry.ResolveAuthConfig(cli.configFile, repoInfo.Index)
return cli.trustedPull(repoInfo, ref, authConfig)
}

v := url.Values{}
v.Set("fromImage", ref.ImageName(taglessRemote))

_, _, err = cli.clientRequestAttemptLogin("POST", "/images/create?"+v.Encode(), nil, cli.out, repoInfo.Index, "pull")
return err
}
5 changes: 5 additions & 0 deletions api/client/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
// Usage: docker push NAME[:TAG]
func (cli *DockerCli) CmdPush(args ...string) error {
cmd := Cli.Subcmd("push", []string{"NAME[:TAG]"}, "Push an image or a repository to a registry", true)
addTrustedFlags(cmd, false)
cmd.Require(flag.Exact, 1)

cmd.ParseFlags(args, true)
Expand All @@ -40,6 +41,10 @@ func (cli *DockerCli) CmdPush(args ...string) error {
return fmt.Errorf("You cannot push a \"root\" repository. Please rename your repository to <user>/<repo> (ex: %s/%s)", username, repoInfo.LocalName)
}

if isTrusted() {
return cli.trustedPush(repoInfo, tag, authConfig)
}

v := url.Values{}
v.Set("tag", tag)

Expand Down
1 change: 1 addition & 0 deletions api/client/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func (cid *cidFile) Write(id string) error {
// Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
func (cli *DockerCli) CmdRun(args ...string) error {
cmd := Cli.Subcmd("run", []string{"IMAGE [COMMAND] [ARG...]"}, "Run a command in a new container", true)
addTrustedFlags(cmd, true)

// These are flags not stored in Config/HostConfig
var (
Expand Down
Loading

0 comments on commit ed13c3a

Please sign in to comment.