docker-machine, none/generic drivers and TLS

I really like the idea of docker-machine. It provides a nice interface where I can see the machines that I’m working with. It’s easy to use the commands to quickly switch between machines, and it has lots of great commands for scripting.

However, if you didn’t create the machine on the computer where you are running docker-machine, it’s a complete mess (at least as of Docker 1.9). There are quite a few reported issues, and acknowledgements that it’s broken (See Docker Issue #1221).

But I was able to get at least the basic connections working by piecing together different comments and other google articles.

The primary issue is the TLS security that surrounds the Docker socket and allowing docker-machine to have access to it.

Additionally, the only docker-machine driver that ‘kind of works’ is the ‘none’ driver. However, it’s really meant as a test driver, so the fact that it works is a hack, and it sounds like that they plan to remove it (See Docker Issue #2437). It seems that the intent in the future is for the ‘generic’ driver to be used for this purpose, but at this point, the generic driver automatically regenerates all certificates and restarts the driver. So, completely useless when you have multiple docker-machine’s managing the same box (ie. in a production environment, you might have multiple administrators who look after the boxes).

So, for now, these steps work, but this will likely fail before long.

Download the necessary files

At this point, the complete set of TLS files are needed on the client box. This is the ca.pem, ca-key.pem, server.pem and server-key.pem.

Most of these are present in the /etc/docker folder on the host, but the ca-key.pem may only be present whereever you originally created this (ie. if you used docker-machine create on some other box, the ca-key.pem is only on the ‘other box’).

Copy all these files to a directory on your client box.

Generate a new Client Certificate

Now, we need to generate a client certificate for your client box, and then sign it with the server certificate.

openssl genrsa -out key.pem 4096
openssl req -subj '/CN=client' -new -key key.pem -out client.csr
echo extendedKeyUsage = clientAuth > extfile.cnf
openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile.cnf

Create the Machine

Now we need to create the machine using docker-machine and then fix up the configuration.

docker-machine --tls-ca-cert ca.pem --tls-client-cert cert.pem --tls-client-key key.pem create -d "none" --url tcp://104.236.140.57:2376 digitalocean-wordpress

Of course, replace your IP address with the IP address of your Docker host. The final argument is the machine name that you want to have it known by.

Unfortunately, the driver doesn’t copy the certificate information into the right folder, so you have to fix things up.

Navigate into the ~/.docker/machine/machines/digitalocean-wordpress folder

cd ~/.docker/machine/machines/digitalocean-wordpress

Now, copy all 5 files (ca.pem, server.pem, server-key.pem, client.pem and key.pem) into this folder.

NOTE: Annoyingly, Docker expects the files to have specific names, even though there is a config file that points to it, so don’t rename them from what’s listed.

Next, modify the config.json, and update the bottom section:

 "AuthOptions": {
 "CertDir": "/home/mmansell/.docker/machine/certs",
 "CaCertPath": "/home/mmansell/.docker/machine/machines/digitalocean-wordpress/ca.pem",
 "CaPrivateKeyPath": "/home/mmansell/.docker/machine/certs/ca-key.pem",
 "CaCertRemotePath": "",
 "ServerCertPath": "/home/mmansell/.docker/machine/machines/digitalocean-wordpress/server.pem",
 "ServerKeyPath": "/home/mmansell/.docker/machine/machines/digitalocean-wordpress/server-key.pem",
 "ClientKeyPath": "/home/mmansell/.docker/machine/machines/digitalocean-wordpress/key.pem",
 "ServerCertRemotePath": "",
 "ServerKeyRemotePath": "",
 "ClientCertPath": "/home/mmansell/.docker/machine/machines/digitalocean-wordpress/cert.pem",
 "ServerCertSANs": [],
 "StorePath": "/home/mmansell/.docker/machine/machines/digitalocean-wordpress"
 }

In specific, you be updating the CaCertPath, ClientKeyPath and ClientCertPath entries.

Testing

At this point, you should be able to use the docker-machine commands.

docker-machine ls

Or

eval $(docker-machine env digitalocean-wordpress)
docker ps

However, some commands such as docker-machine ssh, etc. will not work, since the ssh keys are not present. According to some of the discussions, this functionality is completely broken in the none driver.

Hopefully they’ll fix the generic driver (or create a new one) that allows full access without a ‘reinstall’ that the generic driver does currently.