mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Use secure method to acquire IPA CA certificate
Major changes ipa-client-install: * Use GSSAPI connection to LDAP server to download CA cert (now the default method) * Add --ca-cert-file option to load the CA cert from a disk file. Validate the file. If this option is used the supplied CA cert is considered definitive. * The insecure HTTP retrieval method is still supported but it must be explicitly forced and a warning will be emitted. * Remain backward compatible with unattended case (except for aberrant condition when preexisting /etc/ipa/ca.crt differs from securely obtained CA cert, see below) * If /etc/ipa/ca.crt CA cert preexists the validate it matches the securely acquired CA cert, if not: - If --unattended and not --force abort with error - If interactive query user to accept new CA cert, if not abort In either case warn user. * If interactive and LDAP retrieval fails prompt user if they want to proceed with insecure HTTP method * If not interactive and LDAP retrieval fails abort unless --force * Backup preexisting /etc/ipa/ca.crt in FileStore prior to execution, if ipa-client-install fails it will be restored. Other changes: * Add new exception class CertificateInvalidError * Add utility convert_ldap_error() to ipalib.ipautil * Replace all hardcoded instances of /etc/ipa/ca.crt in ipa-client-install with CACERT constant (matches existing practice elsewhere). * ipadiscovery no longer retrieves CA cert via HTTP. * Handle LDAP minssf failures during discovery, treat failure to check ldap server as a warninbg in absebce of a provided CA certificate via --ca-cert-file or though existing /etc/ipa/ca.crt file. Signed-off-by: Simo Sorce <simo@redhat.com> Signed-off-by: Rob Crittenden <rcritten@redhat.com>
This commit is contained in:
committed by
Rob Crittenden
parent
91f4af7e6a
commit
a1991aeac1
@@ -30,11 +30,14 @@ from ipapython.ipautil import run, CalledProcessError, valid_ip, get_ipa_basedn,
|
||||
realm_to_suffix, format_netloc
|
||||
from ipapython.dn import DN
|
||||
|
||||
CACERT = '/etc/ipa/ca.crt'
|
||||
|
||||
NOT_FQDN = -1
|
||||
NO_LDAP_SERVER = -2
|
||||
REALM_NOT_FOUND = -3
|
||||
NOT_IPA_SERVER = -4
|
||||
NO_ACCESS_TO_LDAP = -5
|
||||
NO_TLS_LDAP = -6
|
||||
BAD_HOST_CONFIG = -10
|
||||
UNKNOWN_ERROR = -15
|
||||
|
||||
@@ -45,6 +48,7 @@ error_names = {
|
||||
REALM_NOT_FOUND: 'REALM_NOT_FOUND',
|
||||
NOT_IPA_SERVER: 'NOT_IPA_SERVER',
|
||||
NO_ACCESS_TO_LDAP: 'NO_ACCESS_TO_LDAP',
|
||||
NO_TLS_LDAP: 'NO_TLS_LDAP',
|
||||
BAD_HOST_CONFIG: 'BAD_HOST_CONFIG',
|
||||
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
|
||||
}
|
||||
@@ -135,7 +139,7 @@ class IPADiscovery(object):
|
||||
domain = domain[p+1:]
|
||||
return (None, None)
|
||||
|
||||
def search(self, domain = "", server = "", hostname=None):
|
||||
def search(self, domain = "", server = "", hostname=None, ca_cert_path=None):
|
||||
root_logger.debug("[IPA Discovery]")
|
||||
root_logger.debug(
|
||||
'Starting IPA discovery with domain=%s, server=%s, hostname=%s',
|
||||
@@ -224,14 +228,14 @@ class IPADiscovery(object):
|
||||
ldapaccess = True
|
||||
if self.server:
|
||||
# check ldap now
|
||||
ldapret = self.ipacheckldap(self.server, self.realm)
|
||||
ldapret = self.ipacheckldap(self.server, self.realm, ca_cert_path=ca_cert_path)
|
||||
|
||||
if ldapret[0] == 0:
|
||||
self.server = ldapret[1]
|
||||
self.realm = ldapret[2]
|
||||
self.server_source = self.realm_source = (
|
||||
'Discovered from LDAP DNS records in %s' % self.server)
|
||||
elif ldapret[0] == NO_ACCESS_TO_LDAP:
|
||||
elif ldapret[0] == NO_ACCESS_TO_LDAP or ldapret[0] == NO_TLS_LDAP:
|
||||
ldapaccess = False
|
||||
|
||||
# If one of LDAP servers checked rejects access (maybe anonymous
|
||||
@@ -260,12 +264,10 @@ class IPADiscovery(object):
|
||||
|
||||
return ldapret[0]
|
||||
|
||||
def ipacheckldap(self, thost, trealm):
|
||||
def ipacheckldap(self, thost, trealm, ca_cert_path=None):
|
||||
"""
|
||||
Given a host and kerberos realm verify that it is an IPA LDAP
|
||||
server hosting the realm. The connection is an SSL connection
|
||||
so the remote IPA CA cert must be available at
|
||||
http://HOST/ipa/config/ca.crt
|
||||
server hosting the realm.
|
||||
|
||||
Returns a list [errno, host, realm] or an empty list on error.
|
||||
Errno is an error number:
|
||||
@@ -279,31 +281,17 @@ class IPADiscovery(object):
|
||||
|
||||
i = 0
|
||||
|
||||
# Get the CA certificate
|
||||
try:
|
||||
# Create TempDir
|
||||
temp_ca_dir = tempfile.mkdtemp()
|
||||
except OSError, e:
|
||||
raise RuntimeError("Creating temporary directory failed: %s" % str(e))
|
||||
|
||||
try:
|
||||
run(["/usr/bin/wget", "-O", "%s/ca.crt" % temp_ca_dir, "-T", "15", "-t", "2",
|
||||
"http://%s/ipa/config/ca.crt" % format_netloc(thost)])
|
||||
except CalledProcessError, e:
|
||||
root_logger.error('Retrieving CA from %s failed', thost)
|
||||
root_logger.debug('Retrieving CA from %s failed: %s', thost, str(e))
|
||||
return [NOT_IPA_SERVER]
|
||||
|
||||
#now verify the server is really an IPA server
|
||||
try:
|
||||
ldap_url = "ldap://" + format_netloc(thost, 389)
|
||||
root_logger.debug("Init LDAP connection with: %s", ldap_url)
|
||||
lh = ldap.initialize(ldap_url)
|
||||
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, True)
|
||||
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, "%s/ca.crt" % temp_ca_dir)
|
||||
if ca_cert_path:
|
||||
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, True)
|
||||
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, ca_cert_path)
|
||||
lh.set_option(ldap.OPT_X_TLS_DEMAND, True)
|
||||
lh.start_tls_s()
|
||||
lh.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
|
||||
lh.set_option(ldap.OPT_X_TLS_DEMAND, True)
|
||||
lh.start_tls_s()
|
||||
lh.simple_bind_s("","")
|
||||
|
||||
# get IPA base DN
|
||||
@@ -358,14 +346,16 @@ class IPADiscovery(object):
|
||||
root_logger.debug("LDAP Error: Anonymous acces not allowed")
|
||||
return [NO_ACCESS_TO_LDAP]
|
||||
|
||||
# We should only get UNWILLING_TO_PERFORM if the remote LDAP server
|
||||
# has minssf > 0 and we have attempted a non-TLS connection.
|
||||
if ca_cert_path is None and isinstance(err, ldap.UNWILLING_TO_PERFORM):
|
||||
root_logger.debug("LDAP server returned UNWILLING_TO_PERFORM. This likely means that minssf is enabled")
|
||||
return [NO_TLS_LDAP]
|
||||
|
||||
root_logger.error("LDAP Error: %s: %s" %
|
||||
(err.args[0]['desc'], err.args[0].get('info', '')))
|
||||
return [UNKNOWN_ERROR]
|
||||
|
||||
finally:
|
||||
os.remove("%s/ca.crt" % temp_ca_dir)
|
||||
os.rmdir(temp_ca_dir)
|
||||
|
||||
|
||||
def ipadns_search_srv(self, domain, srv_record_name, default_port,
|
||||
break_on_first=True):
|
||||
|
||||
Reference in New Issue
Block a user