Commit 02b2e532 by James Cammarata Committed by Michael DeHaan

Rewriting ssl validation to try multiple certs found in paths

Previously, the function checked only for a single CA root cert, however
some distributions may have multiple certs in a directory. This will now
try any .crt or .pem file contained within several common paths for
each platform.

Fixes #6412
parent eef4096e
...@@ -83,53 +83,64 @@ class SSLValidationHandler(urllib2.BaseHandler): ...@@ -83,53 +83,64 @@ class SSLValidationHandler(urllib2.BaseHandler):
self.port = port self.port = port
self.ca_cert = ca_cert self.ca_cert = ca_cert
def get_ca_cert(self): def get_ca_certs(self):
# tries to find a valid CA cert in one of the # tries to find a valid CA cert in one of the
# standard locations for the current distribution # standard locations for the current distribution
if self.ca_cert and os.path.exists(self.ca_cert): ca_certs = []
# the user provided a custom CA cert (ie. one they paths_checked = []
# uploaded themselves), so use it
return self.ca_cert
ca_cert = None
platform = get_platform() platform = get_platform()
distribution = get_distribution() distribution = get_distribution()
if self.ca_cert:
# the user provided a custom CA cert (ie. one they
# uploaded themselves), so add it to the list first
ca_certs.append(self.ca_cert)
# build a list of paths to check for .crt/.pem files
# based on the platform type
paths_checked.append('/etc/ssl/certs')
if platform == 'Linux': if platform == 'Linux':
if distribution in ('Fedora',): paths_checked.append('/etc/pki/ca-trust/extracted/pem')
ca_cert = '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem' paths_checked.append('/etc/pki/tls/certs')
elif distribution in ('RHEL','CentOS','ScientificLinux'): paths_checked.append('/usr/share/ca-certificates/cacert.org')
ca_cert = '/etc/pki/tls/certs/ca-bundle.crt'
elif distribution in ('Ubuntu','Debian'):
ca_cert = '/usr/share/ca-certificates/cacert.org/cacert.org.crt'
elif platform == 'FreeBSD': elif platform == 'FreeBSD':
ca_cert = '/usr/local/share/certs/ca-root.crt' paths_checked.append('/usr/local/share/certs')
elif platform == 'OpenBSD': elif platform == 'OpenBSD':
ca_cert = '/etc/ssl/cert.pem' paths_checked.append('/etc/ssl')
elif platform == 'NetBSD': elif platform == 'NetBSD':
ca_cert = '/etc/openssl/certs/ca-cert.pem' ca_certs.append('/etc/openssl/certs')
elif platform == 'SunOS':
# FIXME? # fall back to a user-deployed cert in a standard
pass # location if the OS platform one is not available
elif platform == 'AIX': paths_checked.append('/etc/ansible')
# FIXME?
pass for path in paths_checked:
if os.path.exists(path) and os.path.isdir(path):
if ca_cert and os.path.exists(ca_cert): dir_contents = os.listdir(path)
return ca_cert for f in dir_contents:
elif os.path.exists('/etc/ansible/ca-cert.pem'): full_path = os.path.join(path, f)
# fall back to a user-deployed cert in a standard if os.path.isfile(full_path) and os.path.splitext(f)[1] in ('.crt','.pem'):
# location if the OS platform one is not available ca_certs.append(full_path)
return '/etc/ansible/ca-cert.pem'
else: return (ca_certs, paths_checked)
# CA cert isn't available, no validation
return None
def http_request(self, req): def http_request(self, req):
try: ca_certs, paths_checked = self.get_ca_certs()
server_cert = ssl.get_server_certificate((self.hostname, self.port), ca_certs=self.get_ca_cert()) if len(ca_certs) > 0:
except ssl.SSLError: for ca_cert in ca_certs:
self.module.fail_json(msg='failed to validate the SSL certificate for %s:%s. You can use validate_certs=no, however this is unsafe and not recommended' % (self.hostname, self.port)) try:
server_cert = ssl.get_server_certificate((self.hostname, self.port), ca_certs=ca_cert)
return req
except ssl.SSLError:
# try the next one
pass
# fail if we tried all of the certs but none worked
self.module.fail_json(msg='Failed to validate the SSL certificate for %s:%s. ' % (self.hostname, self.port) + \
'Use validate_certs=no or make sure your managed systems have a valid CA certificate installed. ' + \
'Paths checked for this platform: %s' % ", ".join(paths_checked))
# if no CA certs were found, we just fall through
# to here and return the request with no SSL validation
return req return req
https_request = http_request https_request = http_request
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment