diff --git a/cmd/podman/login.go b/cmd/podman/login.go index 42b55f7eb1..ce9568382d 100644 --- a/cmd/podman/login.go +++ b/cmd/podman/login.go @@ -2,6 +2,8 @@ package main import ( "context" + "errors" + "fmt" "os" "github.com/containers/common/pkg/auth" @@ -9,6 +11,7 @@ import ( "github.com/containers/image/v5/types" "github.com/containers/podman/v4/cmd/podman/common" "github.com/containers/podman/v4/cmd/podman/registry" + "github.com/containers/podman/v4/pkg/domain/entities" "github.com/spf13/cobra" ) @@ -48,7 +51,11 @@ func init() { completion.CompleteCommandFlags(loginCommand, auth.GetLoginFlagsCompletions()) // Podman flags. - flags.BoolVarP(&loginOptions.tlsVerify, "tls-verify", "", false, "Require HTTPS and verify certificates when contacting registries") + secretFlagName := "secret" + flags.BoolVar(&loginOptions.tlsVerify, "tls-verify", false, "Require HTTPS and verify certificates when contacting registries") + flags.String(secretFlagName, "", "Retrieve password from a podman secret") + _ = loginCommand.RegisterFlagCompletionFunc(secretFlagName, common.AutocompleteSecrets) + loginOptions.Stdin = os.Stdin loginOptions.Stdout = os.Stdout loginOptions.AcceptUnspecifiedRegistry = true @@ -63,6 +70,31 @@ func login(cmd *cobra.Command, args []string) error { skipTLS = types.NewOptionalBool(!loginOptions.tlsVerify) } + secretName := cmd.Flag("secret").Value.String() + if len(secretName) > 0 { + if len(loginOptions.Password) > 0 { + return errors.New("--secret can not be used with --password options") + } + if len(loginOptions.Username) == 0 { + loginOptions.Username = secretName + } + var inspectOpts = entities.SecretInspectOptions{ + ShowSecret: true, + } + inspected, errs, _ := registry.ContainerEngine().SecretInspect(context.Background(), []string{secretName}, inspectOpts) + + if len(errs) > 0 && errs[0] != nil { + return errs[0] + } + if len(inspected) == 0 { + return fmt.Errorf("no secrets found for %q", secretName) + } + if len(inspected) > 1 { + return fmt.Errorf("unexpected error SecretInspect of a single secret should never return more then one secrets %q", secretName) + } + loginOptions.Password = inspected[0].SecretData + } + sysCtx := &types.SystemContext{ AuthFilePath: loginOptions.AuthFile, DockerCertPath: loginOptions.CertDir, diff --git a/docs/source/markdown/podman-login.1.md.in b/docs/source/markdown/podman-login.1.md.in index fd3a088c98..fc5d481207 100644 --- a/docs/source/markdown/podman-login.1.md.in +++ b/docs/source/markdown/podman-login.1.md.in @@ -48,6 +48,11 @@ Password for registry Take the password from stdin +#### **--secret**=*name* + +Read the password for the registry from the podman secret `name`. +If --username is not specified --username=`name` is used. + @@option tls-verify #### **--username**, **-u**=*username* @@ -79,6 +84,13 @@ Password: Login Succeeded! ``` +``` +$ echo -n MySecret! | podman secret create secretname - +a0ad54df3c97cf89d5ca6193c +$ podman login --secret secretname -u testuser quay.io +Login Succeeded! +``` + ``` $ podman login --tls-verify=false -u test -p test localhost:5000 Login Succeeded! @@ -108,7 +120,7 @@ Login Succeeded! ``` ## SEE ALSO -**[podman(1)](podman.1.md)**, **[podman-logout(1)](podman-logout.1.md)**, **[containers-auth.json(5)](https://github.com/containers/image/blob/main/docs/containers-auth.json.5.md)**, **[containers-certs.d(5)](https://github.com/containers/image/blob/main/docs/containers-certs.d.5.md)**, **[containers-registries.conf(5)](https://github.com/containers/image/blob/main/docs/containers-registries.conf.5.md)** +**[podman(1)](podman.1.md)**, **[podman-logout(1)](podman-logout.1.md)**, **[containers-auth.json(5)](https://github.com/containers/image/blob/main/docs/containers-auth.json.5.md)**, **[containers-certs.d(5)](https://github.com/containers/image/blob/main/docs/containers-certs.d.5.md)**, **[containers-registries.conf(5)](https://github.com/containers/image/blob/main/docs/containers-registries.conf.5.md)**, **[podman-secret(1)](podman-secret.1.md)**, **[podman-secret-create(1)](podman-secret-create.1.md)** ## HISTORY August 2017, Originally compiled by Urvashi Mohnani diff --git a/docs/source/markdown/podman-secret-create.1.md b/docs/source/markdown/podman-secret-create.1.md index 428f7cc174..4ef88992cd 100644 --- a/docs/source/markdown/podman-secret-create.1.md +++ b/docs/source/markdown/podman-secret-create.1.md @@ -18,6 +18,8 @@ TLS certificates and keys, SSH keys or other important generic strings or binary Secrets are not committed to an image with `podman commit`, and does not get committed in the archive created by a `podman export` command. +Secrets can also be used to store passwords for `podman login` to authenticate against container registries. + ## OPTIONS #### **--driver**, **-d**=*driver* @@ -55,7 +57,7 @@ $ printf | podman secret create my_secret - ``` ## SEE ALSO -**[podman(1)](podman.1.md)**, **[podman-secret(1)](podman-secret.1.md)** +**[podman(1)](podman.1.md)**, **[podman-secret(1)](podman-secret.1.md)**, **[podman-login(1)](podman-login.1.md)** ## HISTORY January 2021, Originally compiled by Ashley Cui diff --git a/test/system/150-login.bats b/test/system/150-login.bats index c6d6501454..a0342b0f6d 100644 --- a/test/system/150-login.bats +++ b/test/system/150-login.bats @@ -241,6 +241,49 @@ function _test_skopeo_credential_sharing() { rm -f $authfile } +@test "podman login -secret test" { + secret=$(random_string 10) + echo -n ${PODMAN_LOGIN_PASS} > $PODMAN_TMPDIR/secret.file + run_podman secret create $secret $PODMAN_TMPDIR/secret.file + secretID=${output} + run_podman login --tls-verify=false \ + --username ${PODMAN_LOGIN_USER} \ + --secret ${secretID} \ + localhost:${PODMAN_LOGIN_REGISTRY_PORT} + is "$output" "Login Succeeded!" "output from podman login" + # Now log out + run_podman logout localhost:${PODMAN_LOGIN_REGISTRY_PORT} + is "$output" "Removed login credentials for localhost:${PODMAN_LOGIN_REGISTRY_PORT}" \ + "output from podman logout" + run_podman secret rm $secret + + # test using secret id as --username + run_podman secret create ${PODMAN_LOGIN_USER} $PODMAN_TMPDIR/secret.file + run_podman login --tls-verify=false \ + --secret ${PODMAN_LOGIN_USER} \ + localhost:${PODMAN_LOGIN_REGISTRY_PORT} + is "$output" "Login Succeeded!" "output from podman login" + # Now log out + run_podman logout localhost:${PODMAN_LOGIN_REGISTRY_PORT} + is "$output" "Removed login credentials for localhost:${PODMAN_LOGIN_REGISTRY_PORT}" \ + "output from podman logout" + run_podman secret rm ${PODMAN_LOGIN_USER} + + bogus_secret=$(random_string 10) + echo -n ${bogus_secret} > $PODMAN_TMPDIR/secret.file + run_podman secret create $secret $PODMAN_TMPDIR/secret.file + secretID=${output} + run_podman 125 login --tls-verify=false \ + --username ${PODMAN_LOGIN_USER} \ + --secret ${secretID} \ + localhost:${PODMAN_LOGIN_REGISTRY_PORT} + + is "$output" "Error: logging into \"localhost:${PODMAN_LOGIN_REGISTRY_PORT}\": invalid username/password" "output from failed podman login" + + run_podman secret rm $secret + +} + # END cooperation with skopeo # END actual tests ###############################################################################