Exemplo n.º 1
0
    def set_data(self, data, size=None, backend=None, set_active=True):
        if size is None:
            size = 0  # NOTE(markwash): zero -> unknown size

        # Create the verifier for signature verification (if correct properties
        # are present)
        extra_props = self.image.extra_properties
        verifier = None
        if signature_utils.should_create_verifier(extra_props):
            # NOTE(bpoulos): if creating verifier fails, exception will be
            # raised
            img_signature = extra_props[signature_utils.SIGNATURE]
            hash_method = extra_props[signature_utils.HASH_METHOD]
            key_type = extra_props[signature_utils.KEY_TYPE]
            cert_uuid = extra_props[signature_utils.CERT_UUID]
            verifier = signature_utils.get_verifier(
                context=self.context,
                img_signature_certificate_uuid=cert_uuid,
                img_signature_hash_method=hash_method,
                img_signature=img_signature,
                img_signature_key_type=key_type)

        self._upload_to_store(data, verifier, backend, size)
        if set_active and self.image.status != 'active':
            self.image.status = 'active'
Exemplo n.º 2
0
def verify_glance_image_signature(context, image_service, image_id, path):
    verifier = None
    image_meta = image_service.show(context, image_id)
    image_properties = image_meta.get('properties', {})
    img_signature = image_properties.get('img_signature')
    img_sig_hash_method = image_properties.get('img_signature_hash_method')
    img_sig_cert_uuid = image_properties.get('img_signature_certificate_uuid')
    img_sig_key_type = image_properties.get('img_signature_key_type')
    if all(m is None for m in [img_signature,
                               img_sig_cert_uuid,
                               img_sig_hash_method,
                               img_sig_key_type]):
        # NOTE(tommylikehu): We won't verify the image signature
        # if none of the signature metadata presents.
        return False
    if any(m is None for m in [img_signature,
                               img_sig_cert_uuid,
                               img_sig_hash_method,
                               img_sig_key_type]):
        LOG.error('Image signature metadata for image %s is '
                  'incomplete.', image_id)
        raise exception.InvalidSignatureImage(image_id=image_id)

    try:
        verifier = signature_utils.get_verifier(
            context=context,
            img_signature_certificate_uuid=img_sig_cert_uuid,
            img_signature_hash_method=img_sig_hash_method,
            img_signature=img_signature,
            img_signature_key_type=img_sig_key_type,
        )
    except cursive_exception.SignatureVerificationError:
        message = _('Failed to get verifier for image: %s') % image_id
        LOG.error(message)
        raise exception.ImageSignatureVerificationException(
            reason=message)
    if verifier:
        with fileutils.remove_path_on_error(path):
            with open(path, "rb") as tem_file:
                try:
                    tpool.execute(_verify_image, tem_file, verifier)
                    LOG.info('Image signature verification succeeded '
                             'for image: %s', image_id)
                    return True
                except cryptography.exceptions.InvalidSignature:
                    message = _('Image signature verification '
                                'failed for image: %s') % image_id
                    LOG.error(message)
                    raise exception.ImageSignatureVerificationException(
                        reason=message)
                except Exception as ex:
                    message = _('Failed to verify signature for '
                                'image: %(image)s due to '
                                'error: %(error)s ') % {'image': image_id,
                                                        'error':
                                                            six.text_type(ex)}
                    LOG.error(message)
                    raise exception.ImageSignatureVerificationException(
                        reason=message)
    return False
    def test_verify_signature_ECC(self, mock_get_pub_key):
        data = b'224626ae19824466f2a7f39ab7b80f7f'
        # test every ECC curve
        for curve in signature_utils.ECC_CURVES:
            key_type_name = 'ECC_' + curve.name.upper()
            try:
                signature_utils.SignatureKeyType.lookup(key_type_name)
            except exception.SignatureVerificationError:
                import warnings
                warnings.warn("ECC curve '%s' not supported" % curve.name)
                continue

            # Create a private key to use
            private_key = ec.generate_private_key(curve,
                                                  default_backend())
            mock_get_pub_key.return_value = private_key.public_key()
            for hash_name, hash_alg in signature_utils.HASH_METHODS.items():
                signer = private_key.signer(
                    ec.ECDSA(hash_alg)
                )
                signer.update(data)
                signature = base64.b64encode(signer.finalize())
                img_sig_cert_uuid = 'fea14bc2-d75f-4ba5-bccc-b5c924ad0693'
                verifier = signature_utils.get_verifier(None,
                                                        img_sig_cert_uuid,
                                                        hash_name, signature,
                                                        key_type_name)
                verifier.update(data)
                verifier.verify()
