Monday, September 28, 2015

Docker for windows on Azure VM : Securing the host and TLS

In the previous post about docker on windows, we looked into the details of creating a Windows 2016 TP3 VM in Azure and looked into the details of managing containers on the host VM that is running the Docker daemon. This post we’ll look into the security considerations when running Docker and how to secure the Docker daemon with TLS. We’ll be using openssl to create and manage certificates for SSL. 

If you don’t have openssl installed on the machines, download the binaries for windows from the location

To setup TLS for Docker, we need to follow the below given steps.
  1. Create certificate authority (CA)
  2. Setup the server private key
  3. Create certificate signing request for the server (CSR)
  4. Sign the server key with the CSR against the CA
  5. Create client private key and CSR
  6. Sign the client key with the CSR against the CA
  7. Copy the server certificates to the docker host machine
  8. Add firewall rule for allowing communication to port 2376

Before we start using the openssl executable, we need to ensure that the configuration file for openssl is available. The version 1.0 of OpenSSL requires an "openssl.cnf" configuration file. Openssl reads the location of the configuration file by using the environment variable OPENSSL_CONF. For this example, we can download and use the configuration file from

Creating the certificates.

Download and extract the openssl binaries from location to the C:\OpenSSL folder

  • Download and copy the openssl configuration file to C:\OpenSSL\openssl.cnf file
  • Setup the environment variable for opensssl configuration

       [string] $Path = "C:\OpenSSL",
       [string] $CertLocation = "C:\Docker\Certs"
$opensslExe = Join-Path $Path "openssl.exe"
$opensslCnf = Join-Path $Path "openssl.cnf"

if(-not (Test-Path $opensslExe -ErrorAction SilentlyContinue))
       throw "openssl.exe not found at location $Path"

$env:OPENSSL_CONF= $opensslCnf

  • During certificate generation, there is an .rnd file that OpenSSL needs to write to. We need to set the RANDFILE environment variable to a directory at the certificates location

$env:RANDFILE = Join-Path $CertLocation ".rnd"

  • First we need to create the certificate authority private key

& $opensslExe genrsa -aes256 -out ca-key.pem 2048

  • Using the CA private key, create the CA certificate

& $opensslExe req -new -x509 -days 365 -key ca-key.pem -subj "/C=NL/ST=UT/L=Amersfoort/O=Prajeesh" -sha256 -out ca.pem

  • Next we’ll create the server private key

& $opensslExe genrsa -aes256 -out server-key.pem 2048

  • After this we need to create the certificate signing request (CSR) for the server key. Use the host server IP address while creating the server key

& $opensslExe req -subj "/C=NL/ST=UT/L=Amersfoort/O=Prajeesh" -new -key server-key.pem -out server.csr

  • Before we sign the server key we need to define the certificate extension to specify the subjectAltName. The subjectAltName allows us to specify things such as the IP addresses we will allow connections on.

"subjectAltName = IP:,IP:,DNS.1:*,DNS.2:*.*" | Out-File extfile.cnf -Encoding ASCII

  • Now we can sign the server key

& $opensslExe x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf

  • Next we’ll create the client keys. First we’ll create the client’s private key

& $opensslExe genrsa -out client-key.pem 2048

  • Then we’ll create the client certificate signing request

& $opensslExe req -subj "/CN=client" -new -key client-key.pem -out client.csr

  • To sign the client key we need an extensions config file with the extendedKeyUsage extension in order to make the key suitable for client authentication

"extendedKeyUsage = clientAuth" | Out-File extfile.cnf -Encoding ASCII

  • Now we can sign the client key

& $opensslExe x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -extfile extfile.cnf

Configuring the docker host

  • We’ve successfully created all the certificates needed for our setup. Now we need to copy the server certificates to the VM where the docker daemon is running. You can either use AzCopy utility to copy the certificates that are added to the container as blob or download the certificates from an Uri using Invoke-WebRequest cmdlet in the machine. The server certificates should be copied to the directory C:\ProgramData\Docker\certs.d folder

  • Next we have to open the connections to port 2376 using the New-NetFirewallRule cmdlet as given below.

  • Restart the docker service on the host
  • Copy the client certificates to the .docker folder in the $Env:USERPROFILE folder.

Connecting using TLS

  • Now connect to docker host using the ip address of the host and port 2376 using –tlsverify option from the client machine

docker --tlsverify -H tcp:// ps -a

No comments: