diff options
-rwxr-xr-x | ipa-client/ipa-install/ipa-client-install | 67 | ||||
-rw-r--r-- | ipapython/certmonger.py | 80 |
2 files changed, 134 insertions, 13 deletions
diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install index 390e60037..720e81353 100755 --- a/ipa-client/ipa-install/ipa-client-install +++ b/ipa-client/ipa-install/ipa-client-install @@ -49,7 +49,7 @@ error was: """ % sys.exc_value sys.exit(1) -client_nss_nickname = 'IPA Machine Certificate - %s' % socket.getfqdn() +client_nss_nickname_format = 'IPA Machine Certificate - %s' def parse_options(): parser = IPAOptionParser(version=version.VERSION) @@ -186,6 +186,28 @@ def uninstall(options, env): print "IPA client is not configured on this system." return 2 + sssdconfig = SSSDConfig.SSSDConfig() + sssdconfig.import_config() + domains = sssdconfig.list_active_domains() + + hostname = None + for name in domains: + domain = sssdconfig.get_domain(name) + try: + provider = domain.get_option('id_provider') + except SSSDConfig.NoOptionError: + continue + if provider == "ipa": + try: + hostname = domain.get_option('ipa_hostname') + except SSSDConfig.NoOptionError: + continue + + if hostname is None: + hostname = socket.getfqdn() + + client_nss_nickname = client_nss_nickname_format % hostname + # Remove our host cert and CA cert if nickname_exists("IPA CA"): try: @@ -214,6 +236,9 @@ def uninstall(options, env): except: pass + # Remove any special principal names we added to the IPA CA helper + certmonger.remove_principal_from_cas() + try: chkconfig('certmonger', 'off') except: @@ -221,7 +246,7 @@ def uninstall(options, env): if not options.on_master: print "Unenrolling client from IPA server" - join_args = ["/usr/sbin/ipa-join", "--unenroll"] + join_args = ["/usr/sbin/ipa-join", "--unenroll", "-h", hostname] (stdout, stderr, returncode) = run(join_args, raiseonerr=False, env=env) if returncode != 0: print "Unenrolling host failed: %s" % stderr @@ -453,8 +478,27 @@ def configure_krb5_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, d return 0 -def configure_certmonger(fstore, subject_base, cli_realm, options): +def configure_certmonger(fstore, subject_base, cli_realm, hostname, options): started = True + principal = 'host/%s@%s' % (hostname, cli_realm) + + # Ensure that certmonger has been started at least once to generate the + # cas files in /var/lib/certmonger/cas. + try: + service('certmonger', 'restart') + except: + pass + + + if options.hostname: + # It needs to be stopped if we touch them + try: + service('certmonger', 'stop') + except: + pass + # If the hostname is explicitly set then we need to tell certmonger + # which principal name to use when requesting certs. + certmonger.add_principal_to_cas(principal) try: service('certmonger', 'restart') @@ -471,8 +515,8 @@ def configure_certmonger(fstore, subject_base, cli_realm, options): # Request our host cert if started: - subject = 'CN=%s,%s' % (socket.getfqdn(), subject_base) - principal = 'host/%s@%s' % (socket.getfqdn(), cli_realm) + client_nss_nickname = client_nss_nickname_format % hostname + subject = 'CN=%s,%s' % (hostname, subject_base) try: run(["ipa-getcert", "request", "-d", "/etc/pki/nssdb", "-n", client_nss_nickname, "-N", subject, "-K", principal]) except: @@ -488,6 +532,8 @@ def configure_sssd_conf(fstore, cli_realm, cli_domain, cli_server, options): domain.set_option('ipa_server', '_srv_, %s' % cli_server) domain.set_option('ipa_domain', cli_domain) + if options.hostname: + domain.set_option('ipa_hostname', options.hostname) if cli_domain.lower() != cli_realm.lower(): domain.set_option('krb5_realm', cli_realm) @@ -834,6 +880,10 @@ def main(): # Add the CA to the default NSS database and trust it run(["/usr/bin/certutil", "-A", "-d", "/etc/pki/nssdb", "-n", "IPA CA", "-t", "CT,C,C", "-a", "-i", "/etc/ipa/ca.crt"]) + if options.hostname: + hostname = options.hostname + else: + hostname = socket.getfqdn() # If on master assume kerberos is already configured properly. if not options.on_master: @@ -844,15 +894,10 @@ def main(): print "Configured /etc/krb5.conf for IPA realm " + cli_realm - configure_certmonger(fstore, subject_base, cli_realm, options) + configure_certmonger(fstore, subject_base, cli_realm, hostname, options) #Try to update the DNS records, failure is not fatal if not options.on_master: - if options.hostname: - hostname = options.hostname - else: - hostname = socket.gethostname() - client_dns(cli_server, hostname, options.dns_updates) if options.sssd: diff --git a/ipapython/certmonger.py b/ipapython/certmonger.py index 15ae1e52f..1ed907686 100644 --- a/ipapython/certmonger.py +++ b/ipapython/certmonger.py @@ -27,6 +27,7 @@ import time from ipapython import ipautil REQUEST_DIR='/var/lib/certmonger/requests/' +CA_DIR='/var/lib/certmonger/cas/' def find_request_value(filename, directive): """ @@ -34,7 +35,7 @@ def find_request_value(filename, directive): It tries to do this a number of times because sometimes there is a delay when ipa-getcert returns and the file is fully updated, particularly - when doing a request. Genrerating a CSR is fast but not instantaneous. + when doing a request. Generating a CSR is fast but not instantaneous. """ tries = 1 value = None @@ -126,7 +127,7 @@ def add_request_value(request_id, directive, value): def add_principal(request_id, principal): """ - In order for a certmonger request to be renwable it needs a principal. + In order for a certmonger request to be renewable it needs a principal. When an existing certificate is added via start-tracking it won't have a principal. @@ -241,6 +242,81 @@ def stop_tracking(secdir, request_id=None, nickname=None): return (stdout, stderr, returncode) +def _find_IPA_ca(): + """ + Look through all the certmonger CA files to find the one that + has id=IPA + + We can use find_request_value because the ca files have the + same file format. + """ + fileList=os.listdir(CA_DIR) + for file in fileList: + value = find_request_value('%s/%s' % (CA_DIR, file), 'id') + if value is not None and value.strip() == 'IPA': + return '%s/%s' % (CA_DIR, file) + + return None + +def add_principal_to_cas(principal): + """ + If the hostname we were passed to use in ipa-client-install doesn't + match the value of gethostname() then we need to append + -k host/HOSTNAME@REALM to the ca helper defined for + /usr/libexec/certmonger/ipa-submit. + + We also need to restore this on uninstall. + + The certmonger service MUST be stopped in order for this to work. + """ + cafile = _find_IPA_ca() + if cafile is None: + return + + update = False + fp = open(cafile, 'r') + lines = fp.readlines() + fp.close() + + for i in xrange(len(lines)): + if lines[i].startswith('ca_external_helper') and \ + lines[i].find('-k') == -1: + lines[i] = '%s -k %s\n' % (lines[i].strip(), principal) + update = True + + if update: + fp = open(cafile, 'w') + for line in lines: + fp.write(line) + fp.close() + +def remove_principal_from_cas(): + """ + Remove any -k principal options from the ipa_submit helper. + + The certmonger service MUST be stopped in order for this to work. + """ + cafile = _find_IPA_ca() + if cafile is None: + return + + update = False + fp = open(cafile, 'r') + lines = fp.readlines() + fp.close() + + for i in xrange(len(lines)): + if lines[i].startswith('ca_external_helper') and \ + lines[i].find('-k') > 0: + lines[i] = lines[i].strip().split(' ')[0] + '\n' + update = True + + if update: + fp = open(cafile, 'w') + for line in lines: + fp.write(line) + fp.close() + if __name__ == '__main__': request_id = request_cert("/etc/httpd/alias", "Test", "cn=tiger.example.com,O=IPA", "HTTP/tiger.example.com@EXAMPLE.COM") csr = get_request_value(request_id, 'csr') |