Exemplo n.º 4
0
def verify_glance_image_signature(context, image_service, image_id, path):
    verifier = None
    image_meta = image_service.show(context, image_id)
    image_properties = image_meta.get('properties', {})
    img_signature = image_properties.get('img_signature')
    img_sig_hash_method = image_properties.get('img_signature_hash_method')
    img_sig_cert_uuid = image_properties.get('img_signature_certificate_uuid')
    img_sig_key_type = image_properties.get('img_signature_key_type')
    if all(m is None for m in [img_signature,
                               img_sig_cert_uuid,
                               img_sig_hash_method,
                               img_sig_key_type]):
        # NOTE(tommylikehu): We won't verify the image signature
        # if none of the signature metadata presents.
        return False
    if any(m is None for m in [img_signature,
                               img_sig_cert_uuid,
                               img_sig_hash_method,
                               img_sig_key_type]):
            LOG.error('Image signature metadata for image %s is '
                      'incomplete.', image_id)
            raise exception.InvalidSignatureImage(image_id=image_id)

    try:
        verifier = signature_utils.get_verifier(
            context=context,
            img_signature_certificate_uuid=img_sig_cert_uuid,
            img_signature_hash_method=img_sig_hash_method,
            img_signature=img_signature,
            img_signature_key_type=img_sig_key_type,
        )
    except cursive_exception.SignatureVerificationError:
        message = _('Failed to get verifier for image: %s') % image_id
        LOG.error(message)
        raise exception.ImageSignatureVerificationException(
            reason=message)
    if verifier:
        with fileutils.remove_path_on_error(path):
            with open(path, "rb") as tem_file:
                try:
                    tpool.execute(_verify_image, tem_file, verifier)
                    LOG.info('Image signature verification succeeded '
                             'for image: %s', image_id)
                    return True
                except cryptography.exceptions.InvalidSignature:
                    message = _('Image signature verification '
                                'failed for image: %s') % image_id
                    LOG.error(message)
                    raise exception.ImageSignatureVerificationException(
                        reason=message)
                except Exception as ex:
                    message = _('Failed to verify signature for '
                                'image: %(image)s due to '
                                'error: %(error)s ') % {'image': image_id,
                                                        'error':
                                                            six.text_type(ex)}
                    LOG.error(message)
                    raise exception.ImageSignatureVerificationException(
                        reason=message)
    return False
Exemplo n.º 5
0
    def _get_verifier(self, context, image_id, trusted_certs):
        verifier = None

        # Use the default certs if the user didn't provide any (and there are
        # default certs configured).
        if (not trusted_certs and CONF.glance.enable_certificate_validation and
                CONF.glance.default_trusted_certificate_ids):
            trusted_certs = objects.TrustedCerts(
                ids=CONF.glance.default_trusted_certificate_ids)

        # Verify image signature if feature is enabled or trusted
        # certificates were provided
        if trusted_certs or CONF.glance.verify_glance_signatures:
            image_meta_dict = self.show(context, image_id,
                                        include_locations=False)
            image_meta = objects.ImageMeta.from_dict(image_meta_dict)
            img_signature = image_meta.properties.get('img_signature')
            img_sig_hash_method = image_meta.properties.get(
                'img_signature_hash_method'
            )
            img_sig_cert_uuid = image_meta.properties.get(
                'img_signature_certificate_uuid'
            )
            img_sig_key_type = image_meta.properties.get(
                'img_signature_key_type'
            )
            try:
                verifier = signature_utils.get_verifier(
                    context=context,
                    img_signature_certificate_uuid=img_sig_cert_uuid,
                    img_signature_hash_method=img_sig_hash_method,
                    img_signature=img_signature,
                    img_signature_key_type=img_sig_key_type,
                )
            except cursive_exception.SignatureVerificationError:
                with excutils.save_and_reraise_exception():
                    LOG.error('Image signature verification failed '
                              'for image: %s', image_id)
            # Validate image signature certificate if trusted certificates
            # were provided
            # NOTE(jackie-truong): Certificate validation will occur if
            # trusted_certs are provided, even if the certificate validation
            # feature is disabled. This is to provide safety for the user.
            # We may want to consider making this a "soft" check in the future.
            if trusted_certs:
                _verify_certs(context, img_sig_cert_uuid, trusted_certs)
            elif CONF.glance.enable_certificate_validation:
                msg = ('Image signature certificate validation enabled, '
                       'but no trusted certificate IDs were provided. '
                       'Unable to validate the certificate used to '
                       'verify the image signature.')
                LOG.warning(msg)
                raise exception.CertificateValidationFailed(msg)
            else:
                LOG.debug('Certificate validation was not performed. A list '
                          'of trusted image certificate IDs must be provided '
                          'in order to validate an image certificate.')

        return verifier
Exemplo n.º 6
0
    def _get_verifier(self, context, image_id, trusted_certs):
        verifier = None

        # Use the default certs if the user didn't provide any (and there are
        # default certs configured).
        if (not trusted_certs and CONF.glance.enable_certificate_validation
                and CONF.glance.default_trusted_certificate_ids):
            trusted_certs = objects.TrustedCerts(
                ids=CONF.glance.default_trusted_certificate_ids)

        # Verify image signature if feature is enabled or trusted
        # certificates were provided
        if trusted_certs or CONF.glance.verify_glance_signatures:
            image_meta_dict = self.show(context,
                                        image_id,
                                        include_locations=False)
            image_meta = objects.ImageMeta.from_dict(image_meta_dict)
            img_signature = image_meta.properties.get('img_signature')
            img_sig_hash_method = image_meta.properties.get(
                'img_signature_hash_method')
            img_sig_cert_uuid = image_meta.properties.get(
                'img_signature_certificate_uuid')
            img_sig_key_type = image_meta.properties.get(
                'img_signature_key_type')
            try:
                verifier = signature_utils.get_verifier(
                    context=context,
                    img_signature_certificate_uuid=img_sig_cert_uuid,
                    img_signature_hash_method=img_sig_hash_method,
                    img_signature=img_signature,
                    img_signature_key_type=img_sig_key_type,
                )
            except cursive_exception.SignatureVerificationError:
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        'Image signature verification failed '
                        'for image: %s', image_id)
            # Validate image signature certificate if trusted certificates
            # were provided
            # NOTE(jackie-truong): Certificate validation will occur if
            # trusted_certs are provided, even if the certificate validation
            # feature is disabled. This is to provide safety for the user.
            # We may want to consider making this a "soft" check in the future.
            if trusted_certs:
                _verify_certs(context, img_sig_cert_uuid, trusted_certs)
            elif CONF.glance.enable_certificate_validation:
                msg = ('Image signature certificate validation enabled, '
                       'but no trusted certificate IDs were provided. '
                       'Unable to validate the certificate used to '
                       'verify the image signature.')
                LOG.warning(msg)
                raise exception.CertificateValidationFailed(msg)
            else:
                LOG.debug('Certificate validation was not performed. A list '
                          'of trusted image certificate IDs must be provided '
                          'in order to validate an image certificate.')

        return verifier
 def test_verify_signature_bad_signature(self, mock_get_pub_key):
     data = b'224626ae19824466f2a7f39ab7b80f7f'
     mock_get_pub_key.return_value = TEST_RSA_PRIVATE_KEY.public_key()
     img_sig_cert_uuid = 'fea14bc2-d75f-4ba5-bccc-b5c924ad0693'
     verifier = signature_utils.get_verifier(None, img_sig_cert_uuid,
                                             'SHA-256', 'BLAH',
                                             signature_utils.RSA_PSS)
     verifier.update(data)
     self.assertRaises(crypto_exceptions.InvalidSignature,
                       verifier.verify)
