Ejemplo n.º 1
0
    def execute(self, **options):
        ca_enabled = self.api.Command.ca_is_enabled()['result']
        if not ca_enabled:
            return False, []

        olddb = certdb.NSSDatabase(nssdir=paths.HTTPD_ALIAS_DIR)
        if not olddb.has_nickname('ipaCert'):
            # Nothign to do
            return False, []

        newdb = certdb.NSSDatabase(nssdir=paths.IPA_RADB_DIR)
        if os.path.exists(paths.IPA_RADB_DIR):
            if newdb.has_nickname('ipaCert'):
                self.log.warning(
                    "An 'ipaCert' nickname exists in both the old {} and the "
                    "new {} NSS Databases!".format(paths.HTTPD_ALIAS_DIR,
                                                   paths.IPA_RADB_DIR))
                return False, []
        else:
            # Create the DB
            newdb.create_db(user=IPAAPI_USER, group=IPAAPI_GROUP, backup=True)

        # Import cert chain (ignore errors, as certs may already be imported)
        certlist = olddb.list_certs()
        certflags = {}
        for name, flags in certlist:
            certflags[name] = flags
        for name in olddb.get_trust_chain('ipaCert'):
            if name == 'ipaCert':
                continue
            try:
                cert = olddb.get_cert(name, pem=True)
                newdb.add_cert(cert, name, certflags[name], pem=True)
            except Exception as e:  # pylint disable=broad-except
                self.log.warning("Failed to import '{}' from trust "
                                 "chain: {}".format(name, str(e)))

        # As the last step export/import/delete the RA Cert
        pw = binascii.hexlify(os.urandom(10))
        p12file = os.path.join(paths.IPA_RADB_DIR, 'ipaCert.p12')
        olddb.export_pkcs12('ipaCert', p12file, pw)
        newdb.import_pkcs12(p12file, pw)

        certmonger.stop_tracking(secdir=olddb.secdir, nickname='ipaCert')
        certmonger.start_tracking(secdir=newdb.secdir,
                                  nickname='ipaCert',
                                  password_file=newdb.pwd_file)

        olddb.delete_cert('ipaCert')

        return False, []
Ejemplo n.º 2
0
    def update_client(self, certs):
        self.update_file(paths.IPA_CA_CRT, certs)

        ipa_db = certdb.NSSDatabase(paths.IPA_NSSDB_DIR)
        sys_db = certdb.NSSDatabase(paths.NSS_DB_DIR)

        # Remove IPA certs from /etc/pki/nssdb
        for nickname, trust_flags in ipa_db.list_certs():
            while sys_db.has_nickname(nickname):
                try:
                    sys_db.delete_cert(nickname)
                except ipautil.CalledProcessError, e:
                    self.log.error("Failed to remove %s from %s: %s",
                                   nickname, sys_db.secdir, e)
                    break
Ejemplo n.º 3
0
def makecert(reqdir, subject, principal):
    """
    Generate a certificate that can be used during unit testing.
    """

    ra = rabase.rabase(api)
    if (not os.path.exists(ra.client_certfile)
            and api.env.xmlrpc_uri == 'http://localhost:8888/ipa/xml'):
        raise AssertionError('The self-signed CA is not configured, '
                             'see ipatests/test_xmlrpc/test_cert.py')

    nssdb = certdb.NSSDatabase(nssdir=reqdir)
    with open(nssdb.pwd_file, "w") as f:
        # Create an empty password file
        f.write("\n")
    # create db
    nssdb.create_db()
    # create CSR
    csr_file = os.path.join(reqdir, 'req')
    nssdb.run_certutil(
        ["-R", "-s",
         str(subject), "-o", csr_file, "-z", paths.GROUP, "-a"])
    with open(csr_file, "rb") as f:
        csr = f.read().decode('ascii')

    res = api.Command['cert_request'](csr, principal=principal, add=True)
    cert = x509.load_der_x509_certificate(
        base64.b64decode(res['result']['certificate']))
    return cert.public_bytes(x509.Encoding.PEM)
Ejemplo n.º 4
0
def update_db(path, certs):
    db = certdb.NSSDatabase(path)
    for cert, nickname, trusted, eku in certs:
        trust_flags = certstore.key_policy_to_trust_flags(trusted, True, eku)
        try:
            db.add_cert(cert, nickname, trust_flags)
        except ipautil.CalledProcessError as e:
            logger.error("failed to update %s in %s: %s", nickname, path, e)
Ejemplo n.º 5
0
    def cert_restore(self):
        if not os.path.exists(os.path.join(paths.IPA_NSSDB_DIR, 'cert8.db')):
            certdb.create_ipa_nssdb()
            ipa_db = certdb.NSSDatabase(paths.IPA_NSSDB_DIR)
            sys_db = certdb.NSSDatabase(paths.NSS_DB_DIR)
            for nickname, trust_flags in (('IPA CA', 'CT,C,C'),
                                          ('External CA cert', 'C,,')):
                try:
                    cert = sys_db.get_cert(nickname)
                except RuntimeError:
                    pass
                else:
                    try:
                        ipa_db.add_cert(cert, nickname, trust_flags)
                    except ipautil.CalledProcessError as e:
                        self.log.error("Failed to add %s to %s: %s" %
                                       (nickname, paths.IPA_NSSDB_DIR, e))

        tasks.reload_systemwide_ca_store()

        services.knownservices.certmonger.restart()
Ejemplo n.º 6
0
def update_db(path, certs):
    """Drop all CA certs from db then add certs from list provided

       This may result in some churn as existing certs are dropped
       and re-added but this also provides the ability to change
       the trust flags.
    """
    db = certdb.NSSDatabase(path)
    for name, flags in db.list_certs():
        if flags.ca:
            db.delete_cert(name)
    for cert, nickname, trusted, eku in certs:
        trust_flags = certstore.key_policy_to_trust_flags(trusted, True, eku)
        try:
            db.add_cert(cert, nickname, trust_flags)
        except ipautil.CalledProcessError as e:
            logger.error("failed to update %s in %s: %s", nickname, path, e)
Ejemplo n.º 7
0
    def __create_kra_agent(self):
        """
        Create KRA agent, assign a certificate, and add the user to
        the appropriate groups for accessing KRA services.
        """

        # get ipaCert certificate
        with certdb.NSSDatabase(paths.HTTPD_ALIAS_DIR) as ipa_nssdb:
            cert_data = ipa_nssdb.get_cert("ipaCert")
        cert = x509.load_certificate(cert_data, x509.DER)

        # connect to KRA database
        server_id = installutils.realm_to_serverid(api.env.realm)
        dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id
        conn = ldap2.ldap2(api, ldap_uri=dogtag_uri)
        conn.connect(autobind=True)

        # create ipakra user with ipaCert certificate
        user_dn = DN(('uid', "ipakra"), ('ou', 'people'), self.basedn)
        entry = conn.make_entry(
            user_dn,
            objectClass=[
                'top', 'person', 'organizationalPerson', 'inetOrgPerson',
                'cmsuser'
            ],
            uid=["ipakra"],
            sn=["IPA KRA User"],
            cn=["IPA KRA User"],
            usertype=["undefined"],
            userCertificate=[cert_data],
            description=[
                '2;%s;%s;%s' %
                (cert.serial_number,
                 DN(('CN', 'Certificate Authority'),
                    self.subject_base), DN(
                        ('CN', 'IPA RA'), self.subject_base))
            ])
        conn.add_entry(entry)

        # add ipakra user to Data Recovery Manager Agents group
        group_dn = DN(('cn', 'Data Recovery Manager Agents'), ('ou', 'groups'),
                      self.basedn)
        conn.add_entry_to_group(user_dn, group_dn, 'uniqueMember')

        conn.disconnect()
Ejemplo n.º 8
0
    def update_client(self, certs):
        self.update_file(paths.IPA_CA_CRT, certs)

        ipa_db = certdb.NSSDatabase(api.env.nss_dir)

        # Remove old IPA certs from /etc/ipa/nssdb
        for nickname in ('IPA CA', 'External CA cert'):
            while ipa_db.has_nickname(nickname):
                try:
                    ipa_db.delete_cert(nickname)
                except ipautil.CalledProcessError as e:
                    self.log.error("Failed to remove %s from %s: %s", nickname,
                                   ipa_db.secdir, e)
                    break

        self.update_db(ipa_db.secdir, certs)

        tasks.remove_ca_certs_from_systemwide_ca_store()
        tasks.insert_ca_certs_into_systemwide_ca_store(certs)
Ejemplo n.º 9
0
def install_check(api, replica_config, options):
    if replica_config is not None and not replica_config.setup_kra:
        return

    kra = krainstance.KRAInstance(api.env.realm)
    if kra.is_installed():
        raise RuntimeError("KRA is already installed.")

    if not options.setup_ca:
        if cainstance.is_ca_installed_locally():
            if api.env.dogtag_version >= 10:
                # correct dogtag version of CA installed
                pass
            else:
                raise RuntimeError(
                    "Dogtag must be version 10.2 or above to install KRA")
        else:
            raise RuntimeError(
                "Dogtag CA is not installed.  Please install the CA first")

    if replica_config is not None:
        if not api.Command.kra_is_enabled()['result']:
            raise RuntimeError(
                "KRA is not installed on the master system. Please use "
                "'ipa-kra-install' command to install the first instance.")

        if options.promote:
            return

        with certdb.NSSDatabase() as tmpdb:
            pw = ipautil.write_tmp_file(ipautil.ipa_generate_password())
            tmpdb.create_db(pw.name)
            tmpdb.import_pkcs12(replica_config.dir + "/cacert.p12", pw.name,
                                replica_config.dirman_password)
            kra_cert_nicknames = [
                "storageCert cert-pki-kra", "transportCert cert-pki-kra",
                "auditSigningCert cert-pki-kra"
            ]
            if not all(
                    tmpdb.has_nickname(nickname)
                    for nickname in kra_cert_nicknames):
                raise RuntimeError("Missing KRA certificates, please create a "
                                   "new replica file.")
Ejemplo n.º 10
0
    def check(self):
        # For simplicity use the expected certmonger tracking for the
        # list of certificates to check because it already filters out
        # based on whether the CA system is configure and whether the
        # certificates were issued by IPA.
        if not self.ca.is_configured():
            logger.debug('CA is not configured, skipping revocation check')
            return
        requests = get_expected_requests(self.ca, self.ds, self.serverid)
        for request in requests:
            id = certmonger.get_request_id(request)
            if request.get('cert-file') is not None:
                certfile = request.get('cert-file')
                try:
                    cert = x509.load_certificate_from_file(certfile)
                except Exception as e:
                    yield Result(self,
                                 constants.ERROR,
                                 key=id,
                                 certfile=certfile,
                                 error=str(e),
                                 msg='Unable to open cert file {certfile}: '
                                 '{error}')
                    continue
            elif request.get('cert-database') is not None:
                nickname = request.get('cert-nickname')
                dbdir = request.get('cert-database')
                try:
                    db = certdb.NSSDatabase(dbdir)
                except Exception as e:
                    yield Result(self,
                                 constants.ERROR,
                                 key=id,
                                 dbdir=dbdir,
                                 error=str(e),
                                 msg='Unable to open NSS database {dbdir}: '
                                 '{error}')
                    continue
                try:
                    cert = db.get_cert(nickname)
                except Exception as e:
                    yield Result(self,
                                 constants.ERROR,
                                 key=id,
                                 dbdir=dbdir,
                                 nickname=nickname,
                                 error=str(e),
                                 msg='Unable to retrieve certificate '
                                 '\'{nickname}\' from {dbdir}: {error}')
                    continue
            else:
                yield Result(self,
                             constants.ERROR,
                             key=id,
                             msg='Unable to to identify certificate storage '
                             'type for request {key}')
                continue

            issued = is_ipa_issued_cert(api, cert)
            if issued is False:
                logger.debug('\'%s\' was not issued by IPA, skipping',
                             DN(cert.subject))
                continue
            if issued is None:
                logger.debug('LDAP is down, skipping \'%s\'', DN(cert.subject))
                continue

            # Now we have the cert either way, check the recovation
            try:
                result = api.Command.cert_show(cert.serial_number, all=True)
            except Exception as e:
                yield Result(self,
                             constants.ERROR,
                             key=id,
                             serial=cert.serial_number,
                             error=str(e),
                             msg='Request for certificate serial number '
                             '{serial} in request {key} failed: {error}')
                continue

            try:
                if result['result']['revoked']:
                    reason = result['result']['revocation_reason']
                    reason_txt = self.revocation_reason[reason]
                    yield Result(self,
                                 constants.ERROR,
                                 revocation_reason=reason_txt,
                                 key=id,
                                 msg='Certificate tracked by {key} is revoked '
                                 '{revocation_reason}')
                else:
                    yield Result(self, constants.SUCCESS, key=id)
            except Exception as e:
                yield Result(self,
                             constants.ERROR,
                             key=id,
                             error=str(e),
                             msg='Unable to determine revocation '
                             'status for {key}: {error}')
Ejemplo n.º 11
0
    def check(self):
        validate = []
        ca_pw_fname = None

        if self.ca.is_configured():
            try:
                ca_passwd = get_dogtag_cert_password()
            except IOError as e:
                yield Result(
                    self,
                    constants.ERROR,
                    error=str(e),
                    msg='Unable to read CA NSSDB token password: {error}')
                return
            else:
                with tempfile.NamedTemporaryFile(mode='w',
                                                 delete=False) as ca_pw_file:
                    ca_pw_file.write(ca_passwd)
                    ca_pw_fname = ca_pw_file.name

                validate.append((
                    paths.PKI_TOMCAT_ALIAS_DIR,
                    'Server-Cert cert-pki-ca',
                    ca_pw_fname,
                ), )

        validate.append((
            dsinstance.config_dirname(self.serverid),
            self.ds.get_server_cert_nickname(self.serverid),
            os.path.join(dsinstance.config_dirname(self.serverid),
                         'pwdfile.txt'),
        ))

        # Wrap in try/except to ensure the temporary password file is
        # removed
        try:
            for (dbdir, nickname, pinfile) in validate:
                # detect the database type so we have the right prefix
                db = certdb.NSSDatabase(dbdir)

                key = os.path.normpath(dbdir) + ':' + nickname
                try:
                    response = self.validate_nss(dbdir, db.dbtype, pinfile,
                                                 nickname)
                except ipautil.CalledProcessError as e:
                    logger.debug('Validation of NSS certificate failed %s', e)
                    yield Result(
                        self,
                        constants.ERROR,
                        key=key,
                        dbdir=dbdir,
                        nickname=nickname,
                        reason=response.output_error,
                        msg='Validation of {nickname} in {dbdir} failed: '
                        '{reason}')
                else:
                    if 'certificate is valid' not in \
                            response.raw_output.decode('utf-8'):
                        yield Result(
                            self,
                            constants.ERROR,
                            key=key,
                            dbdir=dbdir,
                            nickname=nickname,
                            reason="%s: %s" %
                            (response.raw_output.decode('utf-8'),
                             response.error_log),
                            msg='Validation of {nickname} in {dbdir} failed: '
                            '{reason}')
                    else:
                        yield Result(self,
                                     constants.SUCCESS,
                                     dbdir=dbdir,
                                     nickname=nickname,
                                     key=key)
        finally:
            if ca_pw_fname:
                ipautil.remove_file(ca_pw_fname)
Ejemplo n.º 12
0
    def check(self):
        fqdn = socket.getfqdn()
        requests = get_expected_requests(self.ca, self.ds, self.serverid)

        for request in requests:
            request_id = certmonger.get_request_id(request)
            if request_id is None:
                yield Result(self,
                             constants.ERROR,
                             key=request_id,
                             msg='Found request id {key} but it is not tracked'
                             'by certmonger!?')
                continue

            ca_name = certmonger.get_request_value(request_id, 'ca-name')
            if ca_name != 'IPA':
                logger.debug('Skipping request %s with CA %s', request_id,
                             ca_name)
                continue
            profile = certmonger.get_request_value(request_id,
                                                   'template_profile')
            if profile != 'caIPAserviceCert':
                logger.debug('Skipping request %s with profile %s', request_id,
                             profile)
                continue

            certfile = None
            if request.get('cert-file') is not None:
                certfile = request.get('cert-file')
                try:
                    cert = x509.load_certificate_from_file(certfile)
                except Exception as e:
                    yield Result(self,
                                 constants.ERROR,
                                 key=request_id,
                                 certfile=certfile,
                                 error=str(e),
                                 msg='Unable to open cert file {certfile}: '
                                 '{error}')
                    continue
            elif request.get('cert-database') is not None:
                nickname = request.get('cert-nickname')
                dbdir = request.get('cert-database')
                try:
                    db = certdb.NSSDatabase(dbdir)
                except Exception as e:
                    yield Result(self,
                                 constants.ERROR,
                                 key=request_id,
                                 dbdir=dbdir,
                                 error=str(e),
                                 msg='Unable to open NSS database {dbdir}: '
                                 '{error}')
                    continue
                try:
                    cert = db.get_cert(nickname)
                except Exception as e:
                    yield Result(self,
                                 constants.ERROR,
                                 key=id,
                                 dbdir=dbdir,
                                 nickname=nickname,
                                 error=str(e),
                                 msg='Unable to retrieve certificate '
                                 '\'{nickname}\' from {dbdir}: {error}')
                    continue

            hostlist = [fqdn]
            if self.ca.is_configured() and certfile == paths.HTTPD_CERT_FILE:
                hostlist.append(f'{IPA_CA_RECORD}.{api.env.domain}')
            error = False
            for host in hostlist:
                if host not in cert.san_a_label_dns_names:
                    error = True
                    yield Result(self,
                                 constants.ERROR,
                                 key=request_id,
                                 hostname=host,
                                 san=cert.san_a_label_dns_names,
                                 ca=ca_name,
                                 profile=profile,
                                 msg='Certificate request id {key} with '
                                 'profile {profile} for CA {ca} does not '
                                 'have a DNS SAN {san} matching name '
                                 '{hostname}')
            if not error:
                yield Result(self,
                             constants.SUCCESS,
                             key=request_id,
                             hostname=hostlist,
                             san=cert.san_a_label_dns_names,
                             ca=ca_name,
                             profile=profile)
Ejemplo n.º 13
0
    def check(self):
        cm = certmonger._certmonger()

        all_requests = cm.obj_if.get_requests()
        for req in all_requests:
            request = certmonger._cm_dbus_object(cm.bus, cm, req,
                                                 certmonger.DBUS_CM_REQUEST_IF,
                                                 certmonger.DBUS_CM_IF, True)
            id = request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF, 'nickname')

            store = request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF,
                                        'cert-storage')
            if store == 'FILE':
                certfile = str(
                    request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF,
                                        'cert-file'))
                try:
                    cert = x509.load_certificate_from_file(certfile)
                except Exception as e:
                    yield Result(self,
                                 constants.ERROR,
                                 key=id,
                                 certfile=certfile,
                                 error=str(e),
                                 msg='Request id {key}: Unable to open cert '
                                 'file \'{certfile}\': {error}')
                    continue
            elif store == 'NSSDB':
                nickname = str(
                    request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF,
                                        'key_nickname'))
                dbdir = str(
                    request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF,
                                        'cert_database'))
                try:
                    db = certdb.NSSDatabase(dbdir)
                except Exception as e:
                    yield Result(self,
                                 constants.ERROR,
                                 key=id,
                                 dbdir=dbdir,
                                 error=str(e),
                                 msg='Request id {key}: Unable to open NSS '
                                 'database \'{dbdir}\': {error}')
                    continue

                try:
                    cert = db.get_cert(nickname)
                except Exception as e:
                    yield Result(self,
                                 constants.ERROR,
                                 key=id,
                                 dbdir=dbdir,
                                 nickname=nickname,
                                 error=str(e),
                                 msg='Request id {key}: Unable to retrieve '
                                 'cert \'{nickname}\' from \'{dbdir}\': '
                                 '{error}')
                    continue
            else:
                yield Result(self,
                             constants.ERROR,
                             key=id,
                             store=store,
                             msg='Request id {key}: Unknown certmonger '
                             'storage type: {store}')
                continue

            now = datetime.utcnow()
            notafter = cert.not_valid_after

            if now > notafter:
                yield Result(self,
                             constants.ERROR,
                             key=id,
                             expiration_date=generalized_time(notafter),
                             msg='Request id {key} expired on '
                             '{expiration_date}')
                continue

            delta = notafter - now
            diff = int(delta.total_seconds() / DAY)
            if diff < int(self.config.cert_expiration_days):
                yield Result(self,
                             constants.WARNING,
                             key=id,
                             expiration_date=generalized_time(notafter),
                             days=diff,
                             msg='Request id {key} expires in {days} '
                             'days. certmonger should renew this '
                             'automatically. Watch the status with'
                             'getcert list -i {key}.')
            else:
                yield Result(self, constants.SUCCESS, key=id)
Ejemplo n.º 14
0
    def CreateSelfSignedCerts(self):
        """ 
        Creates NSS DB on the Directory Instance Directory and creates self signed certificates using certutil command. 

	:param: None
	:return bool:  True if certs are created else Raises DirSrvException.
            
	Note: This method uses certdb function from ipapython to create NSS DB directory
        """
        DSCertDBOjb = certdb.NSSDatabase(nssdir=self.DSInstPath)
        DSNSSPassPhrase = 'Secret123'
        (pwdfile_fd, pwd_file_path) = tempfile.mkstemp()
        os.write(pwdfile_fd, DSNSSPassPhrase)
        os.close(pwdfile_fd)

        #setup NSS DB with the password created
        DSCertDBOjb.create_db(pwd_file_path)
        #since there is no exception handling , we need to verify
        #if the nssdb is created properly, we check if cert8.db,
        #secmod.db and key3.db exists
        nss_db_file = ['cert8.db', 'key3.db', 'secmod.db']
        for files in nss_db_file:
            if not exists(os.path.join(self.DSInstPath, files)):
                raise DirSrvException('Could not setup NSS DB on %s' % self.DSInstPath)

        # create Noise File
        noise = array.array('B', os.urandom(128))
        (noise_fd, noise_name) = tempfile.mkstemp()
        os.write(noise_fd, noise)
        os.close(noise_fd)
        ca_args = ["-f", pwd_file_path,
                "-S", 
                "-n", "Example CA",
                "-s", "CN=Example CA,O=Example,L=Raleigh,C=US",
                "-t", "CT,,",
                "-x",
                "-z", noise_name]


        stdin, stdout, return_code = DSCertDBOjb.run_certutil(ca_args)
        if return_code != 0:
            raise DirSrvException('Could not create Self signed CA Cert')

        server_dn = "CN=%s" % (self.DSInstHost)

        server_args = ["-f", pwd_file_path,
                "-S",
                "-n", "Server-Cert",
                "-s", server_dn,
                "-c", "Example CA",
                "-t", "u,u,u",
                "-v", "720",
                "-m", "1001",
                "-z", noise_name]
        
        stdin, stdout, return_code = DSCertDBOjb.run_certutil(server_args)
        if return_code != 0: 
            raise DirSrvException('Could not create Server-Cert')

        os.remove(pwd_file_path)
        os.remove(noise_name)

        ##write password to pin.txt
        pin_file = os.path.join(self.DSInstPath, 'pin.txt')
        pin_fd = open(pin_file, "w")
        pin_fd.write('Internal (Software) Token:%s' % DSNSSPassPhrase)
        pin_fd.close()

        #all these files are to be owned by #dirsrv a/c
        DSUID = pwd.getpwnam(DS_USER)
        DSGID = grp.getgrnam(DS_GROUP)
        for files in nss_db_file:
            os.chown((os.path.join(self.DSInstPath, files)), DSUID.pw_uid, DSGID.gr_gid)
        os.chown(pin_file, DSUID.pw_uid, DSGID.gr_gid)
        os.chmod(pin_file, 0400)

        return True
Ejemplo n.º 15
0
def main():
    module = AnsibleModule(
        argument_spec = dict(
            servers=dict(required=True, type='list'),
            realm=dict(required=True),
            hostname=dict(required=True),
            debug=dict(required=False, type='bool', default="false")
        ),
        supports_check_mode = True,
    )

    module._ansible_debug = True
    realm = module.params.get('realm')
    hostname = module.params.get('hostname')
    servers = module.params.get('servers')
    debug = module.params.get('debug')

    fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
    statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE)
    host_principal = 'host/%s@%s' % (hostname, realm)
    os.environ['KRB5CCNAME'] = paths.IPA_DNS_CCACHE
    
    ca_certs = x509.load_certificate_list_from_file(paths.IPA_CA_CRT)
    if NUM_VERSION >= 40500 and NUM_VERSION < 40590:
        ca_certs = [ cert.public_bytes(serialization.Encoding.DER)
                     for cert in ca_certs ]
    elif NUM_VERSION < 40500:
        ca_certs = [ cert.der_data for cert in ca_certs ]

    with certdb.NSSDatabase() as tmp_db:
        api.bootstrap(context='cli_installer',
                      confdir=paths.ETC_IPA,
                      debug=debug,
                      delegate=False,
                      nss_dir=tmp_db.secdir)

        if 'config_loaded' not in api.env:
            module.fail_json(msg="Failed to initialize IPA API.")

        # Clear out any current session keyring information
        try:
            delete_persistent_client_session_data(host_principal)
        except ValueError:
            pass

        # Add CA certs to a temporary NSS database
        argspec = inspect.getargspec(tmp_db.create_db)
        try:
            if NUM_VERSION > 40404:
                tmp_db.create_db()

                for i, cert in enumerate(ca_certs):
                    tmp_db.add_cert(cert,
                                    'CA certificate %d' % (i + 1),
                                    certdb.EXTERNAL_CA_TRUST_FLAGS)
            else:
                pwd_file = write_tmp_file(ipa_generate_password())
                tmp_db.create_db(pwd_file.name)

                for i, cert in enumerate(ca_certs):
                    tmp_db.add_cert(cert, 'CA certificate %d' % (i + 1), 'C,,')
        except CalledProcessError as e:
            module.fail_json(msg="Failed to add CA to temporary NSS database.")

        api.finalize()

        # Now, let's try to connect to the server's RPC interface
        connected = False
        try:
            api.Backend.rpcclient.connect()
            connected = True
            module.debug("Try RPC connection")
            api.Backend.rpcclient.forward('ping')
        except errors.KerberosError as e:
            if connected:
                api.Backend.rpcclient.disconnect()
            module.log(
                "Cannot connect to the server due to Kerberos error: %s. "
                "Trying with delegate=True" % e)
            try:
                api.Backend.rpcclient.connect(delegate=True)
                module.debug("Try RPC connection")
                api.Backend.rpcclient.forward('ping')

                module.log("Connection with delegate=True successful")

                # The remote server is not capable of Kerberos S4U2Proxy
                # delegation. This features is implemented in IPA server
                # version 2.2 and higher
                module.warn(
                    "Target IPA server has a lower version than the enrolled "
                    "client")
                module.warn(
                    "Some capabilities including the ipa command capability "
                    "may not be available")
            except errors.PublicError as e2:
                module.fail_json(
                    msg="Cannot connect to the IPA server RPC interface: %s" % e2)
        except errors.PublicError as e:
            module.fail_json(
                msg="Cannot connect to the server due to generic error: %s" % e)
    # Use the RPC directly so older servers are supported
    try:
        result = api.Backend.rpcclient.forward(
            'ca_is_enabled',
            version=u'2.107',
        )
        ca_enabled = result['result']
    except (errors.CommandError, errors.NetworkError):
        result = api.Backend.rpcclient.forward(
            'env',
            server=True,
            version=u'2.0',
        )
        ca_enabled = result['result']['enable_ra']
    if not ca_enabled:
        disable_ra()

    # Get subject base from ipa server
    try:
        config = api.Command['config_show']()['result']
        subject_base = str(DN(config['ipacertificatesubjectbase'][0]))
    except errors.PublicError as e:
        module.fail_json(msg="Cannot get subject base from server: %s" % e)

    module.exit_json(changed=True,
                     ca_enabled=ca_enabled,
                     subject_base=subject_base)
Ejemplo n.º 16
0
def get_expected_requests(ca, ds, serverid):
    """Provide the expected certmonger tracking request data

       This list is based in part on certificate_renewal_update() in
       ipaserver/install/server/upgrade.py and various
       start_tracking_certificates() methods in *instance.py.

       The list is filtered depending on whether a CA is running
       and the certificates have been issued by IPA.

      :param ca: the CAInstance
      :param ds: the DSInstance
      :param serverid: the DS serverid name
    """
    template = paths.CERTMONGER_COMMAND_TEMPLATE

    if api.Command.ca_is_enabled()['result']:
        requests = [
            {
                'cert-file': paths.RA_AGENT_PEM,
                'key-file': paths.RA_AGENT_KEY,
                'ca-name': RENEWAL_CA_NAME,
                'cert-presave-command': template % 'renew_ra_cert_pre',
                'cert-postsave-command': template % 'renew_ra_cert',
            },
        ]
    else:
        requests = []

    if ca.is_configured():
        dogtag_reqs = ca.tracking_reqs.items()
        kra = krainstance.KRAInstance(api.env.realm)
        if kra.is_installed():
            dogtag_reqs = itertools.chain(dogtag_reqs,
                                          kra.tracking_reqs.items())
        for nick, profile in dogtag_reqs:
            req = {
                'cert-database':
                paths.PKI_TOMCAT_ALIAS_DIR,
                'cert-nickname':
                nick,
                'ca-name':
                RENEWAL_CA_NAME,
                'cert-presave-command':
                template % 'stop_pkicad',
                'cert-postsave-command':
                (template % 'renew_ca_cert "{}"'.format(nick)),
                'template-profile':
                profile,
            }
            requests.append(req)
    else:
        logger.debug('CA is not configured, skipping CA tracking')

    cert = x509.load_certificate_from_file(paths.HTTPD_CERT_FILE)
    issued = is_ipa_issued_cert(api, cert)
    if issued is None:
        logger.debug('Unable to determine if \'%s\' was issued by IPA '
                     'because no LDAP connection, assuming yes.')
    if issued or issued is None:
        requests.append({
            'cert-file': paths.HTTPD_CERT_FILE,
            'key-file': paths.HTTPD_KEY_FILE,
            'ca-name': 'IPA',
            'cert-postsave-command': template % 'restart_httpd',
        })
    else:
        logger.debug(
            'HTTP cert not issued by IPA, \'%s\', skip tracking '
            'check', DN(cert.issuer))

    # Check the ldap server cert if issued by IPA
    ds_nickname = ds.get_server_cert_nickname(serverid)
    ds_db_dirname = dsinstance.config_dirname(serverid)
    ds_db = certs.CertDB(api.env.realm, nssdir=ds_db_dirname)
    connected = api.Backend.ldap2.isconnected()
    if not connected:
        logger.debug('Unable to determine if \'%s\' was issued by IPA '
                     'because no LDAP connection, assuming yes.')
    if not connected or ds_db.is_ipa_issued_cert(api, ds_nickname):
        requests.append({
            'cert-database':
            ds_db_dirname[:-1],
            'cert-nickname':
            ds_nickname,
            'ca-name':
            'IPA',
            'cert-postsave-command':
            '%s %s' % (template % 'restart_dirsrv', serverid),
        })
    else:
        logger.debug('DS cert is not issued by IPA, skip tracking check')

    # Check if pkinit is enabled
    if os.path.exists(paths.KDC_CERT):
        pkinit_request_ca = krbinstance.get_pkinit_request_ca()
        requests.append({
            'cert-file': paths.KDC_CERT,
            'key-file': paths.KDC_KEY,
            'ca-name': pkinit_request_ca,
            'cert-postsave-command': template % 'renew_kdc_cert',
        })
    else:
        logger.debug('No KDC pkinit certificate')

    # See if a host certificate was issued. This is only to
    # prevent a false-positive if one is indeed installed.
    local = {
        paths.IPA_NSSDB_DIR: 'Local IPA host',
        paths.NSS_DB_DIR: 'IPA Machine Certificate - %s' % socket.getfqdn(),
    }
    for db, nickname in local.items():
        nssdb = certdb.NSSDatabase(db)
        if nssdb.has_nickname(nickname):
            requests.append({
                'cert-database': db,
                'cert-nickname': nickname,
                'ca-name': 'IPA',
            })

    return requests
Ejemplo n.º 17
0
def main():
    module = AnsibleModule(
        argument_spec = dict(
            servers=dict(required=True, type='list'),
            domain=dict(required=True),
            realm=dict(required=True),
            hostname=dict(required=True),
            basedn=dict(required=True),
            principal=dict(required=False),
            subject_base=dict(required=True),
            ca_enabled=dict(required=True, type='bool'),
            mkhomedir=dict(required=False, type='bool'),
            on_master=dict(required=False, type='bool'),
        ),
        supports_check_mode = True,
    )

    module._ansible_debug = True
    servers = module.params.get('servers')
    realm = module.params.get('realm')
    hostname = module.params.get('hostname')
    basedn = module.params.get('basedn')
    domain = module.params.get('domain')
    principal = module.params.get('principal')
    subject_base = module.params.get('subject_base')
    ca_enabled = module.params.get('ca_enabled')
    mkhomedir = module.params.get('mkhomedir')
    on_master = module.params.get('on_master')

    fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
    statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE)

    ###########################################################################

    os.environ['KRB5CCNAME'] = CCACHE_FILE
    
    class Object(object):
        pass
    options = Object()
    options.dns_updates = False
    options.all_ip_addresses = False
    options.ip_addresses = None
    options.request_cert = False
    options.hostname = hostname
    options.preserve_sssd = False
    options.on_master = False
    options.conf_ssh = True
    options.conf_sshd = True
    options.conf_sudo = True
    options.primary = False
    options.permit = False
    options.krb5_offline_passwords = False
    options.create_sshfp = True

    ##########################################################################

    # Create IPA NSS database
    try:
        create_ipa_nssdb()
    except ipautil.CalledProcessError as e:
        module.fail_json(msg="Failed to create IPA NSS database: %s" % e)

    # Get CA certificates from the certificate store
    try:
        ca_certs = get_certs_from_ldap(servers[0], basedn, realm,
                                       ca_enabled)
    except errors.NoCertificateError:
        if ca_enabled:
            ca_subject = DN(('CN', 'Certificate Authority'), subject_base)
        else:
            ca_subject = None
        ca_certs = certstore.make_compat_ca_certs(ca_certs, realm,
                                                  ca_subject)
    ca_certs_trust = [(c, n, certstore.key_policy_to_trust_flags(t, True, u))
                      for (c, n, t, u) in ca_certs]

    if hasattr(paths, "KDC_CA_BUNDLE_PEM"):
        x509.write_certificate_list(
            [c for c, n, t, u in ca_certs if t is not False],
            paths.KDC_CA_BUNDLE_PEM)
    if hasattr(paths, "CA_BUNDLE_PEM"):
        x509.write_certificate_list(
            [c for c, n, t, u in ca_certs if t is not False],
            paths.CA_BUNDLE_PEM)

    # Add the CA certificates to the IPA NSS database
    module.debug("Adding CA certificates to the IPA NSS database.")
    ipa_db = certdb.NSSDatabase(paths.IPA_NSSDB_DIR)
    for cert, nickname, trust_flags in ca_certs_trust:
        try:
            ipa_db.add_cert(cert, nickname, trust_flags)
        except CalledProcessError as e:
            module.fail_json(msg="Failed to add %s to the IPA NSS database." % nickname)

    # Add the CA certificates to the platform-dependant systemwide CA store
    tasks.insert_ca_certs_into_systemwide_ca_store(ca_certs)

    if not on_master:
        client_dns(servers[0], hostname, options)
        configure_certmonger(fstore, subject_base, realm, hostname,
                             options, ca_enabled)

    if hasattr(paths, "SSH_CONFIG_DIR"):
        ssh_config_dir = paths.SSH_CONFIG_DIR
    else:
        ssh_config_dir = services.knownservices.sshd.get_config_dir()
    update_ssh_keys(hostname, ssh_config_dir, options.create_sshfp)

    try:
        os.remove(CCACHE_FILE)
    except Exception:
        pass

    ##########################################################################

    # Name Server Caching Daemon. Disable for SSSD, use otherwise
    # (if installed)
    nscd = services.knownservices.nscd
    if nscd.is_installed():
        save_state(nscd, statestore)

        try:
            nscd_service_action = 'stop'
            nscd.stop()
        except Exception:
            module.warn("Failed to %s the %s daemon" %
                        (nscd_service_action, nscd.service_name))

        try:
            nscd.disable()
        except Exception:
            module.warn("Failed to disable %s daemon. Disable it manually." %
                        nscd.service_name)

    nslcd = services.knownservices.nslcd
    if nslcd.is_installed():
        save_state(nslcd, statestore)

    retcode, conf = (0, None)

    ##########################################################################

    # Modify nsswitch/pam stack
    tasks.modify_nsswitch_pam_stack(sssd=True,
                                    mkhomedir=mkhomedir,
                                    statestore=statestore)

    module.log("SSSD enabled")

    argspec = inspect.getargspec(services.service)
    if len(argspec.args) > 1:
        sssd = services.service('sssd', api)
    else:
        sssd = services.service('sssd')
    try:
        sssd.restart()
    except CalledProcessError:
        module.warn("SSSD service restart was unsuccessful.")

    try:
        sssd.enable()
    except CalledProcessError as e:
        module.warn(
            "Failed to enable automatic startup of the SSSD daemon: "
            "%s", e)

    if configure_openldap_conf(fstore, basedn, servers):
        module.log("Configured /etc/openldap/ldap.conf")
    else:
        module.log("Failed to configure /etc/openldap/ldap.conf")

    # Check that nss is working properly
    if not on_master:
        user = principal
        if user is None or user == "":
            user = "******" % domain
            module.log("Principal is not set when enrolling with OTP"
                       "; using principal '%s' for 'getent passwd'" % user)
        elif '@' not in user:
            user = "******" % (user, domain)
        n = 0
        found = False
        # Loop for up to 10 seconds to see if nss is working properly.
        # It can sometimes take a few seconds to connect to the remote
        # provider.
        # Particulary, SSSD might take longer than 6-8 seconds.
        while n < 10 and not found:
            try:
                ipautil.run(["getent", "passwd", user])
                found = True
            except Exception as e:
                time.sleep(1)
                n = n + 1

        if not found:
            module.fail_json(msg="Unable to find '%s' user with 'getent "
                             "passwd %s'!" % (user.split("@")[0], user))
            if conf:
                module.log("Recognized configuration: %s" % conf)
            else:
                module.fail_json(msg=
                                 "Unable to reliably detect "
                                 "configuration. Check NSS setup manually.")

            try:
                hardcode_ldap_server(servers)
            except Exception as e:
                module.fail_json(msg="Adding hardcoded server name to "
                                 "/etc/ldap.conf failed: %s" % str(e))

    ##########################################################################

    module.exit_json(changed=True,
                     ca_enabled_ra=ca_enabled)
Ejemplo n.º 18
0
    def check(self):
        cm = certmonger._certmonger()

        all_requests = cm.obj_if.get_requests()
        for req in all_requests:
            request = certmonger._cm_dbus_object(cm.bus, cm, req,
                                                 certmonger.DBUS_CM_REQUEST_IF,
                                                 certmonger.DBUS_CM_IF, True)
            id = request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF, 'nickname')

            store = request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF,
                                        'cert-storage')
            if store == 'FILE':
                certfile = str(
                    request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF,
                                        'cert-file'))
                try:
                    cert = x509.load_certificate_from_file(certfile)
                except Exception as e:
                    yield Result(self,
                                 constants.ERROR,
                                 key=id,
                                 certfile=certfile,
                                 error=str(e),
                                 msg='Unable to open cert file \'%s\': %s' %
                                 (certfile, e))
                    continue
            elif store == 'NSSDB':
                nickname = str(
                    request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF,
                                        'key_nickname'))
                dbdir = str(
                    request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF,
                                        'cert_database'))
                try:
                    db = certdb.NSSDatabase(dbdir)
                except Exception as e:
                    yield Result(self,
                                 constants.ERROR,
                                 key=id,
                                 dbdir=dbdir,
                                 error=str(e),
                                 msg='Unable to open NSS database \'%s\': %s' %
                                 (dbdir, e))
                    continue

                try:
                    cert = db.get_cert(nickname)
                except Exception as e:
                    yield Result(self,
                                 constants.ERROR,
                                 key=id,
                                 dbdir=dbdir,
                                 nickname=nickname,
                                 error=str(e),
                                 msg='Unable to retrieve cert \'%s\' from '
                                 '\'%s\': %s' % (nickname, dbdir, e))
                    continue
            else:
                yield Result(self,
                             constants.ERROR,
                             key=id,
                             store=store,
                             msg='Unknown certmonger storage type: %s' % store)
                continue

            now = datetime.utcnow()
            notafter = cert.not_valid_after

            if now > notafter:
                yield Result(self,
                             constants.ERROR,
                             key=id,
                             expiration_date=generalized_time(notafter),
                             msg='Request id %s expired on %s' %
                             (id, generalized_time(notafter)))
                continue

            delta = notafter - now
            diff = int(delta.total_seconds() / DAY)
            if diff < self.config.cert_expiration_days:
                yield Result(self,
                             constants.WARNING,
                             key=id,
                             expiration_date=generalized_time(notafter),
                             days=diff,
                             msg='Request id %s expires in %s days' %
                             (id, diff))
            else:
                yield Result(self, constants.SUCCESS, key=id)