-
Notifications
You must be signed in to change notification settings - Fork 395
Add authentication package to containers/image/pkg #333
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
Conversation
|
Why not just include this with the kpod login pull request? |
|
@rhatdan it is with the kpod login pull request cri-o/cri-o#810. |
|
A one-minute look:
|
7f7067c to
b4cf5ec
Compare
|
whoops, my bad. I messed up while applying the patch - I have fixed that. |
pkg/authentication/authentication.go
Outdated
| "os" | ||
| "strings" | ||
|
|
||
| "github.com/errors" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
github.com/pkg/errors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
pkg/authentication/authentication.go
Outdated
| } | ||
| dir := os.Getenv("HOME") + "/.config/containers" | ||
| if _, err := os.Stat(dir); os.IsNotExist(err) { | ||
| if err = os.Mkdir(dir, os.ModePerm); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably not the right set of permissions to apply to the directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0600, is probably what you want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
pkg/authentication/authentication.go
Outdated
| return "", errors.Wrapf(err, "error creating directory %q", dir) | ||
| } | ||
| } | ||
| return dir + "/auth.json", nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer using path/filepath.Join() to build these file paths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using filepath.Join.
b4cf5ec to
f594141
Compare
|
This package is docker specific, I'd put it under https://github.com/containers/image/blob/master/docker/wwwauthenticate.go ...and the like. I would love this to be abstract though. One way would be to support our own credentials file, but we should have a mechanism to read from docker creds also (that's what most people expect I guess). |
|
@runcom I did not realize this would end up being docker specific. You want me to scratch what I did, and use functions from the Docker package instead? |
f594141 to
177d47e
Compare
|
Is there perhaps a previous conversation were I can catch up about what this is intended to do?
It’s difficult to form an opinion about an implementation when I don’t know what it should be implementing :) |
As a random example, consider today’s #334 . Is the new config file expected to support a similar mechanism? Now? Sometime in the future? Never? Exactly the same mechanism, or a somewhat different one? Or is all of this, perhaps, intended to support exactly the same config file, only supporting a different file name as an alternative? |
|
@mtrmac I forwarded an email chain to you about a conversation we had about this. I believe we want the authentication package to aid in the kpod login command, where the user can log into any container registry and their creds will be stored in I know for I thought it would be generalized and not docker specific, but now I am not so sure. Maybe @rhatdan can explain further. |
Yeah. The docker/distribution-specificity of the code is fairly simple to deal with — we could separate the "read/write data" functionality from the "check whether the user-provided password is valid” functionality, perhaps partially, perhaps entirely and have only The docker/distribution-specificity of the format is worse: if we want the format to be generic, we can’t have an universal But if designing such a new generic thing were out of scope and this were about the file name, I’d much prefer sharing a single implementation between |
|
I would like to keep this simple for now, if we want to add more complex authentication in the future, I am all for it. (Kerberos?) But for now, I am looking for the equiv of docker login so that kpod and buildah can cache the login information. |
Then we could just keep using |
|
I would prefer the default to not be docker/config.json, but ~/config/containers/config.json. But have a fail over to ~/.docker/config.json. Our tools should just read it not write it. Bottom line I would like us to take advantage of |
|
OK, so how about this:
WDY’all think? |
pkg/authentication/authentication.go
Outdated
| if server == "docker.io" { | ||
| return "https://registry-1.docker.io" | ||
| } | ||
| return server |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is using this? There is no user in this repo.
It seems weird to return a URL-like string in one case and an undecorated host-name in the other; and it also feels like the kind of internal implementation detail of the protocol that might be better to hide inside a package instead of exposing it is a very public API point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I agree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mtrmac where would you suggest I put this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there is no default registry, and docker.io maps to registry-1.docker.io, I thought it would be good to add this in the case the user types kpod login docker.io. Maybe containers/image/docker/docker_client.go does this somewhere, not sure but I will look into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I would figure this happens somewhere else in the stack or in DNS. Hard coding this could cause us issues if Docker inc in the future changes docker.io to pint at registry-foobar.docker.io.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I didn’t realize that both the plain-host name and URI forms are actually valid keys in auths (or at least I do have both in my ~/.docker/config.json—except that I have index.docker.io/v1/ in there, not registry-1.docker.io).
This mapping is actually hard-coded in the clients, not in DNS, sadly.
If possible, I’d prefer this to be completely hidden from external users: let them say just docker.io as if it were any example.com, and do this mapping internally in the config file parser/editor package.
|
@mtrmac I am fine with what you are defining. |
|
@mtrmac reusing the format inside the file at the moment sounds fine by me as does the rest of your proposal. It might be I'm just tired tonight, but just wanted to make sure this sequence works in your plan. A kpod/buildah command that requires authentication but no creds are provided is invoked. If that works in your mind, I'm hip. |
|
Exactly. |
Right. To be explicit, the |
177d47e to
252602d
Compare
|
skopeo test fixes in containers/skopeo#422 |
mtrmac
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for fixing the golint errors as well. (In the future, please separate such things into separate commits—but it’s not necessary to split it out now.)
pkg/docker/config/config.go
Outdated
| return ctx.AuthFilePath | ||
| } | ||
| if ctx.RootForImplicitAbsolutePaths != "" { | ||
| return ctx.RootForImplicitAbsolutePaths |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be RootForImplicitAbsolutePaths + default runtimeDir + authCfg + authCfgFileName (e.g. $root/run/$uid/containers/auth.json.
runtimeDir = the first applicable from:
$RootForImplicitAbsolutePaths/run/$uid$XDG_RUNTIME_DIR/run/$uid
auth path = $AuthFilePath if set; otherwise $runtimeDir/containers/auth.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
docker/docker_client.go
Outdated
| // | ||
| // debugging: https://github.com/containers/image/pull/211#issuecomment-273426236 and follows up | ||
| func (c *dockerClient) setupRequestAuth(req *http.Request) error { | ||
| var scope string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Non-blocking: Consider moving the scope declaration just before its first use; it’s used only in case "bearer".)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
5402dd9 to
d5a13b3
Compare
|
LGTM (assuming the skopeo failures will be dealt with somehow.) @runcom PTAL |
61a4cb4 to
fe3ab3d
Compare
|
@runcom PTAL |
docker/docker_client.go
Outdated
| // docker V1 registry. | ||
| ErrV1NotSupported = errors.New("can't talk to a V1 docker registry") | ||
| // ErrUnauthorized is returned when the status code returned is 401 | ||
| ErrUnauthorized = errors.New("unable to retrieve auth token: 401 unauthorized") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drop "401 unauthorized", that's an implementation detail we don't want to expose directly in the API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see it was this way in the past, but we should not expose the error, can you make it private? (lowercasing it)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
… This should probably say something more generic like “invalid credentials”, it is returned also on the Authorization: Basic path where no tokens are involved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see it was this way in the past, but we should not expose the error,
This should allow callers of CheckAuth to distinguish between unexpected failures (e.g. network down) and an invalid username/password.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I can leave the error exposed and just change the error message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just remembered, I am using this error in kpod login to know when a 401 is returned so that the message printed for the user is along the paths of "invalid username/password", hence making it public.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So given the places this error is used it must not contain "401 ..." cause it's HTTP related and should probably be named something like ErrUnauthorizedForCredentials (better naming is advised here but just ErrUnauthorized is misleading).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it, fixed.
| service, _ := challenge.Parameters["service"] // Will be "" if not present | ||
| scope := fmt.Sprintf("repository:%s:%s", c.scope.remoteName, c.scope.actions) | ||
| var scope string | ||
| if c.scope.remoteName != "" && c.scope.actions != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this if was added? I'll keep it how it was
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because a “log in” action (i.e. only verify that the username/password are valid) don’t really have a scope, and Docker seems to do the same thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
awesome, thx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks @mtrmac :)
pkg/docker/config/config.go
Outdated
| var ( | ||
| // ErrNotLoggedIn is returned for users not logged into a registry | ||
| // that they are trying to logout of | ||
| ErrNotLoggedIn = errors.Errorf("not logged in") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errors.New
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
fe3ab3d to
700c99d
Compare
| resp, err := newLoginClient.makeRequest(ctx, "GET", "/v2/", nil, nil) | ||
| if err != nil { | ||
| return err | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you forgot a defer resp.Body.Close()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
b4bdfdc to
eec1511
Compare
mtrmac
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works for me; @runcom please do look at the CredHelpers removal though.
| // RemoveAllAuthentication deletes all the credentials stored in auth.json | ||
| func RemoveAllAuthentication(ctx *types.SystemContext) error { | ||
| return modifyJSON(ctx, func(auths *dockerConfigFile) (bool, error) { | ||
| auths.CredHelpers = make(map[string]string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum, this is a bit surprising. Depending on how one looks at it, it either makes perfect sense or it is extremely unexpected.
I guess, why not — @runcom I just want to make sure you have noticed this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
THis is for
kpod logout --all
Basically you want to cleanup and logout of your container workflow. In most cases not really necessary since the default location is in /run/USER/UID, but it is better to be safe and not leave these credentials around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way CredHelpers work for logging in is that the user must set them up in the config file before starting the log-in process; and it seems reasonable that in a (log in; log out; log in) sequence, the credentials should be stored in the same place (i.e. that the users’ configuration should not be thrown away).
OTOH then kpod logout --all would either have to ignore the helpers-using domains entirely, or clean everything in the helper, and both can be pretty unexpected (removing items from a server-side shared keyring).
As you say, with /run being the default location, it’s likely enough that users of credential helpers will be overriding the path and knowing not to call logout --all, and this is at least conservative in not deleting too much.
(I guess I could argue that logout --all is a problematic concept in itself, but that’s not going to help, is it?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another option rather then doing this through the library would be to
rm -f $autffile
from
kpod logout --all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess do appreciate that would get rid of me with my pesky questions, but it doesn’t really avoid having to make a decision.
As I said at the very start, “I guess, why not”, all I want here is to make sure this choice has been made deliberately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wondering - how is doing rm -f $authfile any different from clearing the CredHelpers field in the authfile? At the end of the day you are still getting rid of the CredHelpers no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@umohnani8 yup, this is just a matter of whether you want it in the library or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah okay. So what is the decision? I don't see a problem with it being in the library just because to me both approaches does the same thing at the end of the day. But you guys know better :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can live with either design.
@runcom still needs to approve the PR as a whole, so it’s ultimately up to him.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@runcom PTAL
|
@runcom PTAL |
This package is used in authenticating a user for kpod login and can be used for authentication in kpod push, pull etc. Signed-off-by: umohnani8 <[email protected]>
eec1511 to
f28367e
Compare
|
@umohnani8 This seems to partially undo #351, at least reintroducing |
There have been redundant calls here since two ref.ref.Hostname() calls were added in aaedc64 (Implement lookaside storage for signatures for Docker registries, 2016-08-11, containers#52). At that point the two calls were separated by a dockerHostname check which could have been shifted by two lines to avoid the doubled function calls. But in f28367e (Add docker/config package to containers/image/pkg, 2017-08-29, containers#333) the dockerHostname check moved to a separate function entirely (newDockerClientWithDetails) while the Domain() calls remained together in newDockerClientFromRef. So now there is no longer any reason for the second call, and this commit drops it. Signed-off-by: W. Trevor King <[email protected]>
Use GetAuthentication directly, replacing: username, err := GetUserLoggedIn(sys, registry) with: username, _, err := GetAuthentication(sys, registry) This is just as convenient and removes the differences between lookup logic from the two functions (e.g. GetUserLoggedIn ignored DockerAuthConfig). GetUserLoggedIn originally landed in f28367e (Add docker/config package to containers/image/pkg, 2017-08-29, containers#333), and neither the commit message nor the pull request motivate the diversion from the GetAuthentication lookup logic. Signed-off-by: W. Trevor King <[email protected]>
Use GetAuthentication directly, replacing: username, err := GetUserLoggedIn(sys, registry) with: username, _, err := GetAuthentication(sys, registry) This is just as convenient and removes the differences between lookup logic from the two functions (e.g. GetUserLoggedIn ignored DockerAuthConfig). I've removed the function instead of deprecating at Miloslav's request [1]. GetUserLoggedIn originally landed in f28367e (Add docker/config package to containers/image/pkg, 2017-08-29, containers#333), and neither the commit message nor the pull request motivate the diversion from the GetAuthentication lookup logic. [1]: containers#597 (comment) Signed-off-by: W. Trevor King <[email protected]>
There have been redundant calls here since two ref.ref.Hostname() calls were added in aaedc64 (Implement lookaside storage for signatures for Docker registries, 2016-08-11, containers#52). At that point the two calls were separated by a dockerHostname check which could have been shifted by two lines to avoid the doubled function calls. But in f28367e (Add docker/config package to containers/image/pkg, 2017-08-29, containers#333) the dockerHostname check moved to a separate function entirely (newDockerClientWithDetails) while the Domain() calls remained together in newDockerClientFromRef. So now there is no longer any reason for the second call, and this commit drops it. Signed-off-by: W. Trevor King <[email protected]>
This package is used in authenticating a user for kpod login
and can be used for authentication in kpod push, pull etc.
Signed-off-by: umohnani8 [email protected]