Allow server-side validation of client ssl certs

This adds a 'ca_file' config option that points to a local
CA cert that will be used to verify certs provided by
connecting clients. The 'ca_file' option is only used if the
server is already properly configured to to use SSL - that
means having a valid 'cert_file' and 'key_file'. If no 'ca_file'
is provided, the behavior will remain the same - the server
will still provide its cert to clients, but it will ignore
certs sent back from those clients.

Fixes bug 1032451

Change-Id: Ie48646b0fc5398ba7cda2fb627b820f533482e00
This commit is contained in:
Brian Waldon 2012-08-03 10:56:06 -07:00
parent 4ac0f4f0a4
commit 006254c505
4 changed files with 33 additions and 3 deletions

View File

@ -187,6 +187,14 @@ SSL-wrapped socket.
Optional. Default: not enabled. Optional. Default: not enabled.
* ``ca_file=PATH``
Path to the CA certificate file the server should use to validate client
certificates provided during an SSL handshake. This is ignored if
``cert_file`` and ''key_file`` are not set.
Optional. Default: not enabled.
* ``registry_client_protocol=PROTOCOL`` * ``registry_client_protocol=PROTOCOL``
If you run a secure Registry server, you need to set this value to ``https`` If you run a secure Registry server, you need to set this value to ``https``

View File

@ -81,6 +81,9 @@ use_syslog = False
# Private key file to use when starting API server securely # Private key file to use when starting API server securely
# key_file = /path/to/keyfile # key_file = /path/to/keyfile
# CA certificate file to use to verify connecting clients
# ca_file = /path/to/cafile
# ================= Security Options ========================== # ================= Security Options ==========================
# AES key for encrypting store 'location' metadata, including # AES key for encrypting store 'location' metadata, including

View File

@ -63,3 +63,6 @@ use_syslog = False
# Private key file to use when starting registry server securely # Private key file to use when starting registry server securely
# key_file = /path/to/keyfile # key_file = /path/to/keyfile
# CA certificate file to use to verify connecting clients
# ca_file = /path/to/cafile

View File

@ -53,6 +53,7 @@ bind_opts = [
socket_opts = [ socket_opts = [
cfg.IntOpt('backlog', default=4096), cfg.IntOpt('backlog', default=4096),
cfg.IntOpt('tcp_keepidle', default=600), cfg.IntOpt('tcp_keepidle', default=600),
cfg.StrOpt('ca_file'),
cfg.StrOpt('cert_file'), cfg.StrOpt('cert_file'),
cfg.StrOpt('key_file'), cfg.StrOpt('key_file'),
] ]
@ -109,15 +110,30 @@ def get_socket(default_port):
"specify both a cert_file and key_file " "specify both a cert_file and key_file "
"option value in your configuration file")) "option value in your configuration file"))
def wrap_ssl(sock):
ssl_kwargs = {
'server_side': True,
'certfile': cert_file,
'keyfile': key_file,
'cert_reqs': ssl.CERT_NONE,
}
if CONF.ca_file:
ssl_kwargs['ca_certs'] = CONF.ca_file
ssl_kwargs['cert_reqs'] = ssl.CERT_REQUIRED
return ssl.wrap_socket(sock, **ssl_kwargs)
sock = None sock = None
retry_until = time.time() + 30 retry_until = time.time() + 30
while not sock and time.time() < retry_until: while not sock and time.time() < retry_until:
try: try:
sock = eventlet.listen(bind_addr, backlog=CONF.backlog, sock = eventlet.listen(bind_addr,
backlog=CONF.backlog,
family=address_family) family=address_family)
if use_ssl: if use_ssl:
sock = ssl.wrap_socket(sock, certfile=cert_file, sock = wrap_ssl(sock)
keyfile=key_file)
except socket.error, err: except socket.error, err:
if err.args[0] != errno.EADDRINUSE: if err.args[0] != errno.EADDRINUSE:
raise raise