Blame roles/ipaserver/module_utils/ansible_ipa_server.py

Packit 8cb997
#!/usr/bin/python
Packit 8cb997
# -*- coding: utf-8 -*-
Packit 8cb997
Packit 8cb997
# Authors:
Packit 8cb997
#   Thomas Woerner <twoerner@redhat.com>
Packit 8cb997
#
Packit 8cb997
# Based on ipa-client-install code
Packit 8cb997
#
Packit 8cb997
# Copyright (C) 2017  Red Hat
Packit 8cb997
# see file 'COPYING' for use and warranty information
Packit 8cb997
#
Packit 8cb997
# This program is free software; you can redistribute it and/or modify
Packit 8cb997
# it under the terms of the GNU General Public License as published by
Packit 8cb997
# the Free Software Foundation, either version 3 of the License, or
Packit 8cb997
# (at your option) any later version.
Packit 8cb997
#
Packit 8cb997
# This program is distributed in the hope that it will be useful,
Packit 8cb997
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8cb997
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8cb997
# GNU General Public License for more details.
Packit 8cb997
#
Packit 8cb997
# You should have received a copy of the GNU General Public License
Packit 8cb997
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 8cb997
Packit 8cb997
__all__ = ["IPAChangeConf", "certmonger", "sysrestore", "root_logger",
Packit 8cb997
           "ipa_generate_password", "run", "ScriptError", "services",
Packit 8cb997
           "tasks", "errors", "x509", "DOMAIN_LEVEL_0", "MIN_DOMAIN_LEVEL",
Packit 8cb997
           "validate_domain_name",
Packit 8cb997
           "no_matching_interface_for_ip_address_warning",
Packit 8cb997
           "check_zone_overlap", "timeconf", "ntpinstance", "adtrust",
Packit 8cb997
           "bindinstance", "ca", "dns", "httpinstance", "installutils",
Packit 8cb997
           "kra", "krbinstance", "otpdinstance", "custodiainstance",
Packit 8cb997
           "replication", "service", "sysupgrade", "IPA_MODULES",
Packit 8cb997
           "BadHostError", "get_fqdn", "get_server_ip_address",
Packit 8cb997
           "is_ipa_configured", "load_pkcs12", "read_password", "verify_fqdn",
Packit 8cb997
           "update_hosts_file", "check_dirsrv", "validate_admin_password",
Packit 8cb997
           "validate_dm_password", "read_cache", "write_cache",
Packit 8cb997
           "adtrustinstance", "IPAAPI_USER", "sync_time", "PKIIniLoader",
Packit 8cb997
           "default_subject_base", "default_ca_subject_dn",
Packit Service 0f71a7
           "check_ldap_conf", "encode_certificate", "decode_certificate"]
Packit 8cb997
Packit 8cb997
import sys
Packit 8cb997
import logging
Packit 8cb997
from contextlib import contextmanager as contextlib_contextmanager
Packit Service 0f71a7
import six
Packit Service 0f71a7
import base64
Packit 8cb997
Packit 8cb997
Packit 8cb997
from ipapython.version import NUM_VERSION, VERSION
Packit 8cb997
Packit 8cb997
if NUM_VERSION < 30201:
Packit 8cb997
    # See ipapython/version.py
Packit 8cb997
    IPA_MAJOR, IPA_MINOR, IPA_RELEASE = [int(x) for x in VERSION.split(".", 2)]
Packit 8cb997
    IPA_PYTHON_VERSION = IPA_MAJOR*10000 + IPA_MINOR*100 + IPA_RELEASE
Packit 8cb997
else:
Packit 8cb997
    IPA_PYTHON_VERSION = NUM_VERSION
Packit 8cb997
Packit 8cb997
Packit 8cb997
if NUM_VERSION >= 40500:
Packit 8cb997
    # IPA version >= 4.5
Packit 8cb997
Packit 8cb997
    from ipaclient.install.ipachangeconf import IPAChangeConf
Packit 8cb997
    from ipalib.install import certmonger, sysrestore
Packit 8cb997
    from ipapython import ipautil
Packit 8cb997
    from ipapython.ipa_log_manager import standard_logging_setup
Packit 8cb997
    try:
Packit 8cb997
        from ipapython.ipa_log_manager import root_logger
Packit 8cb997
    except ImportError:
Packit 8cb997
        root_logger = None
Packit 8cb997
    from ipapython.ipautil import (
Packit 8cb997
        ipa_generate_password, run)
Packit 8cb997
    from ipapython.admintool import ScriptError
Packit 8cb997
    from ipaplatform import services
Packit 8cb997
    from ipaplatform.paths import paths
Packit 8cb997
    from ipaplatform.tasks import tasks
Packit 8cb997
    from ipalib import api, errors, x509
Packit 8cb997
    from ipalib.constants import DOMAIN_LEVEL_0, MIN_DOMAIN_LEVEL, \
Packit 8cb997
        MAX_DOMAIN_LEVEL
Packit 8cb997
    try:
Packit 8cb997
        from ipalib.constants import IPAAPI_USER
Packit 8cb997
    except ImportError:
Packit 8cb997
        IPAAPI_USER = None
Packit 8cb997
    from ipalib.util import (
Packit 8cb997
        validate_domain_name,
Packit 8cb997
        no_matching_interface_for_ip_address_warning,
Packit 8cb997
    )
Packit 8cb997
    from ipapython.dnsutil import check_zone_overlap
Packit 8cb997
    from ipapython.dn import DN
Packit 8cb997
    try:
Packit 8cb997
        from ipaclient.install import timeconf
Packit 8cb997
        from ipaclient.install.client import sync_time
Packit 8cb997
        time_service = "chronyd"
Packit 8cb997
        ntpinstance = None
Packit 8cb997
    except ImportError:
Packit 8cb997
        try:
Packit 8cb997
            from ipaclient.install import ntpconf as timeconf
Packit 8cb997
        except ImportError:
Packit 8cb997
            from ipaclient import ntpconf as timeconf
Packit 8cb997
        from ipaserver.install import ntpinstance
Packit 8cb997
        time_service = "ntpd"
Packit 8cb997
        sync_time = None
Packit 8cb997
    from ipaserver.install import (
Packit 8cb997
        adtrust, bindinstance, ca, dns, dsinstance,
Packit 8cb997
        httpinstance, installutils, kra, krbinstance,
Packit 8cb997
        otpdinstance, custodiainstance, replication, service,
Packit 8cb997
        sysupgrade)
Packit 8cb997
    adtrust_imported = True
Packit 8cb997
    kra_imported = True
Packit 8cb997
    from ipaserver.install.installutils import (
Packit 8cb997
        IPA_MODULES, BadHostError, get_fqdn, get_server_ip_address,
Packit 8cb997
        is_ipa_configured, load_pkcs12, read_password, verify_fqdn,
Packit 8cb997
        update_hosts_file)
Packit 8cb997
    from ipaserver.install.server.install import (
Packit 8cb997
        check_dirsrv, validate_admin_password, validate_dm_password,
Packit 8cb997
        read_cache, write_cache)
Packit 8cb997
    try:
Packit 8cb997
        from ipaserver.install.dogtaginstance import PKIIniLoader
Packit 8cb997
    except ImportError:
Packit 8cb997
        PKIIniLoader = None
Packit 8cb997
    try:
Packit 8cb997
        from ipaserver.install.installutils import default_subject_base
Packit 8cb997
    except ImportError:
Packit 8cb997
        def default_subject_base(realm_name):
Packit 8cb997
            return DN(('O', realm_name))
Packit 8cb997
    try:
Packit 8cb997
        from ipaserver.install.installutils import default_ca_subject_dn
Packit 8cb997
    except ImportError:
Packit 8cb997
        def default_ca_subject_dn(subject_base):
Packit 8cb997
            return DN(('CN', 'Certificate Authority'), subject_base)
Packit 8cb997
Packit 8cb997
    try:
Packit 8cb997
        from ipaserver.install import adtrustinstance
Packit 8cb997
        _server_trust_ad_installed = True
Packit 8cb997
    except ImportError:
Packit 8cb997
        _server_trust_ad_installed = False
Packit 8cb997
Packit 8cb997
    try:
Packit 8cb997
        from ipaclient.install.client import check_ldap_conf
Packit 8cb997
    except ImportError:
Packit 8cb997
        check_ldap_conf = None
Packit 8cb997
Packit Service 0f71a7
    try:
Packit Service 0f71a7
        from ipalib.x509 import Encoding
Packit Service 0f71a7
    except ImportError:
Packit Service 0f71a7
        from cryptography.hazmat.primitives.serialization import Encoding
Packit Service 0f71a7
Packit Service 0f71a7
    try:
Packit Service 0f71a7
        from ipalib.x509 import load_pem_x509_certificate
Packit Service 0f71a7
    except ImportError:
Packit Service 0f71a7
        from ipalib.x509 import load_certificate
Packit Service 0f71a7
        load_pem_x509_certificate = None
Packit Service 0f71a7
Packit 8cb997
else:
Packit 8cb997
    # IPA version < 4.5
Packit 8cb997
Packit 8cb997
    raise Exception("freeipa version '%s' is too old" % VERSION)
Packit 8cb997
Packit 8cb997
Packit 8cb997
logger = logging.getLogger("ipa-server-install")
Packit Service 0f71a7
Packit Service 0f71a7
Packit Service 0f71a7
def setup_logging():
Packit Service 0f71a7
    # logger.setLevel(logging.DEBUG)
Packit Service 0f71a7
    standard_logging_setup(
Packit Service 0f71a7
        paths.IPASERVER_INSTALL_LOG, verbose=False, debug=False,
Packit Service 0f71a7
        filemode='a', console_format='%(message)s')
Packit 8cb997
Packit 8cb997
Packit 8cb997
@contextlib_contextmanager
Packit 8cb997
def redirect_stdout(f):
Packit 8cb997
    sys.stdout = f
Packit 8cb997
    try:
Packit 8cb997
        yield f
Packit 8cb997
    finally:
Packit 8cb997
        sys.stdout = sys.__stdout__
Packit 8cb997
Packit 8cb997
Packit 8cb997
class AnsibleModuleLog():
Packit 8cb997
    def __init__(self, module):
Packit 8cb997
        self.module = module
Packit 8cb997
        _ansible_module_log = self
Packit 8cb997
Packit 8cb997
        class AnsibleLoggingHandler(logging.Handler):
Packit 8cb997
            def emit(self, record):
Packit 8cb997
                _ansible_module_log.write(self.format(record))
Packit 8cb997
Packit 8cb997
        self.logging_handler = AnsibleLoggingHandler()
Packit 8cb997
        logger.setLevel(logging.DEBUG)
Packit 8cb997
        logger.root.addHandler(self.logging_handler)
Packit 8cb997
Packit 8cb997
    def close(self):
Packit 8cb997
        self.flush()
Packit 8cb997
Packit 8cb997
    def flush(self):
Packit 8cb997
        pass
Packit 8cb997
Packit 8cb997
    def log(self, msg):
Packit 8cb997
        # self.write(msg+"\n")
Packit 8cb997
        self.write(msg)
Packit 8cb997
Packit 8cb997
    def debug(self, msg):
Packit 8cb997
        self.module.debug(msg)
Packit 8cb997
Packit 8cb997
    def info(self, msg):
Packit 8cb997
        self.module.debug(msg)
Packit 8cb997
Packit 8cb997
    def write(self, msg):
Packit 8cb997
        self.module.debug(msg)
Packit 8cb997
        # self.module.warn(msg)
Packit 8cb997
Packit 8cb997
Packit 8cb997
class options_obj(object):
Packit 8cb997
    def __init__(self):
Packit 8cb997
        self._replica_install = False
Packit 8cb997
        self.dnssec_master = False  # future unknown
Packit 8cb997
        self.disable_dnssec_master = False  # future unknown
Packit 8cb997
        self.domainlevel = MAX_DOMAIN_LEVEL  # deprecated
Packit 8cb997
        self.domain_level = self.domainlevel  # deprecated
Packit 8cb997
        self.interactive = False
Packit 8cb997
        self.unattended = not self.interactive
Packit 8cb997
Packit 8cb997
    # def __getattribute__(self, attr):
Packit 8cb997
    #    logger.info(" <-- Accessing options.%s" % attr)
Packit 8cb997
    #    return super(options_obj, self).__getattribute__(attr)
Packit 8cb997
Packit 8cb997
    # def __getattr__(self, attr):
Packit 8cb997
    #    logger.info(" --> Adding missing options.%s" % attr)
Packit 8cb997
    #    setattr(self, attr, None)
Packit 8cb997
    #    return getattr(self, attr)
Packit 8cb997
Packit 8cb997
    def knobs(self):
Packit 8cb997
        for name in self.__dict__:
Packit 8cb997
            yield self, name
Packit 8cb997
Packit 8cb997
Packit 8cb997
options = options_obj()
Packit 8cb997
installer = options
Packit 8cb997
Packit 8cb997
# ServerMasterInstall
Packit 8cb997
options.add_sids = True
Packit 8cb997
options.add_agents = False
Packit 8cb997
Packit 8cb997
Packit 8cb997
# Installable
Packit 8cb997
options.uninstalling = False
Packit 8cb997
Packit 8cb997
# ServerInstallInterface
Packit 8cb997
options.description = "Server"
Packit 8cb997
Packit 8cb997
options.kinit_attempts = 1
Packit 8cb997
options.fixed_primary = True
Packit 8cb997
options.permit = False
Packit 8cb997
options.enable_dns_updates = False
Packit 8cb997
options.no_krb5_offline_passwords = False
Packit 8cb997
options.preserve_sssd = False
Packit 8cb997
options.no_sssd = False
Packit 8cb997
Packit 8cb997
# ServerMasterInstall
Packit 8cb997
options.force_join = False
Packit 8cb997
options.servers = None
Packit 8cb997
options.no_wait_for_dns = True
Packit 8cb997
options.host_password = None
Packit 8cb997
options.keytab = None
Packit 8cb997
options.setup_ca = True
Packit 8cb997
# always run sidgen task and do not allow adding agents on first master
Packit 8cb997
options.add_sids = True
Packit 8cb997
options.add_agents = False
Packit 8cb997
Packit 8cb997
# ADTrustInstallInterface
Packit 8cb997
# no_msdcs is deprecated
Packit 8cb997
options.no_msdcs = False
Packit 8cb997
Packit 8cb997
# For pylint
Packit 8cb997
options.external_cert_files = None
Packit 8cb997
options.dirsrv_cert_files = None
Packit 8cb997
Packit 8cb997
# Uninstall
Packit 8cb997
options.ignore_topology_disconnect = False
Packit 8cb997
options.ignore_last_of_role = False
Packit 8cb997
Packit 8cb997
Packit 8cb997
def api_Backend_ldap2(host_name, setup_ca, connect=False):
Packit 8cb997
    # we are sure we have the configuration file ready.
Packit 8cb997
    cfg = dict(context='installer', confdir=paths.ETC_IPA, in_server=True,
Packit 8cb997
               host=host_name)
Packit 8cb997
    if setup_ca:
Packit 8cb997
        # we have an IPA-integrated CA
Packit 8cb997
        cfg['ca_host'] = host_name
Packit 8cb997
Packit 8cb997
    api.bootstrap(**cfg)
Packit 8cb997
    api.finalize()
Packit 8cb997
    if connect:
Packit 8cb997
        api.Backend.ldap2.connect()
Packit 8cb997
Packit 8cb997
Packit 8cb997
def ds_init_info(ansible_log, fstore, domainlevel, dirsrv_config_file,
Packit 8cb997
                 realm_name, host_name, domain_name, dm_password,
Packit 8cb997
                 idstart, idmax, subject_base, ca_subject,
Packit 8cb997
                 no_hbac_allow, dirsrv_pkcs12_info, no_pkinit):
Packit 8cb997
Packit 8cb997
    if not options.external_cert_files:
Packit 8cb997
        ds = dsinstance.DsInstance(fstore=fstore, domainlevel=domainlevel,
Packit 8cb997
                                   config_ldif=dirsrv_config_file)
Packit 8cb997
        ds.set_output(ansible_log)
Packit 8cb997
Packit 8cb997
        if options.dirsrv_cert_files:
Packit 8cb997
            _dirsrv_pkcs12_info = dirsrv_pkcs12_info
