Exemplo n.º 1
0
    def delete(self, certificate_uuid):
        """Uninstall a certificate."""

        # Only support ssl_ca cert type
        log_start = cutils.timestamped("certificate_do_delete_start")

        try:
            certificate = pecan.request.dbapi.certificate_get(certificate_uuid)
        except exception.InvalidParameterValue:
            raise wsme.exc.ClientSideError(
                _("No certificate found for %s" % certificate_uuid))

        if certificate and \
                certificate.certtype not in [constants.CERT_MODE_SSL_CA]:
            msg = "Unupported mode: {}".format(certificate.certtype)
            raise wsme.exc.ClientSideError(_(msg))

        LOG.info("certificate %s certificate_uuid=%s" %
                 (log_start, certificate_uuid))

        try:
            pecan.request.rpcapi.delete_certificate(pecan.request.context,
                                                    certificate.certtype,
                                                    certificate.signature)
        except RemoteError as e:
            msg = "Exception occurred e={}".format(e)
            LOG.warn(msg)
            raise wsme.exc.ClientSideError(
                _("Failed to delete the certificate: %s, %s" %
                  (certificate_uuid, str(e.value))))

        pecan.request.dbapi.certificate_destroy(certificate_uuid)

        log_end = cutils.timestamped("certificate_do_delete_end")
        LOG.info("certificate %s" % log_end)

        return Certificate.convert_with_links(certificate)
Exemplo n.º 2
0
    def certificate_install(self):
        """Install the certificate.

           Certificates are installed according to one of the following modes:
               default: install certificate for ssl
               tpm_mode: install certificate to tpm devices for ssl
               docker_registry: install certificate for docker registry
               openstack: install certificate for openstack
               openstack_ca: install ca certificate for openstack
        """

        log_start = cutils.timestamped("certificate_do_post_start")

        fileitem = pecan.request.POST['file']
        passphrase = pecan.request.POST.get('passphrase')
        mode = pecan.request.POST.get('mode')

        LOG.info("certificate %s mode=%s" % (log_start, mode))

        if mode and mode not in constants.CERT_MODES_SUPPORTED:
            msg = "Invalid mode: %s" % mode
            LOG.info(msg)
            return dict(success="", error=msg)
        elif not mode:
            # Default certificate install is non-tpm SSL
            mode = constants.CERT_MODE_SSL

        system = pecan.request.dbapi.isystem_get_one()
        capabilities = system.capabilities

        # platform-cert 'force' check for backward compatibility
        if mode == constants.CERT_MODE_SSL:
            # Call may not contain 'force' parameter
            # Note: cert-mon will pass a HTTP POST 'force'='true' param
            force = pecan.request.POST.get('force')
            if force == 'true':
                force = True
            else:
                force = False
            # if PLATFORM_CERT_SECRET_NAME secret is present in k8s, we
            # assume that SSL cert is managed by cert-manager/cert-mon
            managed_by_cm = self._kube_op.kube_get_secret(
                constants.PLATFORM_CERT_SECRET_NAME,
                constants.CERT_NAMESPACE_PLATFORM_CERTS)

            if force is False and managed_by_cm is not None:
                msg = "Certificate is currently being managed by cert-manager. \n" \
                        "To manage certificate with this command, first delete " \
                        "the %s Certificate and Secret." % constants.PLATFORM_CERT_SECRET_NAME
                LOG.info(msg)
                return dict(success="", error=msg)

        standalone_certs = [
            constants.CERT_MODE_DOCKER_REGISTRY, constants.CERT_MODE_SSL_CA
        ]
        if mode not in standalone_certs:
            system_https_enabled = capabilities.get('https_enabled', False)
            if system_https_enabled is False or system_https_enabled == 'n':
                msg = "No certificates have been added, https is not enabled."
                LOG.info(msg)
                return dict(success="", error=msg)

        if mode.startswith(constants.CERT_MODE_OPENSTACK):
            try:
                pecan.request.dbapi.certificate_get_by_certtype(
                    constants.CERT_MODE_SSL)
            except exception.CertificateTypeNotFound:
                try:
                    pecan.request.dbapi.certificate_get_by_certtype(
                        constants.CERT_MODE_TPM)
                except exception.CertificateTypeNotFound:
                    msg = "No openstack certificates have been added, " \
                          "platform SSL certificate is not installed."
                    LOG.info(msg)
                    return dict(success="", error=msg)

        if not fileitem.filename:
            return dict(success="", error="Error: No file uploaded")
        try:
            fileitem.file.seek(0, os.SEEK_SET)
            pem_contents = fileitem.file.read()
        except Exception as e:
            return dict(success="",
                        error=("No certificates have been added, "
                               "invalid PEM document: %s" % e))

        # Extract the certificates from the pem file
        try:
            certs = cutils.extract_certs_from_pem(pem_contents)
        except Exception as e:
            msg = "No certificates have been added, %s" % e
            return dict(success="", error=msg)

        if not certs:
            msg = "No certificates have been added, " \
                  "no valid certificates found in file."
            LOG.info(msg)
            return dict(success="", error=msg)

        hash_issuers = []
        for index, cert in enumerate(certs):
            msg = self._check_cert_validity(cert)
            if msg is not True:
                return dict(success="", error=msg)

            # validation checking for ssl, tpm_mode, docker_registry
            # and openstack certficcates
            if mode in [
                    constants.CERT_MODE_SSL,
                    constants.CERT_MODE_TPM,
                    constants.CERT_MODE_DOCKER_REGISTRY,
                    constants.CERT_MODE_OPENSTACK,
            ]:
                try:
                    hash_issuers.append(cutils.get_cert_issuer_hash(cert))
                    if index == 0:
                        if cutils.is_ca_cert(cert):
                            msg = "The first cert in the file should not be " \
                                  "a CA cert"
                            return dict(success="", error=msg)
                    else:
                        if not cutils.is_ca_cert(cert):
                            msg = "Number %s cert in the file should be a " \
                                  "CA cert" % (index + 1)
                            return dict(success="", error=msg)
                        hash_subject = cutils.get_cert_subject_hash(cert)
                        if hash_subject != hash_issuers[index - 1]:
                            msg = "Number %s cert in the file is not " \
                                  "signing cert of the preceding one. Check " \
                                  "certs order in the file." % (index + 1)
                            return dict(success="", error=msg)
                except Exception as e:
                    msg = "No certificates have been added, exception " \
                          "occured on cert %s: %s" % (index, e)
                    return dict(success="", error=msg)

            if mode == constants.CERT_MODE_OPENSTACK and index == 0:
                domain, msg = _check_endpoint_domain_exists()
                if domain:
                    msg = _check_cert_dns_name(cert, domain)
                    if msg is not True:
                        return dict(success="", error=msg.message)
                elif msg:
                    return dict(success="", error=msg)

        if mode == constants.CERT_MODE_TPM:
            try:
                tpm = pecan.request.dbapi.tpmconfig_get_one()
            except exception.NotFound:
                tpm = None
                pass

            if tpm:
                tpmdevices = pecan.request.dbapi.tpmdevice_get_list()
                # if any of the tpm devices are in APPLYING state
                # then disallow a modification until previous config
                # either applies or fails
                for device in tpmdevices:
                    if device.state == constants.TPMCONFIG_APPLYING:
                        msg = ("TPM Device %s is still in APPLYING state. "
                               "Wait for the configuration to finish "
                               "before attempting a modification." %
                               device.uuid)
                        LOG.info(msg)
                        return dict(success="", error=msg)

        try:
            config_dict = {
                'passphrase': passphrase,
                'mode': mode,
            }
            inv_certs = pecan.request.rpcapi.config_certificate(
                pecan.request.context, pem_contents, config_dict)

        except RemoteError as e:
            msg = "Exception occurred e={}".format(e)
            LOG.warn(msg)
            return dict(success="",
                        error=str(e.value),
                        body="",
                        certificates={})

        certificates = pecan.request.dbapi.certificate_get_list()
        # ssl and ssl_tpm certs are mutual exclusive, so
        # if the new cert is a SSL cert, delete the existing TPM cert as well
        # if the new cert is a TPM cert, delete the existing SSL cert as well
        for certificate in certificates:
            if (mode == constants.CERT_MODE_SSL
                    and certificate.certtype == constants.CERT_MODE_TPM) or \
                (mode == constants.CERT_MODE_TPM
                    and certificate.certtype == constants.CERT_MODE_SSL):
                pecan.request.dbapi.certificate_destroy(certificate.uuid)

        # Create new or update existing certificates in sysinv with the
        # information returned from conductor manager.
        certificate_dicts = []
        for inv_cert in inv_certs:
            # for ssl, tmp_mode, docker_registry and openstack certs, if the
            # cert is ICA signed cert (ie, the pem_contents contains
            # intermediate CA certs), skip these intermediate CA certs.
            if mode in [constants.CERT_MODE_SSL,
                        constants.CERT_MODE_TPM,
                        constants.CERT_MODE_DOCKER_REGISTRY,
                        constants.CERT_MODE_OPENSTACK] \
                    and inv_cert.get('is_ca', None):
                continue

            values = {
                'certtype': mode,
                'signature': inv_cert.get('signature'),
                'start_date': inv_cert.get('not_valid_before'),
                'expiry_date': inv_cert.get('not_valid_after'),
            }
            LOG.info("config_certificate values=%s" % values)

            # check to see if the installed cert exist in sysinv
            uuid = None
            for certificate in certificates:
                if mode == constants.CERT_MODE_SSL_CA:
                    if inv_cert.get('signature') == certificate.signature:
                        uuid = certificate.uuid
                        break
                else:
                    if mode == certificate.certtype:
                        uuid = certificate.uuid
                        break
            if uuid:
                certificate = pecan.request.dbapi.certificate_update(
                    uuid, values)
            else:
                certificate = pecan.request.dbapi.certificate_create(values)
            certificate_dict = certificate.as_dict()
            LOG.debug(
                "certificate_install certificate={}".format(certificate_dict))
            certificate_dicts.append(certificate_dict)

        log_end = cutils.timestamped("certificate_do_post_end")
        LOG.info("certificate %s" % log_end)

        return dict(success="",
                    error="",
                    body="",
                    certificates=certificate_dicts)
Exemplo n.º 3
0
    def certificate_install(self):
        """Install the certificate.

           Certificates are installed according to one of the following modes:
               default: install certificate for ssl
               tpm_mode: install certificate to tpm devices for ssl
               docker_registry: install certificate for docker registry
               openstack: install certificate for openstack
               openstack_ca: install ca certificate for openstack
        """

        log_start = cutils.timestamped("certificate_do_post_start")

        fileitem = pecan.request.POST['file']
        passphrase = pecan.request.POST.get('passphrase')
        mode = pecan.request.POST.get('mode')

        LOG.info("certificate %s mode=%s" % (log_start, mode))

        if mode and mode not in constants.CERT_MODES_SUPPORTED:
            msg = "Invalid mode: %s" % mode
            LOG.info(msg)
            return dict(success="", error=msg)
        elif not mode:
            # Default certificate install is non-tpm SSL
            mode = constants.CERT_MODE_SSL

        system = pecan.request.dbapi.isystem_get_one()
        capabilities = system.capabilities

        standalone_certs = [
            constants.CERT_MODE_DOCKER_REGISTRY, constants.CERT_MODE_SSL_CA
        ]
        if mode not in standalone_certs:
            system_https_enabled = capabilities.get('https_enabled', False)
            if system_https_enabled is False or system_https_enabled == 'n':
                msg = "No certificates have been added, https is not enabled."
                LOG.info(msg)
                return dict(success="", error=msg)

        if mode.startswith(constants.CERT_MODE_OPENSTACK):
            try:
                pecan.request.dbapi.certificate_get_by_certtype(
                    constants.CERT_MODE_SSL)
            except exception.CertificateTypeNotFound:
                msg = "No openstack certificates have been added, " \
                      "platform SSL certificate is not installed."
                LOG.info(msg)
                return dict(success="", error=msg)

        if not fileitem.filename:
            return dict(success="", error="Error: No file uploaded")
        try:
            fileitem.file.seek(0, os.SEEK_SET)
            pem_contents = fileitem.file.read()
        except Exception as e:
            return dict(success="",
                        error=("No certificates have been added, "
                               "invalid PEM document: %s" % e))

        # Extract the certificate from the pem file
        cert = x509.load_pem_x509_certificate(pem_contents, default_backend())

        msg = self._check_cert_validity(cert)
        if msg is not True:
            return dict(success="", error=msg)

        if mode == constants.CERT_MODE_OPENSTACK:
            domain, msg = _check_endpoint_domain_exists()
            if domain:
                msg = _check_cert_dns_name(cert, domain)
                if msg is not True:
                    return dict(success="", error=msg.message)
            elif msg:
                return dict(success="", error=msg)

        if mode == constants.CERT_MODE_TPM:
            try:
                tpm = pecan.request.dbapi.tpmconfig_get_one()
            except exception.NotFound:
                tpm = None
                pass

            if tpm:
                tpmdevices = pecan.request.dbapi.tpmdevice_get_list()
                # if any of the tpm devices are in APPLYING state
                # then disallow a modification until previous config
                # either applies or fails
                for device in tpmdevices:
                    if device.state == constants.TPMCONFIG_APPLYING:
                        msg = ("TPM Device %s is still in APPLYING state. "
                               "Wait for the configuration to finish "
                               "before attempting a modification." %
                               device.uuid)
                        LOG.info(msg)
                        return dict(success="", error=msg)

        try:
            config_dict = {
                'passphrase': passphrase,
                'mode': mode,
            }
            signature = pecan.request.rpcapi.config_certificate(
                pecan.request.context, pem_contents, config_dict)

        except Exception as e:
            msg = "Exception occurred e={}".format(e)
            LOG.info(msg)
            return dict(success="", error=str(e), body="", certificates={})

        # Update with installed certificate information
        values = {
            'certtype': mode,
            # TODO(jkung) 'issuer': cert.issuer,
            'signature': signature,
            'start_date': cert.not_valid_before,
            'expiry_date': cert.not_valid_after,
        }
        LOG.info("config_certificate values=%s" % values)

        if mode in [constants.CERT_MODE_SSL, constants.CERT_MODE_TPM]:
            if mode == constants.CERT_MODE_SSL:
                remove_certtype = constants.CERT_MODE_TPM
            else:
                remove_certtype = constants.CERT_MODE_SSL
            try:
                remove_certificate = \
                    pecan.request.dbapi.certificate_get_by_certtype(
                        remove_certtype)
                LOG.info("remove certificate certtype=%s uuid`=%s" %
                         (remove_certtype, remove_certificate.uuid))
                pecan.request.dbapi.certificate_destroy(
                    remove_certificate.uuid)
            except exception.CertificateTypeNotFound:
                pass

        try:
            certificate = \
                pecan.request.dbapi.certificate_get_by_certtype(
                    mode)
            certificate = \
                pecan.request.dbapi.certificate_update(certificate.uuid,
                                                       values)
        except exception.CertificateTypeNotFound:
            certificate = pecan.request.dbapi.certificate_create(values)
            pass

        sp_certificates_dict = certificate.as_dict()

        LOG.debug("certificate_install sp_certificates={}".format(
            sp_certificates_dict))

        log_end = cutils.timestamped("certificate_do_post_end")
        LOG.info("certificate %s" % log_end)

        return dict(success="",
                    error="",
                    body="",
                    certificates=sp_certificates_dict)