{"id":49587598,"url":"https://github.com/anjaustin/secure-docker-with-tls","last_synced_at":"2026-05-03T23:06:08.628Z","repository":{"id":216149541,"uuid":"740586939","full_name":"anjaustin/secure-docker-with-tls","owner":"anjaustin","description":"How to secure vanilla docker with TLS","archived":false,"fork":false,"pushed_at":"2024-01-27T15:13:32.000Z","size":1432,"stargazers_count":0,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-01-27T16:27:56.884Z","etag":null,"topics":["docker","tls"],"latest_commit_sha":null,"homepage":"https://github.com/anjaustin/secure-docker-with-tls","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anjaustin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2024-01-08T16:41:56.000Z","updated_at":"2024-01-27T16:27:57.360Z","dependencies_parsed_at":null,"dependency_job_id":"9ead7b7a-522c-4a1a-af6a-b8391f6d3e4a","html_url":"https://github.com/anjaustin/secure-docker-with-tls","commit_stats":null,"previous_names":["anjaustin/secure-docker-with-tls"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/anjaustin/secure-docker-with-tls","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anjaustin%2Fsecure-docker-with-tls","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anjaustin%2Fsecure-docker-with-tls/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anjaustin%2Fsecure-docker-with-tls/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anjaustin%2Fsecure-docker-with-tls/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anjaustin","download_url":"https://codeload.github.com/anjaustin/secure-docker-with-tls/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anjaustin%2Fsecure-docker-with-tls/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32587829,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T22:12:39.696Z","status":"ssl_error","status_checked_at":"2026-05-03T22:09:10.534Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","tls"],"created_at":"2026-05-03T23:06:04.741Z","updated_at":"2026-05-03T23:06:08.622Z","avatar_url":"https://github.com/anjaustin.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Securing the Docker daemon with TLS\n\n![Secure Docker with TLS](./assets/images/secure-docker-with-tls.png)\n\n**Securing the Docker daemon socket with a self-signed certificate.**\n\n*The following instructions should be executed on the host machine of the Docker daemon you wish to secure. With some modification, the following instructions were sourced from the official [Docker Documentation: Protecting the Docker daemon socket.](https://docs.docker.com/engine/security/protect-access/)*\n\n*StackOverflow was also instrumental in helping me resolve some obscurities in the official Docker docs. [StackOverflow: Unable to start docker after configuring hosts in daemon.json](https://stackoverflow.com/questions/44052054/unable-to-start-docker-after-configuring-hosts-in-daemon-json)*\n\n## Create CA server and client credentials with OpenSSL\n\n### Let us initialize some variables.\n\n```bash\n# Change this to the IP address of your docker host\nexport DOCKER_HOST_IP=\"0.0.0.0\"\n\n# Set the hostname of your docker host.\n# Include the subdomain if your docker host has one.\n# Do `export DOCKER_HOST_FQDN=\"my-subdomain.$(hostname -f)\"`,\n# if `hostname -f` doesn't include it.\n# Or, just type it in explicitly and export it.\n# `export DOCKER_HOST_FQDN=\"subdomain.domain-name.com\"`\nexport DOCKER_HOST_FQDN=\"$(hostname -f)\"\n\n# We'll need this to set up TLS for the `docker.service`.\nexport DOCKER_SERVICE_DIR=\"/etc/systemd/system/docker.service.d\"\n\n# A directory for our Certificate Authority (CA)\n# server credentials.\nexport DOCKER_TLS_DIR=\"/etc/docker/.tls\"\n\n# The `subjectAltName` for your CA credentials. If the IP\n# address of your host machine changes you'll need to recreate\n# and reinstall your server credentials.\nexport CERT_SAN_CONFIGURATION=\"$DOCKER_HOST_FQDN,IP:$DOCKER_HOST_IP,IP:127.0.0.1\"\n\n# Set the docker host.\nexport DOCKER_HOST=\"tcp://$DOCKER_HOST_FQDN:2375\"\n\n# And finally, set `tlsverify` to `true`.\n# Set this to `0` if you need to disable `tlsverify`.\n# For instance, if find yourself in a position at the end of this\n# process in which you need access to the Docker daemon (docker.service)\n# without TLS, setting this to `0` will allow you to access the service.\n# Otherwise, `1` defaults to TLS.\nexport DOCKER_TLS_VERIFY=1\n```\n\n### Now, let's create the server's key and certificate signing request (CSR).\n\n**1. Create and enter the working directory for the creation of your credentials.**\n\n```bash\nmkdir -v ~/.docker/tls/ \u0026\u0026 cd ~/.docker/tls/\n```\n\n**2. Generate your private and public keys.**\n\nPrivate key first.\n\n```bash\nopenssl genrsa -aes256 -out ca-key.pem 4096\n```\n\nEnter a passphrase with which to encrypt the key, and enter it again to verify your passphrase.\n\n```bash\nEnter PEM pass phrase:\nVerifying - Enter PEM pass phrase:\n```\n\nNow, the public key.\n\n```bash\nopenssl req -new -x509 -days 365 \\\n-key ca-key.pem -sha256 \\\n-out ca.pem\n```\n\nEnter the passphrase you used to generate your private key and follow the prompts.\n\n```bash\nEnter pass phrase for ca-key.pem:\nYou are about to be asked to enter information that will be incorporated\ninto your certificate request.\nWhat you are about to enter is what is called a Distinguished Name or a DN.\nThere are quite a few fields, but you can leave some blank\nFor some fields, there will be a default value,\nIf you enter '.', the field will be left blank.\n-----\nCountry Name (2-letter code) [AU]: US\nState or Province Name (full name) [Some-State]: Virginia\nLocality Name (eg, city) []: Alexandria\nOrganization Name (eg, company) [Internet Widgits Pty Ltd]: ACME, Inc.\nOrganizational Unit Name (eg, section) []: Sales\nCommon Name (e.g. server FQDN or YOUR name) []: www.acmeinc.com\nEmail Address []: webmaster@acmeinc.com\n```\n\n**4. Create a server key and certificate signing request (CSR) for the docker host machine.**\n\nFirst, the server key.\n\n```bash\nopenssl genrsa -out server-key.pem 4096\n```\n\nAnd, the certificate signing request (CSR).\n\n```bash\nopenssl req -subj \"/CN=$DOCKER_HOST_FQDN\" -sha256 -new \\\n-key server-key.pem \\\n-out server.csr\n```\n\n**5. Sign the public key with our Certificate Authority.**\n\nCreate the configuration file that will inform `opnessl` of the Subject Alt Name (SAN).\n\n```bash\necho -e \"subjectAltName=DNS:$CERT_SAN_CONFIGURATION\" \u003e server.cnf\n```\n\nNext, set the extended usage attribute of this key to server auth only.\n\n```bash\necho extendedKeyUsage = serverAuth \u003e\u003e server.cnf\n```\n\nGenerate the signed certificate.\n\n```bash\nopenssl x509 -req -days 365 -sha256 \\\n-in server.csr \\\n-CA ca.pem \\\n-CAkey ca-key.pem \\\n-CAcreateserial -out server-cert.pem \\\n-extfile server.cnf\n```\n\nFinally, enter the same passphrase you used at the start.\n\n```bash\nSignature ok\nsubject=/CN=your.host.com\nGetting CA Private Key\nEnter pass phrase for ca-key.pem:\n```\n\nThat takes care of the key and certificate signing request for the server.\n\n---\n\n### Now, let's create the client's key and certificate signing request (CSR).\n\n*Again, the following instructions should be executed on the host machine of the Docker daemon you wish to secure with TLS. We continue the following instructions in the same working directory as before,* `~/.docker/tls`*.*\n\n**1. Create the client key and certificate signing request.**\n\nFirst, the client key.\n\n```bash\nopenssl genrsa -out key.pem 4096\n```\n\nThen, the client's certificate signing request.\n\n```bash\nopenssl req -subj '/CN=client' -new \\\n-key key.pem \\\n-out client.csr\n```\n\n**2. Set the key for client authentication.**\n\n```bash\necho extendedKeyUsage = clientAuth \u003e client-auth.cnf\n```\n\n**3. Generate the client's signed certificate.**\n\n```bash\nopenssl x509 -req -days 365 -sha256 \\\n-in client.csr \\\n-CA ca.pem \\\n-CAkey ca-key.pem \\\n-CAcreateserial -out cert.pem \\\n-extfile client-auth.cnf\n```\n\nEnter your passphrase.\n\n```bash\nSignature ok\nsubject=/CN=client\nGetting CA Private Key\nEnter pass phrase for ca-key.pem:\n```\n\n**4. Garbage collection.**\n\nOnce we've generated the client's `cert.pem` and the `server-cert.pem` credentials, we can safely remove the certificate signing requests and `.cnf` files.\n\n```bash\nrm -v client.csr \\\nserver.csr \\\nserver.cnf \\\nclient-auth.cnf\n```\n\n**5. Setting permissions.**\n\nIf the `umask` of the machine you're using is set to `022`, your secret keys are world-readable and writable for you and your group. You can learn more about setting your system's `umask` [here](https://www.linuxnix.com/umask-define-linuxunix/). Let's protect our credentials from accidental corruption by setting the proper permissions.\n\n👀 ***For your eyes only.***\n\n```bash\nchmod -v 0400 ca-key.pem key.pem server-key.pem\n```\n\nFor the world to see, not to change.\n\n```bash\nchmod -v 0444 ca.pem server-cert.pem cert.pem\n```\n\nFinally, we have all the required credentials for the server and for clients that need to connect to the server. Next, we need to configure the `docker.service` to accept connections from clients that provide a trusted certificate issued by your Certificate Authority (CA). You.\n\n---\n\n## Secure Docker with TLS verification\n\n**1. Configure `docker.service` for TLS using the server credentials you created earlier.**\n\n**NOTE:** *I found the following necessary for Debian and Ubuntu distros. You may not be able to access your* `docker.service` *over TLS without this modification.*\n\nHere, we are not changing existing files in the systemd service directories. We are simply adding an override configuration to enable TLS for the `docker.service`.\n\nFirst, create the `override.conf` file for the `docker.service`.\n\n```bash\ncat \u003e ~/.docker/override.conf \u003c\u003cEOL\n[Service]\nExecStart=\nExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375\nEOL\n```\n\nNext, create the service directory for the `override.conf` file.\n\n```bash\nsudo mkdir -v /etc/systemd/system/docker.service.d\n```\n\nIf you get the following warning, then the directory already exists. At which point, we copy the new configuration file to that directory, reload the systemd daemon, and restart the `docker.service`.\n\n```warning\nmkdir: cannot create directory ‘/etc/systemd/system/docker.service.d’: File exists\n```\n\nCopy the `override.conf` file to the docker service directory and reload the system daemon.\n\n```bash\nsudo cp -v override.conf /etc/systemd/system/docker.service.d/\nsudo systemctl daemon-reload\n```\n\nBefore we restart the `docker.service`, we need to make the server credentials available to the `docker.service`. \n\n**2. Create a directory for the server's credentials and copy the credentials into the new directory.**\n\n```bash\ncd ~/.docker/tls # ...just to be sure. :)\nsudo mkdir -v /etc/docker/.tls\nsudo cp -v {ca,server-cert,server-key}.pem /etc/docker/.tls/\n```\n\nNow that the credentials are in place, we need to create the `daemon.json` for the `docker.service`.\n\n**NOTE:** *If the* `/etc/docker/daemon.json` *already exists, do not run the following* `cat` *command. Simply open your existing* `/etc/docker/daemon.json` *in your preferred editor and add the following* `json` *data to your existing* `/etc/docker/daemon.json`*. Also, even if you are not running a local registry, you still need the `insecure-registries` setting in your `daemon.json`. Otherwise you will encounter the following error when attempting to use docker with TLS: `http: server gave HTTP response to HTTPS client` Remember to change the IP or IP range to the one that matches your `$DOCKER_HOST_IP`*\n\n\n\n```bash\nsudo cat \u003e /etc/docker/daemon.json \u003c\u003cEOL\n{\n  \"tlsverify\": true,\n  \"tlscacert\": \"/etc/docker/.tls/ca.pem\",\n  \"tlscert\": \"/etc/docker/.tls/server-cert.pem\",\n  \"tlskey\": \"/etc/docker/.tls/server-key.pem\",\n  \"insecure-registries\": [\"127.0.0.0/8\"]\n}\nEOL\n```\n\nNow, we restart the `docker.service`.\n\n```bash\nsudo systemctl restart docker\n```\n\nNext, from within your `~/.docker/tls` directory, test your connection with TLS.\n\n```bash\ndocker --tlsverify \\\n--tlscacert=ca.pem \\\n--tlscert=cert.pem \\\n--tlskey=key.pem \\\n-H=$DOCKER_HOST_FQDN:2375 version\n```\n\nA successful test of your credentials should produce something like the following.\n\n```bash\nClient: Docker Engine - Community\n Version:           24.0.7\n API version:       1.43\n Go version:        go1.20.10\n Git commit:        afdd53b\n Built:             Thu Oct 26 09:07:41 2023\n OS/Arch:           linux/amd64\n Context:           default\n\nServer: Docker Engine - Community\n Engine:\n  Version:          24.0.7\n  API version:      1.43 (minimum version 1.12)\n  Go version:       go1.20.10\n  Git commit:       311b9ff\n  Built:            Thu Oct 26 09:07:41 2023\n  OS/Arch:          linux/amd64\n  Experimental:     false\n containerd:\n  Version:          1.6.26\n  GitCommit:        3dd1e886e55dd695541fdcd67420c2888645a495\n runc:\n  Version:          1.1.10\n  GitCommit:        v1.1.10-0-g18a0cb0\n docker-init:\n  Version:          0.19.0\n  GitCommit:        de40ad0\n```\n\n**3. Finally, we can secure the client's connection by default.**\n\nCopy your credentials to your `/home/.docker` directory.\n\n```bash\ncp -v {ca,cert,key}.pem ~/.docker\n```\n\nAfter which, you can do the following.\n\n```bash\ndocker version # If this works, you're in the crypto!\n```\n\n**4. Add the environment variables to your `~/.docker` directory and `~/.profile`.**\n\nYou TLS works now because the environment variables are still in memory, while will be flushed upon reboot. We can resolve this by creating a `.env_docker` file and loading it at login.\n\nCreate the `.env_docker` file and load it with the necessary environment variables.\n\n```bash\ncat \u003e ~/.docker/.env_docker \u003c\u003cEOL\nDOCKER_HOST=\"tcp://$DOCKER_HOST_FQDN:2375\"\nDOCKER_TLS_VERIFY=$DOCKER_TLS_VERIFY\nEOL\n```\n\nUpdate your `.profile` to load the environment variables from `~/.docker/.env_docker`. We'll start with a blank new line so the new bash code isn't bunched up against the existing bash in the file.\n\n```bash\ncat \u003e\u003e ~/.profile \u003c\u003c'EOL'\n\n# Load Docker TLS environment variables if '.env_docker' exists\nif [ -f \"$HOME/.docker/.env_docker\" ]; then\n    export $(cat $HOME/.docker/.env_docker | xargs)\nfi\nEOL\n```\n\nA quick reboot and you're ready to test your new environment.\n\n**5. Endowing additional users with TLS for the secured Docker daemon socket.**\n\nFor any client that needs to connect to your newly secured Docker daemon socket, copy the contents of your `~/.docker/` directory into their `~/.docker` directory, update their `~/.profile` to load the `~/.docker/.env_docker`, and they're good as gold!\n\n**Live long, and Docker!**\n\n![Live long, and Docker!](https://media1.tenor.com/m/A3s-Mk6G2-kAAAAC/star-trek-spock.gif)\n\n---\n\n### Other Connection Modalities\n\nYou can read more about other options for connecting to a secure Docker daemon in the official [Docker Documentation](https://docs.docker.com/engine/security/protect-access/#other-modes).\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanjaustin%2Fsecure-docker-with-tls","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanjaustin%2Fsecure-docker-with-tls","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanjaustin%2Fsecure-docker-with-tls/lists"}