Kowalski
Kowalski

Reputation: 17

Django + S3 Signature expiration

Should my django-storage instance be storing the S3 signature in the database along with the image name?

If so how do you regenerate a new key on each request assuming the old request expiration is already past?

models.py

def user_directory_path(self, filename):
    return 'profile/user_{0}/images/profile/{1}'.format(self.user.id, filename)
    ...
    ...
    user_image = models.ImageField(upload_to=user_directory_path, storage=PrivateMediaStorage(), blank=True)

storage_backends.py

class PrivateMediaStorage(S3Boto3Storage):
    location = 'private'
    default_acl = 'private'
    file_overwrite = False
    custom_domain = False

Sorry new to Django, want to make sure my logic is correct.

Upvotes: 0

Views: 1031

Answers (1)

markwalker_
markwalker_

Reputation: 12859

No you don't want it to be storing that kind of data because then you'll lose access to the file. I've had this exact problem in the past.

The signature should be added by the system at the time the file needs to be accessed.

These are my settings, which work without saving the signature, for a private S3 storage bucket;

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

S3_BUCKET = env('S3_BUCKET', 'my_bucket')
S3_SUB_BUCKET = env('S3_SUB_BUCKET', 'dev')
S3_REGION = env('S3_REGION', 'eu-west-2')
AWS_REGION = env('AWS_REGION', 'eu-west-2')
S3_USE_SIGV4 = True

AWS_S3_PATH_SEPARATOR = '/'
AWS_STORAGE_BUCKET_NAME = S3_BUCKET
AWS_S3_HOST = f'{S3_BUCKET}.s3.{S3_REGION}.amazonaws.com'
AWS_S3_SIGNATURE_VERSION = 's3v4'
AWS_S3_ADDRESSING_STYLE = 'virtual'
AWS_DEFAULT_ACL = 'private'
AWS_LOCATION = S3_SUB_BUCKET
AWS_S3_FILE_OVERWRITE = False

Some of the settings you define in your custom storage class I have in the settings which saves sub-classing.

When using a file/image field I then just do;

photo = models.ImageField(
    verbose_name=_('photo'),
    upload_to='photos',
    default=None,
    blank=True,
    null=True,
)

And on fields where my upload_to is a callable I have these methods;

def uuid():
    """ Generate a UUID """
    return urlsafe_b64encode(uuid4().bytes).decode("ascii").rstrip("=")


def upload_path(instance, filename):
    """ Upload to path with UUID """
    return "{uuid}/{file}".format(uuid=uuid(), file=filename)

The docs for things like AWS_S3_ADDRESSING_STYLE aren't great, but that's one I missed for a while & it lead to things being stored in unexpected locations within my buckets. I think I was seeing <bucket>/<bucket>/<path_to_file type issues without that setting.

Upvotes: 1

Related Questions