Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CloudFront settings to OPTIONS parameter of STORAGES in Django 4.2 #1271

Closed
PetrDlouhy opened this issue Aug 3, 2023 · 2 comments
Closed

Comments

@PetrDlouhy
Copy link
Contributor

With the introduction of Django 4.2, the storages.backends.s3boto3.S3Boto3Storage backend now accepts additional options for configuration. However, I noticed that there are currently no options to configure CloudFront settings directly through these storage options.

Currently it is possible to set AWS_CLOUDFRONT_KEY_ID and AWS_CLOUDFRONT_KEY which would have effect to all storages.

In my specific use case, I require the cloudfront_key_id and cloudfront_key to be set for the CloudFrontSigner. I used to configure this manually in the constructor of my custom S3Boto3Storage subclass, but I think it would be beneficial to have this as part of the official library.

I propose to extend the options for S3Boto3Storage to accept cloudfront_key_id and cloudfront_key. If these options are provided, S3Boto3Storage would create and store an instance of CloudFrontSigner with these credentials.

Example:

'staticfiles': {
    'BACKEND': 'storages.backends.s3boto3.S3Boto3Storage',
    'OPTIONS': {
        'access_key': 'xxxxx',
        'secret_key': 'xxxxx',
        'bucket_name': 'my_bucket',
        'custom_domain': None,
        'default_acl': 'public-read',
        'endpoint_url': 'https://s3.amazonaws.com/my_bucket',
        'location': 'static',
        'region_name': 'us-west-2',
        'cloudfront_key_id': 'my_cloudfront_key_id',
        'cloudfront_key': 'my_cloudfront_key',
    }
}

I would appreciate it if you could consider adding this feature to the library. It would allow a more flexible configuration of S3Boto3Storage and CloudFront in Django 4.2 and later versions. I am willing to contribute to this feature if needed.

@PetrDlouhy
Copy link
Contributor Author

For now I am overriding the S3Boto3Storage like this:

from botocore.signers import CloudFrontSigner
from storages.backends.s3boto3 import S3Boto3Storage


class CloudFrontS3Boto3Storage(S3Boto3Storage):
    def __init__(self, *args, **kwargs):
        cloudfront_key_id = kwargs.pop("cloudfront_key_id", None)
        cloudfront_key = kwargs.pop("cloudfront_key", None)

        super().__init__(*args, **kwargs)

        if cloudfront_key_id and cloudfront_key:
            self.cloudfront_signer = CloudFrontSigner(
                cloudfront_key_id, lambda message: self.rsa_signer(cloudfront_key, message)
            )

    def rsa_signer(self, cloudfront_key, message):
        from cryptography.hazmat.backends import default_backend
        from cryptography.hazmat.primitives import hashes, serialization
        from cryptography.hazmat.primitives.asymmetric import padding

        private_key = serialization.load_pem_private_key(
            cloudfront_key, password=None, backend=default_backend()
        )
        signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1())
        signer.update(message)
        return signer.finalize()

    @property
    def cloudfront_key_id(self):
        return self._settings.get("cloudfront_key_id")

    @property
    def cloudfront_key(self):
        return self._settings.get("cloudfront_key")

@jschneier
Copy link
Owner

Yes I will definitely take a PR to add support for that feature to the library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants