I have a new private key that I'm bringing to a docker container as part of a bash script. After copying the private key to /root/.ssh/id_rsa I wanted to regenerate the public with:

ssh-keygen -yf /root/.ssh/id_rsa > /root/.ssh/id_rsa.pub

Unfortunately this results in the following error:

load failed

I assume this is because the private key has a passphrase which wasn't provided to ssh-keygen command but sadly I don't know how do this. I had read that setting the SSH_AUTH_SOCK environment variable would suffice but it didn't work for me ... still asks for the passphrase.

Then I ran into a small variation on the keygen command which uses the -x parameter:

ssh-keygen -yf /root/.ssh/id_rsa > /root/.ssh/id_rsa.pub -x

And to my great surprise it produces results. The right results? Not sure. In fact the results are distinctly different from the non "-x" variant (when provided the passphrase). I looked at the man file and it doesn't mention -x at all.

I'm confused. Any help would be appreciated. Looking for either:

  • a better understanding of what -x does and how to use it effectively
  • a way to pass in my private key's passphrase to ssh-keygen (and also so git will use it too)
  • You mentioned SSH_AUTH_SOCK but did you setup an ssh-agent and added your key to it? – Glueon Oct 9 '14 at 12:44
  • No. Things get a bit blurry when the word "agent" comes up. Guess that's what I should look into? – ken Oct 9 '14 at 12:46
  • Try to: ssh-agent -a /tmp/agent.sock; ssh-add ~/dir/yourPrivate.key; export SSH_AUTH_SOCK=/tmp/agent.sock – Glueon Oct 9 '14 at 12:50
  • Ok, this is a step in the right direction but when running the ssh-add it still asks for password and since this is a CLI I need to pass this in as a parameter. – ken Oct 9 '14 at 12:58
  • You need to this once. After that in any environment that has SSH_AUTH_SOCK variable exported can use this key without a password. Or that still does not solve your problem and even that first passprhase input should be automated? – Glueon Oct 9 '14 at 13:05

There are use-cases where passing a passcode as a parameter make sense but obviously one must be careful about security and so whatever you do send around passwords or private keys please consider the context of the situation you are in and be very careful. In my case here's what I'm trying to achieve:

  • I have a host machine (running Ubuntu in this case but any *nix based solution will look similar
  • This machine has permission -- via SSH -- to pull (but not write) data to private repos on GitHub and BitBucket
  • I am using Docker to create a storage container which I would like to serve content as well as provide some basic utility functions like being able to pull content from a repo, run and download any dependencies based on npm [node], composer [php], or bower [frontend], etc.
  • The problem I was having is that containers will not have permission to interact with the git repos even if the process kicking them off (the Ubuntu host) does have this permission

My solution was to have the host pass a private key -- one which only has read-only access -- to any of the storage containers it creates. This will allow them to do their bidding with the repos and probably would have been very easy were it not for the fact that it necessitated that the exchange be fully non-interactive (aka, no human interaction).

Here's what I did to make it work:

  • In the Dockerfile I installed a few important dependencies from Ubuntu's apt-get package manager:

    RUN apt-get install -yqq git subversion sshpass \
        && apt-get install -yqq nodejs npm \
        && npm install -g bower \
        && apt-get install -yqq php5 \

    Most of this was just to get the various package managers in place so they could be called at run-time but there are a few others worth mentioning:

    • sshpass allows us to inject a password into an interactive call
    • subversion you can probably ignore this but I had a dependency on this along with the obvious one with git
  • Then also in the Dockerfile I needed to make sure that the SSH config file would point to the write key so I appended the following to ssh_config file. This is needed in Ubuntu, possibly not in some *nix flavours.

    RUN { \
        echo ""; \
        echo "IdentityFile /root/.ssh/id_rsa";  \
    } >> /etc/ssh/ssh_config
  • The container is started on the host with a command like:

    sudo docker run --name foobar \
        -e PREP="['composer.phar install','bower update']" \
        -e PRIVATE_KEY="$(< ~/.ssh/id_rsa_nopass)" \
        -e PASSWORD="" \
        "lifegadget/docker-locker" \
        load git@bitbucket.org:loginname/repo.git
  • Now at run time -- which is when the storage container is being setup after the command above is executed -- you immediately get the private key of the host and that's all that's needed if there's no passcode on the key. If there is a passcode is where it gets more interesting. The following code contends with that:

    sudo ssh-agent -a /tmp/agent.sock
    export SSH_AUTH_SOCK=/tmp/agent.sock
    sshpass -p$PASSWORD sudo ssh-add /root/.ssh/id_rsa
    ssh-keygen -yf /root/.ssh/id_rsa > /root/.ssh/id_rsa.pub

    Basically what's happening is:

    • setup an SSH agent listening on a named unix socket
    • set the SSH_AUTH_SOCK env variable for commands to find the agent
    • wrap the ssh-add (which doesn't have a command line switch for passing the password) with sshpass
    • from this point forward the agent should have the SSH key cached and therefore calls to git should resolve correctly.

Note the use of sudo, this is an odd requirement since we're running as root in the Docker container but for some reason it was still required to get it to work.

Hope this helps. Happy to take any suggestions on optimisations. If anyone's interested my evolving Dockerfile can be found at: https://github.com/lifegadget/docker-locker


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.