Exemplo n.º 8
0
    def set_data(self, data, size=None):
        if size is None:
            size = 0  # NOTE(markwash): zero -> unknown size

        # Create the verifier for signature verification (if correct properties
        # are present)
        extra_props = self.image.extra_properties
        if (signature_utils.should_create_verifier(extra_props)):
            # NOTE(bpoulos): if creating verifier fails, exception will be
            # raised
            img_signature = extra_props[signature_utils.SIGNATURE]
            hash_method = extra_props[signature_utils.HASH_METHOD]
            key_type = extra_props[signature_utils.KEY_TYPE]
            cert_uuid = extra_props[signature_utils.CERT_UUID]
            verifier = signature_utils.get_verifier(
                context=self.context,
                img_signature_certificate_uuid=cert_uuid,
                img_signature_hash_method=hash_method,
                img_signature=img_signature,
                img_signature_key_type=key_type)
        else:
            verifier = None

        location, size, checksum, loc_meta = self.store_api.add_to_backend(
            CONF,
            self.image.image_id,
            utils.LimitingReader(utils.CooperativeReader(data),
                                 CONF.image_size_cap),
            size,
            context=self.context,
            verifier=verifier)

        # NOTE(bpoulos): if verification fails, exception will be raised
        if verifier:
            try:
                verifier.verify()
                LOG.info(_LI("Successfully verified signature for image %s"),
                         self.image.image_id)
            except crypto_exception.InvalidSignature:
                self.store_api.delete_from_backend(location,
                                                   context=self.context)
                raise cursive_exception.SignatureVerificationError(
                    _('Signature verification failed'))

        self.image.locations = [{
            'url': location,
            'metadata': loc_meta,
            'status': 'active'
        }]
        self.image.size = size
        self.image.checksum = checksum
        self.image.status = 'active'
Exemplo n.º 9
0
    def set_data(self, data, size=None):
        if size is None:
            size = 0  # NOTE(markwash): zero -> unknown size

        # Create the verifier for signature verification (if correct properties
        # are present)
        extra_props = self.image.extra_properties
        if (signature_utils.should_create_verifier(extra_props)):
            # NOTE(bpoulos): if creating verifier fails, exception will be
            # raised
            img_signature = extra_props[signature_utils.SIGNATURE]
            hash_method = extra_props[signature_utils.HASH_METHOD]
            key_type = extra_props[signature_utils.KEY_TYPE]
            cert_uuid = extra_props[signature_utils.CERT_UUID]
            verifier = signature_utils.get_verifier(
                context=self.context,
                img_signature_certificate_uuid=cert_uuid,
                img_signature_hash_method=hash_method,
                img_signature=img_signature,
                img_signature_key_type=key_type
            )
        else:
            verifier = None

        location, size, checksum, loc_meta = self.store_api.add_to_backend(
            CONF,
            self.image.image_id,
            utils.LimitingReader(utils.CooperativeReader(data),
                                 CONF.image_size_cap),
            size,
            context=self.context,
            verifier=verifier)

        # NOTE(bpoulos): if verification fails, exception will be raised
        if verifier:
            try:
                verifier.verify()
                LOG.info(_LI("Successfully verified signature for image %s"),
                         self.image.image_id)
            except crypto_exception.InvalidSignature:
                raise cursive_exception.SignatureVerificationError(
                    _('Signature verification failed')
                )

        self.image.locations = [{'url': location, 'metadata': loc_meta,
                                 'status': 'active'}]
        self.image.size = size
        self.image.checksum = checksum
        self.image.status = 'active'
 def test_verify_signature_DSA(self, mock_get_pub_key):
     data = b'224626ae19824466f2a7f39ab7b80f7f'
     mock_get_pub_key.return_value = TEST_DSA_PRIVATE_KEY.public_key()
     for hash_name, hash_alg in signature_utils.HASH_METHODS.items():
         signer = TEST_DSA_PRIVATE_KEY.signer(
             hash_alg
         )
         signer.update(data)
         signature = base64.b64encode(signer.finalize())
         img_sig_cert_uuid = 'fea14bc2-d75f-4ba5-bccc-b5c924ad0693'
         verifier = signature_utils.get_verifier(None, img_sig_cert_uuid,
                                                 hash_name, signature,
                                                 signature_utils.DSA)
         verifier.update(data)
         verifier.verify()
Exemplo n.º 11
0
    def set_data(self, data, size=None, backend=None, set_active=True):
        if size is None:
            size = 0  # NOTE(markwash): zero -> unknown size

        # Create the verifier for signature verification (if correct properties
        # are present)
        extra_props = self.image.extra_properties
        verifier = None
        if signature_utils.should_create_verifier(extra_props):
            # NOTE(bpoulos): if creating verifier fails, exception will be
            # raised
            img_signature = extra_props[signature_utils.SIGNATURE]
            hash_method = extra_props[signature_utils.HASH_METHOD]
            key_type = extra_props[signature_utils.KEY_TYPE]
            cert_uuid = extra_props[signature_utils.CERT_UUID]
            verifier = signature_utils.get_verifier(
                context=self.context,
                img_signature_certificate_uuid=cert_uuid,
                img_signature_hash_method=hash_method,
                img_signature=img_signature,
                img_signature_key_type=key_type)

        if not self.image.virtual_size:
            inspector = format_inspector.get_inspector(self.image.disk_format)
        else:
            # No need to do this again
            inspector = None

        if inspector and self.image.container_format == 'bare':
            fmt = inspector()
            data = format_inspector.InfoWrapper(data, fmt)
            LOG.debug('Enabling in-flight format inspection for %s', fmt)
        else:
            fmt = None

        self._upload_to_store(data, verifier, backend, size)

        if fmt and fmt.format_match and fmt.virtual_size:
            self.image.virtual_size = fmt.virtual_size
            LOG.info('Image format matched and virtual size computed: %i',
                     self.image.virtual_size)
        elif fmt:
            LOG.warning(
                'Image format %s did not match; '
                'unable to calculate virtual size', self.image.disk_format)

        if set_active and self.image.status != 'active':
            self.image.status = 'active'
Exemplo n.º 12
0
    def download(self, context, image_id, data=None, dst_path=None):
        """Calls out to Glance for data and writes data."""
        if CONF.glance.allowed_direct_url_schemes and dst_path is not None:
            image = self.show(context, image_id, include_locations=True)
            for entry in image.get('locations', []):
                loc_url = entry['url']
                loc_meta = entry['metadata']
                o = urlparse.urlparse(loc_url)
                xfer_mod = self._get_transfer_module(o.scheme)
                if xfer_mod:
                    try:
                        xfer_mod.download(context, o, dst_path, loc_meta)
                        LOG.info("Successfully transferred using %s", o.scheme)
                        return
                    except Exception:
                        LOG.exception("Download image error")

        try:
            image_chunks = self._client.call(context, 2, 'data', image_id)
        except Exception:
            _reraise_translated_image_exception(image_id)

        if image_chunks.wrapped is None:
            # None is a valid return value, but there's nothing we can do with
            # a image with no associated data
            raise exception.ImageUnacceptable(
                image_id=image_id, reason='Image has no associated data')

        # Retrieve properties for verification of Glance image signature
        verifier = None
        if CONF.glance.verify_glance_signatures:
            image_meta_dict = self.show(context,
                                        image_id,
                                        include_locations=False)
            image_meta = objects.ImageMeta.from_dict(image_meta_dict)
            img_signature = image_meta.properties.get('img_signature')
            img_sig_hash_method = image_meta.properties.get(
                'img_signature_hash_method')
            img_sig_cert_uuid = image_meta.properties.get(
                'img_signature_certificate_uuid')
            img_sig_key_type = image_meta.properties.get(
                'img_signature_key_type')
            try:
                verifier = signature_utils.get_verifier(
                    context=context,
                    img_signature_certificate_uuid=img_sig_cert_uuid,
                    img_signature_hash_method=img_sig_hash_method,
                    img_signature=img_signature,
                    img_signature_key_type=img_sig_key_type,
                )
            except cursive_exception.SignatureVerificationError:
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        'Image signature verification failed '
                        'for image: %s', image_id)

        close_file = False
        if data is None and dst_path:
            data = open(dst_path, 'wb')
            close_file = True

        if data is None:

            # Perform image signature verification
            if verifier:
                try:
                    for chunk in image_chunks:
                        verifier.update(chunk)
                    verifier.verify()

                    LOG.info(
                        'Image signature verification succeeded '
                        'for image: %s', image_id)

                except cryptography.exceptions.InvalidSignature:
                    with excutils.save_and_reraise_exception():
                        LOG.error(
                            'Image signature verification failed '
                            'for image: %s', image_id)
            return image_chunks
        else:
            try:
                for chunk in image_chunks:
                    if verifier:
                        verifier.update(chunk)
                    data.write(chunk)
                if verifier:
                    verifier.verify()
                    LOG.info(
                        'Image signature verification succeeded '
                        'for image %s', image_id)
            except cryptography.exceptions.InvalidSignature:
                data.truncate(0)
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        'Image signature verification failed '
                        'for image: %s', image_id)
            except Exception as ex:
                with excutils.save_and_reraise_exception():
                    LOG.error("Error writing to %(path)s: %(exception)s", {
                        'path': dst_path,
                        'exception': ex
                    })
            finally:
                if close_file:
                    # Ensure that the data is pushed all the way down to
                    # persistent storage. This ensures that in the event of a
                    # subsequent host crash we don't have running instances
                    # using a corrupt backing file.
                    data.flush()
                    self._safe_fsync(data)
                    data.close()
Exemplo n.º 13
0
Arquivo: glance.py Projeto: sapcc/nova
    def download(self, context, image_id, data=None, dst_path=None):
        """Calls out to Glance for data and writes data."""
        if CONF.glance.allowed_direct_url_schemes and dst_path is not None:
            image = self.show(context, image_id, include_locations=True)
            for entry in image.get('locations', []):
                loc_url = entry['url']
                loc_meta = entry['metadata']
                o = urlparse.urlparse(loc_url)
                xfer_mod = self._get_transfer_module(o.scheme)
                if xfer_mod:
                    try:
                        xfer_mod.download(context, o, dst_path, loc_meta)
                        LOG.info("Successfully transferred using %s", o.scheme)
                        return
                    except Exception:
                        LOG.exception("Download image error")

        try:
            image_chunks = self._client.call(context, 2, 'data', image_id)
        except Exception:
            _reraise_translated_image_exception(image_id)

        # Retrieve properties for verification of Glance image signature
        verifier = None
        if CONF.glance.verify_glance_signatures:
            image_meta_dict = self.show(context, image_id,
                                        include_locations=False)
            image_meta = objects.ImageMeta.from_dict(image_meta_dict)
            img_signature = image_meta.properties.get('img_signature')
            img_sig_hash_method = image_meta.properties.get(
                'img_signature_hash_method'
            )
            img_sig_cert_uuid = image_meta.properties.get(
                'img_signature_certificate_uuid'
            )
            img_sig_key_type = image_meta.properties.get(
                'img_signature_key_type'
            )
            try:
                verifier = signature_utils.get_verifier(
                    context=context,
                    img_signature_certificate_uuid=img_sig_cert_uuid,
                    img_signature_hash_method=img_sig_hash_method,
                    img_signature=img_signature,
                    img_signature_key_type=img_sig_key_type,
                )
            except cursive_exception.SignatureVerificationError:
                with excutils.save_and_reraise_exception():
                    LOG.error('Image signature verification failed '
                              'for image: %s', image_id)

        close_file = False
        if data is None and dst_path:
            data = open(dst_path, 'wb')
            close_file = True

        if data is None:

            # Perform image signature verification
            if verifier:
                try:
                    for chunk in image_chunks:
                        verifier.update(chunk)
                    verifier.verify()

                    LOG.info('Image signature verification succeeded '
                             'for image: %s', image_id)

                except cryptography.exceptions.InvalidSignature:
                    with excutils.save_and_reraise_exception():
                        LOG.error('Image signature verification failed '
                                  'for image: %s', image_id)
            return image_chunks
        else:
            try:
                for chunk in image_chunks:
                    if verifier:
                        verifier.update(chunk)
                    data.write(chunk)
                if verifier:
                    verifier.verify()
                    LOG.info('Image signature verification succeeded '
                             'for image %s', image_id)
            except cryptography.exceptions.InvalidSignature:
                data.truncate(0)
                with excutils.save_and_reraise_exception():
                    LOG.error('Image signature verification failed '
                              'for image: %s', image_id)
            except Exception as ex:
                with excutils.save_and_reraise_exception():
                    LOG.error("Error writing to %(path)s: %(exception)s",
                              {'path': dst_path, 'exception': ex})
            finally:
                if close_file:
                    # Ensure that the data is pushed all the way down to
                    # persistent storage. This ensures that in the event of a
                    # subsequent host crash we don't have running instances
                    # using a corrupt backing file.
                    data.flush()
                    os.fsync(data.fileno())
                    data.close()
Exemplo n.º 14
0
    def download(self, context, image_id, data=None, dst_path=None):
        """Calls out to Glance for data and writes data."""
        if CONF.glance.allowed_direct_url_schemes and dst_path is not None:
            image = self.show(context, image_id, include_locations=True)
            for entry in image.get('locations', []):
                loc_url = entry['url']
                loc_meta = entry['metadata']
                o = urlparse.urlparse(loc_url)
                xfer_mod = self._get_transfer_module(o.scheme)
                if xfer_mod:
                    try:
                        xfer_mod.download(context, o, dst_path, loc_meta)
                        LOG.info("Successfully transferred using %s", o.scheme)
                        return
                    except Exception:
                        LOG.exception("Download image error")

        try:
            image_chunks = self._client.call(context, 2, 'data', image_id)
        except Exception:
            _reraise_translated_image_exception(image_id)

        # Retrieve properties for verification of Glance image signature
        verifier = None
        if CONF.glance.verify_glance_signatures:
            image_meta_dict = self.show(context, image_id,
                                        include_locations=False)
            image_meta = objects.ImageMeta.from_dict(image_meta_dict)
            img_signature = image_meta.properties.get('img_signature')
            img_sig_hash_method = image_meta.properties.get(
                'img_signature_hash_method'
            )
            img_sig_cert_uuid = image_meta.properties.get(
                'img_signature_certificate_uuid'
            )
            img_sig_key_type = image_meta.properties.get(
                'img_signature_key_type'
            )
            try:
                verifier = signature_utils.get_verifier(
                    context=context,
                    img_signature_certificate_uuid=img_sig_cert_uuid,
                    img_signature_hash_method=img_sig_hash_method,
                    img_signature=img_signature,
                    img_signature_key_type=img_sig_key_type,
                )
            except cursive_exception.SignatureVerificationError:
                with excutils.save_and_reraise_exception():
                    LOG.error('Image signature verification failed '
                              'for image: %s', image_id)

        close_file = False
        if data is None and dst_path:
            data = open(dst_path, 'wb')
            close_file = True

        if data is None:

            # Perform image signature verification
            if verifier:
                try:
                    for chunk in image_chunks:
                        verifier.update(chunk)
                    verifier.verify()

                    LOG.info('Image signature verification succeeded '
                             'for image: %s', image_id)

                except cryptography.exceptions.InvalidSignature:
                    with excutils.save_and_reraise_exception():
                        LOG.error('Image signature verification failed '
                                  'for image: %s', image_id)
            return image_chunks
        else:
            # WRS: offload image download to another thread to reduce chances
            #      of nova-compute getting stuck on disk IO
            def write_image(data, image_chunks, close_file, verifier):
                try:
                    for chunk in image_chunks:
                        if verifier:
                            verifier.update(chunk)
                        data.write(chunk)
                        # Without this periodic tasks get delayed
                        time.sleep(0)
                    if verifier:
                        verifier.verify()
                        LOG.info('Image signature verification succeeded '
                                 'for image %s', image_id)
                except cryptography.exceptions.InvalidSignature:
                    data.truncate(0)
                    with excutils.save_and_reraise_exception():
                        LOG.error('Image signature verification failed '
                                  'for image: %s', image_id)
                except Exception as ex:
                    with excutils.save_and_reraise_exception():
                        LOG.error("Error writing to %(path)s: "
                                  "%(exception)s",
                                  {'path': dst_path, 'exception': ex})
                finally:
                    if close_file:
                        # Ensure that the data is pushed all the way down to
                        # persistent storage. This ensures that in the event
                        # of a subsequent host crash we don't have running
                        # instances using a corrupt backing file.
                        data.flush()
                        os.fsync(data.fileno())
                        data.close()
            tpool.execute(write_image, data, image_chunks, close_file,
                          verifier)