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 support for docker-credential-helpers #2651

Merged
merged 2 commits into from
May 31, 2017

Conversation

rawler
Copy link

@rawler rawler commented May 17, 2017

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.

@@ -1495,3 +1538,13 @@ func authOptionFrom(file, repo string) (*docker.AuthConfiguration, error) {

return apiAuthConfig, nil
}

Copy link
Contributor

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.

Copy link
Author

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

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))
Copy link
Contributor

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 :)

Copy link
Author

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?

Copy link
Contributor

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!

@dadgar
Copy link
Contributor

dadgar commented May 17, 2017

Great work so far! This is going to be a great addition!

@rawler
Copy link
Author

rawler commented May 19, 2017

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

@rawler rawler force-pushed the feature/2334 branch 3 times, most recently from 333d09a to 93127f4 Compare May 23, 2017 09:03
@rawler
Copy link
Author

rawler commented May 24, 2017

Hmm. Not sure if I broke test (it does not seem so?) or if this is simply due to master being broken?

Copy link
Contributor

@dadgar dadgar left a 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!


dockerAuthConfig := registry.ResolveAuthConfig(cfile.AuthConfigs, repoInfo.Index)
if response["Username"] != "" || response["Secret"] != "" {
Copy link
Contributor

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?

Copy link
Author

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
Copy link
Contributor

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.

Copy link
Author

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
Copy link
Contributor

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.

Copy link
Author

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
Copy link
Contributor

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?

Copy link
Author

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.

}

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)
Copy link
Contributor

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

@rawler
Copy link
Author

rawler commented May 29, 2017

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

@dadgar
Copy link
Contributor

dadgar commented May 30, 2017

@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"
Copy link
Contributor

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")

Copy link
Author

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"
Copy link
Contributor

Choose a reason for hiding this comment

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

@rawler
Copy link
Author

rawler commented May 31, 2017

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

@dadgar dadgar merged commit 84aba1d into hashicorp:master May 31, 2017
@dadgar
Copy link
Contributor

dadgar commented May 31, 2017

Thanks @rawler

@rawler rawler deleted the feature/2334 branch June 2, 2017 07:53
@aep
Copy link
Contributor

aep commented Jun 26, 2017

@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

@rawler
Copy link
Author

rawler commented Jun 26, 2017

@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 AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment. If the ECRClient is initialized with ECRClient(region, None, None), that should be it.

https://gist.github.com/rawler/03ab8641f280d16505d0d334da8bc312

aep added a commit to aep/nomad that referenced this pull request Jun 27, 2017
this amends the behaviour introduced with hashicorp#2651
and allows pulling public images when docker.auth.helper is set
@aep
Copy link
Contributor

aep commented Jun 27, 2017

@rawler i'm not sure that particular behaviour is documented. seems a bit subtle.
thanks for sharing your script. my python isn't that great, but it's a good starting point.
We're planning to do ECR auth over vault sts.

let me know if you're ok with #2744

btw i found https://godoc.org/github.com/docker/docker-credential-helpers/client

@github-actions
Copy link

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.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 31, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants