diff options
-rw-r--r-- | cmd/podman/pull.go | 20 | ||||
-rw-r--r-- | cmd/podman/push.go | 18 | ||||
-rw-r--r-- | docs/podman-build.1.md | 3 | ||||
-rw-r--r-- | docs/podman-login.1.md | 3 | ||||
-rw-r--r-- | docs/podman-pull.1.md | 7 | ||||
-rw-r--r-- | docs/podman-push.1.md | 7 | ||||
-rw-r--r-- | libpod/common/common.go | 28 | ||||
-rw-r--r-- | pkg/util/utils.go | 46 | ||||
-rw-r--r-- | vendor.conf | 2 | ||||
-rw-r--r-- | vendor/github.com/containers/image/docker/docker_client.go | 50 |
10 files changed, 108 insertions, 76 deletions
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go index 5726b20f1..c19e6715b 100644 --- a/cmd/podman/pull.go +++ b/cmd/podman/pull.go @@ -1,16 +1,14 @@ package main import ( - "fmt" "io" "os" - "golang.org/x/crypto/ssh/terminal" - "github.com/containers/image/types" "github.com/pkg/errors" "github.com/projectatomic/libpod/libpod" "github.com/projectatomic/libpod/libpod/common" + "github.com/projectatomic/libpod/pkg/util" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -80,19 +78,11 @@ func pullCmd(c *cli.Context) error { image := args[0] var registryCreds *types.DockerAuthConfig - if c.String("creds") != "" { - creds, err := common.ParseRegistryCreds(c.String("creds")) + + if c.IsSet("creds") { + creds, err := util.ParseRegistryCreds(c.String("creds")) if err != nil { - if err == common.ErrNoPassword { - fmt.Print("Password: ") - password, err := terminal.ReadPassword(0) - if err != nil { - return errors.Wrapf(err, "could not read password from terminal") - } - creds.Password = string(password) - } else { - return err - } + return err } registryCreds = creds } diff --git a/cmd/podman/push.go b/cmd/podman/push.go index 69d6e6629..2f0d73ffa 100644 --- a/cmd/podman/push.go +++ b/cmd/podman/push.go @@ -13,8 +13,8 @@ import ( "github.com/pkg/errors" "github.com/projectatomic/libpod/libpod" "github.com/projectatomic/libpod/libpod/common" + "github.com/projectatomic/libpod/pkg/util" "github.com/urfave/cli" - "golang.org/x/crypto/ssh/terminal" ) var ( @@ -97,25 +97,15 @@ func pushCmd(c *cli.Context) error { } } - registryCredsString := c.String("creds") certPath := c.String("cert-dir") skipVerify := !c.BoolT("tls-verify") removeSignatures := c.Bool("remove-signatures") signBy := c.String("sign-by") - if registryCredsString != "" { - creds, err := common.ParseRegistryCreds(registryCredsString) + if c.IsSet("creds") { + creds, err := util.ParseRegistryCreds(c.String("creds")) if err != nil { - if err == common.ErrNoPassword { - fmt.Print("Password: ") - password, err := terminal.ReadPassword(0) - if err != nil { - return errors.Wrapf(err, "could not read password from terminal") - } - creds.Password = string(password) - } else { - return err - } + return err } registryCreds = creds } diff --git a/docs/podman-build.1.md b/docs/podman-build.1.md index 61c8d8aaa..d4e9af175 100644 --- a/docs/podman-build.1.md +++ b/docs/podman-build.1.md @@ -38,7 +38,8 @@ resulting image's configuration. **--cert-dir** *path* -Use certificates at *path* (*.crt, *.cert, *.key) to connect to the registry +Use certificates at *path* (*.crt, *.cert, *.key) to connect to the registry. +Default certificates directory is _/etc/containers/certs.d_. **--creds** *creds* diff --git a/docs/podman-login.1.md b/docs/podman-login.1.md index fcf32870a..b22a02553 100644 --- a/docs/podman-login.1.md +++ b/docs/podman-login.1.md @@ -38,7 +38,8 @@ Username for registry Path of the authentication file. Default is ${XDG_\RUNTIME\_DIR}/containers/auth.json **--cert-dir** -Pathname of a directory containing TLS certificates and keys used to connect to the registry +Pathname of a directory containing TLS certificates and keys used to connect to the registry. +Default certificates directory is _/etc/containers/certs.d_. **--tls-verify** Require HTTPS and verify certificates when contacting registries (default: true) diff --git a/docs/podman-pull.1.md b/docs/podman-pull.1.md index b1212ee6b..1a1611fd0 100644 --- a/docs/podman-pull.1.md +++ b/docs/podman-pull.1.md @@ -61,11 +61,14 @@ If the authorization state is not found there, $HOME/.docker/config.json is chec **--cert-dir** -Pathname of a directory containing TLS certificates and keys +Pathname of a directory containing TLS certificates and keys. +Default certificates directory is _/etc/containers/certs.d_. **--creds** -Credentials (USERNAME:PASSWORD) to use for authenticating to a registry +The [username[:password]] to use to authenticate with the registry if required. +If one or both values are not supplied, a command line prompt will appear and the +value can be entered. The password is entered without echo. **--quiet, -q** diff --git a/docs/podman-push.1.md b/docs/podman-push.1.md index 63c75ea36..964758da6 100644 --- a/docs/podman-push.1.md +++ b/docs/podman-push.1.md @@ -53,11 +53,14 @@ If the authorization state is not found there, $HOME/.docker/config.json is chec **--creds="CREDENTIALS"** -Credentials (USERNAME:PASSWORD) to use for authenticating to a registry +The [username[:password]] to use to authenticate with the registry if required. +If one or both values are not supplied, a command line prompt will appear and the +value can be entered. The password is entered without echo. **cert-dir="PATHNAME"** -Pathname of a directory containing TLS certificates and keys +Pathname of a directory containing TLS certificates and keys. +Default certificates directory is _/etc/containers/certs.d_. **--compress** diff --git a/libpod/common/common.go b/libpod/common/common.go index 6af3cd232..932f1f6da 100644 --- a/libpod/common/common.go +++ b/libpod/common/common.go @@ -2,17 +2,9 @@ package common import ( "io" - "strings" - "syscall" cp "github.com/containers/image/copy" "github.com/containers/image/types" - "github.com/pkg/errors" -) - -var ( - // ErrNoPassword is returned if the user did not supply a password - ErrNoPassword = errors.Wrapf(syscall.EINVAL, "password was not supplied") ) // GetCopyOptions constructs a new containers/image/copy.Options{} struct from the given parameters @@ -60,23 +52,3 @@ func IsFalse(str string) bool { func IsValidBool(str string) bool { return IsTrue(str) || IsFalse(str) } - -// ParseRegistryCreds takes a credentials string in the form USERNAME:PASSWORD -// and returns a DockerAuthConfig -func ParseRegistryCreds(creds string) (*types.DockerAuthConfig, error) { - if creds == "" { - return nil, errors.New("no credentials supplied") - } - if !strings.Contains(creds, ":") { - return &types.DockerAuthConfig{ - Username: creds, - Password: "", - }, ErrNoPassword - } - v := strings.SplitN(creds, ":", 2) - cfg := &types.DockerAuthConfig{ - Username: v[0], - Password: v[1], - } - return cfg, nil -} diff --git a/pkg/util/utils.go b/pkg/util/utils.go new file mode 100644 index 000000000..9a93021e4 --- /dev/null +++ b/pkg/util/utils.go @@ -0,0 +1,46 @@ +package util + +import ( + "fmt" + "strings" + + "github.com/containers/image/types" + "github.com/pkg/errors" + "golang.org/x/crypto/ssh/terminal" +) + +// Helper function to determine the username/password passed +// in the creds string. It could be either or both. +func parseCreds(creds string) (string, string) { + if creds == "" { + return "", "" + } + up := strings.SplitN(creds, ":", 2) + if len(up) == 1 { + return up[0], "" + } + return up[0], up[1] +} + +// ParseRegistryCreds takes a credentials string in the form USERNAME:PASSWORD +// and returns a DockerAuthConfig +func ParseRegistryCreds(creds string) (*types.DockerAuthConfig, error) { + username, password := parseCreds(creds) + if username == "" { + fmt.Print("Username: ") + fmt.Scanln(&username) + } + if password == "" { + fmt.Print("Password: ") + termPassword, err := terminal.ReadPassword(0) + if err != nil { + return nil, errors.Wrapf(err, "could not read password from terminal") + } + password = string(termPassword) + } + + return &types.DockerAuthConfig{ + Username: username, + Password: password, + }, nil +} diff --git a/vendor.conf b/vendor.conf index 4e7bff400..ea659eab8 100644 --- a/vendor.conf +++ b/vendor.conf @@ -1,6 +1,6 @@ # github.com/sirupsen/logrus v1.0.0 -github.com/containers/image 2524e50daed223ad84b827238ed409bbf44296c5 +github.com/containers/image 3ab2e31e6ff9fc2b21b81188c1f6cf545658ff4a github.com/docker/docker-credential-helpers d68f9aeca33f5fd3f08eeae5e9d175edf4e731d1 github.com/ostreedev/ostree-go master github.com/containers/storage 1824cf917a6b42d8c41179e807bb20a5fd6c0f0a diff --git a/vendor/github.com/containers/image/docker/docker_client.go b/vendor/github.com/containers/image/docker/docker_client.go index b1256b9cb..ff1af8f65 100644 --- a/vendor/github.com/containers/image/docker/docker_client.go +++ b/vendor/github.com/containers/image/docker/docker_client.go @@ -9,6 +9,7 @@ import ( "io/ioutil" "net/http" "net/url" + "os" "path/filepath" "strconv" "strings" @@ -30,8 +31,6 @@ const ( dockerV1Hostname = "index.docker.io" dockerRegistry = "registry-1.docker.io" - systemPerHostCertDirPath = "/etc/docker/certs.d" - resolvedPingV2URL = "%s://%s/v2/" resolvedPingV1URL = "%s://%s/v1/_ping" tagsPath = "/v2/%s/tags/list" @@ -52,6 +51,7 @@ var ( ErrV1NotSupported = errors.New("can't talk to a V1 docker registry") // ErrUnauthorizedForCredentials is returned when the status code returned is 401 ErrUnauthorizedForCredentials = errors.New("unable to retrieve auth token: invalid username/password") + systemPerHostCertDirPaths = [2]string{"/etc/containers/certs.d", "/etc/docker/certs.d"} ) // extensionSignature and extensionSignatureList come from github.com/openshift/origin/pkg/dockerregistry/server/signaturedispatcher.go: @@ -131,19 +131,42 @@ func serverDefault() *tls.Config { } // dockerCertDir returns a path to a directory to be consumed by tlsclientconfig.SetupCertificates() depending on ctx and hostPort. -func dockerCertDir(ctx *types.SystemContext, hostPort string) string { +func dockerCertDir(ctx *types.SystemContext, hostPort string) (string, error) { if ctx != nil && ctx.DockerCertPath != "" { - return ctx.DockerCertPath + return ctx.DockerCertPath, nil } - var hostCertDir string if ctx != nil && ctx.DockerPerHostCertDirPath != "" { - hostCertDir = ctx.DockerPerHostCertDirPath - } else if ctx != nil && ctx.RootForImplicitAbsolutePaths != "" { - hostCertDir = filepath.Join(ctx.RootForImplicitAbsolutePaths, systemPerHostCertDirPath) - } else { - hostCertDir = systemPerHostCertDirPath + return filepath.Join(ctx.DockerPerHostCertDirPath, hostPort), nil } - return filepath.Join(hostCertDir, hostPort) + + var ( + hostCertDir string + fullCertDirPath string + ) + for _, systemPerHostCertDirPath := range systemPerHostCertDirPaths { + if ctx != nil && ctx.RootForImplicitAbsolutePaths != "" { + hostCertDir = filepath.Join(ctx.RootForImplicitAbsolutePaths, systemPerHostCertDirPath) + } else { + hostCertDir = systemPerHostCertDirPath + } + + fullCertDirPath = filepath.Join(hostCertDir, hostPort) + _, err := os.Stat(fullCertDirPath) + if err == nil { + break + } + if os.IsNotExist(err) { + continue + } + if os.IsPermission(err) { + logrus.Debugf("error accessing certs directory due to permissions: %v", err) + continue + } + if err != nil { + return "", err + } + } + return fullCertDirPath, nil } // newDockerClientFromRef returns a new dockerClient instance for refHostname (a host a specified in the Docker image reference, not canonicalized to dockerRegistry) @@ -177,7 +200,10 @@ func newDockerClientWithDetails(ctx *types.SystemContext, registry, username, pa // dockerHostname here, because it is more symmetrical to read the configuration in that case as well, and because // generally the UI hides the existence of the different dockerRegistry. But note that this behavior is // undocumented and may change if docker/docker changes. - certDir := dockerCertDir(ctx, hostName) + certDir, err := dockerCertDir(ctx, hostName) + if err != nil { + return nil, err + } if err := tlsclientconfig.SetupCertificates(certDir, tr.TLSClientConfig); err != nil { return nil, err } |