-
Notifications
You must be signed in to change notification settings - Fork 2k
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 support for docker-credential-helpers #2651
Conversation
client/driver/docker.go
Outdated
@@ -1495,3 +1538,13 @@ func authOptionFrom(file, repo string) (*docker.AuthConfiguration, error) { | |||
|
|||
return apiAuthConfig, 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.
Hey it would be great if we could actually reuse the auth config file. That file supports setting credential helpers per repo and we parse it right above: https://github.com/hashicorp/nomad/pull/2651/files#diff-a6757d41ad7cd7f37f0f0243e3575307R1524.
I would suggest we use that to determine if we should use a credential helper.
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.
credHelpers
is indeed a nice solution. I will see if we can use it somehow
client/driver/docker.go
Outdated
cmd.Stdin = strings.NewReader(repoName) | ||
|
||
// For helper to be able to read credentials from vault | ||
cmd.Env = append(os.Environ(), fmt.Sprintf("VAULT_TOKEN=%s", clientConfig.VaultConfig.Token)) |
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 would like to see an operator option to allow passing the vault token to credential helpers. I would probably treat it as a white list of allowed helpers. You generally do not want to give that out any more than you have to! Isn't security fun :)
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 considered this when writing the code. I get a feeling this deserve something bigger than a small helper-detail in the docker driver though. There must be more places where external processes/plugins are called for as a part of the task-setup, needing access to different nomad-config, for example the vault-address used, the consul-connection details etc?
From a security-standpoint however; the helper will run in the same security-context as the nomad process. This means whomever control the helper can still read the token from the nomad-config?
If it simplifies the approval of this PR, we could skip the custom env altogether, postpone it for something more thought-through?
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 your point! Once we have generic plugin support, a overall whitelist for the things Nomad fork/execs to delegate work would probably make sense. I can see the Vault use case being nice for people writing custom credential-helpers. However I would like even the first cut to allow operators to control which ones have access, so given it expands the PR I would be okay if you want to skip that functionality for the first PR!
Great work so far! This is going to be a great addition! |
There. I kept the docker.auth.helpers variable (for simple use-cases it avoid an extra file entirely) and added handling of auth, credHelpers and credsStore (in priority order) from the config file. And removed VAULT_TOKEN, let's take that in a separate patch later |
333d09a
to
93127f4
Compare
Hmm. Not sure if I broke test (it does not seem so?) or if this is simply due to master being broken? |
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 super sweet work @rawler! Sorry for the delayed review! Had HashiDays NYC and playing catch up still!
client/driver/docker.go
Outdated
|
||
dockerAuthConfig := registry.ResolveAuthConfig(cfile.AuthConfigs, repoInfo.Index) | ||
if response["Username"] != "" || response["Secret"] != "" { |
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.
Should this be an and?
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.
Not my intention, no? If either of the two relevant fields is filled-in, we consider it an authentication.
For example, blank password is a completely possible scenario and should not be ignored. Likewise, it's conceivable for a private repo to auth using a blank username and I.E. api-key in Secret.
information for a private registry, from either (in order) `auths`, | ||
`credHelpers` or `credsStore`. | ||
|
||
* `docker.auth.helper` <a id="auth_helper"></a>- Allows an operator to specify |
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 would prefer if we remove this. Sometimes optionality actually just leads to confusion! I think it is better to have one well documented, canonical way to do 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.
I tend to agree. The rationale I see for it here, is that for simple scenarios (like in my organization) it's very likely to only have a single helper required. For those cases, a docker-config really isn't needed. Another possible such scenario is to have all secrets stored in Vault. Hashicorp might even want to have an official docker-helper for that.
With this option, moving nomad docker-auth from clear-text docker-config, to protected in vault, is simply a matter of
- one config-line in the nomad agent-config
- a VAULT_TOKEN in env
- a script installed to $PATH
Without this option, an entire extra config-file is required. (Likely needlessly, since the nomad agent host should preferably not be shared for other purposes, I guess?)
[docker.auth.config](#auth_file) value on the client. | ||
you will need to specify credentials in your job via: | ||
|
||
* the `auth` option |
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 auth
option in the driver's config.
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.
"task-config" more precisely, right?
|
||
* the `auth` option | ||
|
||
* by storing credentials or `credHelpers` in a file and setting the |
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.
Would you be willing to inline an example of what that file would look like with cred helpers set and plain base64 credentials set for a separate repo?
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.
Sure thing. One example says more than 1000 words.
client/driver/docker.go
Outdated
} | ||
|
||
d.emitEvent("Downloading image %s:%s", repo, tag) | ||
coordinator, callerID := d.getDockerCoordinator(client) | ||
return coordinator.PullImage(driverConfig.ImageName, authOptions, callerID) | ||
} | ||
|
||
type authBackend func(string) (*docker.AuthConfiguration, error) |
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.
Can we get comments on all the functions/types
So, I think all the questions are now addressed, except possibly the existence of "docker.auth.helper". If you still want it dropped, it's quickly done |
@rawler Thanks for the great work and thoughtful reply! Lets keep the separate helper option. Would you mind fixing this and then we can merge: https://travis-ci.org/hashicorp/nomad/builds/237122683#L830 |
"credHelpers": { | ||
"<XYZ>.dkr.ecr.<region>.amazonaws.com": "vault-ecr-login" | ||
}, | ||
"credsStore": "vault" |
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.
Could you use a publicly available credential store (maybe "secretservice")
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.
Sure thing, but ideally, maybe we should even (after this PR) write a small example-script to pull credentials from vault? I suspect more people would find that useful, since secretservice is more oriented to desktop, I believe.
"internal.repo": { "auth": "`echo -n '<username>:<password>' | base64 -w0`" } | ||
}, | ||
"credHelpers": { | ||
"<XYZ>.dkr.ecr.<region>.amazonaws.com": "vault-ecr-login" |
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.
As an example, here is an (untested, I don't really have a good setup for it) script for pulling secrets from vault: https://pastebin.com/vyUHGgbX |
Thanks @rawler |
@rawler could you share your ecr creds script? https://github.com/awslabs/amazon-ecr-credential-helper is not compatible with docker.auth.helper, because it (correctly?) returns a non zero exist code for non-ecr repos. the official docker client seems to just continue without creds |
@aep oh, sorry I did not notice this behavior when building the patch. Do you happen to know if the behavior is documented somewhere? Is there a precedent set from git-credential-helpers? Anyways, sure I can share the script we're using for ECR. Not though that this is probably really interesting for us, who is using AWS and ECR in combination with Vault, whereas Vault is responsible for generating short-lived AWS-credentials, to convert into ECR-credentials However, with some simple hacking it should be doable to bypass the Vault-parts, and get ECR-creds from simple https://gist.github.com/rawler/03ab8641f280d16505d0d334da8bc312 |
this amends the behaviour introduced with hashicorp#2651 and allows pulling public images when docker.auth.helper is set
@rawler i'm not sure that particular behaviour is documented. seems a bit subtle. let me know if you're ok with #2744 btw i found https://godoc.org/github.com/docker/docker-credential-helpers/client |
I'm going to lock this pull request because it has been closed for 120 days ⏳. This helps our maintainers find and focus on the active contributions. |
Solves: #2334
The exact ENV for the docker-helper to run in could be discussed, but at the very least I think it needs the vault-token of the runner.
For our specific use-case, we have a self-contained python-script that from vaults pulls out a restricted AWS-key and ECR-token. A simple solution for running containers from ECR.