Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement credsStore in credential config files #1179

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

matejvasek
Copy link

Config file on macOS may contain "credsStore" property indicating what cred store should be used.
This patch checks for its presence and uses it if appropriate.

Signed-off-by: Matej Vasek [email protected]

@mtrmac
Copy link
Collaborator

mtrmac commented Mar 15, 2021

(Drive-by comment, by no means a review:)

@matejvasek
Copy link
Author

@QiWang19 does #971 fixes this?

@matejvasek
Copy link
Author

@vrothberg do you know whether #971 fixes this?

@QiWang19
Copy link
Collaborator

@matejvasek Current #971 plans to embed credential helper configurations into registries.conf. Not the same syntax as credsStore.
There were PRs for this credsStore, but didn't get a chance to be merged. #656

@vrothberg
Copy link
Member

Would #1193 help?

@lkingland
Copy link

This seems to be working for me.

Given the following ~/.docker/config.json

{
  "HttpHeaders" : {
    "User-Agent" : "Docker-Client/19.03.12 (darwin)"
  },
  "credsStore" : "desktop",
  "auths" : {
    "https://index.docker.io/v1/" : {

    }
  },
  "experimental" : "enabled",
  "stackOrchestrator" : "swarm"
}

The following program:

package main

import (
        "fmt"
        "github.com/containers/image/v5/pkg/docker/config"
        "log"
)

func main() {
        dauth, err := config.GetAllCredentials(nil)
        if err != nil {
                log.Fatal(err)
        }
        fmt.Printf("dauths: %+v\n", dauth)
}

accesses credentials from the credsStore:

> go run main.go
dauths: map[index.docker.io:{Username:[REDACTED] Password:[REDACTED] IdentityToken:}]

@lkingland
Copy link

lkingland commented Apr 1, 2021

Would #1193 help?

Unfortunately, when trying with #1193, the Username and Password output from the aforementioned program are blank

@rhuss
Copy link

rhuss commented Jun 14, 2021

I have a similar issue, in that config.GetAllCredentials(nil) does not find my real passwords, but returns bogus (possibly stale) passwords. Even when I do a docker logout the passwords are still present.

I'm a bit puzzled as I checked all credentials helpers available (docker-credential-desktop, docker-credential-ecr-login, docker-credential-osxkeychain) and none has the bogus password that containers/images find.

My config.json looks the same:

{
	"auths": {
		"index.docker.io": {},
		"public.ecr.aws": {},
		"quay.io": {}
	},
	"credsStore": "desktop",
	"experimental": "enabled",
	"stackOrchestrator": "swarm"
}%

Any help is highly appreciated.

@matejvasek
Copy link
Author

@vrothberg ^^^ any idea what could be issue for Roland?

@mtrmac
Copy link
Collaborator

mtrmac commented Jun 14, 2021

@rhuss this seems to have nothing to do with this proposed PR, please file a separate issue.

@rhuss
Copy link

rhuss commented Jun 15, 2021

@rhuss this seems to have nothing to do with this proposed PR, please file a separate issue.

I added my comments here, as I think that is the issue for implementing support for credential helpers, right ? --> #111 (comment)

@mtrmac
Copy link
Collaborator

mtrmac commented Jun 18, 2021

Would #1193 help?

Unfortunately, when trying with #1193, the Username and Password output from the aforementioned program are blank

#1193 requires the configuration to be present in a registries.conf option named credential-helpers, not in credsStore.

@rhatdan
Copy link
Member

rhatdan commented Jun 24, 2021

@matejvasek Are you still working on this?

@matejvasek
Copy link
Author

@rhatdan for now I made a workaround in our SW. I could get back to this if there is no one else willing to work on this. For now my priority is to fix containers/podman#10776.

Employ "CredsStore" field of standard docker config.

Signed-off-by: Matej Vasek <[email protected]>
The test was reading "~/.docker/config" which can cause test failure.

