diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py index e9006b649..aaa1943f9 100644 --- a/ipaserver/install/server/replicainstall.py +++ b/ipaserver/install/server/replicainstall.py @@ -27,8 +27,7 @@ from ipaclient.install.ipachangeconf import IPAChangeConf import ipaclient.install.timeconf from ipalib.install import certstore, sysrestore from ipalib.install.kinit import kinit_keytab -from ipapython import ipaldap, ipautil, version -from ipapython.certdb import IPA_CA_TRUST_FLAGS, EXTERNAL_CA_TRUST_FLAGS +from ipapython import ipaldap, ipautil from ipapython.dn import DN from ipapython.admintool import ScriptError from ipaplatform import services @@ -39,10 +38,10 @@ from ipalib.config import Env from ipalib.util import no_matching_interface_for_ip_address_warning from ipaclient.install.client import configure_krb5_conf, purge_host_keytab from ipaserver.install import ( - adtrust, bindinstance, ca, certs, dns, dsinstance, httpinstance, + adtrust, bindinstance, ca, dns, dsinstance, httpinstance, installutils, kra, krbinstance, otpdinstance, custodiainstance, service) from ipaserver.install.installutils import ( - create_replica_config, ReplicaConfig, load_pkcs12, is_ipa_configured) + ReplicaConfig, load_pkcs12, is_ipa_configured) from ipaserver.install.replication import ( ReplicationManager, replica_conn_check) import SSSDConfig @@ -79,7 +78,7 @@ def make_pkcs12_info(directory, cert_name, password_name): def install_replica_ds(config, options, ca_is_configured, remote_api, - ca_file, promote=False, pkcs12_info=None, fstore=None): + ca_file, pkcs12_info=None, fstore=None): dsinstance.check_ports() # if we have a pkcs12 file, create the cert db from @@ -108,7 +107,6 @@ def install_replica_ds(config, options, ca_is_configured, remote_api, pkcs12_info=pkcs12_info, ca_is_configured=ca_is_configured, ca_file=ca_file, - promote=promote, # we need promote because of replication setup api=remote_api, setup_pkinit=not options.no_pkinit, ) @@ -116,8 +114,7 @@ def install_replica_ds(config, options, ca_is_configured, remote_api, return ds -def install_krb(config, setup_pkinit=False, pkcs12_info=None, promote=False, - fstore=None): +def install_krb(config, setup_pkinit=False, pkcs12_info=None, fstore=None): krb = krbinstance.KrbInstance(fstore=fstore) # pkinit files @@ -129,8 +126,7 @@ def install_krb(config, setup_pkinit=False, pkcs12_info=None, promote=False, config.master_host_name, config.host_name, config.domain_name, config.dirman_password, setup_pkinit, pkcs12_info, - subject_base=config.subject_base, - promote=promote) + subject_base=config.subject_base) return krb @@ -154,9 +150,7 @@ def install_ca_cert(ldap, base_dn, realm, cafile, destfile=paths.IPA_CA_CRT): def install_http(config, auto_redirect, ca_is_configured, ca_file, - promote=False, - pkcs12_info=None, - fstore=None): + pkcs12_info=None, fstore=None): # if we have a pkcs12 file, create the cert db from # that. Otherwise the ds setup will create the CA # cert @@ -169,7 +163,7 @@ def install_http(config, auto_redirect, ca_is_configured, ca_file, config.realm_name, config.host_name, config.domain_name, config.dirman_password, pkcs12_info, auto_redirect=auto_redirect, ca_file=ca_file, - ca_is_configured=ca_is_configured, promote=promote, + ca_is_configured=ca_is_configured, promote=True, subject_base=config.subject_base, master_fqdn=config.master_host_name) return http @@ -679,244 +673,6 @@ def enroll_dl0_replica(installer, fstore, remote_api, debug=False): raise RuntimeError("Failed to fetch host keytab: {}".format(e)) -@common_cleanup -@preserve_enrollment_state -def install_check(installer): - options = installer - filename = installer.replica_file - installer._enrollment_performed = False - - print("This program will set up FreeIPA replica.") - print("Version {}".format(version.VERSION)) - print("") - - if tasks.is_fips_enabled(): - raise RuntimeError( - "Installing IPA server in FIPS mode on domain level 0 is not " - "supported") - - # check selinux status, http and DS ports, NTP conflicting services - common_check(options.no_ntp) - - client_fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) - if client_fstore.has_files(): - raise ScriptError( - "IPA client is already configured on this system.\n" - "Please uninstall it first before configuring the replica, " - "using 'ipa-client-install --uninstall'.") - - sstore = sysrestore.StateFile(paths.SYSRESTORE) - - fstore = sysrestore.FileStore(paths.SYSRESTORE) - - # get the directory manager password - dirman_password = options.password - if not dirman_password: - try: - dirman_password = get_dirman_password() - except KeyboardInterrupt: - raise ScriptError(rval=0) - if dirman_password is None: - raise ScriptError("Directory Manager password required") - - config = create_replica_config(dirman_password, filename, options) - config.ca_host_name = config.master_host_name - config.kra_host_name = config.ca_host_name - - config.setup_ca = options.setup_ca - config.setup_kra = options.setup_kra - config.basedn = ipautil.realm_to_suffix(config.realm_name) - installer._top_dir = config.top_dir - installer._config = config - - ca_enabled = os.path.isfile(os.path.join(config.dir, "cacert.p12")) - # Create the management framework config file - # Note: We must do this before bootstraping and finalizing ipalib.api - create_ipa_conf(fstore, config, ca_enabled) - - api.bootstrap(in_server=True, context='installer', confdir=paths.ETC_IPA) - api.finalize() - - installutils.verify_fqdn(config.master_host_name, options.no_host_dns) - - cafile = os.path.join(config.dir, "ca.crt") - if not os.path.isfile(cafile): - raise RuntimeError("CA cert file is not available. Please run " - "ipa-replica-prepare to create a new replica file.") - - # look up CA subject name (needed for DS certmap.conf) - options.ca_subject = unicode( - DN(x509.load_certificate_from_file(cafile).subject)) - - for pkcs12_name, pin_name in (('dscert.p12', 'dirsrv_pin.txt'), - ('httpcert.p12', 'http_pin.txt')): - pkcs12_info = make_pkcs12_info(config.dir, pkcs12_name, pin_name) - tmp_db_dir = tempfile.mkdtemp('ipa') - try: - tmp_db = certs.CertDB(config.realm_name, - nssdir=tmp_db_dir, - subject_base=config.subject_base) - if ca_enabled: - trust_flags = IPA_CA_TRUST_FLAGS - else: - trust_flags = EXTERNAL_CA_TRUST_FLAGS - tmp_db.create_from_pkcs12(pkcs12_info[0], pkcs12_info[1], - ca_file=cafile, - trust_flags=trust_flags) - if not tmp_db.find_server_certs(): - raise RuntimeError( - "Could not find a suitable server cert in import in %s" % - pkcs12_info[0]) - except Exception as e: - logger.error('%s', e) - raise RuntimeError( - "Server cert is not valid. Please run ipa-replica-prepare to " - "create a new replica file.") - finally: - shutil.rmtree(tmp_db_dir) - - ldapuri = 'ldaps://%s' % ipautil.format_netloc(config.master_host_name) - remote_api = create_api(mode=None) - remote_api.bootstrap(in_server=True, - context='installer', - confdir=paths.ETC_IPA, - ldap_uri=ldapuri) - remote_api.finalize() - installer._remote_api = remote_api - - conn = remote_api.Backend.ldap2 - replman = None - try: - # Try out the password - conn.connect(bind_dn=ipaldap.DIRMAN_DN, bind_pw=config.dirman_password, - cacert=cafile) - replman = ReplicationManager(config.realm_name, - config.master_host_name, - config.dirman_password) - - # Check that we don't already have a replication agreement - if replman.get_replication_agreement(config.host_name): - logger.info('Error: A replication agreement for this ' - 'host already exists.') - msg = ("A replication agreement for this host already exists. " - "It needs to be removed.\n" - "Run this on the master that generated the info file:\n" - " %% ipa-replica-manage del %s --force" % - config.host_name) - raise ScriptError(msg, rval=3) - - domain_level = current_domain_level(remote_api) - check_domain_level_is_supported(domain_level) - if domain_level != constants.DOMAIN_LEVEL_0: - raise RuntimeError( - "You used the wrong mechanism to install a replica in " - "domain level {dl}:\n" - "\tFor domain level >= 1 replica installation, first join the " - "domain by running ipa-client-install, then run " - "ipa-replica-install without a replica file." - .format(dl=domain_level) - ) - - # Check pre-existing host entry - try: - conn.find_entries( - u'fqdn=%s' % config.host_name, ['fqdn'], - DN(api.env.container_host, api.env.basedn)) - except errors.NotFound: - pass - else: - logger.info('Error: Host %s already exists on the master ' - 'server.', config.host_name) - msg = ("The host %s already exists on the master server.\n" - "You should remove it before proceeding:\n" - " %% ipa host-del %s" % - (config.host_name, config.host_name)) - raise ScriptError(msg, rval=3) - - dns_masters = remote_api.Object['dnsrecord'].get_dns_masters() - if dns_masters: - if not options.no_host_dns: - master = config.master_host_name - logger.debug('Check forward/reverse DNS resolution') - resolution_ok = ( - check_dns_resolution(master, dns_masters) and - check_dns_resolution(config.host_name, dns_masters)) - if not resolution_ok and installer.interactive: - if not ipautil.user_input("Continue?", False): - raise ScriptError(rval=0) - else: - logger.debug('No IPA DNS servers, ' - 'skipping forward/reverse resolution check') - - kra_enabled = remote_api.Command.kra_is_enabled()['result'] - - if ca_enabled: - options.realm_name = config.realm_name - options.host_name = config.host_name - ca.install_check(False, config, options) - - if kra_enabled: - try: - kra.install_check(remote_api, config, options) - except RuntimeError as e: - raise ScriptError(e) - - if options.setup_dns: - dns.install_check(False, remote_api, True, options, - config.host_name) - config.ips = dns.ip_addresses - else: - config.ips = installutils.get_server_ip_address( - config.host_name, not installer.interactive, False, - options.ip_addresses) - - # check addresses here, dns module is doing own check - no_matching_interface_for_ip_address_warning(config.ips) - - if options.setup_adtrust: - adtrust.install_check(False, options, remote_api) - - enroll_dl0_replica(installer, fstore, remote_api) - ccache = os.environ['KRB5CCNAME'] - kinit_keytab('host/{env.host}@{env.realm}'.format(env=api.env), - paths.KRB5_KEYTAB, - ccache) - - except errors.ACIError: - raise ScriptError("\nThe password provided is incorrect for LDAP server " - "%s" % config.master_host_name) - except errors.LDAPError: - raise ScriptError("\nUnable to connect to LDAP server %s" % - config.master_host_name) - finally: - if replman and replman.conn: - replman.conn.unbind() - if conn.isconnected(): - conn.disconnect() - - # installer needs to update hosts file when DNS subsystem will be - # installed or custom addresses are used - if options.setup_dns or options.ip_addresses: - installer._update_hosts_file = True - - # check connection - if not options.skip_conncheck: - try: - del os.environ['KRB5CCNAME'] - replica_conn_check( - config.master_host_name, config.host_name, config.realm_name, - options.setup_ca, config.ca_ds_port, options.admin_password, - ca_cert_file=cafile) - finally: - os.environ['KRB5CCNAME'] = ccache - - installer._ca_enabled = ca_enabled - installer._kra_enabled = kra_enabled - installer._ca_file = cafile - installer._fstore = fstore - installer._sstore = sstore - - def ensure_enrolled(installer): args = [paths.IPA_CLIENT_INSTALL, "--unattended"] stdin = None @@ -1373,10 +1129,7 @@ def install(installer): ca_enabled = installer._ca_enabled kra_enabled = installer._kra_enabled fstore = installer._fstore - sstore = installer._sstore config = installer._config - config.promote = installer.promote - promote = installer.promote cafile = installer._ca_file dirsrv_pkcs12_info = installer._dirsrv_pkcs12_info http_pkcs12_info = installer._http_pkcs12_info @@ -1386,40 +1139,25 @@ def install(installer): conn = remote_api.Backend.ldap2 ccache = os.environ['KRB5CCNAME'] - if promote: - if installer._add_to_ipaservers: - try: - conn.connect(ccache=installer._ccache) - remote_api.Command['hostgroup_add_member']( - u'ipaservers', - host=[unicode(api.env.host)], - ) - finally: - if conn.isconnected(): - conn.disconnect() - os.environ['KRB5CCNAME'] = ccache - config.dirman_password = ipautil.ipa_generate_password() + if installer._add_to_ipaservers: + try: + conn.connect(ccache=installer._ccache) + remote_api.Command['hostgroup_add_member']( + u'ipaservers', + host=[unicode(api.env.host)], + ) + finally: + if conn.isconnected(): + conn.disconnect() + os.environ['KRB5CCNAME'] = ccache + config.dirman_password = ipautil.ipa_generate_password() - # FIXME: allow to use passed in certs instead - if ca_enabled: - configure_certmonger() - elif installer._update_hosts_file: - installutils.update_hosts_file(config.ips, config.host_name, fstore) - - if not promote and not options.no_ntp: - # in DL1, chrony is already installed - ipaclient.install.timeconf.force_chrony(sstore) + # FIXME: allow to use passed in certs instead + if ca_enabled: + configure_certmonger() try: - if promote: - conn.connect(ccache=ccache) - else: - # dmlvl 0 replica install should always use DM credentials - # to create remote LDAP connection. Since ACIs permitting hosts - # to manage their own services were added in 4.2 release, - # the master denies this operations. - conn.connect(bind_dn=ipaldap.DIRMAN_DN, cacert=cafile, - bind_pw=config.dirman_password) + conn.connect(ccache=ccache) # Update and istall updated CA file cafile = install_ca_cert(conn, api.env.basedn, api.env.realm, cafile) @@ -1432,7 +1170,6 @@ def install(installer): ds = install_replica_ds(config, options, ca_enabled, remote_api, ca_file=cafile, - promote=promote, pkcs12_info=dirsrv_pkcs12_info, fstore=fstore) @@ -1443,40 +1180,37 @@ def install(installer): if conn.isconnected(): conn.disconnect() - if promote: - # Create the management framework config file. Do this irregardless - # of the state of DS installation. Even if it fails, - # we need to have master-like configuration in order to perform a - # successful uninstallation - # The configuration creation has to be here otherwise previous call - # To config certmonger would try to connect to local server - create_ipa_conf(fstore, config, ca_enabled) + # Create the management framework config file. Do this irregardless + # of the state of DS installation. Even if it fails, + # we need to have master-like configuration in order to perform a + # successful uninstallation + # The configuration creation has to be here otherwise previous call + # To config certmonger would try to connect to local server + create_ipa_conf(fstore, config, ca_enabled) krb = install_krb( config, setup_pkinit=not options.no_pkinit, pkcs12_info=pkinit_pkcs12_info, - promote=promote, fstore=fstore) - if promote: - # We need to point to the master when certmonger asks for - # a DS or HTTP certificate. - # During http installation, the /hostname principal is - # created locally then the installer waits for the entry to appear - # on the master selected for the installation. - # In a later step, the installer requests a SSL certificate through - # Certmonger (and the op adds the principal if it does not exist yet). - # If xmlrpc_uri points to the soon-to-be replica, - # the httpd service is not ready yet to handle certmonger requests - # and certmonger tries to find another master. The master can be - # different from the one selected for the installation, and it is - # possible that the principal has not been replicated yet. This - # may lead to a replication conflict. - # This is why we need to force the use of the same master by - # setting xmlrpc_uri - create_ipa_conf(fstore, config, ca_enabled, - master=config.master_host_name) + # We need to point to the master when certmonger asks for + # a DS or HTTP certificate. + # During http installation, the /hostname principal is + # created locally then the installer waits for the entry to appear + # on the master selected for the installation. + # In a later step, the installer requests a SSL certificate through + # Certmonger (and the op adds the principal if it does not exist yet). + # If xmlrpc_uri points to the soon-to-be replica, + # the httpd service is not ready yet to handle certmonger requests + # and certmonger tries to find another master. The master can be + # different from the one selected for the installation, and it is + # possible that the principal has not been replicated yet. This + # may lead to a replication conflict. + # This is why we need to force the use of the same master by + # setting xmlrpc_uri + create_ipa_conf(fstore, config, ca_enabled, + master=config.master_host_name) # we now need to enable ssl on the ds ds.enable_ssl() @@ -1484,15 +1218,13 @@ def install(installer): install_http( config, auto_redirect=not options.no_ui_redirect, - promote=promote, pkcs12_info=http_pkcs12_info, ca_is_configured=ca_enabled, ca_file=cafile, fstore=fstore) - if promote: - # Need to point back to ourself after the cert for HTTP is obtained - create_ipa_conf(fstore, config, ca_enabled) + # Need to point back to ourself after the cert for HTTP is obtained + create_ipa_conf(fstore, config, ca_enabled) otpd = otpdinstance.OtpdInstance() otpd.create_instance('OTPD', config.host_name, @@ -1530,10 +1262,9 @@ def install(installer): service.print_msg("Restarting the KDC") krb.restart() - if promote: - custodia.import_dm_password() - promote_sssd(config.host_name) - promote_openldap_conf(config.host_name, config.master_host_name) + custodia.import_dm_password() + promote_sssd(config.host_name) + promote_openldap_conf(config.host_name, config.master_host_name) if options.setup_dns: dns.install(False, True, options, api) @@ -1541,33 +1272,6 @@ def install(installer): if options.setup_adtrust: adtrust.install(False, options, fstore, api) - if not promote: - # Call client install script - service.print_msg("Configuring client side components") - try: - args = [paths.IPA_CLIENT_INSTALL, "--on-master", "--unattended", - "--domain", config.domain_name, - "--server", config.host_name, - "--realm", config.realm_name, "--no-ntp"] - if options.no_dns_sshfp: - args.append("--no-dns-sshfp") - if options.ssh_trust_dns: - args.append("--ssh-trust-dns") - if options.no_ssh: - args.append("--no-ssh") - if options.no_sshd: - args.append("--no-sshd") - if options.mkhomedir: - args.append("--mkhomedir") - ipautil.run(args, redirect_output=True) - print() - except Exception: - print("Configuration of client side components failed!") - raise RuntimeError("Failed to configure the client") - - # remove the extracted replica file - remove_replica_info_dir(installer) - # Enable configured services and update DNS SRV records service.enable_services(config.host_name) api.Command.dns_update_system_records() @@ -1589,16 +1293,12 @@ def install(installer): def init(installer): installer.unattended = not installer.interactive - installer.promote = installer.replica_file is None if installer.servers: installer.server = installer.servers[0] else: installer.server = None - if installer.replica_file is None: - installer.password = installer.host_password - else: - installer.password = installer.dm_password + installer.password = installer.host_password installer._ccache = os.environ.get('KRB5CCNAME')