From 53d984f1e8fdd9fd6ff7e81493d1dab844a63eaf Mon Sep 17 00:00:00 2001 From: Thomas Woerner <twoerner@redhat.com> Date: Wed, 4 Apr 2018 15:25:57 +0200 Subject: [PATCH] New role for ipareplica installation The support for external cert files is not complete yet. Please have a look at the example inventory file inventory/hosts.replica and also the install and uninstall playbook files install-replica.yml and uninstall-replica.yml --- install-replica.yml | 8 + inventory/hosts.replica | 10 + module_utils/ansible_ipa_replica.py | 593 ++++++++++++++ roles/ipareplica/defaults/main.yml | 40 + roles/ipareplica/files/py3test.py | 9 + .../library/ipareplica_add_to_ipaservers.py | 138 ++++ .../library/ipareplica_create_ipa_conf.py | 303 +++++++ .../ipareplica_custodia_import_dm_password.py | 178 ++++ .../library/ipareplica_ds_apply_updates.py | 167 ++++ .../library/ipareplica_ds_enable_ssl.py | 191 +++++ .../library/ipareplica_install_ca_certs.py | 309 +++++++ .../library/ipareplica_krb_enable_ssl.py | 147 ++++ .../ipareplica/library/ipareplica_prepare.py | 759 ++++++++++++++++++ .../ipareplica_promote_openldap_conf.py | 141 ++++ .../library/ipareplica_promote_sssd.py | 140 ++++ .../library/ipareplica_restart_kdc.py | 148 ++++ .../library/ipareplica_setup_adtrust.py | 144 ++++ .../ipareplica/library/ipareplica_setup_ca.py | 218 +++++ .../library/ipareplica_setup_certmonger.py | 78 ++ .../library/ipareplica_setup_custodia.py | 180 +++++ .../library/ipareplica_setup_dns.py | 150 ++++ .../ipareplica/library/ipareplica_setup_ds.py | 341 ++++++++ .../library/ipareplica_setup_http.py | 180 +++++ .../library/ipareplica_setup_kra.py | 225 ++++++ .../library/ipareplica_setup_krb.py | 160 ++++ .../library/ipareplica_setup_otpd.py | 171 ++++ roles/ipareplica/library/ipareplica_test.py | 316 ++++++++ .../library/ipaserver_enable_ipa.py | 100 +++ .../library/ipaserver_master_password.py | 93 +++ .../ipareplica/library/ipaserver_setup_ntp.py | 79 ++ roles/ipareplica/meta/main.yml | 27 + roles/ipareplica/tasks/install.yml | 619 ++++++++++++++ roles/ipareplica/tasks/main.yml | 18 + roles/ipareplica/tasks/python_2_3_test.yml | 19 + roles/ipareplica/tasks/uninstall.yml | 38 + roles/ipareplica/vars/Fedora-25.yml | 5 + roles/ipareplica/vars/Fedora-26.yml | 5 + roles/ipareplica/vars/Fedora.yml | 5 + roles/ipareplica/vars/RedHat-7.3.yml | 5 + roles/ipareplica/vars/RedHat-7.yml | 5 + roles/ipareplica/vars/default.yml | 5 + uninstall-replica.yml | 8 + 42 files changed, 6475 insertions(+) create mode 100644 install-replica.yml create mode 100644 inventory/hosts.replica create mode 100644 module_utils/ansible_ipa_replica.py create mode 100644 roles/ipareplica/defaults/main.yml create mode 100644 roles/ipareplica/files/py3test.py create mode 100644 roles/ipareplica/library/ipareplica_add_to_ipaservers.py create mode 100644 roles/ipareplica/library/ipareplica_create_ipa_conf.py create mode 100644 roles/ipareplica/library/ipareplica_custodia_import_dm_password.py create mode 100644 roles/ipareplica/library/ipareplica_ds_apply_updates.py create mode 100644 roles/ipareplica/library/ipareplica_ds_enable_ssl.py create mode 100644 roles/ipareplica/library/ipareplica_install_ca_certs.py create mode 100644 roles/ipareplica/library/ipareplica_krb_enable_ssl.py create mode 100644 roles/ipareplica/library/ipareplica_prepare.py create mode 100644 roles/ipareplica/library/ipareplica_promote_openldap_conf.py create mode 100644 roles/ipareplica/library/ipareplica_promote_sssd.py create mode 100644 roles/ipareplica/library/ipareplica_restart_kdc.py create mode 100644 roles/ipareplica/library/ipareplica_setup_adtrust.py create mode 100644 roles/ipareplica/library/ipareplica_setup_ca.py create mode 100644 roles/ipareplica/library/ipareplica_setup_certmonger.py create mode 100644 roles/ipareplica/library/ipareplica_setup_custodia.py create mode 100644 roles/ipareplica/library/ipareplica_setup_dns.py create mode 100644 roles/ipareplica/library/ipareplica_setup_ds.py create mode 100644 roles/ipareplica/library/ipareplica_setup_http.py create mode 100644 roles/ipareplica/library/ipareplica_setup_kra.py create mode 100644 roles/ipareplica/library/ipareplica_setup_krb.py create mode 100644 roles/ipareplica/library/ipareplica_setup_otpd.py create mode 100644 roles/ipareplica/library/ipareplica_test.py create mode 100644 roles/ipareplica/library/ipaserver_enable_ipa.py create mode 100644 roles/ipareplica/library/ipaserver_master_password.py create mode 100644 roles/ipareplica/library/ipaserver_setup_ntp.py create mode 100644 roles/ipareplica/meta/main.yml create mode 100644 roles/ipareplica/tasks/install.yml create mode 100644 roles/ipareplica/tasks/main.yml create mode 100644 roles/ipareplica/tasks/python_2_3_test.yml create mode 100644 roles/ipareplica/tasks/uninstall.yml create mode 100644 roles/ipareplica/vars/Fedora-25.yml create mode 100644 roles/ipareplica/vars/Fedora-26.yml create mode 100644 roles/ipareplica/vars/Fedora.yml create mode 100644 roles/ipareplica/vars/RedHat-7.3.yml create mode 100644 roles/ipareplica/vars/RedHat-7.yml create mode 100644 roles/ipareplica/vars/default.yml create mode 100644 uninstall-replica.yml diff --git a/install-replica.yml b/install-replica.yml new file mode 100644 index 00000000..fef9654e --- /dev/null +++ b/install-replica.yml @@ -0,0 +1,8 @@ +--- +- name: Playbook to configure IPA replicas + hosts: ipareplicas + become: true + + roles: + - role: ipareplica + state: present diff --git a/inventory/hosts.replica b/inventory/hosts.replica new file mode 100644 index 00000000..653f9274 --- /dev/null +++ b/inventory/hosts.replica @@ -0,0 +1,10 @@ +[ipaservers] +ipaserver.test.local + +[ipareplicas] +ipareplica1.test.local + +[ipareplicas:vars] +ipaadmin_password=password1 +ipadm_password=password1 +ipaclient_force_join=yes diff --git a/module_utils/ansible_ipa_replica.py b/module_utils/ansible_ipa_replica.py new file mode 100644 index 00000000..565912a3 --- /dev/null +++ b/module_utils/ansible_ipa_replica.py @@ -0,0 +1,593 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import sys +import logging +#import fcntl +from contextlib import contextmanager as contextlib_contextmanager + + +from ipapython.version import NUM_VERSION, VERSION + +if NUM_VERSION < 30201: + # See ipapython/version.py + IPA_MAJOR,IPA_MINOR,IPA_RELEASE = [ int(x) for x in VERSION.split(".", 2) ] + IPA_PYTHON_VERSION = IPA_MAJOR*10000 + IPA_MINOR*100 + IPA_RELEASE +else: + IPA_PYTHON_VERSION = NUM_VERSION + + +if NUM_VERSION >= 40600: + # IPA version >= 4.6 + + import contextlib + import logging + + import dns.exception as dnsexception + import dns.name as dnsname + import dns.resolver as dnsresolver + import dns.reversename as dnsreversename + import os + import shutil + import socket + import tempfile + import traceback + + from pkg_resources import parse_version + import six + + from ipaclient.install.ipachangeconf import IPAChangeConf + import ipaclient.install.ntpconf + from ipalib.install import certstore, sysrestore + from ipalib.install.kinit import kinit_keytab + from ipapython import ipaldap, ipautil, kernel_keyring + from ipapython.certdb import IPA_CA_TRUST_FLAGS, EXTERNAL_CA_TRUST_FLAGS + from ipapython.dn import DN + from ipapython.admintool import ScriptError + from ipaplatform import services + from ipaplatform.tasks import tasks + from ipaplatform.paths import paths + from ipalib import api, constants, create_api, errors, rpc, x509 + from ipalib.config import Env + from ipalib.util import ( + validate_domain_name, + 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, + installutils, kra, krbinstance, + ntpinstance, otpdinstance, custodiainstance, service, + upgradeinstance) + from ipaserver.install.installutils import ( + create_replica_config, ReplicaConfig, load_pkcs12, is_ipa_configured) + from ipaserver.install.replication import ( + ReplicationManager, replica_conn_check) + from ipaserver.install.server.replicainstall import ( + make_pkcs12_info, install_replica_ds, install_krb, install_ca_cert, + install_http, install_dns_records, create_ipa_conf, check_dirsrv, + check_dns_resolution, configure_certmonger, remove_replica_info_dir, + #common_cleanup, + preserve_enrollment_state, uninstall_client, + promote_sssd, promote_openldap_conf, rpc_client, + check_remote_fips_mode, check_remote_version, common_check, + current_domain_level, check_domain_level_is_supported, + #enroll_dl0_replica, + #ensure_enrolled, + promotion_check_ipa_domain + ) + import SSSDConfig + from subprocess import CalledProcessError + + if six.PY3: + unicode = str + + """ + import errno + import pickle + import shutil + import tempfile + import textwrap + import random + + import six + + from ipalib.install import certmonger, sysrestore + from ipapython import ipautil + from ipapython.ipautil import ( + format_netloc, ipa_generate_password, run) + from ipapython.admintool import ScriptError + from ipaplatform import services + from ipaplatform.paths import paths + from ipaplatform.tasks import tasks + from ipalib import api, errors, x509 + from ipalib.constants import DOMAIN_LEVEL_0, MIN_DOMAIN_LEVEL, MAX_DOMAIN_LEVEL + from ipalib.util import ( + validate_domain_name, + no_matching_interface_for_ip_address_warning, + ) + from ipapython.dnsutil import check_zone_overlap + from ipaclient.install import ntpconf + from ipaserver.install import ( + adtrust, bindinstance, ca, dns, dsinstance, + httpinstance, installutils, kra, krbinstance, + ntpinstance, otpdinstance, custodiainstance, replication, service, + sysupgrade) + adtrust_imported = True + kra_imported = True + from ipaserver.install.installutils import ( + IPA_MODULES, BadHostError, get_fqdn, get_server_ip_address, + is_ipa_configured, load_pkcs12, read_password, verify_fqdn, + update_hosts_file) + from ipaserver.install.server.install import ( + check_dirsrv, validate_admin_password, validate_dm_password, + write_cache) + try: + from ipaserver.install.installutils import default_subject_base + except ImportError: + def default_subject_base(realm_name): + return DN(('O', realm_name)) + try: + from ipaserver.install.installutils import default_ca_subject_dn + except ImportError: + def default_ca_subject_dn(subject_base): + return DN(('CN', 'Certificate Authority'), subject_base) + + if six.PY3: + unicode = str + + try: + from ipaserver.install import adtrustinstance + _server_trust_ad_installed = True + except ImportError: + _server_trust_ad_installed = False + """ + +else: + # IPA version < 4.6 + + raise Exception("freeipa version '%s' is too old" % VERSION) + + +logger = logging.getLogger("ipa-server-install") +logger.setLevel(logging.DEBUG) + + +@contextlib_contextmanager +def redirect_stdout(f): + sys.stdout = f + try: + yield f + finally: + sys.stdout = sys.__stdout__ + + +class AnsibleModuleLog(): + def __init__(self, module): + self.module = module + _ansible_module_log = self + + class AnsibleLoggingHandler(logging.Handler): + def emit(self, record): + _ansible_module_log.write(self.format(record)) + + self.logging_handler = AnsibleLoggingHandler() + logger.setLevel(logging.DEBUG) + logger.root.addHandler(self.logging_handler) + + def close(self): + self.flush() + + def flush(self): + pass + + def log(self, msg): + #self.write(msg+"\n") + self.write(msg) + + def debug(self, msg): + self.module.debug(msg) + + def write(self, msg): + # self.module.debug(msg) + self.module.warn(msg) + +def show_obj(obj): + s="%s = {" % obj.__class__ + for key in dir(obj): + #if key in [ "__class__", "__dict__" ]: + # continue + if key.startswith("--") and key.endswith("--"): + continue + if not hasattr(obj, key): + continue + value = getattr(obj, key) + if callable(value): + continue + s += " '%s': %s," % (key, repr(value)) + logger.info(s+" }") + +class installer_obj(object): + def __init__(self): + # CompatServerReplicaInstall + self.ca_cert_files = None + self.all_ip_addresses = False + self.no_wait_for_dns = True + self.nisdomain = None + self.no_nisdomain = False + self.no_sudo = False + self.request_cert = False + self.ca_file = None + self.zonemgr = None + self.replica_file = None + # ServerReplicaInstall + self.subject_base = None + self.ca_subject = None + # others + self._ccache = None + self.password = None + self.reverse_zones = [ ] + #def _is_promote(self): + # return self.replica_file is None + #self.skip_conncheck = False + self._replica_install = False + #self.dnssec_master = False # future unknown + #self.disable_dnssec_master = False # future unknown + #self.domainlevel = MAX_DOMAIN_LEVEL # deprecated + #self.domain_level = self.domainlevel # deprecated + self.interactive = False + self.unattended = not self.interactive + #self.promote = self.replica_file is None + self.promote = True + + #def __getattribute__(self, attr): + # value = super(installer_obj, self).__getattribute__(attr) + # if not attr.startswith("--") and not attr.endswith("--"): + # logger.debug( + # " <-- Accessing installer.%s (%s)" % (attr, repr(value))) + # return value + + def __getattr__(self, attr): + logger.info(" --> ADDING missing installer.%s" % attr) + setattr(self, attr, None) + return getattr(self, attr) + + #def __setattr__(self, attr, value): + # logger.debug(" --> Setting installer.%s to %s" % (attr, repr(value))) + # return super(installer_obj, self).__setattr__(attr, value) + + def knobs(self): + for name in self.__dict__: + yield self, name + + +installer = installer_obj() +options = installer + + +def api_Backend_ldap2(host_name, setup_ca, connect=False): + # we are sure we have the configuration file ready. + cfg = dict(context='installer', confdir=paths.ETC_IPA, in_server=True, + host=host_name, + ) + if setup_ca: + # we have an IPA-integrated CA + cfg['ca_host'] = host_name + + api.bootstrap(**cfg) + api.finalize() + if connect: + api.Backend.ldap2.connect() + + +def gen_env_boostrap_finalize_core(etc_ipa, default_config): + env = Env() + #env._bootstrap(context='installer', confdir=paths.ETC_IPA, log=None) + #env._finalize_core(**dict(constants.DEFAULT_CONFIG)) + env._bootstrap(context='installer', confdir=etc_ipa, log=None) + env._finalize_core(**dict(default_config)) + return env + + +def api_bootstrap_finalize(env): + # pylint: disable=no-member + xmlrpc_uri = 'https://{}/ipa/xml'.format(ipautil.format_netloc(env.host)) + api.bootstrap(in_server=True, + context='installer', + confdir=paths.ETC_IPA, + ldap_uri=installutils.realm_to_ldapi_uri(env.realm), + xmlrpc_uri=xmlrpc_uri) + # pylint: enable=no-member + api.finalize() + + +def gen_ReplicaConfig(): + class ExtendedReplicaConfig(ReplicaConfig): + def __init__(self, top_dir=None): + super(ExtendedReplicaConfig, self).__init__(top_dir) + + #def __getattribute__(self, attr): + # value = super(ExtendedReplicaConfig, self).__getattribute__(attr) + # if attr not in [ "__dict__", "knobs" ]: + # logger.debug(" <== Accessing config.%s (%s)" % (attr, repr(value))) + # return value + + def __getattr__(self, attr): + logger.info(" ==> ADDING missing config.%s" % attr) + setattr(self, attr, None) + return getattr(self, attr) + + #def __setattr__(self, attr, value): + # logger.debug(" ==> Setting config.%s to %s" % (attr, repr(value))) + # return super(ExtendedReplicaConfig, self).__setattr__(attr, value) + + def knobs(self): + for name in self.__dict__: + yield self, name + + #config = ReplicaConfig() + config = ExtendedReplicaConfig() + config.realm_name = api.env.realm + config.host_name = api.env.host + config.domain_name = api.env.domain + config.master_host_name = api.env.server + config.ca_host_name = api.env.ca_host + config.kra_host_name = config.ca_host_name + config.ca_ds_port = 389 + config.setup_ca = options.setup_ca + config.setup_kra = options.setup_kra + config.dir = options._top_dir + config.basedn = api.env.basedn + #config.subject_base = options.subject_base + + #show_obj(config) + + return config + + +def ds_init_info(ansible_log, fstore, domainlevel, dirsrv_config_file, + realm_name, host_name, domain_name, dm_password, + idstart, idmax, subject_base, ca_subject, + #no_hbac_allow, + dirsrv_pkcs12_info, no_pkinit, + external_cert_files, dirsrv_cert_files): + + if not external_cert_files: + ds = dsinstance.DsInstance(fstore=fstore, domainlevel=domainlevel, + config_ldif=dirsrv_config_file) + ds.set_output(ansible_log) + + if dirsrv_cert_files: + _dirsrv_pkcs12_info = dirsrv_pkcs12_info + else: + _dirsrv_pkcs12_info = None + + with redirect_stdout(ansible_log): + ds.init_info(realm_name, host_name, domain_name, dm_password, + subject_base, ca_subject, idstart, idmax, + #hbac_allow=not no_hbac_allow, + _dirsrv_pkcs12_info, setup_pkinit=not no_pkinit) + else: + ds = dsinstance.DsInstance(fstore=fstore, domainlevel=domainlevel) + ds.set_output(ansible_log) + + with redirect_stdout(ansible_log): + ds.init_info(realm_name, host_name, domain_name, dm_password, + subject_base, ca_subject, 1101, 1100, None, + setup_pkinit=not no_pkinit) + + return ds + + +def replica_ds_init_info(ansible_log, + config, options, ca_is_configured, remote_api, + ds_ca_subject, ca_file, + promote=False, pkcs12_info=None): + + dsinstance.check_ports() + + # if we have a pkcs12 file, create the cert db from + # that. Otherwise the ds setup will create the CA + # cert + if pkcs12_info is None: + pkcs12_info = make_pkcs12_info(config.dir, "dscert.p12", + "dirsrv_pin.txt") + + # during replica install, this gets invoked before local DS is + # available, so use the remote api. + #if ca_is_configured: + # ca_subject = ca.lookup_ca_subject(_api, config.subject_base) + #else: + # ca_subject = installutils.default_ca_subject_dn(config.subject_base) + ca_subject = ds_ca_subject + + ds = dsinstance.DsInstance( + config_ldif=options.dirsrv_config_file) + ds.set_output(ansible_log) + + # Source: ipaserver/install/dsinstance.py + + # idstart and idmax are configured so that the range is seen as + # depleted by the DNA plugin and the replica will go and get a + # new range from the master. + # This way all servers use the initially defined range by default. + idstart = 1101 + idmax = 1100 + + with redirect_stdout(ansible_log): + ds.init_info( + realm_name=config.realm_name, + fqdn=config.host_name, + domain_name=config.domain_name, + dm_password=config.dirman_password, + subject_base=config.subject_base, + ca_subject=ca_subject, + idstart=idstart, + idmax=idmax, + pkcs12_info=pkcs12_info, + ca_file=ca_file, + setup_pkinit=not options.no_pkinit, + ) + ds.master_fqdn = config.master_host_name + if ca_is_configured is not None: + ds.ca_is_configured = ca_is_configured + ds.promote = promote + ds.api = remote_api + + # from __setup_replica + + # Always connect to ds over ldapi + ldap_uri = ipaldap.get_ldap_uri(protocol='ldapi', realm=ds.realm) + conn = ipaldap.LDAPClient(ldap_uri) + conn.external_bind() + + return ds + + +def krb_init_info(ansible_log, fstore, realm_name, host_name, no_pkinit, + subject_base): + krb = krbinstance.KrbInstance(fstore) + krb.set_output(ansible_log) + with redirect_stdout(ansible_log): + krb.init_info(realm_name, host_name, etup_pkinit=not no_pkinit, + subject_base=subject_base) + + +def replica_krb_init_info(ansible_log, fstore, realm_name, master_host_name, + host_name, domain_name, admin_password, + no_pkinit, subject_base, pkcs12_info=None): + # promote is not needed here + + # From replicainstall.install_krb + krb = krbinstance.KrbInstance(fstore=fstore) + krb.set_output(ansible_log) + + # pkinit files + if pkcs12_info is None: + pkcs12_info = make_pkcs12_info(config.dir, "pkinitcert.p12", + "pkinit_pin.txt") + + #krb.create_replica(realm_name, + # master_host_name, host_name, + # domain_name, dirman_password, + # setup_pkinit, pkcs12_info, + # subject_base=subject_base, + # promote=promote) + with redirect_stdout(ansible_log): + krb.init_info(realm_name, host_name, setup_pkinit=not no_pkinit, + subject_base=subject_base) + + # From ipaserver.install.krbinstance.create_replica + + krb.pkcs12_info = pkcs12_info + krb.subject_base = subject_base + krb.master_fqdn = master_host_name + krb.config_pkinit = not no_pkinit + + #krb.__common_setup(realm_name, host_name, domain_name, admin_password) + krb.fqdn = host_name + krb.realm = realm_name.upper() + krb.host = host_name.split(".")[0] + krb.ip = socket.getaddrinfo(host_name, None, socket.AF_UNSPEC, socket.SOCK_STREAM)[0][4][0] + krb.domain = domain_name + krb.suffix = ipautil.realm_to_suffix(krb.realm) + krb.kdc_password = ipautil.ipa_generate_password() + krb.admin_password = admin_password + krb.dm_password = admin_password + + #krb.__setup_sub_dict() + if os.path.exists(paths.COMMON_KRB5_CONF_DIR): + includes = 'includedir {}'.format(paths.COMMON_KRB5_CONF_DIR) + else: + includes = '' + + krb.sub_dict = dict(FQDN=krb.fqdn, + IP=krb.ip, + PASSWORD=krb.kdc_password, + SUFFIX=krb.suffix, + DOMAIN=krb.domain, + HOST=krb.host, + SERVER_ID=installutils.realm_to_serverid(krb.realm), + REALM=krb.realm, + KRB5KDC_KADM5_ACL=paths.KRB5KDC_KADM5_ACL, + DICT_WORDS=paths.DICT_WORDS, + KRB5KDC_KADM5_KEYTAB=paths.KRB5KDC_KADM5_KEYTAB, + KDC_CERT=paths.KDC_CERT, + KDC_KEY=paths.KDC_KEY, + CACERT_PEM=paths.CACERT_PEM, + KDC_CA_BUNDLE_PEM=paths.KDC_CA_BUNDLE_PEM, + CA_BUNDLE_PEM=paths.CA_BUNDLE_PEM, + INCLUDES=includes) + + # IPA server/KDC is not a subdomain of default domain + # Proper domain-realm mapping needs to be specified + domain = dnsname.from_text(krb.domain) + fqdn = dnsname.from_text(krb.fqdn) + if not fqdn.is_subdomain(domain): + logger.debug("IPA FQDN '%s' is not located in default domain '%s'", + fqdn, domain) + server_domain = fqdn.parent().to_unicode(omit_final_dot=True) + logger.debug("Domain '%s' needs additional mapping in krb5.conf", + server_domain) + dr_map = " .%(domain)s = %(realm)s\n %(domain)s = %(realm)s\n" \ + % dict(domain=server_domain, realm=krb.realm) + else: + dr_map = "" + krb.sub_dict['OTHER_DOMAIN_REALM_MAPS'] = dr_map + + # Configure KEYRING CCACHE if supported + if kernel_keyring.is_persistent_keyring_supported(): + logger.debug("Enabling persistent keyring CCACHE") + krb.sub_dict['OTHER_LIBDEFAULTS'] = \ + " default_ccache_name = KEYRING:persistent:%{uid}\n" + else: + logger.debug("Persistent keyring CCACHE is not enabled") + krb.sub_dict['OTHER_LIBDEFAULTS'] = '' + + return krb + + +def ansible_module_get_parsed_ip_addresses(ansible_module, + param='ip_addresses'): + ip_addrs = [ ] + for ip in ansible_module.params.get(param): + try: + ip_parsed = ipautil.CheckedIPAddress(ip) + except Exception as e: + ansible_module.fail_json(msg="Invalid IP Address %s: %s" % (ip, e)) + ip_addrs.append(ip_parsed) + return ip_addrs + + +def gen_remote_api(master_host_name, etc_ipa): + ldapuri = 'ldaps://%s' % ipautil.format_netloc(master_host_name) + xmlrpc_uri = 'https://{}/ipa/xml'.format(ipautil.format_netloc(master_host_name)) + remote_api = create_api(mode=None) + remote_api.bootstrap(in_server=True, + context='installer', + confdir=etc_ipa, + ldap_uri=ldapuri, + xmlrpc_uri=xmlrpc_uri) + remote_api.finalize() + return remote_api diff --git a/roles/ipareplica/defaults/main.yml b/roles/ipareplica/defaults/main.yml new file mode 100644 index 00000000..fb8c904b --- /dev/null +++ b/roles/ipareplica/defaults/main.yml @@ -0,0 +1,40 @@ +--- +# defaults file for ipareplica + +### basic ### +ipareplica_no_host_dns: no +ipareplica_skip_conncheck: no +### server ### +ipareplica_setup_adtrust: no +ipareplica_setup_ca: no +ipareplica_setup_kra: no +ipareplica_setup_dns: no +ipareplica_no_pkinit: no +ipareplica_no_ui_redirect: no +### client ### +ipaclient_mkhomedir: no +ipaclient_force_join: no +ipaclient_no_ntp: no +#ipaclient_ssh_trust_dns: no +#ipaclient_no_ssh: no +#ipaclient_no_sshd: no +#ipaclient_no_dns_sshfp: no +### certificate system ### +ipareplica_skip_schema_check: no +### dns ### +ipareplica_allow_zone_overlap: no +ipareplica_no_reverse: no +ipareplica_auto_reverse: no +ipareplica_no_forwarders: no +ipareplica_auto_forwarders: no +ipareplica_no_dnssec_validation: no +### ad trust ### +ipareplica_add_sids: no +ipareplica_add_agents: no +ipareplica_enable_compat: no +### uninstall ### +ipareplica_ignore_topology_disconnect: no +ipareplica_ignore_last_of_role: no +### additional ### +ipareplica_no_package_install: no +ipareplica_no_firewalld: no diff --git a/roles/ipareplica/files/py3test.py b/roles/ipareplica/files/py3test.py new file mode 100644 index 00000000..a7617cff --- /dev/null +++ b/roles/ipareplica/files/py3test.py @@ -0,0 +1,9 @@ +#!/usr/bin/python3 + +# Test ipaerver python3 binding +from ipaserver.install.server.replicainstall import install_check + +# Check ipapython version to be >= 4.6 +from ipapython.version import NUM_VERSION, VERSION +if NUM_VERSION < 40590: + raise Exception("ipa %s not usable with python3" % VERSION) diff --git a/roles/ipareplica/library/ipareplica_add_to_ipaservers.py b/roles/ipareplica/library/ipareplica_add_to_ipaservers.py new file mode 100644 index 00000000..a7253e3d --- /dev/null +++ b/roles/ipareplica/library/ipareplica_add_to_ipaservers.py @@ -0,0 +1,138 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_add_to_ipaservers +short description: Add to ipaservers +description: + Add to ipaservers +options: + setup_kra: + description: + required: yes + config_master_host_name: + description: + required: yes + ccache: + description: + required: yes + installer_ccache: + description: + required: yes + _top_dir: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + ### server ### + setup_kra=dict(required=True, type='bool'), + ### additional ### + config_master_host_name=dict(required=True), + ccache=dict(required=True), + installer_ccache=dict(required=True), + _top_dir = dict(required=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_kra = ansible_module.params.get('setup_kra') + ### additional ### + config_master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + options._ccache = ansible_module.params.get('installer_ccache') + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + options._top_dir = ansible_module.params.get('_top_dir') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALLER ==") + + options = installer + promote = installer.promote + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + #config = gen_ReplicaConfig() + + remote_api = gen_remote_api(config_master_host_name, paths.ETC_IPA) + #installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + ansible_log.debug("-- HOSTGROUP_ADD_MEMBER --") + try: + ansible_log.debug("-- CONNECT --") + conn.connect(ccache=installer._ccache) + remote_api.Command['hostgroup_add_member']( + u'ipaservers', + host=[unicode(api.env.host)], + ) + finally: + if conn.isconnected(): + ansible_log.debug("-- DISCONNECT --") + conn.disconnect() + os.environ['KRB5CCNAME'] = ccache + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_create_ipa_conf.py b/roles/ipareplica/library/ipareplica_create_ipa_conf.py new file mode 100644 index 00000000..529988b0 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_create_ipa_conf.py @@ -0,0 +1,303 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_create_ipa_conf +short description: Create ipa.conf +description: + Create ipa.conf +options: + dm_password: + description: Directory Manager password + required: yes + password: + description: Admin user kerberos password + required: yes + ip_addresses: + description: List of Master Server IP Addresses + required: no + domain: + description: Primary DNS domain of the IPA deployment + required: yes + realm: + description: Kerberos realm name of the IPA deployment + required: yes + hostname: + description: Fully qualified name of this host + required: yes + ca_cert_files: + description: List of iles containing CA certificates for the service certificate files + required: yes + no_host_dns: + description: Do not use DNS for hostname lookup during installation + required: yes + setup_adtrust: + description: + required: yes + setup_ca: + description: + required: yes + setup_kra: + description: + required: yes + setup_dns: + description: + required: yes + dirserv_cert_files: + description: + required: yes + force_join: + description: + required: yes + subject_base: + description: + required: yes + server: + description: + required: yes + ccache: + description: + required: yes + installer_ccache: + description: + required: yes + _ca_enabled: + description: + required: yes + _kra_enabled: + description: + required: yes + _dirsrv_pkcs12_info: + description: + required: yes + _http_pkcs12_info: + description: + required: yes + _pkinit_pkcs12_info: + description: + required: yes + _top_dir: + description: + required: yes + _add_to_ipaservers: + description: + required: yes + _ca_subject: + description: + required: yes + _subject_base: + description: + required: yes + dirman_password: + description: + required: yes + config_setup_ca: + description: + required: yes + config_master_host_name: + description: + required: yes + config_ca_host_name: + description: + required: yes + config_ips: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + ### basic ### + dm_password=dict(required=False, no_log=True), + password=dict(required=False, no_log=True), + ip_addresses=dict(required=False, type='list', default=[]), + domain=dict(required=False), + realm=dict(required=False), + hostname=dict(required=False), + ca_cert_files=dict(required=False, type='list', default=[]), + no_host_dns=dict(required=False, type='bool', default=False), + ### server ### + setup_adtrust=dict(required=False, type='bool'), + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + setup_dns=dict(required=False, type='bool'), + ### ssl certificate ### + dirsrv_cert_files=dict(required=False, type='list', default=[]), + ### client ### + force_join=dict(required=False, type='bool'), + ### certificate system ### + subject_base=dict(required=True), + ### additional ### + server=dict(required=True), + config_master_host_name=dict(required=True), + ccache=dict(required=True), + installer_ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _kra_enabled=dict(required=False, type='bool'), + _dirsrv_pkcs12_info = dict(required=False), + _http_pkcs12_info = dict(required=False), + _pkinit_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + _add_to_ipaservers = dict(required=True), + _ca_subject=dict(required=True), + _subject_base=dict(required=True), + + dirman_password=dict(required=True, no_log=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + options.dm_password = ansible_module.params.get('dm_password') + options.password = options.dm_password + options.admin_password = ansible_module.params.get('password') + options.ip_addresses = ansible_module_get_parsed_ip_addresses( + ansible_module) + options.domain_name = ansible_module.params.get('domain') + options.realm_name = ansible_module.params.get('realm') + options.host_name = ansible_module.params.get('hostname') + options.ca_cert_files = ansible_module.params.get('ca_cert_files') + options.no_host_dns = ansible_module.params.get('no_host_dns') + ### server ### + options.setup_adtrust = ansible_module.params.get('setup_adtrust') + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.setup_dns = ansible_module.params.get('setup_dns') + ### ssl certificate ### + options.dirsrv_cert_files = ansible_module.params.get('dirsrv_cert_files') + ### client ### + options.force_join = ansible_module.params.get('force_join') + ### certificate system ### + options.external_ca = ansible_module.params.get('external_ca') + options.external_cert_files = ansible_module.params.get( + 'external_cert_files') + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + options.ca_subject = ansible_module.params.get('ca_subject') + ### dns ### + options.reverse_zones = ansible_module.params.get('reverse_zones') + options.no_reverse = ansible_module.params.get('no_reverse') + options.auto_reverse = ansible_module.params.get('auto_reverse') + options.forwarders = ansible_module.params.get('forwarders') + options.no_forwarders = ansible_module.params.get('no_forwarders') + options.auto_forwarders = ansible_module.params.get('auto_forwarders') + options.forward_policy = ansible_module.params.get('forward_policy') + + ### additional ### + #options._host_name_overridden = ansible_module.params.get( + # '_hostname_overridden') + options.server = ansible_module.params.get('server') + master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + kra_enabled = ansible_module.params.get('_kra_enabled') + + dirsrv_pkcs12_info = ansible_module.params.get('_dirsrv_pkcs12_info') + http_pkcs12_info = ansible_module.params.get('_http_pkcs12_info') + pkinit_pkcs12_info = ansible_module.params.get('_pkinit_pkcs12_info') + + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + options._top_dir = ansible_module.params.get('_top_dir') + options._add_to_ipaservers = ansible_module.params.get('_add_to_ipaservers') + + options._ca_subject = ansible_module.params.get('_ca_subject') + options._subject_base = ansible_module.params.get('_subject_base') + + dirman_password = ansible_module.params.get('dirman_password') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + # prepare (install prepare, install checks) # + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.subject_base = options.subject_base + config.dirman_password = dirman_password + + remote_api = gen_remote_api(master_host_name, paths.ETC_IPA) + installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + cafile = paths.IPA_CA_CRT + + if promote: + ansible_log.debug("-- CREATE_IPA_CONF --") + # 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) + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_custodia_import_dm_password.py b/roles/ipareplica/library/ipareplica_custodia_import_dm_password.py new file mode 100644 index 00000000..4b3284f0 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_custodia_import_dm_password.py @@ -0,0 +1,178 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_custodia_import_dm_password +short description: Import dm password into custodia +description: + Import dm password into custodia +options: + setup_ca: + description: + required: yes + setup_kra: + description: + required: yes + no_pkinit: + description: + required: yes + no_ui_redirect: + description: + required: yes + subject_base: + description: + required: yes + config_master_host_name: + description: + required: yes + ccache: + description: + required: yes + _ca_enabled: + description: + required: yes + _ca_file: + description: + required: yes + _dirsrv_pkcs12_info: + description: + required: yes + _pkinit_pkcs12_info: + description: + required: yes + _top_dir: + description: + required: yes + dirman_password: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + #### server ### + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + no_pkinit=dict(required=False, type='bool'), + no_ui_redirect=dict(required=False, type='bool'), + #### certificate system ### + subject_base=dict(required=True), + #### additional ### + config_master_host_name=dict(required=True), + ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _ca_file=dict(required=False), + _dirsrv_pkcs12_info = dict(required=False), + _pkinit_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + dirman_password=dict(required=True, no_log=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.no_pkinit = ansible_module.params.get('no_pkinit') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + #installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + dirsrv_pkcs12_info = ansible_module.params.get('_dirsrv_pkcs12_info') + pkinit_pkcs12_info = ansible_module.params.get('_pkinit_pkcs12_info') + options._top_dir = ansible_module.params.get('_top_dir') + dirman_password = ansible_module.params.get('dirman_password') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.subject_base = options.subject_base + + remote_api = gen_remote_api(master_host_name, paths.ETC_IPA) + installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + # do the work # + + with redirect_stdout(ansible_log): + custodia = custodiainstance.CustodiaInstance(config.host_name, + config.realm_name) + + ansible_log.debug("-- CUSTODIA IMPORT DM PASSWORD --") + + custodia.import_dm_password(config.master_host_name) + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_ds_apply_updates.py b/roles/ipareplica/library/ipareplica_ds_apply_updates.py new file mode 100644 index 00000000..a2fc4bb3 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_ds_apply_updates.py @@ -0,0 +1,167 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_ds_apply_updates +short description: DS apply updates +description: + DS apply updates +options: +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + #### server ### + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + no_pkinit=dict(required=False, type='bool'), + no_ui_redirect=dict(required=False, type='bool'), + dirsrv_config_file=dict(required=False), + #### certificate system ### + subject_base=dict(required=True), + #### additional ### + config_master_host_name=dict(required=True), + ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _ca_file=dict(required=False), + _dirsrv_pkcs12_info = dict(required=False), + _pkinit_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + dirman_password=dict(required=True, no_log=True), + ds_ca_subject=dict(required=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.no_pkinit = ansible_module.params.get('no_pkinit') + options.dirsrv_config_file = ansible_module.params.get('dirsrv_config_file') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + #installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + installer._dirsrv_pkcs12_info = ansible_module.params.get('_dirsrv_pkcs12_info') + installer._pkinit_pkcs12_info = ansible_module.params.get('_pkinit_pkcs12_info') + options._top_dir = ansible_module.params.get('_top_dir') + dirman_password = ansible_module.params.get('dirman_password') + ds_ca_subject = ansible_module.params.get('ds_ca_subject') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + pkinit_pkcs12_info = installer._pkinit_pkcs12_info + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.dirman_password = dirman_password + config.subject_base = options.subject_base + + remote_api = gen_remote_api(master_host_name, paths.ETC_IPA) + #installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + # There is a api.Backend.ldap2.connect call somewhere in ca, ds, dns or + # ntpinstance + api.Backend.ldap2.connect() + conn.connect(ccache=ccache) + + cafile = paths.IPA_CA_CRT + with redirect_stdout(ansible_log): + ds = replica_ds_init_info(ansible_log, + config, options, ca_enabled, + remote_api, ds_ca_subject, + ca_file=paths.IPA_CA_CRT, + promote=promote, + pkcs12_info=installer._dirsrv_pkcs12_info) + + ansible_log.debug("-- DS APPLY_UPDATES --") + + # Apply any LDAP updates. Needs to be done after the replica is + # synced-up + #service.print_msg("Applying LDAP updates") + #ds.apply_updates() + schema_files = dsinstance.get_all_external_schema_files( + paths.EXTERNAL_SCHEMA_DIR) + data_upgrade = upgradeinstance.IPAUpgrade(ds.realm, + schema_files=schema_files) + data_upgrade.set_output(ansible_log) + try: + data_upgrade.create_instance() + except Exception as e: + # very fatal errors only will raise exception + raise RuntimeError("Update failed: %s" % e) + installutils.store_version() + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_ds_enable_ssl.py b/roles/ipareplica/library/ipareplica_ds_enable_ssl.py new file mode 100644 index 00000000..d82a0704 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_ds_enable_ssl.py @@ -0,0 +1,191 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_ds_enable_ssl +short description: DS enable SSL +description: + DS enable SSL +options: + setup_ca: + description: + required: yes + setup_kra: + description: + required: yes + no_pkinit: + description: + required: yes + subject_base: + description: + required: yes + config_master_host_name: + description: + required: yes + ccache: + description: + required: yes + _ca_enabled: + description: + required: yes + _ca_file: + description: + required: yes + _dirsrv_pkcs12_info: + description: + required: yes + _pkinit_pkcs12_info: + description: + required: yes + _top_dir: + description: + required: yes + dirman_password: + description: + required: yes + ds_ca_subject: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + #### server ### + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + no_pkinit=dict(required=False, type='bool'), + dirsrv_config_file=dict(required=False), + #### certificate system ### + subject_base=dict(required=True), + #### additional ### + config_master_host_name=dict(required=True), + ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _ca_file=dict(required=False), + _dirsrv_pkcs12_info = dict(required=False), + _pkinit_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + dirman_password=dict(required=True, no_log=True), + ds_ca_subject=dict(required=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.no_pkinit = ansible_module.params.get('no_pkinit') + options.dirsrv_config_file = ansible_module.params.get('dirsrv_config_file') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + #installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + options._dirsrv_pkcs12_info = ansible_module.params.get('_dirsrv_pkcs12_info') + options._pkinit_pkcs12_info = ansible_module.params.get('_pkinit_pkcs12_info') + options._top_dir = ansible_module.params.get('_top_dir') + dirman_password = ansible_module.params.get('dirman_password') + ds_ca_subject = ansible_module.params.get('ds_ca_subject') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + pkinit_pkcs12_info = installer._pkinit_pkcs12_info + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.dirman_password = dirman_password + config.subject_base = options.subject_base + + remote_api = gen_remote_api(master_host_name, paths.ETC_IPA) + #installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + # There is a api.Backend.ldap2.connect call somewhere in ca, ds, dns or + # ntpinstance + api.Backend.ldap2.connect() + conn.connect(ccache=ccache) + + with redirect_stdout(ansible_log): + ds = replica_ds_init_info(ansible_log, + config, options, ca_enabled, + remote_api, ds_ca_subject, + ca_file=paths.IPA_CA_CRT, + promote=promote, + pkcs12_info=installer._dirsrv_pkcs12_info) + + ansible_log.debug("-- DS.ENABLE_SSL --") + + # we now need to enable ssl on the ds + ds.enable_ssl() + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_install_ca_certs.py b/roles/ipareplica/library/ipareplica_install_ca_certs.py new file mode 100644 index 00000000..ef1a4d3b --- /dev/null +++ b/roles/ipareplica/library/ipareplica_install_ca_certs.py @@ -0,0 +1,309 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_install_ca_cert +short description: Install CA certs +description: + Install CA certs +options: + dm_password: + description: Directory Manager password + required: yes + password: + description: Admin user kerberos password + required: yes + ip_addresses: + description: List of Master Server IP Addresses + required: no + domain: + description: Primary DNS domain of the IPA deployment + required: yes + realm: + description: Kerberos realm name of the IPA deployment + required: yes + hostname: + description: Fully qualified name of this host + required: yes + ca_cert_files: + description: List of iles containing CA certificates for the service certificate files + required: yes + no_host_dns: + description: Do not use DNS for hostname lookup during installation + required: yes + setup_adtrust: + description: + required: yes + setup_kra: + description: + required: yes + setup_dns: + description: + required: yes + external_ca: + description: + required: yes + external_cert_files: + description: + required: yes + subject_base: + description: + required: yes + ca_subject: + description: + required: yes + reverse_zones: + description: + required: yes + no_reverse: + description: + required: yes + auto_reverse: + description: + required: yes + forwarders: + description: + required: yes + no_forwarders: + description: + required: yes +G auto_forwarders: + description: + required: yes + forward_policy: + description: + required: yes + enable_compat: + description: + required: yes + netbios_name: + description: + required: yes + rid_base: + description: + required: yes + secondary_rid_base: + description: + required: yes + setup_ca: + description: + required: yes + _hostname_overridden: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + ### basic ### + dm_password=dict(required=False, no_log=True), + password=dict(required=False, no_log=True), + ip_addresses=dict(required=False, type='list', default=[]), + domain=dict(required=False), + realm=dict(required=False), + hostname=dict(required=False), + ca_cert_files=dict(required=False, type='list', default=[]), + no_host_dns=dict(required=False, type='bool', default=False), + ### server ### + setup_adtrust=dict(required=False, type='bool'), + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + setup_dns=dict(required=False, type='bool'), + ### ssl certificate ### + dirsrv_cert_files=dict(required=False, type='list', default=[]), + ### client ### + force_join=dict(required=False, type='bool'), + ### certificate system ### + subject_base=dict(required=True), + ### additional ### + server=dict(required=True), + ccache=dict(required=True), + installer_ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _kra_enabled=dict(required=False, type='bool'), + _dirsrv_pkcs12_info = dict(required=False), + _http_pkcs12_info = dict(required=False), + _pkinit_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + _add_to_ipaservers = dict(required=True), + _ca_subject=dict(required=True), + _subject_base=dict(required=True), + dirman_password=dict(required=True, no_log=True), + config_setup_ca=dict(required=True), + config_master_host_name=dict(required=True), + config_ca_host_name=dict(required=True), + config_ips=dict(required=False, type='list', default=[]), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### basic ### + options.dm_password = ansible_module.params.get('dm_password') + options.password = options.dm_password + options.admin_password = ansible_module.params.get('password') + options.ip_addresses = ansible_module_get_parsed_ip_addresses( + ansible_module) + options.domain_name = ansible_module.params.get('domain') + options.realm_name = ansible_module.params.get('realm') + options.host_name = ansible_module.params.get('hostname') + options.ca_cert_files = ansible_module.params.get('ca_cert_files') + options.no_host_dns = ansible_module.params.get('no_host_dns') + ### server ### + options.setup_adtrust = ansible_module.params.get('setup_adtrust') + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.setup_dns = ansible_module.params.get('setup_dns') + ### ssl certificate ### + options.dirsrv_cert_files = ansible_module.params.get('dirsrv_cert_files') + ### client ### + options.force_join = ansible_module.params.get('force_join') + ### certificate system ### + options.external_ca = ansible_module.params.get('external_ca') + options.external_cert_files = ansible_module.params.get( + 'external_cert_files') + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + options.ca_subject = ansible_module.params.get('ca_subject') + ### dns ### + options.reverse_zones = ansible_module.params.get('reverse_zones') + options.no_reverse = ansible_module.params.get('no_reverse') + options.auto_reverse = ansible_module.params.get('auto_reverse') + options.forwarders = ansible_module.params.get('forwarders') + options.no_forwarders = ansible_module.params.get('no_forwarders') + options.auto_forwarders = ansible_module.params.get('auto_forwarders') + options.forward_policy = ansible_module.params.get('forward_policy') + ### additional ### + options.server = ansible_module.params.get('server') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + kra_enabled = ansible_module.params.get('_kra_enabled') + dirsrv_pkcs12_info = ansible_module.params.get('_dirsrv_pkcs12_info') + http_pkcs12_info = ansible_module.params.get('_http_pkcs12_info') + pkinit_pkcs12_info = ansible_module.params.get('_pkinit_pkcs12_info') + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + options._top_dir = ansible_module.params.get('_top_dir') + options._add_to_ipaservers = ansible_module.params.get('_add_to_ipaservers') + options._ca_subject = ansible_module.params.get('_ca_subject') + options._subject_base = ansible_module.params.get('_subject_base') + dirman_password = ansible_module.params.get('dirman_password') + config_setup_ca = ansible_module.params.get('config_setup_ca') + config_master_host_name = ansible_module.params.get('config_master_host_name') + config_ca_host_name = ansible_module.params.get('config_ca_host_name') + config_ips = ansible_module_get_parsed_ip_addresses(ansible_module, + "config_ips") + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALLER ==") + + options = installer + promote = installer.promote + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.dirman_password = dirman_password + config.setup_ca = config_setup_ca + config.master_host_name = config_master_host_name + config.ca_host_name = config_ca_host_name + config.ips = config_ips + + remote_api = gen_remote_api(config.master_host_name, paths.ETC_IPA) + installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + cafile = paths.IPA_CA_CRT + with redirect_stdout(ansible_log): + try: + ansible_log.debug("-- CONNECT --") + 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=dirman_password) + + ansible_log.debug("-- INSTALL_CA_CERT --") + # Update and istall updated CA file + cafile = install_ca_cert(conn, api.env.basedn, api.env.realm, cafile) + install_ca_cert(conn, api.env.basedn, api.env.realm, cafile, + destfile=paths.KDC_CA_BUNDLE_PEM) + install_ca_cert(conn, api.env.basedn, api.env.realm, cafile, + destfile=paths.CA_BUNDLE_PEM) + + finally: + if conn.isconnected(): + ansible_log.debug("-- DISCONNECT --") + conn.disconnect() + + # done # + + ansible_module.exit_json(changed=True, + config_master_host_name=config.master_host_name, + config_ca_host_name=config.ca_host_name) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_krb_enable_ssl.py b/roles/ipareplica/library/ipareplica_krb_enable_ssl.py new file mode 100644 index 00000000..26ff48df --- /dev/null +++ b/roles/ipareplica/library/ipareplica_krb_enable_ssl.py @@ -0,0 +1,147 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_krb_enable_ssl +short description: KRB enable SSL +description: + KRB enable SSL +options: +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + #### server ### + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + no_pkinit=dict(required=False, type='bool'), + #### certificate system ### + subject_base=dict(required=True), + #### additional ### + config_master_host_name=dict(required=True), + ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _ca_file=dict(required=False), + _dirsrv_pkcs12_info = dict(required=False), + _pkinit_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + dirman_password=dict(required=True, no_log=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.no_pkinit = ansible_module.params.get('no_pkinit') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + #installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + dirsrv_pkcs12_info = ansible_module.params.get('_dirsrv_pkcs12_info') + options._pkinit_pkcs12_info = ansible_module.params.get('_pkinit_pkcs12_info') + options._top_dir = ansible_module.params.get('_top_dir') + dirman_password = ansible_module.params.get('dirman_password') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + pkinit_pkcs12_info = installer._pkinit_pkcs12_info + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.dirman_password = dirman_password + + remote_api = gen_remote_api(master_host_name, paths.ETC_IPA) + #installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + # There is a api.Backend.ldap2.connect call somewhere in ca, ds, dns or + # ntpinstance + api.Backend.ldap2.connect() + conn.connect(ccache=ccache) + + # krb + krb = krbinstance.KrbInstance(fstore) + krb.set_output(ansible_log) + with redirect_stdout(ansible_log): + krb.init_info(api.env.realm, api.env.host, + setup_pkinit=not options.no_pkinit, + subject_base=options.subject_base) + + ansible_log.debug("-- KRB ENABLE_SSL --") + + # configure PKINIT now that all required services are in place + krb.enable_ssl() + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_prepare.py b/roles/ipareplica/library/ipareplica_prepare.py new file mode 100644 index 00000000..ab9313a3 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_prepare.py @@ -0,0 +1,759 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_prepare +short description: Prepare ipa replica installation +description: + Prepare ipa replica installation: Create IPA configuration file, run install + checks again and also update the host name and the hosts file if needed. + The tests and also the results from ipareplica_test are needed. +ptions: + dm_password: + description: Directory Manager password + required: yes + password: + description: Admin user kerberos password + required: yes + ip_addresses: + description: List of Master Server IP Addresses + required: no + domain: + description: Primary DNS domain of the IPA deployment + required: yes + realm: + description: Kerberos realm name of the IPA deployment + required: yes + hostname: + description: Fully qualified name of this host + required: yes + ca_cert_files: + description: List of iles containing CA certificates for the service certificate files + required: yes + no_host_dns: + description: Do not use DNS for hostname lookup during installation + required: yes + setup_adtrust: + description: + required: yes + setup_kra: + description: + required: yes + setup_dns: + description: + required: yes + external_ca: + description: + required: yes + external_cert_files: + description: + required: yes + subject_base: + description: + required: yes + ca_subject: + description: + required: yes + reverse_zones: + description: + required: yes + no_reverse: + description: + required: yes + auto_reverse: + description: + required: yes + forwarders: + description: + required: yes + no_forwarders: + description: + required: yes + auto_forwarders: + description: + required: yes + forward_policy: + description: + required: yes + enable_compat: + description: + required: yes + netbios_name: + description: + required: yes + rid_base: + description: + required: yes + secondary_rid_base: + description: + required: yes + setup_ca: + description: + required: yes + _hostname_overridden: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + ### basic ### + dm_password=dict(required=False, no_log=True), + password=dict(required=False, no_log=True), + ip_addresses=dict(required=False, type='list', default=[]), + domain=dict(required=False), + realm=dict(required=False), + hostname=dict(required=False), + principal=dict(required=True), + ca_cert_files=dict(required=False, type='list', default=[]), + no_host_dns=dict(required=False, type='bool', default=False), + ### server ### + setup_adtrust=dict(required=False, type='bool'), + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + setup_dns=dict(required=False, type='bool'), + ### ssl certificate ### + dirsrv_cert_files=dict(required=False, type='list', default=[]), + dirsrv_pin=dict(required=False), + http_cert_files=dict(required=False, type='list', default=[]), + http_pin=dict(required=False), + pkinit_cert_files=dict(required=False, type='list', default=[]), + pkinit_pin=dict(required=False), + ### client ### + keytab=dict(required=False), + mkhomedir=dict(required=False, type='bool'), + force_join=dict(required=False, type='bool'), + no_ntp=dict(required=False, type='bool'), + ssh_trust_dns=dict(required=False, type='bool'), + no_ssh=dict(required=False, type='bool'), + no_sshd=dict(required=False, type='bool'), + no_dns_sshfp=dict(required=False, type='bool'), + ### certificate system ### + #subject_base=dict(required=False), + no_dnssec_validation=dict(required=False, type='bool'), + ### dns ### + ### ad trust ### + ### additional ### + server=dict(required=True), + skip_conncheck=dict(required=False, type='bool'), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options.dm_password = ansible_module.params.get('dm_password') + options.password = options.dm_password + options.admin_password = ansible_module.params.get('password') + options.ip_addresses = ansible_module_get_parsed_ip_addresses( + ansible_module) + options.domain_name = ansible_module.params.get('domain') + options.realm_name = ansible_module.params.get('realm') + options.host_name = ansible_module.params.get('hostname') + options.principal = ansible_module.params.get('principal') + options.ca_cert_files = ansible_module.params.get('ca_cert_files') + options.no_host_dns = ansible_module.params.get('no_host_dns') + ### server ### + options.setup_adtrust = ansible_module.params.get('setup_adtrust') + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.setup_dns = ansible_module.params.get('setup_dns') + ### ssl certificate ### + options.dirsrv_cert_files = ansible_module.params.get('dirsrv_cert_files') + options.http_cert_files = ansible_module.params.get('http_cert_files') + options.pkinit_cert_files = ansible_module.params.get('pkinit_cert_files') + ### client ### + options.keytab = ansible_module.params.get('keytab') + options.mkhomedir = ansible_module.params.get('mkhomedir') + options.force_join = ansible_module.params.get('force_join') + options.no_ntp = ansible_module.params.get('no_ntp') + options.ssh_trust_dns = ansible_module.params.get('ssh_trust_dns') + options.no_ssh = ansible_module.params.get('no_ssh') + options.no_sshd = ansible_module.params.get('no_sshd') + options.no_dns_sshfp = ansible_module.params.get('no_dns_sshfp') + ### certificate system ### + options.external_ca = ansible_module.params.get('external_ca') + options.external_cert_files = ansible_module.params.get( + 'external_cert_files') + #options.subject_base = ansible_module.params.get('subject_base') + #options.ca_subject = ansible_module.params.get('ca_subject') + options.no_dnssec_validation = ansible_module.params.get('no_dnssec_validation') + ### dns ### + options.reverse_zones = ansible_module.params.get('reverse_zones') + options.no_reverse = ansible_module.params.get('no_reverse') + options.auto_reverse = ansible_module.params.get('auto_reverse') + options.forwarders = ansible_module.params.get('forwarders') + options.no_forwarders = ansible_module.params.get('no_forwarders') + options.auto_forwarders = ansible_module.params.get('auto_forwarders') + options.forward_policy = ansible_module.params.get('forward_policy') + + ### additional ### + #options._host_name_overridden = ansible_module.params.get( + # '_hostname_overridden') + options.server = ansible_module.params.get('server') + options.skip_conncheck = ansible_module.params.get('skip_conncheck') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + # prepare (install prepare, install checks) # + + ########################################################################## + # replica promote_check ################################################## + ########################################################################## + + ansible_log.debug("== PROMOTE CHECK ==") + + #ansible_log.debug("-- NO_NTP --") # already done in test + + ## check selinux status, http and DS ports, NTP conflicting services + #common_check(options.no_ntp) + + ansible_log.debug("-- ENROLLED? --") + + client_fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) + if not client_fstore.has_files(): + try: + with redirect_stdout(ansible_log): + # do not use ensure_enrolled, it uses redirect_output + # ensure_enrolled(installer) + + args = [paths.IPA_CLIENT_INSTALL, "--unattended", "--no-ntp"] + stdin = None + nolog = [] + + if installer.domain_name: + args.extend(["--domain", installer.domain_name]) + if installer.server: + args.extend(["--server", installer.server]) + if installer.realm_name: + args.extend(["--realm", installer.realm_name]) + if installer.host_name: + args.extend(["--hostname", installer.host_name]) + + if installer.password: + args.extend(["--password", installer.password]) + nolog.append(installer.password) + else: + if installer.admin_password: + # Always set principal if password was set explicitly, + # the password itself gets passed directly via stdin + args.extend(["--principal", installer.principal or "admin"]) + stdin = installer.admin_password + if installer.keytab: + args.extend(["--keytab", installer.keytab]) + + if installer.no_dns_sshfp: + args.append("--no-dns-sshfp") + if installer.ssh_trust_dns: + args.append("--ssh-trust-dns") + if installer.no_ssh: + args.append("--no-ssh") + if installer.no_sshd: + args.append("--no-sshd") + if installer.mkhomedir: + args.append("--mkhomedir") + if installer.force_join: + args.append("--force-join") + + ansible_log.debug(" ".join(args)) + try: + # Call client install script + service.print_msg("Configuring client side components") + installer._enrollment_performed = True + ipautil.run(args, stdin=stdin, nolog=nolog) #, redirect_output=True) + #print() + except ipautil.CalledProcessError: + raise ScriptError("Configuration of client side components failed!") + + except ScriptError as msg: + ansible_module.fail_json(msg=str(msg)) + else: + if (options.domain_name or options.server or options.realm_name or + options.host_name or options.password or options.keytab): + ansible_module.log( + "IPA client is already configured on this system, ignoring " + "the --domain, --server, --realm, --hostname, --password " + "and --keytab options.") + + sstore = sysrestore.StateFile(paths.SYSRESTORE) + fstore = sysrestore.FileStore(paths.SYSRESTORE) + + installer._enrollment_performed = False + installer._top_dir = tempfile.mkdtemp("ipa") + + #with ipautil.private_ccache(): + dir_path = tempfile.mkdtemp(prefix='krbcc') + os.environ['KRB5CCNAME'] = os.path.join(dir_path, 'ccache') + + ansible_log.debug("-- API --") + + env = Env() + env._bootstrap(context='installer', confdir=paths.ETC_IPA, log=None) + env._finalize_core(**dict(constants.DEFAULT_CONFIG)) + + # pylint: disable=no-member + xmlrpc_uri = 'https://{}/ipa/xml'.format(ipautil.format_netloc(env.host)) + api.bootstrap(in_server=True, + context='installer', + confdir=paths.ETC_IPA, + ldap_uri=installutils.realm_to_ldapi_uri(env.realm), + xmlrpc_uri=xmlrpc_uri) + # pylint: enable=no-member + api.finalize() + + ansible_log.debug("-- REPLICA_CONFIG --") + + config = ReplicaConfig() + config.realm_name = api.env.realm + config.host_name = api.env.host + config.domain_name = api.env.domain + config.master_host_name = api.env.server + config.ca_host_name = api.env.ca_host + config.kra_host_name = config.ca_host_name + config.ca_ds_port = 389 + config.setup_ca = options.setup_ca + config.setup_kra = options.setup_kra + config.dir = installer._top_dir + config.basedn = api.env.basedn + + # load and check certificates # + + ansible_log.debug("-- CERT_FILES --") + + http_pkcs12_file = None + http_pkcs12_info = None + http_ca_cert = None + dirsrv_pkcs12_file = None + dirsrv_pkcs12_info = None + dirsrv_ca_cert = None + pkinit_pkcs12_file = None + pkinit_pkcs12_info = None + pkinit_ca_cert = None + + if options.http_cert_files: + ansible_log.debug("-- HTTP_CERT_FILES --") + if options.http_pin is None: + ansible_module.fail_json(msg= + "Apache Server private key unlock password required") + http_pkcs12_file, http_pin, http_ca_cert = load_pkcs12( + cert_files=options.http_cert_files, + key_password=options.http_pin, + key_nickname=options.http_cert_name, + ca_cert_files=options.ca_cert_files, + host_name=config.host_name) + http_pkcs12_info = (http_pkcs12_file.name, http_pin) + + if options.dirsrv_cert_files: + ansible_log.debug("-- DIRSRV_CERT_FILES --") + if options.dirsrv_pin is None: + ansible_module.fail_json(msg= + "Directory Server private key unlock password required") + dirsrv_pkcs12_file, dirsrv_pin, dirsrv_ca_cert = load_pkcs12( + cert_files=options.dirsrv_cert_files, + key_password=options.dirsrv_pin, + key_nickname=options.dirsrv_cert_name, + ca_cert_files=options.ca_cert_files, + host_name=config.host_name) + dirsrv_pkcs12_info = (dirsrv_pkcs12_file.name, dirsrv_pin) + + if options.pkinit_cert_files: + ansible_log.debug("-- PKINIT_CERT_FILES --") + if options.pkinit_pin is None: + ansible_module.fail_json(msg= + "Kerberos KDC private key unlock password required") + pkinit_pkcs12_file, pkinit_pin, pkinit_ca_cert = load_pkcs12( + cert_files=options.pkinit_cert_files, + key_password=options.pkinit_pin, + key_nickname=options.pkinit_cert_name, + ca_cert_files=options.ca_cert_files, + realm_name=config.realm_name) + pkinit_pkcs12_info = (pkinit_pkcs12_file.name, pkinit_pin) + + if (options.http_cert_files and options.dirsrv_cert_files and + http_ca_cert != dirsrv_ca_cert): + ansible_module.fail_json( + msg="Apache Server SSL certificate and Directory " + "Server SSL certificate are not signed by the same" + " CA certificate") + + if (options.http_cert_files and + options.pkinit_cert_files and + http_ca_cert != pkinit_ca_cert): + ansible_module.fail_json( + msg="Apache Server SSL certificate and PKINIT KDC " + "certificate are not signed by the same CA " + "certificate") + + ansible_log.debug("-- FQDN --") + + installutils.verify_fqdn(config.host_name, options.no_host_dns) + installutils.verify_fqdn(config.master_host_name, options.no_host_dns) + + ansible_log.debug("-- KINIT_KEYTAB --") + + ccache = os.environ['KRB5CCNAME'] + kinit_keytab('host/{env.host}@{env.realm}'.format(env=api.env), + paths.KRB5_KEYTAB, + ccache) + + ansible_log.debug("-- CA_CRT --") + + cafile = paths.IPA_CA_CRT + if not os.path.isfile(cafile): + ansible_module.fail_json( + msg="CA cert file is not available! Please reinstall" + "the client and try again.") + + ansible_log.debug("-- REMOTE_API --") + + ldapuri = 'ldaps://%s' % ipautil.format_netloc(config.master_host_name) + xmlrpc_uri = 'https://{}/ipa/xml'.format( + 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, + xmlrpc_uri=xmlrpc_uri) + remote_api.finalize() + installer._remote_api = remote_api + + ansible_log.debug("-- RPC_CLIENT --") + + with rpc_client(remote_api) as client: + check_remote_version(client, parse_version(api.env.version)) + check_remote_fips_mode(client, api.env.fips_mode) + + conn = remote_api.Backend.ldap2 + replman = None + try: + ansible_log.debug("-- CONNECT --") + # Try out authentication + conn.connect(ccache=ccache) + replman = ReplicationManager(config.realm_name, + config.master_host_name, None) + + ansible_log.debug("-- CHECK IPA_DOMAIN --") + + promotion_check_ipa_domain(conn, remote_api.env.basedn) + + ansible_log.debug("-- CHECK DOMAIN_LEVEL --") + + domain_level = current_domain_level(remote_api) + check_domain_level_is_supported(domain_level) + if domain_level < constants.DOMAIN_LEVEL_1: + ansible_module.fail_json(msg= + "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) + ) + + ansible_log.debug("-- CHECK AUTHORIZATION --") + + # Check authorization + result = remote_api.Command['hostgroup_find']( + cn=u'ipaservers', + host=[unicode(api.env.host)] + )['result'] + add_to_ipaservers = not result + + ansible_log.debug("-- ADD_TO_IPASERVERS --") + + if add_to_ipaservers: + if options.password and not options.admin_password: + raise errors.ACIError(info="Not authorized") + + if installer._ccache is None: + del os.environ['KRB5CCNAME'] + else: + os.environ['KRB5CCNAME'] = installer._ccache + + try: + installutils.check_creds(options, config.realm_name) + installer._ccache = os.environ.get('KRB5CCNAME') + finally: + os.environ['KRB5CCNAME'] = ccache + + conn.disconnect() + conn.connect(ccache=installer._ccache) + + try: + result = remote_api.Command['hostgroup_show']( + u'ipaservers', + all=True, + rights=True + )['result'] + + if 'w' not in result['attributelevelrights']['member']: + raise errors.ACIError(info="Not authorized") + finally: + ansible_log.debug("-- RECONNECT --") + conn.disconnect() + conn.connect(ccache=ccache) + + ansible_log.debug("-- CHECK FOR REPLICATION AGREEMENT --") + + # Check that we don't already have a replication agreement + if replman.get_replication_agreement(config.host_name): + msg = ("A replication agreement for this host already exists. " + "It needs to be removed.\n" + "Run this command:\n" + " %% ipa-replica-manage del {host} --force" + .format(host=config.host_name)) + raise ScriptError(msg, rval=3) + + ansible_log.debug("-- DETECT REPLICATION MANAGER GROUP --") + + # Detect if the other master can handle replication managers + # cn=replication managers,cn=sysaccounts,cn=etc,$SUFFIX + dn = DN(('cn', 'replication managers'), ('cn', 'sysaccounts'), + ('cn', 'etc'), ipautil.realm_to_suffix(config.realm_name)) + try: + conn.get_entry(dn) + except errors.NotFound: + msg = ("The Replication Managers group is not available in " + "the domain. Replica promotion requires the use of " + "Replication Managers to be able to replicate data. " + "Upgrade the peer master or use the ipa-replica-prepare " + "command on the master and use a prep file to install " + "this replica.") + logger.error("%s", msg) + raise ScriptError(rval=3) + + ansible_log.debug("-- CHECK DNS_MASTERS --") + + dns_masters = remote_api.Object['dnsrecord'].get_dns_masters() + if dns_masters: + if not options.no_host_dns: + logger.debug('Check forward/reverse DNS resolution') + resolution_ok = ( + check_dns_resolution(config.master_host_name, + 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') + + ansible_log.debug("-- GET_IPA_CONFIG --") + + entry_attrs = conn.get_ipa_config() + subject_base = entry_attrs.get('ipacertificatesubjectbase', [None])[0] + if subject_base is not None: + config.subject_base = DN(subject_base) + + ansible_log.debug("-- SEARCH FOR CA --") + + # Find if any server has a CA + ca_host = service.find_providing_server( + 'CA', conn, config.ca_host_name) + if ca_host is not None: + config.ca_host_name = ca_host + ca_enabled = True + if options.dirsrv_cert_files: + logger.error("Certificates could not be provided when " + "CA is present on some master.") + raise ScriptError(rval=3) + else: + if options.setup_ca: + logger.error("The remote master does not have a CA " + "installed, can't set up CA") + raise ScriptError(rval=3) + ca_enabled = False + if not options.dirsrv_cert_files: + logger.error("Cannot issue certificates: a CA is not " + "installed. Use the --http-cert-file, " + "--dirsrv-cert-file options to provide " + "custom certificates.") + raise ScriptError(rval=3) + + ansible_log.debug("-- SEARCH FOR KRA --") + + kra_host = service.find_providing_server( + 'KRA', conn, config.kra_host_name) + if kra_host is not None: + config.kra_host_name = kra_host + kra_enabled = True + else: + if options.setup_kra: + logger.error("There is no KRA server in the domain, " + "can't setup a KRA clone") + raise ScriptError(rval=3) + kra_enabled = False + + ansible_log.debug("-- CHECK CA --") + + if ca_enabled: + options.realm_name = config.realm_name + options.host_name = config.host_name + ca.install_check(False, config, options) + + ansible_log.debug(" ca.external_cert_file=%s" % repr(ca.external_cert_file)) + ansible_log.debug(" ca.external_ca_file=%s" % repr(ca.external_ca_file)) + + # TODO + # TODO + # Save global vars external_cert_file, external_ca_file for + # later use + # TODO + # TODO + + ansible_log.debug("-- CHECK KRA --") + + if kra_enabled: + try: + kra.install_check(remote_api, config, options) + except RuntimeError as e: + raise ScriptError(e) + + ansible_log.debug("-- CHECK DNS --") + + 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) + + ansible_log.debug("-- CHECK ADTRUST --") + + if options.setup_adtrust: + adtrust.install_check(False, options, remote_api) + + except errors.ACIError: + logger.debug("%s", traceback.format_exc()) + raise ScriptError("\nInsufficient privileges to promote the server." + "\nPossible issues:" + "\n- A user has insufficient privileges" + "\n- This client has insufficient privileges " + "to become an IPA replica") + except errors.LDAPError: + logger.debug("%s", traceback.format_exc()) + raise ScriptError("\nUnable to connect to LDAP server %s" % + config.master_host_name) + finally: + if replman and replman.conn: + ansible_log.debug("-- UNBIND REPLMAN--") + replman.conn.unbind() + if conn.isconnected(): + ansible_log.debug("-- DISCONNECT --") + conn.disconnect() + + ansible_log.debug("-- CHECK CONNECTION --") + + # check connection + if not options.skip_conncheck: + if add_to_ipaservers: + # use user's credentials when the server host is not ipaservers + if installer._ccache is None: + del os.environ['KRB5CCNAME'] + else: + os.environ['KRB5CCNAME'] = installer._ccache + + try: + with redirect_stdout(ansible_log): + replica_conn_check( + config.master_host_name, config.host_name, + config.realm_name, options.setup_ca, 389, + options.admin_password, principal=options.principal, + ca_cert_file=cafile) + finally: + if add_to_ipaservers: + os.environ['KRB5CCNAME'] = ccache + + installer._ca_enabled = ca_enabled + installer._kra_enabled = kra_enabled + installer._ca_file = cafile + installer._fstore = fstore + installer._sstore = sstore + installer._config = config + installer._add_to_ipaservers = add_to_ipaservers + + # done # + + ansible_module.exit_json(changed=True, + ccache=ccache, + installer_ccache=installer._ccache, + subject_base=str(config.subject_base), + _ca_enabled=ca_enabled, + _ca_subject=str(options._ca_subject), + _subject_base=str(options._subject_base) if options._subject_base is not None else None, + _kra_enabled=kra_enabled, + _ca_file=cafile, + _top_dir=installer._top_dir, + _add_to_ipaservers=add_to_ipaservers, + _dirsrv_pkcs12_file=dirsrv_pkcs12_file, + _dirsrv_pkcs12_info=dirsrv_pkcs12_info, + _dirsrv_ca_cert=dirsrv_ca_cert, + _http_pkcs12_file=http_pkcs12_file, + _http_pkcs12_info=http_pkcs12_info, + _http_ca_cert=http_ca_cert, + _pkinit_pkcs12_file=pkinit_pkcs12_file, + _pkinit_pkcs12_info=pkinit_pkcs12_info, + _pkinit_ca_cert=pkinit_ca_cert, + no_dnssec_validation=options.no_dnssec_validation, + config_setup_ca=config.setup_ca, + config_master_host_name=config.master_host_name, + config_ca_host_name=config.ca_host_name, + config_ips=[ str(ip) for ip in config.ips ]) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_promote_openldap_conf.py b/roles/ipareplica/library/ipareplica_promote_openldap_conf.py new file mode 100644 index 00000000..308c6e2d --- /dev/null +++ b/roles/ipareplica/library/ipareplica_promote_openldap_conf.py @@ -0,0 +1,141 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_promote_openldap_conf +short description: Promote openldap.conf +description: + Promote openldap.conf +options: + setup_kra: + description: + required: no + subject_base: + description: + required: yes + ccache: + description: + required: yes + _top_dir: + description: + required: yes + config_setup_ca: + description: + required: yes + config_master_host_name: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + ### server ### + setup_kra=dict(required=False, type='bool'), + ### certificate system ### + subject_base=dict(required=True), + ### additional ### + ccache=dict(required=True), + _top_dir = dict(required=True), + config_setup_ca=dict(required=True), + config_master_host_name=dict(required=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_kra = ansible_module.params.get('setup_kra') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + options._top_dir = ansible_module.params.get('_top_dir') + config_setup_ca = ansible_module.params.get('config_setup_ca') + installer.setup_ca = config_setup_ca + config_master_host_name = ansible_module.params.get('config_master_host_name') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + + ansible_log.debug("== INSTALL ==") + + promote = installer.promote + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.subject_base = options.subject_base + config.setup_ca = config_setup_ca + config.master_host_name = config_master_host_name + + remote_api = gen_remote_api(config.master_host_name, paths.ETC_IPA) + installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + with redirect_stdout(ansible_log): + ansible_log.debug("-- PROMOTE OPENLDAP_CONF--") + + promote_openldap_conf(config.host_name, config.master_host_name) + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_promote_sssd.py b/roles/ipareplica/library/ipareplica_promote_sssd.py new file mode 100644 index 00000000..f8bcd317 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_promote_sssd.py @@ -0,0 +1,140 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_promote_sssd +short description: Promote sssd +description: + Promote sssd +options: + setup_kra: + description: + required: no + subject_base: + description: + required: yes + ccache: + description: + required: yes + _top_dir: + description: + required: yes + config_setup_ca: + description: + required: yes + config_master_host_name: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + ### server ### + setup_kra=dict(required=False, type='bool'), + ### certificate system ### + subject_base=dict(required=True), + ### additional ### + ccache=dict(required=True), + _top_dir = dict(required=True), + config_setup_ca=dict(required=True), + config_master_host_name=dict(required=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_kra = ansible_module.params.get('setup_kra') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + options._top_dir = ansible_module.params.get('_top_dir') + config_setup_ca = ansible_module.params.get('config_setup_ca') + installer.setup_ca = config_setup_ca + config_master_host_name = ansible_module.params.get('config_master_host_name') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + promote = installer.promote + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.subject_base = options.subject_base + config.setup_ca = config_setup_ca + config.master_host_name = config_master_host_name + + remote_api = gen_remote_api(config.master_host_name, paths.ETC_IPA) + installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + with redirect_stdout(ansible_log): + ansible_log.debug("-- PROMOTE SSSD --") + + promote_sssd(config.host_name) + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_restart_kdc.py b/roles/ipareplica/library/ipareplica_restart_kdc.py new file mode 100644 index 00000000..05b91596 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_restart_kdc.py @@ -0,0 +1,148 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_restart_kdc +short description: Restart KDC +description: + Restart KDC +options: +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + #### server ### + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + no_pkinit=dict(required=False, type='bool'), + no_ui_redirect=dict(required=False, type='bool'), + #### certificate system ### + subject_base=dict(required=True), + #### additional ### + config_master_host_name=dict(required=True), + ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _ca_file=dict(required=False), + _dirsrv_pkcs12_info = dict(required=False), + _pkinit_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + dirman_password=dict(required=True, no_log=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.no_pkinit = ansible_module.params.get('no_pkinit') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + #installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + dirsrv_pkcs12_info = ansible_module.params.get('_dirsrv_pkcs12_info') + pkinit_pkcs12_info = ansible_module.params.get('_pkinit_pkcs12_info') + options._top_dir = ansible_module.params.get('_top_dir') + dirman_password = ansible_module.params.get('dirman_password') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + pkinit_pkcs12_info = installer._pkinit_pkcs12_info + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.dirman_password = dirman_password + + remote_api = gen_remote_api(master_host_name, paths.ETC_IPA) + #installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + # There is a api.Backend.ldap2.connect call somewhere in ca, ds, dns or + # ntpinstance + api.Backend.ldap2.connect() + conn.connect(ccache=ccache) + + # krb + krb = krbinstance.KrbInstance(fstore) + krb.set_output(ansible_log) + with redirect_stdout(ansible_log): + krb.init_info(api.env.realm, api.env.host, + setup_pkinit=not options.no_pkinit, + subject_base=options.subject_base) + + ansible_log.debug("-- RESTART KDC --") + + service.print_msg("Restarting the KDC") + krb.restart() + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_setup_adtrust.py b/roles/ipareplica/library/ipareplica_setup_adtrust.py new file mode 100644 index 00000000..b892f330 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_setup_adtrust.py @@ -0,0 +1,144 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_setup_adtrust +short description: Setup adtrust +description: + Setup adtrust +options: + setup_adtrust: + description: + required: yes + setup_kra: + description: + required: yes + subject_base: + description: + required: yes + ccache: + description: + required: yes + _top_dir: + description: + required: yes + config_setup_ca: + description: + required: yes + config_master_host_name: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + ### server ### + setup_adtrust=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + ### certificate system ### + subject_base=dict(required=True), + ### additional ### + ccache=dict(required=True), + _top_dir = dict(required=True), + config_setup_ca=dict(required=True), + config_master_host_name=dict(required=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_adtrust = ansible_module.params.get('setup_adtrust') + options.setup_kra = ansible_module.params.get('setup_kra') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + options._top_dir = ansible_module.params.get('_top_dir') + config_setup_ca = ansible_module.params.get('config_setup_ca') + config_master_host_name = ansible_module.params.get('config_master_host_name') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.subject_base = options.subject_base + + remote_api = gen_remote_api(master_host_name, paths.ETC_IPA) + installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + with redirect_stdout(ansible_log): + #if options.setup_adtrust: + ansible_log.debug("-- INSTALL ADTRUST --") + + adtrust.install(False, options, fstore, api) + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_setup_ca.py b/roles/ipareplica/library/ipareplica_setup_ca.py new file mode 100644 index 00000000..b322da58 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_setup_ca.py @@ -0,0 +1,218 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_setup_ca +short description: Setup CA +description: + Setup CA +options: + setup_ca: + description: + required: yes + setup_kra: + description: + required: yes + no_pkinit: + description: + required: yes + no_ui_redirect: + description: + required: yes + subject_base: + description: + required: yes + ccache: + description: + required: yes + _ca_enabled: + description: + required: yes + _ca_file: + description: + required: yes + _dirsrv_pkcs12_info: + description: + required: yes + _pkinit_pkcs12_info: + description: + required: yes + _top_dir: + description: + required: yes + _ca_subject: + description: + required: yes + _subject_base: + description: + required: yes + dirman_password: + description: + required: yes + config_setup_ca: + description: + required: yes + config_master_host_name: + description: + required: yes + config_ca_host_name: + description: + required: yes + config_ips: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + #### server ### + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + no_pkinit=dict(required=False, type='bool'), + no_ui_redirect=dict(required=False, type='bool'), + #### certificate system ### + subject_base=dict(required=True), + #### additional ### + ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _ca_file=dict(required=False), + _dirsrv_pkcs12_info = dict(required=False), + _pkinit_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + _ca_subject=dict(required=True), + _subject_base=dict(required=True), + dirman_password=dict(required=True, no_log=True), + config_setup_ca=dict(required=True), + config_master_host_name=dict(required=True), + config_ca_host_name=dict(required=True), + config_ips=dict(required=False, type='list', default=[]), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.no_pkinit = ansible_module.params.get('no_pkinit') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + #installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + installer._dirsrv_pkcs12_info = ansible_module.params.get('_dirsrv_pkcs12_info') + installer._pkinit_pkcs12_info = ansible_module.params.get('_pkinit_pkcs12_info') + options._top_dir = ansible_module.params.get('_top_dir') + options._ca_subject = ansible_module.params.get('_ca_subject') + if options._ca_subject is not None: + options._ca_subject = DN(options._ca_subject) + options._subject_base = ansible_module.params.get('_subject_base') + if options._subject_base is not None: + options._subject_base = DN(options._subject_base) + dirman_password = ansible_module.params.get('dirman_password') + config_setup_ca = ansible_module.params.get('config_setup_ca') + config_master_host_name = ansible_module.params.get('config_master_host_name') + config_ca_host_name = ansible_module.params.get('config_ca_host_name') + config_ips = ansible_module_get_parsed_ip_addresses(ansible_module, + "config_ips") + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + pkinit_pkcs12_info = installer._pkinit_pkcs12_info + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + + config = gen_ReplicaConfig() + config.dirman_password = dirman_password + config.setup_ca = config_setup_ca + config.master_host_name = config_master_host_name + config.ca_host_name = config_ca_host_name + config.ips = config_ips + + remote_api = gen_remote_api(config.master_host_name, paths.ETC_IPA) + options._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + # There is a api.Backend.ldap2.connect call somewhere in ca, ds, dns or + # ntpinstance + api.Backend.ldap2.connect() + #conn.connect(ccache=ccache) + + ansible_log.debug("-- INSTALL CA --") + + with redirect_stdout(ansible_log): + options.realm_name = config.realm_name + options.domain_name = config.domain_name + options.host_name = config.host_name + options.dm_password = config.dirman_password + ca.install(False, config, options) + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_setup_certmonger.py b/roles/ipareplica/library/ipareplica_setup_certmonger.py new file mode 100644 index 00000000..d9829757 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_setup_certmonger.py @@ -0,0 +1,78 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_setup_certmonger +short description: Setup certmonger +description: + Setup certmonger +options: +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + + with redirect_stdout(ansible_log): + ansible_log.debug("-- CONFIGURE_CERTMONGER --") + + # FIXME: allow to use passed in certs instead + configure_certmonger() + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_setup_custodia.py b/roles/ipareplica/library/ipareplica_setup_custodia.py new file mode 100644 index 00000000..628eb495 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_setup_custodia.py @@ -0,0 +1,180 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_setup_custodia +short description: Setup custodia +description: + Setup custodia +options: + setup_ca: + description: + required: yes + setup_kra: + description: + required: yes + no_pkinit: + description: + required: yes + no_ui_redirect: + description: + required: yes + subject_base: + description: + required: yes + config_master_host_name: + description: + required: yes + ccache: + description: + required: yes + _ca_enabled: + description: + required: yes + _ca_file: + description: + required: yes + _top_dir: + description: + required: yes + dirman_password: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + #### server ### + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + no_pkinit=dict(required=False, type='bool'), + no_ui_redirect=dict(required=False, type='bool'), + #### certificate system ### + subject_base=dict(required=True), + #### additional ### + config_master_host_name=dict(required=True), + ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _ca_file=dict(required=False), + _dirsrv_pkcs12_info = dict(required=False), + _pkinit_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + dirman_password=dict(required=True, no_log=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.no_pkinit = ansible_module.params.get('no_pkinit') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + #installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + dirsrv_pkcs12_info = ansible_module.params.get('_dirsrv_pkcs12_info') + options._pkinit_pkcs12_info = ansible_module.params.get('_pkinit_pkcs12_info') + options._top_dir = ansible_module.params.get('_top_dir') + dirman_password = ansible_module.params.get('dirman_password') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + pkinit_pkcs12_info = installer._pkinit_pkcs12_info + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.dirman_password = dirman_password + + remote_api = gen_remote_api(master_host_name, paths.ETC_IPA) + #installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + # There is a api.Backend.ldap2.connect call somewhere in ca, ds, dns or + # ntpinstance + api.Backend.ldap2.connect() + conn.connect(ccache=ccache) + + with redirect_stdout(ansible_log): + ansible_log.debug("-- INSTALL_CUSTODIA --") + + custodia = custodiainstance.CustodiaInstance(config.host_name, + config.realm_name) + if promote: + ansible_log.debug("-- CUSTODIA CREATE_REPLICA --") + custodia.create_replica(config.master_host_name) + else: + ansible_log.debug("-- CUSTODIA CREATE_INSTANCE --") + custodia.create_instance() + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_setup_dns.py b/roles/ipareplica/library/ipareplica_setup_dns.py new file mode 100644 index 00000000..6d6701a7 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_setup_dns.py @@ -0,0 +1,150 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_setup_dns +short description: Setup DNS +description: + Setup DNS +options: + setup_kra: + description: + required: yes + setup_dns: + description: + required: yes + subject_base: + description: + required: yes + ccache: + description: + required: yes + _top_dir: + description: + required: yes + config_setup_ca: + description: + required: yes + config_master_host_name: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + ### server ### + setup_kra=dict(required=False, type='bool'), + setup_dns=dict(required=False, type='bool'), + ### certificate system ### + subject_base=dict(required=True), + ### additional ### + ccache=dict(required=True), + _top_dir = dict(required=True), + config_setup_ca=dict(required=True), + config_master_host_name=dict(required=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_kra = ansible_module.params.get('setup_kra') + options.setup_dns = ansible_module.params.get('setup_dns') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + options._top_dir = ansible_module.params.get('_top_dir') + config_setup_ca = ansible_module.params.get('config_setup_ca') + config_master_host_name = ansible_module.params.get('config_master_host_name') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + promote = installer.promote + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.subject_base = options.subject_base + config.master_host_name = config_master_host_name + + remote_api = gen_remote_api(config.master_host_name, paths.ETC_IPA) + installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + # There is a api.Backend.ldap2.connect call somewhere in ca, ds, dns or + # ntpinstance + api.Backend.ldap2.connect() + + with redirect_stdout(ansible_log): + if options.setup_dns: + ansible_log.debug("-- INSTALL DNS --") + dns.install(False, True, options, api) + else: + ansible_log.debug("-- DNS UPDATE_SYSTEM_RECORDS --") + api.Command.dns_update_system_records() + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_setup_ds.py b/roles/ipareplica/library/ipareplica_setup_ds.py new file mode 100644 index 00000000..24b976aa --- /dev/null +++ b/roles/ipareplica/library/ipareplica_setup_ds.py @@ -0,0 +1,341 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_setup_ds +short description: Setup DS +description: + Setup DS +options: + dm_password: + description: Directory Manager password + required: yes + password: + description: Admin user kerberos password + required: yes + ip_addresses: + description: List of Master Server IP Addresses + required: no + domain: + description: Primary DNS domain of the IPA deployment + required: yes + realm: + description: Kerberos realm name of the IPA deployment + required: yes + hostname: + description: Fully qualified name of this host + required: yes + ca_cert_files: + description: List of iles containing CA certificates for the service certificate files + required: yes + no_host_dns: + description: Do not use DNS for hostname lookup during installation + required: yes + setup_adtrust: + description: + required: yes + setup_ca: + description: + required: yes + setup_kra: + description: + required: yes + setup_dns: + description: + required: yes + dirserv_cert_files: + description: + required: yes + force_join: + description: + required: yes + subject_base: + description: + required: yes + server: + description: + required: yes + ccache: + description: + required: yes + installer_ccache: + description: + required: yes + _ca_enabled: + description: + required: yes + _kra_enabled: + description: + required: yes + _dirsrv_pkcs12_info: + description: + required: yes + _http_pkcs12_info: + description: + required: yes + _pkinit_pkcs12_info: + description: + required: yes + _top_dir: + description: + required: yes + _add_to_ipaservers: + description: + required: yes + _ca_subject: + description: + required: yes + _subject_base: + description: + required: yes + dirman_password: + description: + required: yes + config_setup_ca: + description: + required: yes + config_master_host_name: + description: + required: yes + config_ca_host_name: + description: + required: yes + config_ips: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + ### basic ### + dm_password=dict(required=False, no_log=True), + password=dict(required=False, no_log=True), + ip_addresses=dict(required=False, type='list', default=[]), + domain=dict(required=False), + realm=dict(required=False), + hostname=dict(required=False), + ca_cert_files=dict(required=False, type='list', default=[]), + no_host_dns=dict(required=False, type='bool', default=False), + ### server ### + setup_adtrust=dict(required=False, type='bool'), + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + setup_dns=dict(required=False, type='bool'), + no_pkinit=dict(required=False, type='bool', default=False), + dirsrv_config_file=dict(required=False), + ### ssl certificate ### + dirsrv_cert_files=dict(required=False, type='list', default=[]), + ### client ### + force_join=dict(required=False, type='bool'), + ### certificate system ### + subject_base=dict(required=True), + ### additional ### + server=dict(required=True), + ccache=dict(required=True), + installer_ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _kra_enabled=dict(required=False, type='bool'), + _dirsrv_pkcs12_info = dict(required=False), + _http_pkcs12_info = dict(required=False), + _pkinit_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + _add_to_ipaservers = dict(required=True), + _ca_subject=dict(required=True), + _subject_base=dict(required=True), + dirman_password=dict(required=True, no_log=True), + config_setup_ca=dict(required=True), + config_master_host_name=dict(required=True), + config_ca_host_name=dict(required=True), + config_ips=dict(required=False, type='list', default=[]), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + options.dm_password = ansible_module.params.get('dm_password') + options.password = options.dm_password + options.admin_password = ansible_module.params.get('password') + options.ip_addresses = ansible_module_get_parsed_ip_addresses( + ansible_module) + options.domain_name = ansible_module.params.get('domain') + options.realm_name = ansible_module.params.get('realm') + options.host_name = ansible_module.params.get('hostname') + options.ca_cert_files = ansible_module.params.get('ca_cert_files') + options.no_host_dns = ansible_module.params.get('no_host_dns') + ### server ### + options.setup_adtrust = ansible_module.params.get('setup_adtrust') + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.setup_dns = ansible_module.params.get('setup_dns') + options.no_pkinit = ansible_module.params.get('no_pkinit') + options.dirsrv_config_file = ansible_module.params.get('dirsrv_config_file') + ### ssl certificate ### + options.dirsrv_cert_files = ansible_module.params.get('dirsrv_cert_files') + ### client ### + options.force_join = ansible_module.params.get('force_join') + ### certificate system ### + options.external_ca = ansible_module.params.get('external_ca') + options.external_cert_files = ansible_module.params.get( + 'external_cert_files') + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + options.ca_subject = ansible_module.params.get('ca_subject') + ### dns ### + options.reverse_zones = ansible_module.params.get('reverse_zones') + options.no_reverse = ansible_module.params.get('no_reverse') + options.auto_reverse = ansible_module.params.get('auto_reverse') + options.forwarders = ansible_module.params.get('forwarders') + options.no_forwarders = ansible_module.params.get('no_forwarders') + options.auto_forwarders = ansible_module.params.get('auto_forwarders') + options.forward_policy = ansible_module.params.get('forward_policy') + + ### additional ### + #options._host_name_overridden = ansible_module.params.get( + # '_hostname_overridden') + options.server = ansible_module.params.get('server') + master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + kra_enabled = ansible_module.params.get('_kra_enabled') + + dirsrv_pkcs12_info = ansible_module.params.get('_dirsrv_pkcs12_info') + http_pkcs12_info = ansible_module.params.get('_http_pkcs12_info') + pkinit_pkcs12_info = ansible_module.params.get('_pkinit_pkcs12_info') + + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + options._top_dir = ansible_module.params.get('_top_dir') + options._add_to_ipaservers = ansible_module.params.get('_add_to_ipaservers') + + options._ca_subject = ansible_module.params.get('_ca_subject') + options._subject_base = ansible_module.params.get('_subject_base') + + dirman_password = ansible_module.params.get('dirman_password') + config_setup_ca = ansible_module.params.get('config_setup_ca') + config_master_host_name = ansible_module.params.get('config_master_host_name') + config_ca_host_name = ansible_module.params.get('config_ca_host_name') + config_ips = ansible_module_get_parsed_ip_addresses(ansible_module, + "config_ips") + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.subject_base = options.subject_base + config.dirman_password = dirman_password + config.setup_ca = config_setup_ca + config.master_host_name = config_master_host_name + config.ca_host_name = config_ca_host_name + config.ips = config_ips + + remote_api = gen_remote_api(master_host_name, paths.ETC_IPA) + installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + cafile = paths.IPA_CA_CRT + try: + ansible_log.debug("-- CONNECT --") + 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=dirman_password) + + ansible_log.debug("-- CONFIGURE DIRSRV --") + # Configure dirsrv + with redirect_stdout(ansible_log): + ds = install_replica_ds(config, options, ca_enabled, + remote_api, + ca_file=cafile, + promote=promote, + pkcs12_info=dirsrv_pkcs12_info) + #show_obj(ds) + + ansible_log.debug("-- INSTALL DNS RECORDS --") + # Always try to install DNS records + install_dns_records(config, options, remote_api) + + ansible_log.debug("-- NTP LDAP ENABLE --") + ntpinstance.ntp_ldap_enable(config.host_name, ds.suffix, + remote_api.env.realm) + finally: + if conn.isconnected(): + ansible_log.debug("-- DISCONNECT --") + conn.disconnect() + + # done # + + ansible_module.exit_json(changed=True, + ds_suffix=str(ds.suffix), + ds_ca_subject=str(ds.ca_subject)) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_setup_http.py b/roles/ipareplica/library/ipareplica_setup_http.py new file mode 100644 index 00000000..ff6450a3 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_setup_http.py @@ -0,0 +1,180 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_setup_http +short description: Setup HTTP +description: + Setup HTTP +options: + setup_ca: + description: + required: yes + setup_kra: + description: + required: yes + no_pkinit: + description: + required: yes + no_ui_redirect: + description: + required: yes + subject_base: + description: + required: yes + config_master_host_name: + description: + required: yes + ccache: + description: + required: yes + _ca_enabled: + description: + required: yes + _ca_file: + description: + required: yes + _http_pkcs12_info: + description: + required: yes + _top_dir: + description: + required: yes + dirman_password: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + #### server ### + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + no_pkinit=dict(required=False, type='bool'), + no_ui_redirect=dict(required=False, type='bool'), + #### certificate system ### + subject_base=dict(required=True), + config_master_host_name=dict(required=True), + ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _ca_file=dict(required=False), + _http_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + dirman_password=dict(required=True, no_log=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.no_pkinit = ansible_module.params.get('no_pkinit') + options.no_ui_redirect = ansible_module.params.get('no_ui_redirect') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + #installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + http_pkcs12_info = ansible_module.params.get('_http_pkcs12_info') + options._top_dir = ansible_module.params.get('_top_dir') + dirman_password = ansible_module.params.get('dirman_password') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.dirman_password = dirman_password + config.subject_base = options.subject_base + + remote_api = gen_remote_api(master_host_name, paths.ETC_IPA) + #installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + # There is a api.Backend.ldap2.connect call somewhere in ca, ds, dns or + # ntpinstance + api.Backend.ldap2.connect() + conn.connect(ccache=ccache) + + cafile = paths.IPA_CA_CRT + with redirect_stdout(ansible_log): + ansible_log.debug("-- INSTALL_HTTP --") + + 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) + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_setup_kra.py b/roles/ipareplica/library/ipareplica_setup_kra.py new file mode 100644 index 00000000..5a96fd9f --- /dev/null +++ b/roles/ipareplica/library/ipareplica_setup_kra.py @@ -0,0 +1,225 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_setup_kra +short description: Setup KRA +description: + Setup KRA +options: + dm_password: + description: Directory Manager password + required: yes + password: + description: Admin user kerberos password + required: yes + ip_addresses: + description: List of Master Server IP Addresses + required: no + domain: + description: Primary DNS domain of the IPA deployment + required: yes + realm: + description: Kerberos realm name of the IPA deployment + required: yes + hostname: + description: Fully qualified name of this host + required: yes + ca_cert_files: + description: List of iles containing CA certificates for the service certificate files + required: yes + no_host_dns: + description: Do not use DNS for hostname lookup during installation + required: yes + setup_adtrust: + description: + required: yes + setup_kra: + description: + required: yes + setup_dns: + description: + required: yes + external_ca: + description: +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + ### basic ### + dm_password=dict(required=False, no_log=True), + password=dict(required=False, no_log=True), + ip_addresses=dict(required=False, type='list', default=[]), + domain=dict(required=False), + realm=dict(required=False), + hostname=dict(required=False), + ca_cert_files=dict(required=False, type='list', default=[]), + no_host_dns=dict(required=False, type='bool', default=False), + ### server ### + setup_adtrust=dict(required=False, type='bool'), + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + setup_dns=dict(required=False, type='bool'), + ### ssl certificate ### + dirsrv_cert_files=dict(required=False, type='list', default=[]), + ### client ### + force_join=dict(required=False, type='bool'), + ### certificate system ### + subject_base=dict(required=True), + ### additional ### + server=dict(required=True), + config_master_host_name=dict(required=True), + ccache=dict(required=True), + installer_ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _kra_enabled=dict(required=False, type='bool'), + _dirsrv_pkcs12_info = dict(required=False), + _http_pkcs12_info = dict(required=False), + _pkinit_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + _add_to_ipaservers = dict(required=True), + _ca_subject=dict(required=True), + _subject_base=dict(required=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + options.dm_password = ansible_module.params.get('dm_password') + options.password = options.dm_password + options.admin_password = ansible_module.params.get('password') + options.ip_addresses = ansible_module_get_parsed_ip_addresses( + ansible_module) + options.domain_name = ansible_module.params.get('domain') + options.realm_name = ansible_module.params.get('realm') + options.host_name = ansible_module.params.get('hostname') + options.ca_cert_files = ansible_module.params.get('ca_cert_files') + options.no_host_dns = ansible_module.params.get('no_host_dns') + ### server ### + options.setup_adtrust = ansible_module.params.get('setup_adtrust') + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.setup_dns = ansible_module.params.get('setup_dns') + ### ssl certificate ### + options.dirsrv_cert_files = ansible_module.params.get('dirsrv_cert_files') + ### client ### + options.force_join = ansible_module.params.get('force_join') + ### certificate system ### + options.external_ca = ansible_module.params.get('external_ca') + options.external_cert_files = ansible_module.params.get( + 'external_cert_files') + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + options.ca_subject = ansible_module.params.get('ca_subject') + ### dns ### + options.reverse_zones = ansible_module.params.get('reverse_zones') + options.no_reverse = ansible_module.params.get('no_reverse') + options.auto_reverse = ansible_module.params.get('auto_reverse') + options.forwarders = ansible_module.params.get('forwarders') + options.no_forwarders = ansible_module.params.get('no_forwarders') + options.auto_forwarders = ansible_module.params.get('auto_forwarders') + options.forward_policy = ansible_module.params.get('forward_policy') + ### additional ### + options.server = ansible_module.params.get('server') + master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + #os.environ['KRB5CCNAME'] = ccache + os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + kra_enabled = ansible_module.params.get('_kra_enabled') + + dirsrv_pkcs12_info = ansible_module.params.get('_dirsrv_pkcs12_info') + http_pkcs12_info = ansible_module.params.get('_http_pkcs12_info') + pkinit_pkcs12_info = ansible_module.params.get('_pkinit_pkcs12_info') + + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + options._top_dir = ansible_module.params.get('_top_dir') + options._add_to_ipaservers = ansible_module.params.get('_add_to_ipaservers') + + options._ca_subject = ansible_module.params.get('_ca_subject') + options._subject_base = ansible_module.params.get('_subject_base') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.subject_base = options.subject_base + + remote_api = gen_remote_api(master_host_name, paths.ETC_IPA) + installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + with redirect_stdout(ansible_log): + ansible_log.debug("-- INSTALL KRA --") + + kra.install(api, config, options) + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_setup_krb.py b/roles/ipareplica/library/ipareplica_setup_krb.py new file mode 100644 index 00000000..a5c19520 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_setup_krb.py @@ -0,0 +1,160 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_setup_krb +short description: Setup KRB +description: + Setup KRB +options: + setup_ca: + description: + required: yes + setup_kra: + description: + required: yes + no_pkinit: + description: + required: yes + subject_base: + description: + required: yes + config_master_host_name: + description: + required: yes + ccache: + description: + required: yes + _pkinit_pkcs12_info: + description: + required: yes + _top_dir: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + #### server ### + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + no_pkinit=dict(required=False, type='bool'), + #### certificate system ### + subject_base=dict(required=True), + #### additional ### + config_master_host_name=dict(required=True), + ccache=dict(required=True), + _pkinit_pkcs12_info = dict(required=False), + _top_dir = dict(required=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + ### server ### + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.no_pkinit = ansible_module.params.get('no_pkinit') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + config_master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + installer._pkinit_pkcs12_info = ansible_module.params.get('_pkinit_pkcs12_info') + + options._top_dir = ansible_module.params.get('_top_dir') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + pkinit_pkcs12_info = installer._pkinit_pkcs12_info + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.master_host_name = config_master_host_name + config.subject_base = options.subject_base + + remote_api = gen_remote_api(config.master_host_name, paths.ETC_IPA) + #installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + # There is a api.Backend.ldap2.connect call somewhere in ca, ds, dns or + # ntpinstance + api.Backend.ldap2.connect() + + ansible_log.debug("-- INSTALL_KRB --") + + with redirect_stdout(ansible_log): + krb = install_krb( + config, + setup_pkinit=not options.no_pkinit, + pkcs12_info=pkinit_pkcs12_info, + promote=promote) + + # done # + + ansible_module.exit_json(changed=True, + config_master_host_name=config.master_host_name) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_setup_otpd.py b/roles/ipareplica/library/ipareplica_setup_otpd.py new file mode 100644 index 00000000..71d1ef84 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_setup_otpd.py @@ -0,0 +1,171 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_setup_otpd +short description: Setup OTPD +description: + Setup OTPD +options: + setup_ca: + description: + required: yes + setup_kra: + description: + required: yes + no_pkinit: + description: + required: yes + no_ui_redirect: + description: + required: yes + subject_base: + description: + required: yes + config_master_host_name: + description: + required: yes + ccache: + description: + required: yes + _ca_enabled: + description: + required: yes + _ca_file: + description: + required: yes + _top_dir: + description: + required: yes + dirman_password: + description: + required: yes +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + #### server ### + setup_ca=dict(required=False, type='bool'), + setup_kra=dict(required=False, type='bool'), + no_pkinit=dict(required=False, type='bool'), + no_ui_redirect=dict(required=False, type='bool'), + #### certificate system ### + subject_base=dict(required=True), + #### additional ### + config_master_host_name=dict(required=True), + ccache=dict(required=True), + _ca_enabled=dict(required=False, type='bool'), + _ca_file=dict(required=False), + _top_dir = dict(required=True), + dirman_password=dict(required=True, no_log=True), + ), + supports_check_mode = True, + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + options = installer + options.setup_ca = ansible_module.params.get('setup_ca') + options.setup_kra = ansible_module.params.get('setup_kra') + options.no_pkinit = ansible_module.params.get('no_pkinit') + ### certificate system ### + options.subject_base = ansible_module.params.get('subject_base') + if options.subject_base is not None: + options.subject_base = DN(options.subject_base) + ### additional ### + master_host_name = ansible_module.params.get('config_master_host_name') + ccache = ansible_module.params.get('ccache') + os.environ['KRB5CCNAME'] = ccache + #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache') + #installer._ccache = ansible_module.params.get('installer_ccache') + ca_enabled = ansible_module.params.get('_ca_enabled') + options._top_dir = ansible_module.params.get('_top_dir') + dirman_password = ansible_module.params.get('dirman_password') + + # init # + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ansible_log.debug("== INSTALL ==") + + options = installer + promote = installer.promote + + env = gen_env_boostrap_finalize_core(paths.ETC_IPA, + constants.DEFAULT_CONFIG) + api_bootstrap_finalize(env) + config = gen_ReplicaConfig() + config.dirman_password = dirman_password + + remote_api = gen_remote_api(master_host_name, paths.ETC_IPA) + #installer._remote_api = remote_api + + conn = remote_api.Backend.ldap2 + ccache = os.environ['KRB5CCNAME'] + + # There is a api.Backend.ldap2.connect call somewhere in ca, ds, dns or + # ntpinstance + api.Backend.ldap2.connect() + conn.connect(ccache=ccache) + + cafile = paths.IPA_CA_CRT + with redirect_stdout(ansible_log): + ansible_log.debug("-- INSTALL_OTPD --") + + otpd = otpdinstance.OtpdInstance() + otpd.set_output(ansible_log) + otpd.create_instance('OTPD', config.host_name, + ipautil.realm_to_suffix(config.realm_name)) + + # done # + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipareplica_test.py b/roles/ipareplica/library/ipareplica_test.py new file mode 100644 index 00000000..9af95a80 --- /dev/null +++ b/roles/ipareplica/library/ipareplica_test.py @@ -0,0 +1,316 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-replica-install code +# +# Copyright (C) 2018 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: ipareplica_test +short description: +description: +options: +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +import os +import sys +import logging +import tempfile, shutil + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_replica import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + ### basic ### + ip_addresses=dict(required=False, type='list', default=[]), + domain=dict(required=False), + servers=dict(required=False, type='list', default=[]), + realm=dict(required=False), + hostname=dict(required=False), + ca_cert_files=dict(required=False, type='list', default=[]), + ### server ### + setup_adtrust=dict(required=False, type='bool', default=False), + setup_kra=dict(required=False, type='bool', default=False), + setup_dns=dict(required=False, type='bool', default=False), + no_pkinit=dict(required=False, type='bool', default=False), + dirsrv_config_file=dict(required=False), + ### ssl certificate ### + dirsrv_cert_files=dict(required=False, type='list', default=[]), + http_cert_files=dict(required=False, type='list', default=[]), + pkinit_cert_files=dict(required=False, type='list', default=[]), + ### client ### + no_ntp=dict(required=False, type='bool', default=False), + ### dns ### + no_reverse=dict(required=False, type='bool', default=False), + auto_reverse=dict(required=False, type='bool', default=False), + forwarders=dict(required=False, type='list', default=[]), + no_forwarders=dict(required=False, type='bool', default=False), + auto_forwarders=dict(required=False, type='bool', default=False), + forward_policy=dict(default=None, choices=['first', 'only']), + no_dnssec_validation=dict(required=False, type='bool', + default=False), + ), + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # get parameters # + + ### basic ### + options.ip_addresses = ansible_module_get_parsed_ip_addresses( + ansible_module) + options.domain_name = ansible_module.params.get('domain') + options.servers = ansible_module.params.get('servers') + options.realm_name = ansible_module.params.get('realm') + options.host_name = ansible_module.params.get('hostname') + options.ca_cert_files = ansible_module.params.get('ca_cert_files') + ### server ### + options.setup_adtrust = ansible_module.params.get('setup_adtrust') + options.setup_kra = ansible_module.params.get('setup_kra') + options.setup_dns = ansible_module.params.get('setup_dns') + options.no_pkinit = ansible_module.params.get('no_pkinit') + options.dirsrv_config_file = ansible_module.params.get('dirsrv_config_file') + ### ssl certificate ### + options.dirsrv_cert_files = ansible_module.params.get('dirsrv_cert_files') + options.http_cert_files = ansible_module.params.get('http_cert_files') + options.pkinit_cert_files = ansible_module.params.get('pkinit_cert_files') + ### client ### + options.no_ntp = ansible_module.params.get('no_ntp') + ### dns ### + options.no_reverse = ansible_module.params.get('no_reverse') + options.auto_reverse = ansible_module.params.get('auto_reverse') + options.forwarders = ansible_module.params.get('forwarders') + options.no_forwarders = ansible_module.params.get('no_forwarders') + options.auto_forwarders = ansible_module.params.get('auto_forwarders') + options.forward_policy = ansible_module.params.get('forward_policy') + options.no_dnssec_validation = ansible_module.params.get( + 'no_dnssec_validation') + + ########################################################################## + # replica init ########################################################### + ########################################################################## + + if installer.servers: + installer.server = installer.servers[0] + else: + installer.server = None + # TODO: Kills ipa-client-install + #if installer.replica_file is None: + # installer.password = installer.admin_password + #else: + # installer.password = installer.dm_password + + #installer._ccache = os.environ.get('KRB5CCNAME') + + # If not defined, set domain from server name + if installer.domain_name is None and installer.server is not None: + installer.domain_name = installer.server[installer.server.find(".")+1:] + # If not defined, set realm from domain name + if installer.realm_name is None and installer.domain_name is not None: + installer.realm_name = installer.domain_name.upper() + + ########################################################################## + # other checks ########################################################### + ########################################################################## + + # version specific tests # + + if options.setup_adtrust and not adtrust_imported: + #if "adtrust" not in options._allow_missing: + ansible_module.fail_json(msg="adtrust can not be imported") + #else: + # options.setup_adtrust = False + # ansible_module.warn(msg="adtrust is not supported, disabling") + + if options.setup_kra and not kra_imported: + #if "kra" not in options._allow_missing: + ansible_module.fail_json(msg="kra can not be imported") + #else: + # options.setup_kra = False + # ansible_module.warn(msg="kra is not supported, disabling") + + # From ipa installer classes + + # pkinit is not supported on DL0, don't allow related options + if installer.replica_file is not None: + ansible_module.fail_json( + msg="Replica installation using a replica file is not supported") + + # If any of the key file options are selected, all are required. + cert_file_req = (installer.dirsrv_cert_files, installer.http_cert_files) + cert_file_opt = (installer.pkinit_cert_files,) + if not installer.no_pkinit: + cert_file_req += cert_file_opt + if installer.no_pkinit and installer.pkinit_cert_files: + ansible_module.fail_json( + msg="--no-pkinit and --pkinit-cert-file cannot be specified " + "together") + if any(cert_file_req + cert_file_opt) and not all(cert_file_req): + ansible_module.fail_json( + msg="--dirsrv-cert-file, --http-cert-file, and --pkinit-cert-file " + "or --no-pkinit are required if any key file options are used.") + + if not installer.setup_dns: + if installer.forwarders: + ansible_module.fail_json( + msg="You cannot specify a --forwarder option without the " + "--setup-dns option") + if installer.auto_forwarders: + ansible_module.fail_json( + msg="You cannot specify a --auto-forwarders option without " + "the --setup-dns option") + if installer.no_forwarders: + ansible_module.fail_json( + msg="You cannot specify a --no-forwarders option without the " + "--setup-dns option") + if installer.forward_policy: + ansible_module.fail_json( + msg="You cannot specify a --forward-policy option without the " + "--setup-dns option") + if installer.reverse_zones: + ansible_module.fail_json( + msg="You cannot specify a --reverse-zone option without the " + "--setup-dns option") + if installer.auto_reverse: + ansible_module.fail_json( + msg="You cannot specify a --auto-reverse option without the " + "--setup-dns option") + if installer.no_reverse: + ansible_module.fail_json( + msg="You cannot specify a --no-reverse option without the " + "--setup-dns option") + if installer.no_dnssec_validation: + ansible_module.fail_json( + msg="You cannot specify a --no-dnssec-validation option " + "without the --setup-dns option") + elif installer.forwarders and installer.no_forwarders: + ansible_module.fail_json( + msg="You cannot specify a --forwarder option together with " + "--no-forwarders") + elif installer.auto_forwarders and installer.no_forwarders: + ansible_module.fail_json( + msg="You cannot specify a --auto-forwarders option together with " + "--no-forwarders") + elif installer.reverse_zones and installer.no_reverse: + ansible_module.fail_json( + msg="You cannot specify a --reverse-zone option together with " + "--no-reverse") + elif installer.auto_reverse and installer.no_reverse: + ansible_module.fail_json( + msg="You cannot specify a --auto-reverse option together with " + "--no-reverse") + + # replica installers + if installer.servers and not installer.domain_name: + ansible_module.fail_json( + msg="The --server option cannot be used without providing " + "domain via the --domain option") + + if installer.setup_dns: + if (not installer.forwarders and + not installer.no_forwarders and + not installer.auto_forwarders): + ansible_module.fail_json( + msg="You must specify at least one of --forwarder, " + "--auto-forwarders, or --no-forwarders options") + + if installer.dirsrv_config_file is not None and not os.path.exists(installer.dirsrv_config_file): + ansible_module.fail_json(msg="File %s does not exist." % installer.dirsrv_config_file) + + if installer.ca_cert_files is not None: + if not isinstance(installer.ca_cert_files, list): + ansible_module.fail_json(msg="Expected list, got {!r}".format(installer.ca_cert_files)) + for cert in installer.ca_cert_files: + if not os.path.exists(cert): + ansible_module.fail_json(msg="'%s' does not exist" % cert) + if not os.path.isfile(cert): + ansible_module.fail_json(msg="'%s' is not a file" % cert) + if not os.path.isabs(cert): + ansible_module.fail_json(msg="'%s' is not an absolute file path" % cert) + + try: + x509.load_certificate_from_file(cert) + except Exception: + ansible_module.fail_json(msg="'%s' is not a valid certificate file" % cert) + + if installer.ip_addresses is not None: + for value in installer.ip_addresses: + try: + CheckedIPAddress(value) + except Exception as e: + ansible_module.fail_json(msg="invalid IP address {0}: {1}".format( + value, e)) + + if installer.domain_name is not None: + validate_domain_name(installer.domain_name) + + ########################################################################## + # replica promote_check excerpts ######################################### + ########################################################################## + + # check selinux status, http and DS ports, NTP conflicting services + try: + with redirect_stdout(ansible_log): + common_check(options.no_ntp) + except Exception as msg: #ScriptError as msg: + ansible_module.fail_json(msg=str(msg)) + + # client enrolled? + + client_fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) + client_enrolled = client_fstore.has_files() + + # done # + + #ip_addresses = [ ] + ansible_module.exit_json(changed=True, + ipa_python_version=IPA_PYTHON_VERSION, + ### basic ### + domain=options.domain_name, + realm=options.realm_name, + hostname=options.host_name, + ### server ### + setup_adtrust=options.setup_adtrust, + setup_kra=options.setup_kra, + server=options.server, + ### additional ### + client_enrolled=client_enrolled, + ) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipaserver_enable_ipa.py b/roles/ipareplica/library/ipaserver_enable_ipa.py new file mode 100644 index 00000000..77e4aade --- /dev/null +++ b/roles/ipareplica/library/ipaserver_enable_ipa.py @@ -0,0 +1,100 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-server-install code +# +# Copyright (C) 2017 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: enable_ipa +short description: +description: +options: +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_server import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict( + hostname=dict(required=False), + setup_ca=dict(required=True, type='bool'), + ), + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # set values ############################################################# + + options.host_name = ansible_module.params.get('hostname') + options.setup_ca = ansible_module.params.get('setup_ca') + + # Configuration for ipalib, we will bootstrap and finalize later, after + # we are sure we have the configuration file ready. + cfg = dict( + context='installer', + confdir=paths.ETC_IPA, + in_server=True, + # make sure host name specified by user is used instead of default + host=options.host_name, + ) + if options.setup_ca: + # we have an IPA-integrated CA + cfg['ca_host'] = options.host_name + + api.bootstrap(**cfg) + api.finalize() + api.Backend.ldap2.connect() + + # setup ds ###################################################### + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + if NUM_VERSION < 40600: + # Make sure the files we crated in /var/run are recreated at startup + tasks.configure_tmpfiles() + + with redirect_stdout(ansible_log): + services.knownservices.ipa.enable() + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipaserver_master_password.py b/roles/ipareplica/library/ipaserver_master_password.py new file mode 100644 index 00000000..d3dc7686 --- /dev/null +++ b/roles/ipareplica/library/ipaserver_master_password.py @@ -0,0 +1,93 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-server-install code +# +# Copyright (C) 2017 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: master_password +short description: Generate kerberos master password if not given +description: + Generate kerberos master password if not given +options: + master_password: + description: kerberos master password (normally autogenerated) + required: false +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +password: + description: The master password + returned: always +''' + +import os + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_server import * + +def main(): + module = AnsibleModule( + argument_spec = dict( + #basic + dm_password=dict(required=True, no_log=True), + master_password=dict(required=False, no_log=True), + ), + supports_check_mode = True, + ) + + module._ansible_debug = True + + options.dm_password = module.params.get('dm_password') + options.master_password = module.params.get('master_password') + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + ## This will override any settings passed in on the cmdline + #if os.path.isfile(paths.ROOT_IPA_CACHE): + # # dm_password check removed, checked already + # try: + # cache_vars = read_cache(options.dm_password) + # options.__dict__.update(cache_vars) + # except Exception as e: + # module.fail_json(msg="Cannot process the cache file: %s" % str(e)) + + if not options.master_password: + options.master_password = ipa_generate_password() + + module.exit_json(changed=True, + password=options.master_password) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/library/ipaserver_setup_ntp.py b/roles/ipareplica/library/ipaserver_setup_ntp.py new file mode 100644 index 00000000..0fd0f776 --- /dev/null +++ b/roles/ipareplica/library/ipaserver_setup_ntp.py @@ -0,0 +1,79 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Based on ipa-server-install code +# +# Copyright (C) 2017 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'supported_by': 'community', + 'status': ['preview'], +} + +DOCUMENTATION = ''' +--- +module: setup_ntp +short description: +description: +options: +author: + - Thomas Woerner +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ansible_ipa_server import * + +def main(): + ansible_module = AnsibleModule( + argument_spec = dict(), + ) + + ansible_module._ansible_debug = True + ansible_log = AnsibleModuleLog(ansible_module) + + # init ########################################################## + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + # setup NTP ##################################################### + + ntpconf.force_ntpd(sstore) + ntp = ntpinstance.NTPInstance(fstore) + ntp.set_output(ansible_log) + with redirect_stdout(ansible_log): + if not ntp.is_configured(): + ntp.create_instance() + + # done ########################################################## + + ansible_module.exit_json(changed=True) + +if __name__ == '__main__': + main() diff --git a/roles/ipareplica/meta/main.yml b/roles/ipareplica/meta/main.yml new file mode 100644 index 00000000..7b5740af --- /dev/null +++ b/roles/ipareplica/meta/main.yml @@ -0,0 +1,27 @@ +galaxy_info: + author: Thomas Woerner + description: A role to setup an IPA domain replica + company: Red Hat, Inc + + # issue_tracker_url: http://example.com/issue/tracker + + license: GPLv3 + + min_ansible_version: 2.0 + + #github_branch: + + platforms: + - name: Fedora + versions: + - 25 + - 26 + - 27 + - name: rhel + versions: + - 7.3 + - 7.4 + + galaxy_tags: [ 'identity', 'ipa'] + +dependencies: [] diff --git a/roles/ipareplica/tasks/install.yml b/roles/ipareplica/tasks/install.yml new file mode 100644 index 00000000..260c29f4 --- /dev/null +++ b/roles/ipareplica/tasks/install.yml @@ -0,0 +1,619 @@ +--- +# tasks file for ipareplica + +- name: Install - Ensure IPA replica packages are installed + package: + name: "{{ item }}" + state: present + with_items: "{{ ipareplica_packages }}" + when: not ipareplica_no_package_install | bool + +- name: Install - Ensure IPA replica packages for dns are installed + package: + name: "{{ item }}" + state: present + with_items: "{{ ipareplica_packages_dns }}" + when: not ipareplica_no_package_install | bool and ipareplica_setup_dns | bool + +- name: Install - Ensure IPA replica packages for adtrust are installed + package: + name: "{{ item }}" + state: present + with_items: "{{ ipareplica_packages_adtrust }}" + when: not ipareplica_no_package_install | bool and ipareplica_setup_adtrust | bool + +- name: Install - Include Python2/3 import test + include: "{{role_path}}/tasks/python_2_3_test.yml" + static: yes + +- name: Install - Set default principal if no keytab is given + set_fact: + ipaadmin_principal: admin + when: ipaadmin_principal is undefined and ipaclient_keytab is undefined + +- name: Install - Replica installation test + ipareplica_test: + ### basic ### + ip_addresses: "{{ ipareplica_ip_addresses | default([]) }}" + domain: "{{ ipareplica_domain | default(ipaserver_domain) | default(omit) }}" + servers: "{{ groups.ipaservers | default(groups.ipaserver) | default(omit) }}" + realm: "{{ ipareplica_realm | default(omit) }}" + hostname: "{{ ipareplica_hostname | default(ansible_fqdn) }}" + ca_cert_files: "{{ ipareplica_ca_cert_files | default([]) }}" + ### server ### + setup_adtrust: "{{ ipareplica_setup_adtrust }}" + setup_kra: "{{ ipareplica_setup_kra }}" + setup_dns: "{{ ipareplica_setup_dns }}" + no_pkinit: "{{ ipareplica_no_pkinit }}" + dirsrv_config_file: "{{ ipareplica_dirsrv_config_file | default(omit) }}" + ### ssl certificate ### + dirsrv_cert_files: "{{ ipareplica_dirsrv_cert_files | default([]) }}" + http_cert_files: "{{ ipareplica_http_cert_files | default([]) }}" + pkinit_cert_files: "{{ ipareplica_pkinit_cert_files | default([]) }}" + ### client ### + no_ntp: "{{ ipaclient_no_ntp }}" + ### dns ### + no_reverse: "{{ ipareplica_no_reverse }}" + auto_reverse: "{{ ipareplica_auto_reverse }}" + forwarders: "{{ ipareplica_forwarders | default([]) }}" + no_forwarders: "{{ ipareplica_no_forwarders }}" + auto_forwarders: "{{ ipareplica_auto_forwarders }}" + forward_policy: "{{ ipareplica_forward_policy | default(omit) }}" + no_dnssec_validation: "{{ ipareplica_no_dnssec_validation }}" + register: result_ipareplica_test + +- block: + + #- name: Install - Setup client + # include_role: + # name: ipaclient + # vars: + # state: present + # ipaclient_domain: "{{ result_ipareplica_test.domain }}" + # ipaclient_realm: "{{ result_ipareplica_test.realm }}" + # ipaclient_server: "{{ result_ipareplica_test.server }}" + # ipaclient_hostname: "{{ result_ipareplica_test.hostname }}" + # #ipaclient_no_dns_sshfp: "{{ ipaclient_no_dns_sshfp }}" + # #ipaclient_ssh_trust_dns: "{{ ipaclient_ssh_trust_dns }}" + # #ipaclient_no_ssh: "{{ ipaclient_no_ssh }}" + # #ipaclient_no_sshd: "{{ ipaclient_no_sshd }}" + # #ipaclient_mkhomedir: "{{ ipaclient_mkhomedir }}" + + #- name: Install - Setup client + # command: > + # /usr/sbin/ipa-client-install + # --unattended + # --no-ntp + # --domain "{{ result_ipareplica_test.domain }}" + # --realm "{{ result_ipareplica_test.realm }}" + # --server "{{ result_ipareplica_test.server }}" + # --hostname "{{ result_ipareplica_test.hostname }}" + # {{ "--principal" if ipaadmin_password is defined else "" }} {{ ipaadmin_principal if ipaadmin_password is defined else "" }} + # {{ "--password" if ipaadmin_password is defined else "" }} {{ ipaadmin_password if ipaadmin_password is defined else "" }} + # {{ "--mkhomedir" if ipaclient_mkhomedir | bool else "" }} + # # {{ "--no-dns-sshfp" if ipaclient_no_dns_sshfp | bool else "" }} + # # {{ "--ssh-trust-dns" if ipaclient_ssh_trust_dns | bool else "" }} + # # {{ "--no-ssh" if ipaclient_no_ssh | bool else "" }} + # # {{ "--no-sshd" if ipaclient_no_sshd | bool else "" }} + # when: not result_ipareplica_test.client_enrolled + + - name: Install - Configure firewalld + command: > + firewall-cmd + --permanent + --add-service=freeipa-ldap + --add-service=freeipa-ldaps + --add-service=freeipa-replication + {{ "--add-service=dns" if ipareplica_setup_dns | bool else "" }} + {{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }} + when: not ipareplica_no_firewalld | bool + + - name: Install - Configure firewalld runtime + command: > + firewall-cmd + --add-service=freeipa-ldap + --add-service=freeipa-ldaps + --add-service=freeipa-replication + {{ "--add-service=dns" if ipareplica_setup_dns | bool else "" }} + {{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }} + when: not ipareplica_no_firewalld | bool + + - name: Install - Replica preparation + ipareplica_prepare: + ### basic ### + password: "{{ ipaadmin_password | default(omit) }}" + ip_addresses: "{{ ipareplica_ip_addresses | default([]) }}" + domain: "{{ result_ipareplica_test.domain }}" + realm: "{{ result_ipareplica_test.realm }}" + hostname: "{{ result_ipareplica_test.hostname }}" + principal: "{{ ipaadmin_principal | default(omit) }}" + ca_cert_files: "{{ ipareplica_ca_cert_files | default([]) }}" + no_host_dns: "{{ ipareplica_no_host_dns }}" + ### replica ### + setup_adtrust: "{{ result_ipareplica_test.setup_adtrust }}" + setup_ca: "{{ ipareplica_setup_ca }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + setup_dns: "{{ ipareplica_setup_dns }}" + ### ssl certificate ### + dirsrv_cert_files: "{{ ipareplica_dirsrv_cert_files | default([]) }}" + dirsrv_pin: "{{ ipareplica_dirsrv_pin | default(omit) }}" + http_cert_files: "{{ ipareplica_http_cert_files | default([]) }}" + http_pin: "{{ ipareplica_http_pin | default(omit) }}" + pkinit_cert_files: "{{ ipareplica_pkinit_cert_files | default([]) }}" + pkinit_pin: "{{ ipareplica_pkinit_pin | default(omit) }}" + ### client ### + keytab: "{{ ipaclient_keytab | default(omit) }}" + mkhomedir: "{{ ipaclient_mkhomedir | default(omit) }}" + force_join: "{{ ipaclient_force_join | default(omit) }}" + no_ntp: "{{ ipaclient_no_ntp | default(omit) }}" + ssh_trust_dns: "{{ ipaclient_ssh_trust_dns | default(omit) }}" + no_ssh: no + no_sshd: no + no_dns_sshfp: no + ### dns ### + no_dnssec_validation: "{{ ipareplica_no_dnssec_validation }}" + forward_policy: "{{ ipareplica_forward_policy | default(omit) }}" + ### ad trust ### + netbios_name: "{{ ipareplica_netbios_name | default(omit) }}" + rid_base: "{{ ipareplica_rid_base | default(omit) }}" + secondary_rid_base: "{{ ipareplica_secondary_rid_base | default(omit) }}" + ### additional ### + server: "{{ result_ipareplica_test.server }}" + skip_conncheck: "{{ ipareplica_skip_conncheck }}" + register: result_ipareplica_prepare + + - name: Install - Setup NTP + ipaserver_setup_ntp: + when: not ipaclient_no_ntp | bool + + - name: Install - Add to ipaservers + ipareplica_add_to_ipaservers: + ### server ### + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + ### additional ### + config_master_host_name: "{{ result_ipareplica_prepare.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + installer_ccache: "{{ result_ipareplica_prepare.installer_ccache }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + when: result_ipareplica_prepare._add_to_ipaservers + + - name: Install - Create dirman password + no_log: yes + ipaserver_master_password: + dm_password: "{{ ipadm_password }}" + master_password: "{{ ipaserver_master_password | default(omit) }}" + register: result_ipaserver_master_password + + - name: Install - Set dirman password + no_log: yes + set_fact: + ipareplica_dirman_password: "{{ result_ipaserver_master_password.password }}" + + - name: Install - Setup certmonger + ipareplica_setup_certmonger: + when: result_ipareplica_prepare._ca_enabled + + - name: Install - Install CA certs + ipareplica_install_ca_certs: + ### basic ### + dm_password: "{{ ipadm_password | default(omit) }}" + password: "{{ ipaadmin_password | default(omit) }}" + ip_addresses: "{{ ipareplica_ip_addresses | default([]) }}" + domain: "{{ result_ipareplica_test.domain }}" + realm: "{{ result_ipareplica_test.realm }}" + hostname: "{{ result_ipareplica_test.hostname }}" + ca_cert_files: "{{ ipareplica_ca_cert_files | default([]) }}" + no_host_dns: "{{ ipareplica_no_host_dns }}" + ### replica ### + setup_adtrust: "{{ result_ipareplica_test.setup_adtrust }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + setup_dns: "{{ ipareplica_setup_dns }}" + ### ssl certificate ### + dirsrv_cert_files: "{{ ipareplica_dirsrv_cert_files | default([]) }}" + ### client ### + force_join: "{{ ipaclient_force_join }}" + ### dns ### + forward_policy: "{{ ipareplica_forward_policy | default(omit) }}" + ### ad trust ### + netbios_name: "{{ ipareplica_netbios_name | default(omit) }}" + rid_base: "{{ ipareplica_rid_base | default(omit) }}" + secondary_rid_base: "{{ ipareplica_secondary_rid_base | default(omit) }}" + ### additional ### + server: "{{ result_ipareplica_test.server }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + installer_ccache: "{{ result_ipareplica_prepare.installer_ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _kra_enabled: "{{ result_ipareplica_prepare._kra_enabled }}" + _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info }}" + _http_pkcs12_info: "{{ result_ipareplica_prepare._http_pkcs12_info }}" + _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + _add_to_ipaservers: "{{ result_ipareplica_prepare._add_to_ipaservers }}" + _ca_subject: "{{ result_ipareplica_prepare._ca_subject }}" + _subject_base: "{{ result_ipareplica_prepare._subject_base }}" + dirman_password: "{{ ipareplica_dirman_password }}" + config_setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}" + config_master_host_name: "{{ result_ipareplica_prepare.config_master_host_name }}" + config_ca_host_name: "{{ result_ipareplica_prepare.config_ca_host_name }}" + config_ips: "{{ result_ipareplica_prepare.config_ips }}" + register: result_ipareplica_install_ca_certs + + - name: Install - Setup DS + ipareplica_setup_ds: + ### basic ### + dm_password: "{{ ipadm_password | default(omit) }}" + password: "{{ ipaadmin_password | default(omit) }}" + ip_addresses: "{{ ipareplica_ip_addresses | default([]) }}" + domain: "{{ result_ipareplica_test.domain }}" + realm: "{{ result_ipareplica_test.realm }}" + hostname: "{{ result_ipareplica_test.hostname }}" + ca_cert_files: "{{ ipareplica_ca_cert_files | default([]) }}" + no_host_dns: "{{ ipareplica_no_host_dns }}" + ### replica ### + setup_adtrust: "{{ result_ipareplica_test.setup_adtrust }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + setup_dns: "{{ ipareplica_setup_dns }}" + no_pkinit: "{{ ipareplica_no_pkinit }}" + dirsrv_config_file: "{{ ipareplica_dirsrv_config_file | default(omit) }}" + ### ssl certificate ### + dirsrv_cert_files: "{{ ipareplica_dirsrv_cert_files | default([]) }}" + ### client ### + force_join: "{{ ipaclient_force_join }}" + ### dns ### + forward_policy: "{{ ipareplica_forward_policy | default(omit) }}" + ### ad trust ### + netbios_name: "{{ ipareplica_netbios_name | default(omit) }}" + rid_base: "{{ ipareplica_rid_base | default(omit) }}" + secondary_rid_base: "{{ ipareplica_secondary_rid_base | default(omit) }}" + ### additional ### + server: "{{ result_ipareplica_test.server }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + installer_ccache: "{{ result_ipareplica_prepare.installer_ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _kra_enabled: "{{ result_ipareplica_prepare._kra_enabled }}" + _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info }}" + _http_pkcs12_info: "{{ result_ipareplica_prepare._http_pkcs12_info }}" + _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + _add_to_ipaservers: "{{ result_ipareplica_prepare._add_to_ipaservers }}" + _ca_subject: "{{ result_ipareplica_prepare._ca_subject }}" + _subject_base: "{{ result_ipareplica_prepare._subject_base }}" + dirman_password: "{{ ipareplica_dirman_password }}" + config_setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}" + config_master_host_name: "{{ result_ipareplica_install_ca_certs.config_master_host_name }}" + config_ca_host_name: "{{ result_ipareplica_prepare.config_ca_host_name }}" + config_ips: "{{ result_ipareplica_prepare.config_ips }}" + register: result_ipareplica_setup_ds + + - name: Install - Create IPA conf + ipareplica_create_ipa_conf: + ### basic ### + dm_password: "{{ ipadm_password | default(omit) }}" + password: "{{ ipaadmin_password | default(omit) }}" + ip_addresses: "{{ ipareplica_ip_addresses | default([]) }}" + domain: "{{ result_ipareplica_test.domain }}" + realm: "{{ result_ipareplica_test.realm }}" + hostname: "{{ result_ipareplica_test.hostname }}" + ca_cert_files: "{{ ipareplica_ca_cert_files | default([]) }}" + no_host_dns: "{{ ipareplica_no_host_dns }}" + ### replica ### + setup_adtrust: "{{ result_ipareplica_test.setup_adtrust }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + setup_dns: "{{ ipareplica_setup_dns }}" + ### ssl certificate ### + dirsrv_cert_files: "{{ ipareplica_dirsrv_cert_files | default([]) }}" + ### client ### + force_join: "{{ ipaclient_force_join }}" + ### dns ### + forward_policy: "{{ ipareplica_forward_policy | default(omit) }}" + ### ad trust ### + netbios_name: "{{ ipareplica_netbios_name | default(omit) }}" + rid_base: "{{ ipareplica_rid_base | default(omit) }}" + secondary_rid_base: "{{ ipareplica_secondary_rid_base | default(omit) }}" + ### additional ### + server: "{{ result_ipareplica_test.server }}" + config_master_host_name: "{{ result_ipareplica_install_ca_certs.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + installer_ccache: "{{ result_ipareplica_prepare.installer_ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _kra_enabled: "{{ result_ipareplica_prepare._kra_enabled }}" + _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info }}" + _http_pkcs12_info: "{{ result_ipareplica_prepare._http_pkcs12_info }}" + _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + _add_to_ipaservers: "{{ result_ipareplica_prepare._add_to_ipaservers }}" + _ca_subject: "{{ result_ipareplica_prepare._ca_subject }}" + _subject_base: "{{ result_ipareplica_prepare._subject_base }}" + dirman_password: "{{ ipareplica_dirman_password }}" + + - name: Install - Setup KRB + ipareplica_setup_krb: + ### server ### + setup_ca: "{{ ipareplica_setup_ca }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + no_pkinit: "{{ ipareplica_no_pkinit }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + config_master_host_name: "{{ result_ipareplica_install_ca_certs.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + + - name: Install - DS enable SSL + ipareplica_ds_enable_ssl: + ### server ### + setup_ca: "{{ ipareplica_setup_ca }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + no_pkinit: "{{ ipareplica_no_pkinit }}" + dirsrv_config_file: "{{ ipareplica_dirsrv_config_file | default(omit) }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + config_master_host_name: "{{ result_ipareplica_install_ca_certs.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" + _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + ds_ca_subject: "{{ result_ipareplica_setup_ds.ds_ca_subject }}" + + - name: Install - Setup http + ipareplica_setup_http: + ### server ### + setup_ca: "{{ ipareplica_setup_ca }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + no_pkinit: "{{ ipareplica_no_pkinit }}" + no_ui_redirect: "{{ ipareplica_no_ui_redirect }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + config_master_host_name: "{{ result_ipareplica_install_ca_certs.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" + _http_pkcs12_info: "{{ result_ipareplica_prepare._http_pkcs12_info }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + + - name: Install - Setup otpd + ipareplica_setup_otpd: + ### server ### + setup_ca: "{{ ipareplica_setup_ca }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + no_pkinit: "{{ ipareplica_no_pkinit }}" + no_ui_redirect: "{{ ipareplica_no_ui_redirect }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + config_master_host_name: "{{ result_ipareplica_install_ca_certs.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + + - name: Install - Setup custodia + ipareplica_setup_custodia: + ### server ### + setup_ca: "{{ ipareplica_setup_ca }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + no_pkinit: "{{ ipareplica_no_pkinit }}" + no_ui_redirect: "{{ ipareplica_no_ui_redirect }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + config_master_host_name: "{{ result_ipareplica_prepare.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" + _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + + - name: Install - Setup CA + ipareplica_setup_ca: + ### server ### + setup_ca: "{{ ipareplica_setup_ca }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + no_pkinit: "{{ ipareplica_no_pkinit }}" + no_ui_redirect: "{{ ipareplica_no_ui_redirect }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" + _ca_subject: "{{ result_ipareplica_prepare._ca_subject }}" + _subject_base: "{{ result_ipareplica_prepare._subject_base }}" + _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + config_setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}" + config_master_host_name: "{{ result_ipareplica_install_ca_certs.config_master_host_name }}" + config_ca_host_name: "{{ result_ipareplica_install_ca_certs.config_ca_host_name }}" + config_ips: "{{ result_ipareplica_prepare.config_ips }}" + when: result_ipareplica_prepare._ca_enabled + + - name: Install - KRB enable SSL + ipareplica_krb_enable_ssl: + ### server ### + setup_ca: "{{ ipareplica_setup_ca }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + no_pkinit: "{{ ipareplica_no_pkinit }}" + #no_ui_redirect: "{{ ipareplica_no_ui_redirect }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + config_master_host_name: "{{ result_ipareplica_install_ca_certs.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" + _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + + - name: Install - DS apply updates + ipareplica_ds_apply_updates: + ### server ### + setup_ca: "{{ ipareplica_setup_ca }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + no_pkinit: "{{ ipareplica_no_pkinit }}" + no_ui_redirect: "{{ ipareplica_no_ui_redirect }}" + dirsrv_config_file: "{{ ipareplica_dirsrv_config_file | default(omit) }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + config_master_host_name: "{{ result_ipareplica_install_ca_certs.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" + _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + ds_ca_subject: "{{ result_ipareplica_setup_ds.ds_ca_subject }}" + + - name: Install - Setup kra + ipareplica_setup_kra: + ### basic ### + dm_password: "{{ ipadm_password | default(omit) }}" + password: "{{ ipaadmin_password | default(omit) }}" + ip_addresses: "{{ ipareplica_ip_addresses | default([]) }}" + domain: "{{ result_ipareplica_test.domain }}" + realm: "{{ result_ipareplica_test.realm }}" + hostname: "{{ result_ipareplica_test.hostname }}" + ca_cert_files: "{{ ipareplica_ca_cert_files | default([]) }}" + no_host_dns: "{{ ipareplica_no_host_dns }}" + ### replica ### + setup_adtrust: "{{ result_ipareplica_test.setup_adtrust }}" + setup_ca: "{{ ipareplica_setup_ca }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + setup_dns: "{{ ipareplica_setup_dns }}" + ### ssl certificate ### + dirsrv_cert_files: "{{ ipareplica_dirsrv_cert_files | default([]) }}" + ### client ### + force_join: "{{ ipaclient_force_join }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + server: "{{ result_ipareplica_test.server }}" + config_master_host_name: "{{ result_ipareplica_prepare.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + installer_ccache: "{{ result_ipareplica_prepare.installer_ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _kra_enabled: "{{ result_ipareplica_prepare._kra_enabled }}" + _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info }}" + _http_pkcs12_info: "{{ result_ipareplica_prepare._http_pkcs12_info }}" + _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + _add_to_ipaservers: "{{ result_ipareplica_prepare._add_to_ipaservers }}" + _ca_subject: "{{ result_ipareplica_prepare._ca_subject }}" + _subject_base: "{{ result_ipareplica_prepare._subject_base }}" + when: result_ipareplica_test.setup_kra + + - name: Install - Restart KDC + ipareplica_restart_kdc: + ### server ### + setup_ca: "{{ ipareplica_setup_ca }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + no_pkinit: "{{ ipareplica_no_pkinit }}" + no_ui_redirect: "{{ ipareplica_no_ui_redirect }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + config_master_host_name: "{{ result_ipareplica_install_ca_certs.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" + _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + + - name: Install - Custodia import dm password + ipareplica_custodia_import_dm_password: + ### server ### + setup_ca: "{{ ipareplica_setup_ca }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + no_pkinit: "{{ ipareplica_no_pkinit }}" + no_ui_redirect: "{{ ipareplica_no_ui_redirect }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + config_master_host_name: "{{ result_ipareplica_prepare.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" + _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + + - name: Install - Promote SSSD + ipareplica_promote_sssd: + ### replica ### + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + ccache: "{{ result_ipareplica_prepare.ccache }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + config_setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}" + config_master_host_name: "{{ result_ipareplica_prepare.config_master_host_name }}" + + - name: Install - Promote openldap.conf + ipareplica_promote_openldap_conf: + ### replica ### + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + ccache: "{{ result_ipareplica_prepare.ccache }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + config_setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}" + config_master_host_name: "{{ result_ipareplica_prepare.config_master_host_name }}" + + - name: Install - Setup DNS + ipareplica_setup_dns: + ### server ### + setup_dns: "{{ ipareplica_setup_dns }}" + ### replica ### + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + ccache: "{{ result_ipareplica_prepare.ccache }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + config_setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}" + config_master_host_name: "{{ result_ipareplica_prepare.config_master_host_name }}" + + - name: Install - Setup adtrust + ipareplica_setup_adtrust: + ### replica ### + setup_adtrust: "{{ result_ipareplica_test.setup_adtrust }}" + setup_kra: "{{ result_ipareplica_test.setup_kra }}" + ### certificate system ### + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + ### additional ### + ccache: "{{ result_ipareplica_prepare.ccache }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + config_setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}" + config_master_host_name: "{{ result_ipareplica_prepare.config_master_host_name }}" + when: result_ipareplica_test.setup_adtrust + + #- name: Install - Disconnect backend + # ipareplica_backend_disconnect: + + - name: Install - Enable IPA + ipaserver_enable_ipa: + hostname: "{{ result_ipareplica_test.hostname }}" + setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}" + register: result_ipareplica_enable_ipa + + - name: Install - Cleanup root IPA cache + file: + path: "/root/.ipa_cache" + state: absent + when: result_ipareplica_enable_ipa.changed diff --git a/roles/ipareplica/tasks/main.yml b/roles/ipareplica/tasks/main.yml new file mode 100644 index 00000000..59f337b4 --- /dev/null +++ b/roles/ipareplica/tasks/main.yml @@ -0,0 +1,18 @@ +--- +# tasks file for ipareplica + +- name: Import variables specific to distribution + include_vars: "{{ item }}" + with_first_found: + - "vars/{{ ansible_distribution }}-{{ ansible_distribution_version }}.yml" + - "vars/{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml" + - "vars/{{ ansible_distribution }}.yml" + - "vars/default.yml" + +- name: Install IPA replica + include: tasks/install.yml + when: state|default('present') == 'present' + +- name: Uninstall IPA replica + include: tasks/uninstall.yml + when: state|default('present') == 'absent' diff --git a/roles/ipareplica/tasks/python_2_3_test.yml b/roles/ipareplica/tasks/python_2_3_test.yml new file mode 100644 index 00000000..64353ee6 --- /dev/null +++ b/roles/ipareplica/tasks/python_2_3_test.yml @@ -0,0 +1,19 @@ +- block: + - name: Verify Python3 import + script: py3test.py + register: py3test + failed_when: False + + - name: Set python interpreter to 3 + set_fact: + ansible_python_interpreter: "/usr/bin/python3" + when: py3test.rc == 0 + + - name: Fail for IPA 4.5.90 + fail: msg="You need to install python2 bindings for ipa server usage" + when: py3test.rc != 0 and "not usable with python3" in py3test.stdout + + - name: Set python interpreter to 2 + set_fact: + ansible_python_interpreter: "/usr/bin/python2" + when: py3test.failed or py3test.rc != 0 diff --git a/roles/ipareplica/tasks/uninstall.yml b/roles/ipareplica/tasks/uninstall.yml new file mode 100644 index 00000000..98269f07 --- /dev/null +++ b/roles/ipareplica/tasks/uninstall.yml @@ -0,0 +1,38 @@ +--- +# tasks to uninstall IPA replica + +#- name: Uninstall - Include Python2/3 import test +# include: "{{role_path}}/tasks/python_2_3_test.yml" +# static: yes + +- name: Uninstall - Uninstall IPA replica + command: > + /usr/sbin/ipa-server-install + --uninstall + -U + {{ "--ignore-topology-disconnect" if ipareplica_ignore_topology_disconnect | bool else "" }} + {{ "--ignore-last-of-role" if ipareplica_ignore_last_of_role | bool else "" }} + register: result_uninstall + # 2 means that uninstall failed because IPA replica was not configured + failed_when: result_uninstall.rc != 0 and "'Env' object has no attribute 'basedn'" not in result_uninstall.stderr + #IPA server is not configured on this system" not in result_uninstall.stdout_lines + #changed_when: result_uninstall.rc == 0 + #until: result_uninstall.rc == 0 + retries: 2 + delay: 1 + +- name: Uninstall - Remove all replication agreements and data about replica + command: > + /usr/sbin/ipa-replica-manage + del + {{ ipareplica_hostname | default(ansible_fqdn) }} + --force + --password={{ ipadm_password }} + failed_when: False + delegate_to: "{{ groups.ipaserver[0] | default(fail) }}" + +#- name: Remove IPA replica packages +# package: +# name: "{{ item }}" +# state: absent +# with_items: "{{ ipareplica_packages }}" diff --git a/roles/ipareplica/vars/Fedora-25.yml b/roles/ipareplica/vars/Fedora-25.yml new file mode 100644 index 00000000..9c0827f3 --- /dev/null +++ b/roles/ipareplica/vars/Fedora-25.yml @@ -0,0 +1,5 @@ +# Fedora-25 defaults file for ipareplica +# vars/Fedora-25.yml +ipareplica_packages: [ "ipa-server", "libselinux-python" ] +ipareplica_packages_dns: [ "ipa-server-dns" ] +ipareplica_packages_adtrust: [ ] \ No newline at end of file diff --git a/roles/ipareplica/vars/Fedora-26.yml b/roles/ipareplica/vars/Fedora-26.yml new file mode 100644 index 00000000..bd24033d --- /dev/null +++ b/roles/ipareplica/vars/Fedora-26.yml @@ -0,0 +1,5 @@ +# Fedora defaults file for ipareplica +# vars/Fedora-26.yml +ipareplica_packages: [ "ipa-server", "libselinux-python" ] +ipareplica_packages_dns: [ "ipa-server-dns" ] +ipareplica_packages_adtrust: [ ] \ No newline at end of file diff --git a/roles/ipareplica/vars/Fedora.yml b/roles/ipareplica/vars/Fedora.yml new file mode 100644 index 00000000..ced045cb --- /dev/null +++ b/roles/ipareplica/vars/Fedora.yml @@ -0,0 +1,5 @@ +# Fedora defaults file for ipareplica +# vars/Fedora.yml +ipareplica_packages: [ "ipa-server", "libselinux-python" ] +ipareplica_packages_dns: [ "ipa-server-dns" ] +ipareplica_packages_adtrust: [ "samba" ] \ No newline at end of file diff --git a/roles/ipareplica/vars/RedHat-7.3.yml b/roles/ipareplica/vars/RedHat-7.3.yml new file mode 100644 index 00000000..04481290 --- /dev/null +++ b/roles/ipareplica/vars/RedHat-7.3.yml @@ -0,0 +1,5 @@ +# defaults file for ipareplica +# vars/RedHat-7.3.yml +ipareplica_packages: [ "ipa-server", "libselinux-python" ] +ipareplica_packages_dns: [ "ipa-server-dns" ] +ipareplica_packages_adtrust: [ ] \ No newline at end of file diff --git a/roles/ipareplica/vars/RedHat-7.yml b/roles/ipareplica/vars/RedHat-7.yml new file mode 100644 index 00000000..27d796d7 --- /dev/null +++ b/roles/ipareplica/vars/RedHat-7.yml @@ -0,0 +1,5 @@ +# defaults file for ipareplica +# vars/RedHat-7.yml +ipareplica_packages: [ "ipa-server", "libselinux-python" ] +ipareplica_packages_dns: [ "ipa-server-dns" ] +ipareplica_packages_adtrust: [ ] \ No newline at end of file diff --git a/roles/ipareplica/vars/default.yml b/roles/ipareplica/vars/default.yml new file mode 100644 index 00000000..4b2275ab --- /dev/null +++ b/roles/ipareplica/vars/default.yml @@ -0,0 +1,5 @@ +# defaults file for ipareplica +# vars/default.yml +ipareplica_packages: [ "ipa-server", "libselinux-python" ] +ipareplica_packages_dns: [ "ipa-server-dns" ] +ipareplica_packages_adtrust: [ "samba" ] diff --git a/uninstall-replica.yml b/uninstall-replica.yml new file mode 100644 index 00000000..53f06542 --- /dev/null +++ b/uninstall-replica.yml @@ -0,0 +1,8 @@ +--- +- name: Playbook to unconfigure IPA replicas + hosts: ipareplicas + become: true + + roles: + - role: ipareplica + state: absent -- GitLab