Skip to content

Instantly share code, notes, and snippets.

@marcwittke
Last active August 8, 2024 08:58
Show Gist options
  • Save marcwittke/716fecdf87d6b17ea298e503c774cdf9 to your computer and use it in GitHub Desktop.
Save marcwittke/716fecdf87d6b17ea298e503c774cdf9 to your computer and use it in GitHub Desktop.
Securing the docker daemon with TLS certificates

Secure the docker daemon with TLS

first, let's create some directories to work in

mkdir -p ./docker_certs/ca ./docker_certs/server ./docker_certs/client
cd ./docker_certs

Generate Root CA certificate

Generate the CA private key and certificate:

# Generate CA private key
openssl genpkey -algorithm RSA -out ca/local-root-ca.key -aes256

# Generate CA certificate
openssl req -new -x509 -days 3650 -key ca/local-root-ca.key -sha256 -out ca/local-root-ca.pem

Add the CA to the trusted Root CAs (Redhat flavor)

sudo cp ca/local-root-ca.pem /etc/pki/ca-trust/source/anchors/local-root-ca.pem
sudo update-ca-trust

Generate Docker Server certificate

Generate the server private key:

openssl genpkey -algorithm RSA -out server/docker-daemon.key

Create a certificate signing request (CSR) for the server:

openssl req -new -key server/docker-daemon.key -out server/docker-daemon.csr

Create a configuration file for the server certificate (server/server-ext.cnf):

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
IP.1 = 127.0.0.1
IP.2 = 192.168.122.1
IP.3 = 192.168.85.30

Generate the server certificate:

openssl x509 -req -days 3650 \
  -in server/docker-daemon.csr \
  -CA ca/local-root-ca.pem \
  -CAkey ca/local-root-ca.key \
  -CAcreateserial \
  -out server/docker-daemon.pem \
  -extfile server/server-ext.cnf

Verify the generated server certificate:

openssl x509 -noout -text -in server/docker-daemon.pem

Summary of Files

  • ./ca/local-root-ca.key: CA private key
  • ./ca/local-root-ca.pem: CA certificate
  • ./server/docker-daemon.key: Server private key
  • ./server/docker-daemon.pem: Server certificate

Configure the Docker daemon to use the Certificates

Copy the certificates to the Docker daemon:

sudo mkdir -p /etc/docker/certs.d
sudo cp ./server/docker-daemon.pem /etc/docker/certs.d/
sudo cp ./server/docker-daemon.key /etc/docker/certs.d/
sudo cp ./ca/local-root-ca.pem /etc/docker/certs.d/ca.pem

Edit the Docker daemon configuration (/etc/docker/daemon.json):

{
    "tls": true,
    "tlscert": "/etc/docker/certs.d/docker-daemon.pem",
    "tlskey": "/etc/docker/certs.d/docker-daemon.key",
    "tlscacert": "/etc/docker/certs.d/ca.pem"
}

Restart the Docker daemon:

sudo systemctl restart docker

Now the Docker daemon should be using the generated certificates for secure communication.

Generate a Client Certificate

Generate the client private key:

openssl genpkey -algorithm RSA -out client/docker-client.key

Create a certificate signing request (CSR) for the client:

openssl req -new -key client/docker-client.key -out client/client.csr

Create a configuration file for the client certificate (client/client-ext.cnf):

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = clientAuth

Generate the client certificate:

openssl x509 -req -days 3650 \
  -in client/client.csr \
  -CA ca/local-root-ca.pem \
  -CAkey ca/local-root-ca.key \
  -CAcreateserial \
  -out client/docker-client.pem \
  -extfile client/client-ext.cnf

Summary of Client Certificate Files

  • docker-client.key: Client private key
  • docker-client.pem: Client certificate
  • local-root-ca.pem: CA certificate (same as for the server)

Verifying the client certificate using cURL

Use the following curl command, providing the CA certificate, client certificate, and client key:

curl \
  --cacert ca/local-root-ca.pem \
  --cert client/docker-client.pem \
  --key client/docker-client.key \
  https://192.168.122.1:2375

Create a Docker Context that uses the Client Certificate

Create a Directory for Docker Client Certificates

Store your client certificates and keys in a dedicated directory:

mkdir -p ~/.docker/certs
cp client/docker-client.pem ~/.docker/certs/
cp client/docker-client.key ~/.docker/certs/
cp ca/local-root-ca.pem ~/.docker/certs/

Create a Docker Context

Use the docker context command to create a new context with the specified certificates:

docker context create docker-tls \
    --description "Context for secure Docker daemon at 192.168.122.1" \
    --docker "host=tcp://192.168.122.1:2375,ca=~/.docker/certs/local-root-ca.pem,cert=~/.docker/certs/docker-client.pem,key=~/.docker/certs/docker-client.key"

Verify the New Context

List all available Docker contexts to verify the new context has been created:

docker context ls

You should see an output similar to:

NAME                DESCRIPTION                                 DOCKER ENDPOINT                      KUBERNETES ENDPOINT   ORCHESTRATOR
default *           Current DOCKER_HOST based configuration     unix:///var/run/docker.sock                               swarm
docker-tls          Context for secure Docker daemon at 192.168.122.1   tcp://192.168.122.1:2375                             swarm

Use the New Context

docker context use docker-tls
docker info
@don-rumata
Copy link

F*cking great! Many thanks!

@don-rumata
Copy link

don-rumata commented Aug 6, 2024

In the /etc/docker/daemon config.json needs to add an option:

"hosts": [
  "unix:///var/run/docker.sock",
  "tcp://<my-ip>:2375"
]

@marcwittke
Copy link
Author

you're right. Another option would be to add this in the systemd unit as drop-in

sudo systemctl edit docker

### Editing /etc/systemd/system/docker.service.d/override.conf
### Anything between here and the comment below will become the contents of the drop-in file

[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://192.168.122.1:2375

### Edits below this comment will be discarded

I am using this setup to share the docker daemon on my main development machine (Fedora) with a windows-VM for a legacy project. Running Docker Desktop for Windows in kvm is possible but slow, since it requires nested virtualization.

@don-rumata
Copy link

The ExecStart= and ExecStart=/usr/bin/dockerd options will be enough.

@don-rumata
Copy link

https://gist.github.com/marcwittke/716fecdf87d6b17ea298e503c774cdf9#create-a-docker-context

lsb_release --all
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 24.04 LTS
Release:        24.04
Codename:       noble
docker --version
Docker version 27.1.1, build 6312585

The ~/ construction does not work. Only the absolute path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment