Automating docker pull from a private hub registry using pass as credential helper

The context:

I run a private docker hub registry. It is accessed remotely and non-interactively by different client hosts. Up until recently, everything was fine: I could login/pull/push/logout from client hosts non-interactively.

Then docker evolved and required a GPG private key to access the private hub. First, I discovered that it was necessary to export the same private key on all the client and server hosts. I am able now to perform docker login non interactively from any client.

The situation arises when trying to perform docker pull (or push) as it asks for the passphrase of the GPG private key using (in my case) the gpg-agent. docker pull has no parameter to enter this passphrase non interactively.

The tentative workaround:

I seems it’s not possible to seed the gpg-agent non interactively before running the docker pull which would consequently not ask for the passphrase.

I tried this mock command, but I still need to enter the passphrase afterwards when trying docker pull:

cat "$password_file" | gpg --batch --yes --status-fd --with-colons --passphrase-fd 0 --pinentry-mode loopback --symmetric --cipher-algo AES256 filename

with ~/.gnupg/gpg-agent.conf

pinentry-program /usr/bin/pinentry-curses

My proposal: --gpg-passphrase

So, in order to be able to perform docker pull/push non-interactively, we need to pass the GPG private key passphrase to docker with --gpg-passphrase .
Then docker would be able to pass that passphrase for instance to gpg-agent to be able to unlock and use the private key.

The only viable workaround right now is to remove the password of that specific GPG private key which of course lowers the security posture.

If any new feature is implemented, I doubt there would be a --gpg-passphrase parameter for docker pull, because how the client gets the necessary password depends on the credential helper. There is no required GPG key and copying GPG private keys to multiple machines doesn’t seem to be a good idea. At least copying private keys in general is not a good practice unless it is on a portable device.

The “pass” credential helper requires a GPG key. because “pass” requires a GPG key. Whenever the credential is required, the credential helper is called and the docker pull command or any other doesn’t have to know what that credential helper requires.

I used pass a few times in the past on servers, but I think never non-interactively. I know you have been fighting with this and similar issues for a while. Can I ask where did you see recommending “pass” in a non-interactive pipeline, especially with passphrase?

Or where you saw that GPG key is required for non-interactivbe logins? Normally I would just pass the password to the docker login command in the pipeline to the standard input. If you are using pass with a passphrase, you still need to pass the paspshrase, so I don’t see the benefit. What is important is not using the same credentials that you would use interactively, but a service account or PErsonal Access Tokens as it is called in Docker Hub.

https://docs.docker.com/security/access-tokens/.

If you still want to recommend a feature that can improve docker login experience, please, open a ticket in the roadmap

We can only discuss feature recommendations here to help making it better, but there is no guarantee that the developers will read it here on the forum.

I couldn’t agree more, but that’s the only way to make it work in my context.

It’s not like there are many choices on Linux:

  1. osxkeychain: Provides a helper to use the OS X keychain as credentials store.
  2. secretservice: Provides a helper to use the D-Bus secret service as credentials store.
  3. wincred: Provides a helper to use Windows credentials manager as store.
  4. pass: Provides a helper to use pass as credentials store.

Only option 2 and 4 are available. Is secretservice more suited to this use case?

You clearly haven’t used pass recently; you need to perform the following to pull an image:

echo "$hub_password" | docker login --username $hub_user --password-stdin ${hub_fqdn}

docker pull ${hub_fqdn}/image:${version}

The gpg private key passphrase is required during the docker pull.

Yes, it is true :slight_smile: Last time probably only on Linux for Docker Desktop, but I have no Linux Desktop either currently.

You were right to catch I did not rmember that pass required a passphrase, but my main point I wanted to share is that I would not use “pass” in a non-interactive environment. So not even an alternative.

Last time when I used GPG besides Docker Desktop, it was for Ansible secrets before I switched to SOPS (Secret Operations) with “age” keys. In any case, when I am in a non-interactive environment, in a pipeline, I would use a method that either only requires passing a personal access token in an environment variable temporarily with restricted access, or would do the same with a temporarily mounted file from memory if possible.

I haven’t used a lot of pipelines recently, but I don’t remember any where a passphrase was required for anything.

not sure. I haven’t used that either. In fact that was new to me when I looked at it today.

Except it’s the only solution here. Apparently, according to some users online, secretservice requires a GUI.

Thx, it gave me another idea and I finally found the solution :slight_smile:

right before docker pull/push:

export PASSWORD_STORE_GPG_OPTS="--batch --status-fd --with-colons --passphrase-file filename --pinentry-mode loopback"

and cleared once it’s done.

export PASSWORD_STORE_GPG_OPTS=""

Tested and approved!

I would like to understand why. Do you have any reference or just that this is what you experienced? Once you have the credential store configured for the client towards the registry (globally or to a specific registry) Docker will use it. So if the machine is also a deskotp machine where you work interactively and want to or have to use pass when logging in to Docker Hub, then I can understand it.

Can you help me understand it so I don’t misinform other users if there is something I don’t know about?

Based on the officially supported docker-credential-helpers

No it’s not; the context is automated headless Linux servers which need to be hub registry clients for some of them.
I don’t understand what you don’t understand.
pass is the only solution which works in this context out of the 4 already listed.
Maybe there are other docker-credential-helpers which are not listed in the link above which do a better job in this context while being as simple as pass or more complex but offering more features. Well I like simplicity and there is no need for more features here.

I see where the misunderstanding is. You assume I want to say that you should use another credential helper, not pass. If I wanted to say that, I would have recommended which one you should use.

I’m saying I would not use a credential helper at all. And I was asking for a reference/link to a recommendation where credential helper is recommended for docker login in a non-interactive environment. That’s all.

Whenever I used CI/CD pipelines, credentials were passed to the standard input of docker login unless there was a specific module for authentication. Just an example

https://circleci.com/docs/guides/execution-managed/private-images/#machine-executor-with-docker-cli

another example

https://docs.travis-ci.com/user/docker/#push-a-docker-image-to-a-registry

In these cases the environments are usually destroyed after the pipeline finished, but I could manually delete the file or log out at the end.

I can accept that a credential helper is still required in some cases, and I also accept if you have a specific goal even if it was not specifically recommended anywhere. That is totally fine. I was just curious if you knew something I didn’t.

This one?

But this is not official. And if you already solved the problem with pass, you might not want to change it to this one.