How to use docker-credential-pass to login to a private registry?

Viewed 9125

Docker by default saves passwords unencrypted on disk, encoded in base64. I want to securely store a login password using docker-credentials-pass keystore plugin to log in to my private registry.

https://github.com/docker/docker-credential-helpers/

I am stucked at this issue: https://github.com/docker/docker-credential-helpers/issues/102

I've tried everything the users comment and I couldn't find any documentation for docker and pass. I google some tutorials as well without success. I restarted docker multiple times when trying and it just doesn't work. I would appreciate some help if someone knows how to set it up.

3 Answers

Don't know if it's still relevant to you but this worked for us (rh7 system):

Generate a new gpg2 key with gpg2 --gen-key and select all the default answers (apart from name, mail and passphrase). The output you get should contain a row that looks something like this:

pub 2048R/A154BD21 2019-09-12

Take the part after the / and init your pass with pass init <after-slash-part>, so in this example pass init A154BD21.

Add the line "credsStore":"pass" to your ~/.docker/config.json so that it looks something like

{
  "credsStore":"pass"
}

Make sure that the location of your docker-credential-pass file is in your $PATH environment variable.

Now try logging in. If it's not working, please describe a bit more in detail what you do and if you get any error messages, etc.

I went with a bash script like this that automates much of the process.

#!/bin/sh

# Sets up a docker credential helper so docker login credentials are not stored encoded in base64 plain text.
# Uses the pass secret service as the credentials store.
# If previously logged in w/o cred helper, docker logout <registry> under each user or remove ~/.docker/config.json.

# Tested on Ubuntu 18.04.5 LTS.

if ! [ $(id -u) = 0 ]; then
   echo "This script must be run as root"
   exit 1
fi

echo "Installing dependencies"
apt update && apt-get -y install gnupg2 pass rng-tools jq

# Check for later releases at https://github.com/docker/docker-credential-helpers/releases
version="v0.6.3"
archive="docker-credential-pass-$version-amd64.tar.gz"
url="https://github.com/docker/docker-credential-helpers/releases/download/$version/$archive"

# Download cred helper, unpack, make executable, and move it where Docker will find it.
wget $url \
    && tar -xf $archive \
    && chmod +x docker-credential-pass \
    && mv -f docker-credential-pass /usr/local/bin/

# Done with the archive
rm -f $archive

config_path=~/.docker
config_filename=$config_path/config.json

# Could assume config.json isn't there or overwrite regardless and not use jq (or sed etc.)
# echo '{ "credsStore": "pass" }' > $config_filename

if [ ! -f $config_filename ]
then
    if [ ! -d $config_path ]
    then
        mkdir -p $config_path
    fi

    # Create default docker config file if it doesn't exist (never logged in etc.). Empty is fine currently.
    cat > $config_filename <<EOL
{
}
EOL
    echo "$config_filename created with defaults"
else
    echo "$config_filename already exists"
fi

# Whether config is new or existing, read into variable for easier file redirection (cat > truncate timing)
config_json=`cat $config_filename`

if [ -z "$config_json" ]; then
    # Empty file will prevent jq from working
    $config_json="{}"
fi

# Update Docker config to set the credential store. Used sed before but messy / edge cases.
echo "$config_json" | jq --arg credsStore pass '. + {credsStore: $credsStore}' > $config_filename

# Output / verify contents
echo "$config_filename:"
cat $config_filename | jq

# Help with entropy to prevent gpg2 full key generation hang
# Feeds data from a random number generator to the kernel's random number entropy pool
rngd -r /dev/urandom

# To cleanup extras from multiple runs: gpg --delete-secret-key <key-id>; gpg --delete-key <key-id>
echo "Generating GPG key, accept defaults but consider key size to 2048, supply user info"
gpg2 --full-generate-key

echo "Adjusting permissions"
sudo chown -R $USER:$USER ~/.gnupg
sudo find ~/.gnupg -type d -exec chmod 700 {} \;
sudo find ~/.gnupg -type f -exec chmod 600 {} \;

# List keys
gpg2 -k

key=$(gpg2 --list-secret-keys | grep uid -B 1 | head -n 1 | sed 's/^ *//g')

echo "Initializing pass with key $key"
pass init $key

echo "Enter a password to add to the secure store"
pass insert docker-credential-helpers/docker-pass-initialized-check

# Just a verification. Don't need to show actual password, mask it.
echo "Password verification:"
pass show docker-credential-helpers/docker-pass-initialized-check | sed -e 's/\(.\)/\*/g'

echo "Docker credential password list (empty initially):"
docker-credential-pass list

echo "Done. Ready to test. Run: sudo docker login <registry>"
echo "Afterwards run: sudo docker-credential-pass list; sudo cat ~/.docker/config.json"

The docker-credentials-pass helper doesn't setup a pass-based password store - it expects an already functional password store, so I would advise you to first set that up before incorporating the credentials helper

Pass is a password manager that is essentially a bash script that automates encrypting/decrypting secrets using GnuPG. That means a working pass setup requires each of those tools to function: pass and gpg2. Optionally the password store can be a git repository, in which case you'll need git installed as well.

After downloading pass and setting up GnuPG, initialize the password store with your gpg id. From the docs (assuming "ZX2C4 Password Storage Key" is your gpg id):

$ pass init "ZX2C4 Password Storage Key"
mkdir: created directory ‘/home/zx2c4/.password-store’
Password store initialized for ZX2C4 Password Storage Key.

You should then be able to add passwords using the pass command, and if that works then enable the docker-credentials-pass helper as you've already done.

https://www.passwordstore.org/

Related