Signed-off-by: Matej Vasek <[email protected]>
Signed-off-by: Matej Vasek <[email protected]>
@matejvasek
Copy link
Author

@mtrmac @vrothberg PTAL

Signed-off-by: Matej Vasek <[email protected]>
@mtrmac mtrmac changed the title fix: use credsStore from config file on macOS fix: use credsStore from config file Aug 23, 2021
Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.

The implementation looks reasonable reading each operation in isolation, but does this actually work end-to-end?

  • The user sets $XDG_RUNTIME_DIR/containers/auth.json to contain a credsStore; that works fine for a while, but is wiped on a reboot. Not good.
  • The user sets ~/.docker/config.json to contain a credsStore; that allows reading fine, and survives reboot, but the first modification (SetCredentials/RemoveAuthentication only reads auth.json) only reads …/auth.json, doesn’t see any credsStore entry in there, and happily writes credentials to …/auth.json. That’s not good either.

(Yes, this was already broken with credHelpers; in that case it’s more plausible to argue that the read-only path is good enough because the helper might point at a cloud-specific helper and credentials for that registry are never updated via this package. That’s not the case if this is intended to handle all credentials.

I realize that this is not an issue on macOS, where we don’t have $XDG_RUNTIME_DIR and the configuration is persistent; having a macOS-only feature is somewhat a stretch, having it available and badly broken on Linux is not really acceptable.

[That’s why we have ended up implementing the registries.conf helper configuration.])

@vrothberg PTAL independently, this is tricky and I could well be missing something.

