Предварительно подписанные URL-адреса в хранилище объектов Vultr с использованием boto3

#python #django #amazon-s3 #pre-signed-url #vultr

Вопрос:

Я довольно долго работал с Vultr, и когда мне захотелось сохранить некоторые медиафайлы, я подумал о S3 AWS, а Vultr предоставляет совместимый с S3 сервис (Хранилище объектов). Я могу использовать интерфейс командной строки s3cmd для работы со службой, и они указывают на использование boto3 для взаимодействия со службой S3. Я хотел, чтобы мои объекты имели подписанные URL-адреса, но я считаю, что у amazonaws.com boto3 есть имя хоста в качестве константы где-то в коде, и это нельзя изменить из конфигураций, как показано ниже:

 import logging
from django.conf import settings
import boto3
from botocore.exceptions import ClientError
from premarket.models import PreMarket
from .models import SupervisorLogs


class Supervisor():

    def __init__(self) -> None:
        self.bucket_name = settings.BUCKET_NAME
        self.link_expiration = settings.ONE_WEEK
        self.queryset = PreMarket.objects.all()
        # Generate a presigned URL for the S3 object
        self.s3_configs_object = settings.AWS_S3_CREDS
        self.s3_client = boto3.client('s3', **self.s3_configs_object)

    def sign_objects(self):
        for obj in self.queryset:
            try:
                presigned_url = self.create_presigned_url(obj.video_url)
                obj.presigned_url = presigned_url
                obj.save()
            except Exception as e:
                self.supervisor_logs(level="ERROR", message=e, description=e)
                logging.error(e)
        self.supervisor_logs(level="COMPLETE",
                            message="Object URL signing has completed",
                            description="Object URL signing has completed")

    def create_presigned_url(self, object_name):
        """Generate a presigned URL to share an S3 object

        :param object_name: string
        :return: Presigned URL as string. If error, returns None.
        """

        try:
            response = self.s3_client.generate_presigned_url('get_object',
                                                            Params={
                                                                'Bucket': self.bucket_name,
                                                                'Key': object_name},
                                                            ExpiresIn=self.link_expiration)
        except ClientError as e:
            logging.error(e)
            self.supervisor_logs(level="ERROR", message=e, description=e)
            return None

        # The response contains the presigned URL
        return response

    def supervisor_logs(self, message: str = None, level: str = None, description: str = None) -> None:
        SupervisorLogs.objects.create(
            message=message, level=level, description=description)
 

Учетные данные AWS S3:

 AWS_S3_CREDS = {
    'aws_access_key_id': AWS_ACCESS_KEY_ID,
    'aws_secret_access_key': AWS_SECRET_ACCESS_KEY,
    'region_name': 'ewr',
    'endpoint_url': AWS_BUCKET_HOSTNAME
}
 

Но Vultr предоставляет другое имя хоста, как в:

ewr1.vultrobjects.com

Пример объекта:

https://ewr1.vultrobjects.com/my-s3-bucket/basics/video.mp4

Попытка подписать его кодом, который я написал выше, приводит к следующему (что не работает):

 https://ewr1.vultrobjects.com/my-s3-bucket/https://ewr1.vultrobjects.com/my-s3-bucket/basics/video.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256amp;X-Amz-Credential=AccessKeyHere/20210706/ewr/s3/aws4_requestamp;X-Amz-Date=20210706T133319Zamp;X-Amz-Expires=604800amp;X-Amz-SignedHeaders=hostamp;X-Amz-Signature=bb7da3183691052ea5b25218ab1fb876fec7053a2b045957fec12cd131393a19
 

У которого на первый взгляд есть несколько проблем: URL-адрес недействителен, так как кажется, что он объединяется, и даже если я вручную удалю его только для целей тестирования, он все равно не будет работать.

Vultr не предоставляет никаких документов по этому поводу, как сообщила мне их служба поддержки. На данный момент мне интересно, как я могу получить доступ к объектам в их нынешнем виде (без предварительно подписанных URL-адресов), используя только ключ доступа, который все равно не будет работать.

Я не знаю, чего мне не хватает, и я надеюсь, что у кого-то есть некоторый опыт в этом раньше, так как я ничего не мог найти за последние пару дней?

Спасибо вам за вашу помощь.

Ответ №1:

В приведенном выше коде вы используете URL-адрес:

  presigned_url = self.create_presigned_url(obj.video_url)
 

Вы пытались использовать местоположение s3 для создания URL-адреса? Судя по всему, obj.video_url является https://ewr1…… где URL-адрес s3 будет s3:// и может быть лучше использован используемой вами библиотекой.

Кроме того, прежде чем выполнять весь цикл для каждого URL-адреса, я бы попробовал что-нибудь ручное, например:

 presigned_url = self.create_presigned_url('s3://ewr1.vultrobjects.com/my-s3-bucket/basics/video.mp4')
 

Посмотрим, доставит ли это тебе хоть какую-то радость.

Комментарии:

1. Я удалил свое хранилище объектов Vultur, так как поддержка была не очень полезной, но так как я получил ответ, я настрою тестовый и попытаюсь посмотреть, сработает ли это, надеюсь, это поможет кому-нибудь еще в будущем. Спасибо вам за ваш ответ. Вернусь с результатами.

2. Я не уверен в плагине boto3 и языке, который вы используете выше, но я знаю, что библиотеки PHP, которые предлагает Vultr, имеют отличную интеграцию с s3, и в них много документов о них. На самом деле, вы можете использовать встроенный пакет AWS S3 PHP Composer, который делает именно то, что вы хотите.