Information Security 11 min read

How to Secure Docker’s Remote API (Port 2375) with TLS and OpenSSL

Learn how to protect Docker’s exposed remote management port 2375 by generating CA, server, and client certificates with OpenSSL, configuring Docker daemon for TLS verification, and adjusting docker-maven-plugin settings to safely build and push images without exposing insecure endpoints.

macrozheng
macrozheng
macrozheng
How to Secure Docker’s Remote API (Port 2375) with TLS and OpenSSL
Many users encounter security issues when the docker-maven-plugin opens Docker’s remote management port 2375 without any protection, leading to potential attacks such as unauthorized access, mining, or CPU spikes.

Reason for the issue

Docker provides a remote management port (2375) for cluster control. Adding

-H tcp://0.0.0.0:2375

to

docker.service

opens this port without encryption or authentication, which is acceptable only for internal testing. Exposing it on a public server allows anyone who knows the IP to control containers and images.

Solution approach

Secure the remote management port by using TLS for transport and CA‑based authentication.

Generate certificates and keys

Use OpenSSL on the Docker host to create a CA, server, and client certificates.

Create a directory for the certificates:

<code>mkdir /mydata/docker-ca && cd /mydata/docker-ca</code>

Create the CA private key:

<code>openssl genrsa -aes256 -out ca-key.pem 4096</code>

Create the CA certificate:

<code>openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -subj "/CN=*" -out ca.pem</code>

Create the server private key:

<code>openssl genrsa -out server-key.pem 4096</code>

Create the server CSR:

<code>openssl req -subj "/CN=*" -sha256 -new -key server-key.pem -out server.csr</code>

Sign the server certificate with the CA:

<code>openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem</code>

Create the client private key:

<code>openssl genrsa -out key.pem 4096</code>

Create the client CSR:

<code>openssl req -subj "/CN=client" -new -key key.pem -out client.csr</code>

Create an extension file for client authentication:

<code>echo extendedKeyUsage = clientAuth > extfile-client.cnf</code>

Sign the client certificate with the CA:

<code>openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile-client.cnf</code>

Remove temporary files:

<code>rm -rf ca.srl server.csr client.csr extfile-client.cnf</code>

Resulting files:

<code>ca.pem          # CA certificate
ca-key.pem      # CA private key
server-cert.pem # Server certificate
server-key.pem  # Server private key
cert.pem        # Client certificate
key.pem         # Client private key</code>

Configure Docker to support TLS

Edit

docker.service

with vim:

Replace the

ExecStart

line to enable TLS verification and point to the generated certificates:

<code>ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --tlsverify --tlscacert=/mydata/docker-ca/ca.pem --tlscert=/mydata/docker-ca/server-cert.pem --tlskey=/mydata/docker-ca/server-key.pem</code>

Reload the systemd daemon and restart Docker:

<code>systemctl daemon-reload && systemctl restart docker</code>

Client access

Use docker-maven-plugin to build Docker images, now pointing to the secured endpoint.

Upgrade the plugin to version 1.2.2 to avoid compatibility issues.

Change the

&lt;dockerHost&gt;

configuration from

http

to

https

:

<code>&lt;dockerHost&gt;https://192.168.3.101:2375&lt;/dockerHost&gt;</code>

Copy the CA, client certificate, and client key to a local directory (e.g.,

I:\developer\env\docker-ca

) and reference it in the plugin configuration:

<code>&lt;dockerCertPath&gt;I:\developer\env\docker-ca&lt;/dockerCertPath&gt;</code>

Full plugin configuration example:

<code>&lt;plugin&gt;
    &lt;groupId&gt;com.spotify&lt;/groupId&gt;
    &lt;artifactId&gt;docker-maven-plugin&lt;/artifactId&gt;
    &lt;version&gt;1.2.2&lt;/version&gt;
    &lt;executions&gt;
        &lt;execution&gt;
            &lt;id&gt;build-image&lt;/id&gt;
            &lt;phase&gt;package&lt;/phase&gt;
            &lt;goals&gt;
                &lt;goal&gt;build&lt;/goal&gt;
            &lt;/goals&gt;
        &lt;/execution&gt;
    &lt;/executions&gt;
    &lt;configuration&gt;
        &lt;imageName&gt;mall-tiny/${project.artifactId}:${project.version}&lt;/imageName&gt;
        &lt;dockerHost&gt;https://192.168.3.101:2375&lt;/dockerHost&gt;
        &lt;baseImage&gt;java:8&lt;/baseImage&gt;
        &lt;entryPoint&gt;["java", "-jar", "/${project.build.finalName}.jar"]&lt;/entryPoint&gt;
        &lt;dockerCertPath&gt;I:\developer\env\docker-ca&lt;/dockerCertPath&gt;
        &lt;resources&gt;
            &lt;resource&gt;
                &lt;targetPath>/&lt;/targetPath&gt;
                &lt;directory>${project.build.directory}&lt;/directory&gt;
                &lt;include>${project.build.finalName}.jar&lt;/include&gt;
            &lt;/resource&gt;
        &lt;/resources&gt;
    &lt;/configuration&gt;
&lt;/plugin&gt;</code>

After these changes, the image builds successfully and the 2375 port can be used safely over TLS.

Reference

Official Docker security documentation: https://docs.docker.com/engine/security/https/

DockersecurityOpenSSLTLSCertificatesdocker-maven-pluginRemote API
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.