@@ -156,6 +160,13 @@ func GetAllCredentials(sys *types.SystemContext) (map[string]types.DockerAuthCon
for registry := range auths.AuthConfigs {
addRegistry(registry)
}
if auths.CredsStore != "" {
if creds, err := listAuthsFromCredHelper(auths.CredsStore); err == nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it OK to completely ignore errors here? I’d expect this to work similarly to a helper returned by CredentialHelpers.

@@ -440,6 +451,14 @@ func RemoveAllAuthentication(sys *types.SystemContext) error {
}
auths.CredHelpers = make(map[string]string)
auths.AuthConfigs = make(map[string]dockerAuthConfig)
if auths.CredsStore != "" {
if creds, err := listAuthsFromCredHelper(auths.CredsStore); err == nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it OK to completely ignore errors here? I’d expect this to work similarly to a helper returned by CredentialHelpers.

if auths.CredsStore != "" {
if creds, err := listAuthsFromCredHelper(auths.CredsStore); err == nil {
for registry := range creds {
_ = deleteAuthFromCredHelper(auths.CredsStore, registry)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

@@ -646,6 +665,12 @@ func findAuthentication(ref reference.Named, registry, path string, legacyFormat
return getAuthFromCredHelper(ch, registry)
}

if auths.CredsStore != "" {
if cred, err := getAuthFromCredHelper(auths.CredsStore, registry); err == nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it OK to completely ignore errors here?

@@ -559,6 +559,7 @@ func TestGetAuthFailsOnBadInput(t *testing.T) {
}

func TestGetAllCredentials(t *testing.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests for the other modified functions as well.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests for the other modified functions as well.

Are those functions properly tested right now anyway? I believe they are not tested with respect to helpers right now.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe they are not tested with respect to helpers right now.

For instance the mock helper does noting for the store operation so you can really assert it written anything when calling the SetCredentials function.

Comment on lines 649 to 650
SystemRegistriesConfPath: "",
SystemRegistriesConfDirPath: "",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is (sadly?) the same as leaving the values unset, in particular it doesn’t disable any ordinary users’ configuration. So if this data matters, it should point at real files.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mtrmac Do I need to set it? I think that for this test AuthFilePath is enough, isn't it?

os.Setenv("HOME", dir)
return func() {
if oldHomeExists {
os.Setenv("HOME", oldHome)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t immediately see that this is necessary (the existing GetAllCredentials test got by without), and anyway, AFAIK it doesn’t work; containers/storage/pkg/homedir.Get() caches the value throughout its lifetime, so a single-test override is either completely ineffective, or is effective only if that test happens to run first.

So, to make some of the code testable, we had to introduce getCredentialsWithHomeDir and I suspect something similar would be necessary in other cases that tried to override HOME.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mtrmac without this the test is failing on my machine because the GetAllCredentials function also returns credentials from my docker config.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I you don't have $HOME/.docker/config.json on your machine it probably works. But for me it's failing.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

caches the value throughout its lifetime, so a single-test override is either completely ineffective, or is effective only if that test happens to run first.

I don't what to do about this.

Copy link
Author

@matejvasek matejvasek Aug 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test is touching not only testing config files but also actual user config files, that's not good.

@@ -440,6 +451,14 @@ func RemoveAllAuthentication(sys *types.SystemContext) error {
}
auths.CredHelpers = make(map[string]string)
auths.AuthConfigs = make(map[string]dockerAuthConfig)
if auths.CredsStore != "" {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RemoveAuthentication also needs adding the support.

@@ -85,6 +86,9 @@ func SetCredentials(sys *types.SystemContext, key, username, password string) (s
}
return false, setAuthToCredHelper(ch, key, username, password)
}
if auths.CredsStore != "" {
return false, setAuthToCredHelper(auths.CredsStore, key, username, password)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep the order of handling CredHelpers/CredsStore/AuthConfigs consistent throughout the package, to make it easier to check that all operations handle the same data. (I guess in the order above, unless there’s a specific reason to do something else.)

@mtrmac mtrmac changed the title fix: use credsStore from config file Implement credsStore in credential config files Aug 23, 2021
Copy link
Member

@vrothberg vrothberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really just found a mini nit in addition to @mtrmac's comments.

@@ -59,7 +60,7 @@ var (
// Returns a human-redable description of the location that was updated.
// NOTE: The return value is only intended to be read by humans; its form is not an API,
// it may change (or new forms can be added) any time.
func SetCredentials(sys *types.SystemContext, key, username, password string) (string, error) {
func SetCredentials(sys *types.SystemContext, key, username, password string) (string, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: not sure why the extra space is needed.

@matejvasek
Copy link
Author

I realize that this is not an issue on macOS, where we don’t have $XDG_RUNTIME_DIR and the configuration is persistent; having a macOS-only feature is somewhat a stretch, having it available and badly broken on Linux is not really acceptable.

@mtrmac actually this is not just macOS specific, you can use credStore also on Linux (and Windows).

@matejvasek
Copy link
Author

The user sets $XDG_RUNTIME_DIR/containers/auth.json to contain a credsStore; that works fine for a while, but is wiped on a reboot. Not good.

@mtrmac so user has to login after each reboot with podman?

@matejvasek
Copy link
Author

The user sets $XDG_RUNTIME_DIR/containers/auth.json to contain a credsStore; that works fine for a while, but is wiped on a reboot. Not good.

Doesn't this also apply to already used credHelpers field?

@matejvasek
Copy link
Author

matejvasek commented Aug 24, 2021

Aren't most objections against credsStore also valid to already implemented credHelpers?

@matejvasek
Copy link
Author

What about if we implemented only read only part?

The function didn't work as expected, it only worked if the test using
it was run as the first test since HOME envvar is cached somewhere.

Signed-off-by: Matej Vasek <[email protected]>
Signed-off-by: Matej Vasek <[email protected]>
@matejvasek
Copy link
Author

@mtrmac What about if we implemented only read only part?

@matejvasek
Copy link
Author

@mtrmac why is containers/auth.json not persistent?

Signed-off-by: Matej Vasek <[email protected]>
Signed-off-by: Matej Vasek <[email protected]>
@mtrmac mtrmac added the kind/feature A request for, or a PR adding, new functionality label Dec 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/feature A request for, or a PR adding, new functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants