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
This commit is contained in:
parent
0b0ca95731
commit
804e4166c8
1 changed files with 50 additions and 39 deletions
|
@ -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 platform == 'Linux':
|
|
||||||
if distribution in ('Fedora',):
|
|
||||||
ca_cert = '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem'
|
|
||||||
elif distribution in ('RHEL','CentOS','ScientificLinux'):
|
|
||||||
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':
|
|
||||||
ca_cert = '/usr/local/share/certs/ca-root.crt'
|
|
||||||
elif platform == 'OpenBSD':
|
|
||||||
ca_cert = '/etc/ssl/cert.pem'
|
|
||||||
elif platform == 'NetBSD':
|
|
||||||
ca_cert = '/etc/openssl/certs/ca-cert.pem'
|
|
||||||
elif platform == 'SunOS':
|
|
||||||
# FIXME?
|
|
||||||
pass
|
|
||||||
elif platform == 'AIX':
|
|
||||||
# FIXME?
|
|
||||||
pass
|
|
||||||
|
|
||||||
if ca_cert and os.path.exists(ca_cert):
|
if self.ca_cert:
|
||||||
return ca_cert
|
# the user provided a custom CA cert (ie. one they
|
||||||
elif os.path.exists('/etc/ansible/ca-cert.pem'):
|
# uploaded themselves), so add it to the list first
|
||||||
# fall back to a user-deployed cert in a standard
|
ca_certs.append(self.ca_cert)
|
||||||
# location if the OS platform one is not available
|
|
||||||
return '/etc/ansible/ca-cert.pem'
|
# build a list of paths to check for .crt/.pem files
|
||||||
else:
|
# based on the platform type
|
||||||
# CA cert isn't available, no validation
|
paths_checked.append('/etc/ssl/certs')
|
||||||
return None
|
if platform == 'Linux':
|
||||||
|
paths_checked.append('/etc/pki/ca-trust/extracted/pem')
|
||||||
|
paths_checked.append('/etc/pki/tls/certs')
|
||||||
|
paths_checked.append('/usr/share/ca-certificates/cacert.org')
|
||||||
|
elif platform == 'FreeBSD':
|
||||||
|
paths_checked.append('/usr/local/share/certs')
|
||||||
|
elif platform == 'OpenBSD':
|
||||||
|
paths_checked.append('/etc/ssl')
|
||||||
|
elif platform == 'NetBSD':
|
||||||
|
ca_certs.append('/etc/openssl/certs')
|
||||||
|
|
||||||
|
# fall back to a user-deployed cert in a standard
|
||||||
|
# location if the OS platform one is not available
|
||||||
|
paths_checked.append('/etc/ansible')
|
||||||
|
|
||||||
|
for path in paths_checked:
|
||||||
|
if os.path.exists(path) and os.path.isdir(path):
|
||||||
|
dir_contents = os.listdir(path)
|
||||||
|
for f in dir_contents:
|
||||||
|
full_path = os.path.join(path, f)
|
||||||
|
if os.path.isfile(full_path) and os.path.splitext(f)[1] in ('.crt','.pem'):
|
||||||
|
ca_certs.append(full_path)
|
||||||
|
|
||||||
|
return (ca_certs, paths_checked)
|
||||||
|
|
||||||
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
|
||||||
|
|
Loading…
Reference in a new issue