Q: Your enterprise security standard mandates zero-trust communication across all infrastructure components. Your private container registry (`registry.internal.company`) holds proprietary proprietary IP. The security team forbids basic authentication over passwords. You must configure mutual TLS (mTLS) on the Docker daemon so that only nodes presenting a cryptographically signed corporate client certificate can push or pull images, while integrating an OAuth2 token authentication service.
Architect and configure enterprise-grade mutual TLS (mTLS) client authentication and Bearer token OAuth2 workflows for private Docker registries (Distribution / Harbor).
Want to master this scenario in a live sandbox? KodeKloud's Docker Certified Associate (DCA) Hands-On Lab Course covers this exact problem with hands-on terminal drills.
🛠️ Production Runbook & Step-by-Step Resolution
Understand Docker Daemon Registry Certificate Resolution Hierarchy
The Docker daemon searches for client certificates and trusted CA roots under `/etc/docker/certs.d/
<!-- Certificate Directory Hierarchy -->
/etc/docker/certs.d/registry.internal.company:5000/
├── ca.crt (Internal Root CA certificate verifying registry)
├── client.cert (Client certificate presented to registry for mTLS)
└── client.key (Client private key)
Generate and Provision mTLS Client Certificates
Generate an x509 client certificate signed by the internal enterprise Public Key Infrastructure (PKI). Ensure the certificate includes the `clientAuth` Extended Key Usage (EKU) attribute.
# Generate client key and CSR with clientAuth extension
openssl req -new -nodes -newkey rsa:4096 \
-keyout client.key -out client.csr \
-subj "/CN=ci-worker-node-42/O=Engineering"
# Sign with corporate intermediate CA
openssl x509 -req -in client.csr -CA internal-ca.crt -CAkey internal-ca.key \
-CAcreateserial -out client.cert -days 365 \
-extfile <(echo "extendedKeyUsage = clientAuth")
Deploy Registry with Client Verification Enforced
Configure the registry server (Docker Distribution or Harbor) to require client certificates by setting `clientcas` and enabling TLS verification.
# registry config.yml
version: 0.1
http:
addr: :5000
tls:
certificate: /certs/registry.crt
key: /certs/registry.key
clientcas:
- /certs/internal-ca.crt
auth:
token:
realm: https://auth.internal.company/service/token
service: container-registry
issuer: auth-server
rootcertbundle: /certs/auth-ca.crt
Verify mTLS Connection and Reject Unauthenticated Clients
Test container pull from authorized node and verify rejection when attempting to pull from a client lacking corporate certificates.
# From authorized node with /etc/docker/certs.d configured:
docker pull registry.internal.company:5000/app:v1
# Successfully pulls image via mTLS handshake!
# From unauthorized node without client cert:
# Output: tls: bad certificate / certificate required
- W
- e
- s
- e
- c
- u
- r
- e
- d
- o
- u
- r
- e
- n
- t
- e
- r
- p
- r
- i
- s
- e
- i
- m
- a
- g
- e
- r
- e
- g
- i
- s
- t
- r
- y
- a
- g
- a
- i
- n
- s
- t
- u
- n
- a
- u
- t
- h
- o
- r
- i
- z
- e
- d
- a
- c
- c
- e
- s
- s
- b
- y
- d
- e
- p
- l
- o
- y
- i
- n
- g
- e
- n
- d
- -
- t
- o
- -
- e
- n
- d
- m
- u
- t
- u
- a
- l
- T
- L
- S
- (
- m
- T
- L
- S
- )
- .
- C
- l
- i
- e
- n
- t
- c
- e
- r
- t
- i
- f
- i
- c
- a
- t
- e
- s
- i
- s
- s
- u
- e
- d
- b
- y
- o
- u
- r
- i
- n
- t
- e
- r
- n
- a
- l
- P
- K
- I
- a
- r
- e
- d
- i
- s
- t
- r
- i
- b
- u
- t
- e
- d
- t
- o
- `
- /
- e
- t
- c
- /
- d
- o
- c
- k
- e
- r
- /
- c
- e
- r
- t
- s
- .
- d
- /
- `
- ,
- e
- n
- s
- u
- r
- i
- n
- g
- t
- h
- a
- t
- o
- n
- l
- y
- a
- u
- t
- h
- e
- n
- t
- i
- c
- a
- t
- e
- d
- ,
- s
- e
- c
- u
- r
- i
- t
- y
- -
- c
- o
- m
- p
- l
- i
- a
- n
- t
- w
- o
- r
- k
- e
- r
- n
- o
- d
- e
- s
- c
- a
- n
- p
- e
- r
- f
- o
- r
- m
- p
- u
- s
- h
- o
- r
- p
- u
- l
- l
- o
- p
- e
- r
- a
- t
- i
- o
- n
- s
- .