Packit 8cb997
        else:
Packit 8cb997
            _dirsrv_pkcs12_info = None
Packit 8cb997
Packit 8cb997
        with redirect_stdout(ansible_log):
Packit 8cb997
            ds.init_info(realm_name, host_name, domain_name, dm_password,
Packit 8cb997
                         subject_base, ca_subject, idstart, idmax,
Packit 8cb997
                         # hbac_allow=not no_hbac_allow,
Packit 8cb997
                         _dirsrv_pkcs12_info, setup_pkinit=not no_pkinit)
Packit 8cb997
    else:
Packit 8cb997
        ds = dsinstance.DsInstance(fstore=fstore, domainlevel=domainlevel)
Packit 8cb997
        ds.set_output(ansible_log)
Packit 8cb997
Packit 8cb997
        with redirect_stdout(ansible_log):
Packit 8cb997
            ds.init_info(realm_name, host_name, domain_name, dm_password,
Packit 8cb997
                         subject_base, ca_subject, 1101, 1100, None,
Packit 8cb997
                         setup_pkinit=not no_pkinit)
Packit 8cb997
Packit 8cb997
    return ds
Packit 8cb997
Packit 8cb997
Packit 8cb997
def ansible_module_get_parsed_ip_addresses(ansible_module,
Packit 8cb997
                                           param='ip_addresses'):
Packit 8cb997
    ip_addrs = []
Packit 8cb997
    for ip in ansible_module.params.get(param):
Packit 8cb997
        try:
Packit 8cb997
            ip_parsed = ipautil.CheckedIPAddress(ip)
Packit 8cb997
        except Exception as e:
Packit 8cb997
            ansible_module.fail_json(msg="Invalid IP Address %s: %s" % (ip, e))
Packit 8cb997
        ip_addrs.append(ip_parsed)
Packit 8cb997
    return ip_addrs
Packit Service 0f71a7
Packit Service 0f71a7
Packit Service 0f71a7
def encode_certificate(cert):
Packit Service 0f71a7
    """
Packit Service 0f71a7
    Encode a certificate using base64.
Packit Service 0f71a7
Packit Service 0f71a7
    It also takes FreeIPA and Python versions into account.
Packit Service 0f71a7
    """
Packit Service 0f71a7
    if isinstance(cert, (str, bytes)):
Packit Service 0f71a7
        encoded = base64.b64encode(cert)
Packit Service 0f71a7
    else:
Packit Service 0f71a7
        encoded = base64.b64encode(cert.public_bytes(Encoding.DER))
Packit Service 0f71a7
    if not six.PY2:
Packit Service 0f71a7
        encoded = encoded.decode('ascii')
Packit Service 0f71a7
    return encoded
Packit Service 0f71a7
Packit Service 0f71a7
Packit Service 0f71a7
def decode_certificate(cert):
Packit Service 0f71a7
    """
Packit Service 0f71a7
    Decode a certificate using base64.
Packit Service 0f71a7
Packit Service 0f71a7
    It also takes FreeIPA versions into account and returns a IPACertificate
Packit Service 0f71a7
    for newer IPA versions.
Packit Service 0f71a7
    """
Packit Service 0f71a7
    if hasattr(x509, "IPACertificate"):
Packit Service 0f71a7
        cert = cert.strip()
Packit Service 0f71a7
        if not cert.startswith("-----BEGIN CERTIFICATE-----"):
Packit Service 0f71a7
            cert = "-----BEGIN CERTIFICATE-----\n" + cert
Packit Service 0f71a7
        if not cert.endswith("-----END CERTIFICATE-----"):
Packit Service 0f71a7
            cert += "\n-----END CERTIFICATE-----"
Packit Service 0f71a7
Packit Service 0f71a7
        if load_pem_x509_certificate is not None:
Packit Service 0f71a7
            cert = load_pem_x509_certificate(cert.encode('utf-8'))
Packit Service 0f71a7
        else:
Packit Service 0f71a7
            cert = load_certificate(cert.encode('utf-8'))
Packit Service 0f71a7
    else:
Packit Service 0f71a7
        cert = base64.b64decode(cert)
Packit Service 0f71a7
    return cert