Configuring Docker Remote API with TLS on CoreOS

Problem

I recently set up a CoreOS box for futzing around and wanted to use it as a replacement for my qemu-kvm workflow (amongst other things). Typically this involves spinning up various distros of linux to compile software, provide services, or do demos on. They're typically ephemeral in that I frequently tear them down when I'm done and the workspace is configured automatically using some setup scripts. Before I'd done this with virsh behind a rather restrictive vpn, but this box is a little more exposed and I wanted some kind of auth in front. Luckily, docker 0.10.0 provides TLS authentication for its remote tcp API. Perfect.

Solution

I'm going to assume you already have a working coreos and docker instance somwhere. After that, we're going to merge a couple of tutorials from the docker side for https auth and the coreos side for configuring the remote api. But we're not going to use the docker-tcp.socket example as I was unable to get that to work with the docker cert options.

Creating Certificates

Tip

I've updated this script, making it more generalized, supporting multiple client cert generation, and using an openssl.cnf file that gets rid of those annoying questions.

Docker uses client/server certificates to grant access. So we need to create some private/public key pairs and a CA serial file. The example below creates one with a 10 year expiration.

#!/bin/bash
set -ex
mkdir certs && cd certs
echo "Creating server keys..."
echo 01 > ca.srl
openssl genrsa -des3 -out ca-key.pem
openssl req -new -x509 -days 3650 -key ca-key.pem -out ca.pem
openssl genrsa -des3 -out server-key.pem
openssl req -new -key server-key.pem -out server.csr
openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem \
    -out server-cert.pem

echo "Creating client keys..."
openssl genrsa -des3 -out client-key.pem
openssl req -new -key client-key.pem -out client.csr
echo extendedKeyUsage = clientAuth > extfile.cnf
openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca-key.pem \
    -out client-cert.pem -extfile extfile.cnf

echo "Stripping passwords from keys..."
openssl rsa -in server-key.pem -out server-key.pem
openssl rsa -in client-key.pem -out client-key.pem

After being asked a bunch of annoying questions, you'll need to copy the generated client certificates from your server to your client or vice versa if you created the certs on your client.

Make sure you use the correct FQDN (or '*' to match all servers) of the server for the server certificate. We don't have a fully working dns for our lab network, so I just made sure I had a /etc/hosts entry on my client.

Configuring CoreOS

We need to tweak the default docker.service definition in CoreOS to use the TLS certs we created. This should be done as root. The below script assumes the server certificates are in working directory of the script.

#!/bin/bash
set -ex
systemctl stop docker
systemctl disable docker
echo "Copying scripts to /var/ssl/"
mkdir -p /var/ssl
cp ca.pem server-cert.pem server-key.pem /var/ssl/

cat<<-EOF > /etc/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io

[Service]
ExecStartPre=/bin/mount --make-rprivate /
# Run docker but don't have docker automatically restart
# containers. This is a job for systemd and unit files.
ExecStart=/usr/bin/docker -d -s=btrfs -r=false --tlsverify --tlscacert=/var/ssl/ca.pem --tlscert=/var/ssl/server-cert.pem --tlskey=/var/ssl/server-key.pem -H fd:// -H 0.0.0.0:4243
#ExecStart=/usr/bin/docker -d -s=btrfs -r=false -H fd://

[Install]
WantedBy=multi-user.target
EOF

systemctl enable /etc/systemd/system/docker.service
systemctl start docker

Setting Up Your Client

Coy the client certificates to a good location, I put mine in ~/.docker/. Also, for convenience, set the DOCKER_HOST environment variable.

mkdir ~/.docker
cp ca.pem ~/.docker
cp client-cert.pem ~/.docker/cert.pem
cp client-key.pem ~/.docker/key.pem

export DOCKER_HOST=<docker service fqdn>:4243

If you named the files exactly like above, you should be able to access your TLS protected docker api with with the following command from your client.

docker --tlsverify images

Share on: TwitterFacebookGoogle+Email

Comments !