2013-12-04 09:03:51 -05:00
|
|
|
page_title: Using certificates for repository client verification
|
2014-07-20 06:57:36 -04:00
|
|
|
page_description: How to set up and use certificates with a registry to verify access
|
|
|
|
page_keywords: Usage, registry, repository, client, root, certificate, docker, apache, ssl, tls, documentation, examples, articles, tutorials
|
2013-12-04 09:03:51 -05:00
|
|
|
|
|
|
|
# Using certificates for repository client verification
|
|
|
|
|
2014-07-20 06:57:36 -04:00
|
|
|
In [Running Docker with HTTPS](/articles/https), you learned that, by default,
|
|
|
|
Docker runs via a non-networked Unix socket and TLS must be enabled in order
|
|
|
|
to have the Docker client and the daemon communicate securely over HTTPS.
|
2013-12-04 09:03:51 -05:00
|
|
|
|
2014-07-20 06:57:36 -04:00
|
|
|
Now, you will see how to allow the Docker registry (i.e., *a server*) to
|
|
|
|
verify that the Docker daemon (i.e., *a client*) has the right to access the
|
|
|
|
images being hosted with *certificate-based client-server authentication*.
|
2013-12-04 09:03:51 -05:00
|
|
|
|
2014-07-20 06:57:36 -04:00
|
|
|
We will show you how to install a Certificate Authority (CA) root certificate
|
|
|
|
for the registry and how to set the client TLS certificate for verification.
|
2013-12-04 09:03:51 -05:00
|
|
|
|
2014-07-20 06:57:36 -04:00
|
|
|
## Understanding the configuration
|
2013-12-04 09:03:51 -05:00
|
|
|
|
2014-07-20 06:57:36 -04:00
|
|
|
A custom certificate is configured by creating a directory under
|
|
|
|
`/etc/docker/certs.d` using the same name as the registry's hostname (e.g.,
|
|
|
|
`localhost`). All `*.crt` files are added to this directory as CA roots.
|
2013-12-04 09:03:51 -05:00
|
|
|
|
2014-07-20 06:57:36 -04:00
|
|
|
> **Note:**
|
|
|
|
> In the absence of any root certificate authorities, Docker
|
|
|
|
> will use the system default (i.e., host's root CA set).
|
2013-12-04 09:03:51 -05:00
|
|
|
|
2014-07-20 06:57:36 -04:00
|
|
|
The presence of one or more `<filename>.key/cert` pairs indicates to Docker
|
|
|
|
that there are custom certificates required for access to the desired
|
|
|
|
repository.
|
|
|
|
|
|
|
|
> **Note:**
|
|
|
|
> If there are multiple certificates, each will be tried in alphabetical
|
On Red Hat Registry Servers we return 404 on certification errors.
We do this to prevent leakage of information, we don't want people
to be able to probe for existing content.
According to RFC 2616, "This status code (404) is commonly used when the server does not
wish to reveal exactly why the request has been refused, or when no other response i
is applicable."
https://www.ietf.org/rfc/rfc2616.txt
10.4.4 403 Forbidden
The server understood the request, but is refusing to fulfill it.
Authorization will not help and the request SHOULD NOT be repeated.
If the request method was not HEAD and the server wishes to make
public why the request has not been fulfilled, it SHOULD describe the
reason for the refusal in the entity. If the server does not wish to
make this information available to the client, the status code 404
(Not Found) can be used instead.
10.4.5 404 Not Found
The server has not found anything matching the Request-URI. No
indication is given of whether the condition is temporary or
permanent. The 410 (Gone) status code SHOULD be used if the server
knows, through some internally configurable mechanism, that an old
resource is permanently unavailable and has no forwarding address.
This status code is commonly used when the server does not wish to
reveal exactly why the request has been refused, or when no other
response is applicable.
When docker is running through its certificates, it should continue
trying with a new certificate even if it gets back a 404 error code.
Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: rhatdan)
2014-10-14 09:19:45 -04:00
|
|
|
> order. If there is an authentication error (e.g., 403, 404, 5xx, etc.), Docker
|
2014-07-20 06:57:36 -04:00
|
|
|
> will continue to try with the next certificate.
|
|
|
|
|
|
|
|
Our example is set up like this:
|
|
|
|
|
|
|
|
/etc/docker/certs.d/ <-- Certificate directory
|
|
|
|
└── localhost <-- Hostname
|
|
|
|
├── client.cert <-- Client certificate
|
|
|
|
├── client.key <-- Client key
|
|
|
|
└── localhost.crt <-- Registry certificate
|
|
|
|
|
|
|
|
## Creating the client certificates
|
|
|
|
|
|
|
|
You will use OpenSSL's `genrsa` and `req` commands to first generate an RSA
|
2015-02-03 09:42:26 -05:00
|
|
|
key and then use the key to create the certificate.
|
2014-07-20 06:57:36 -04:00
|
|
|
|
|
|
|
$ openssl genrsa -out client.key 1024
|
|
|
|
$ openssl req -new -x509 -text -key client.key -out client.cert
|
|
|
|
|
|
|
|
> **Warning:**:
|
|
|
|
> Using TLS and managing a CA is an advanced topic.
|
|
|
|
> You should be familiar with OpenSSL, x509, and TLS before
|
|
|
|
> attempting to use them in production.
|
|
|
|
|
|
|
|
> **Warning:**
|
|
|
|
> These TLS commands will only generate a working set of certificates on Linux.
|
|
|
|
> The version of OpenSSL in Mac OS X is incompatible with the type of
|
|
|
|
> certificate Docker requires.
|
|
|
|
|
|
|
|
## Testing the verification setup
|
|
|
|
|
|
|
|
You can test this setup by using Apache to host a Docker registry.
|
|
|
|
For this purpose, you can copy a registry tree (containing images) inside
|
|
|
|
the Apache root.
|
|
|
|
|
|
|
|
> **Note:**
|
|
|
|
> You can find such an example [here](
|
|
|
|
> http://people.gnome.org/~alexl/v1.tar.gz) - which contains the busybox image.
|
|
|
|
|
|
|
|
Once you set up the registry, you can use the following Apache configuration
|
|
|
|
to implement certificate-based protection.
|
2013-12-04 09:03:51 -05:00
|
|
|
|
|
|
|
# This must be in the root context, otherwise it causes a re-negotiation
|
2014-07-20 06:57:36 -04:00
|
|
|
# which is not supported by the TLS implementation in go
|
2013-12-04 09:03:51 -05:00
|
|
|
SSLVerifyClient optional_no_ca
|
|
|
|
|
|
|
|
<Location /v1>
|
|
|
|
Action cert-protected /cgi-bin/cert.cgi
|
|
|
|
SetHandler cert-protected
|
|
|
|
|
|
|
|
Header set x-docker-registry-version "0.6.2"
|
|
|
|
SetEnvIf Host (.*) custom_host=$1
|
|
|
|
Header set X-Docker-Endpoints "%{custom_host}e"
|
|
|
|
</Location>
|
|
|
|
|
2014-07-20 06:57:36 -04:00
|
|
|
Save the above content as `/etc/httpd/conf.d/registry.conf`, and
|
|
|
|
continue with creating a `cert.cgi` file under `/var/www/cgi-bin/`.
|
2013-12-04 09:03:51 -05:00
|
|
|
|
|
|
|
#!/bin/bash
|
|
|
|
if [ "$HTTPS" != "on" ]; then
|
|
|
|
echo "Status: 403 Not using SSL"
|
|
|
|
echo "x-docker-registry-version: 0.6.2"
|
|
|
|
echo
|
|
|
|
exit 0
|
|
|
|
fi
|
|
|
|
if [ "$SSL_CLIENT_VERIFY" == "NONE" ]; then
|
|
|
|
echo "Status: 403 Client certificate invalid"
|
|
|
|
echo "x-docker-registry-version: 0.6.2"
|
|
|
|
echo
|
|
|
|
exit 0
|
|
|
|
fi
|
|
|
|
echo "Content-length: $(stat --printf='%s' $PATH_TRANSLATED)"
|
|
|
|
echo "x-docker-registry-version: 0.6.2"
|
|
|
|
echo "X-Docker-Endpoints: $SERVER_NAME"
|
|
|
|
echo "X-Docker-Size: 0"
|
|
|
|
echo
|
|
|
|
|
|
|
|
cat $PATH_TRANSLATED
|
|
|
|
|
2014-07-20 06:57:36 -04:00
|
|
|
This CGI script will ensure that all requests to `/v1` *without* a valid
|
|
|
|
certificate will be returned with a `403` (i.e., HTTP forbidden) error.
|